Remove bytecode mode from the VM
Change-Id: Ief167b7ffc128105a03cc225ab750234c9a6a7a0 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/169147 Commit-Queue: Alexander Markov <alexmarkov@google.com> Reviewed-by: Régis Crelier <regis@google.com> Reviewed-by: Ryan Macnak <rmacnak@google.com>
This commit is contained in:
committed by
commit-bot@chromium.org
parent
c877d5bf3e
commit
7588ed86de
@@ -732,10 +732,10 @@ Future _processLoadRequest(request) async {
|
||||
final bool enableAsserts = request[9];
|
||||
final List<String> experimentalFlags =
|
||||
request[10] != null ? request[10].cast<String>() : null;
|
||||
final String packageConfig = request[12];
|
||||
final String multirootFilepaths = request[13];
|
||||
final String multirootScheme = request[14];
|
||||
final String workingDirectory = request[15];
|
||||
final String packageConfig = request[11];
|
||||
final String multirootFilepaths = request[12];
|
||||
final String multirootScheme = request[13];
|
||||
final String workingDirectory = request[14];
|
||||
|
||||
Uri platformKernelPath = null;
|
||||
List<int> platformKernel = null;
|
||||
@@ -981,7 +981,6 @@ Future trainInternal(String scriptUri, String platformKernelPath) async {
|
||||
false /* suppress warnings */,
|
||||
false /* enable asserts */,
|
||||
null /* experimental_flags */,
|
||||
null /* unused */,
|
||||
null /* package_config */,
|
||||
null /* multirootFilepaths */,
|
||||
null /* multirootScheme */,
|
||||
|
||||
@@ -125,7 +125,6 @@ static const char* kSnapshotKindNames[] = {
|
||||
V(compile_all, compile_all) \
|
||||
V(help, help) \
|
||||
V(obfuscate, obfuscate) \
|
||||
V(read_all_bytecode, read_all_bytecode) \
|
||||
V(strip, strip) \
|
||||
V(verbose, verbose) \
|
||||
V(version, version)
|
||||
@@ -390,13 +389,6 @@ static void MaybeLoadExtraInputs(const CommandLineOptions& inputs) {
|
||||
}
|
||||
|
||||
static void MaybeLoadCode() {
|
||||
if (read_all_bytecode &&
|
||||
((snapshot_kind == kCore) || (snapshot_kind == kCoreJIT) ||
|
||||
(snapshot_kind == kApp) || (snapshot_kind == kAppJIT))) {
|
||||
Dart_Handle result = Dart_ReadAllBytecode();
|
||||
CHECK_RESULT(result);
|
||||
}
|
||||
|
||||
if (compile_all &&
|
||||
((snapshot_kind == kCoreJIT) || (snapshot_kind == kAppJIT))) {
|
||||
Dart_Handle result = Dart_CompileAll();
|
||||
|
||||
@@ -178,8 +178,6 @@ DART_EXPORT bool Dart_CloseNativePort(Dart_Port native_port_id);
|
||||
*/
|
||||
DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle Dart_CompileAll();
|
||||
|
||||
DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle Dart_ReadAllBytecode();
|
||||
|
||||
/**
|
||||
* Finalizes all classes.
|
||||
*/
|
||||
|
||||
+13
-17
@@ -31,25 +31,21 @@ static ScriptPtr FindScript(DartFrameIterator* iterator) {
|
||||
ASSERT(!assert_error_class.IsNull());
|
||||
bool hit_assertion_error = false;
|
||||
for (; stack_frame != NULL; stack_frame = iterator->NextFrame()) {
|
||||
if (stack_frame->is_interpreted()) {
|
||||
func = stack_frame->LookupDartFunction();
|
||||
} else {
|
||||
code = stack_frame->LookupDartCode();
|
||||
if (code.is_optimized()) {
|
||||
InlinedFunctionsIterator inlined_iterator(code, stack_frame->pc());
|
||||
while (!inlined_iterator.Done()) {
|
||||
func = inlined_iterator.function();
|
||||
if (hit_assertion_error) {
|
||||
return func.script();
|
||||
}
|
||||
ASSERT(!hit_assertion_error);
|
||||
hit_assertion_error = (func.Owner() == assert_error_class.raw());
|
||||
inlined_iterator.Advance();
|
||||
code = stack_frame->LookupDartCode();
|
||||
if (code.is_optimized()) {
|
||||
InlinedFunctionsIterator inlined_iterator(code, stack_frame->pc());
|
||||
while (!inlined_iterator.Done()) {
|
||||
func = inlined_iterator.function();
|
||||
if (hit_assertion_error) {
|
||||
return func.script();
|
||||
}
|
||||
continue;
|
||||
} else {
|
||||
func = code.function();
|
||||
ASSERT(!hit_assertion_error);
|
||||
hit_assertion_error = (func.Owner() == assert_error_class.raw());
|
||||
inlined_iterator.Advance();
|
||||
}
|
||||
continue;
|
||||
} else {
|
||||
func = code.function();
|
||||
}
|
||||
ASSERT(!func.IsNull());
|
||||
if (hit_assertion_error) {
|
||||
|
||||
+1
-28
@@ -306,36 +306,9 @@ DEFINE_NATIVE_ENTRY(Ffi_sizeOf, 1, 0) {
|
||||
return Integer::New(SizeOf(type_arg, zone));
|
||||
}
|
||||
|
||||
// Static invocations to this method are translated directly in streaming FGB
|
||||
// and bytecode FGB. However, we can still reach this entrypoint in the bytecode
|
||||
// interpreter.
|
||||
// Static invocations to this method are translated directly in streaming FGB.
|
||||
DEFINE_NATIVE_ENTRY(Ffi_asFunctionInternal, 2, 1) {
|
||||
#if defined(DART_PRECOMPILED_RUNTIME) || defined(DART_PRECOMPILER)
|
||||
UNREACHABLE();
|
||||
#else
|
||||
ASSERT(FLAG_enable_interpreter);
|
||||
|
||||
GET_NON_NULL_NATIVE_ARGUMENT(Pointer, pointer, arguments->NativeArgAt(0));
|
||||
GET_NATIVE_TYPE_ARGUMENT(dart_type, arguments->NativeTypeArgAt(0));
|
||||
GET_NATIVE_TYPE_ARGUMENT(native_type, arguments->NativeTypeArgAt(1));
|
||||
|
||||
const Function& dart_signature =
|
||||
Function::Handle(zone, Type::Cast(dart_type).signature());
|
||||
const Function& native_signature =
|
||||
Function::Handle(zone, Type::Cast(native_type).signature());
|
||||
const Function& function = Function::Handle(
|
||||
compiler::ffi::TrampolineFunction(dart_signature, native_signature));
|
||||
|
||||
// Set the c function pointer in the context of the closure rather than in
|
||||
// the function so that we can reuse the function for each c function with
|
||||
// the same signature.
|
||||
const Context& context = Context::Handle(Context::New(1));
|
||||
context.SetAt(0, pointer);
|
||||
|
||||
return Closure::New(Object::null_type_arguments(),
|
||||
Object::null_type_arguments(), function, context,
|
||||
Heap::kOld);
|
||||
#endif
|
||||
}
|
||||
|
||||
DEFINE_NATIVE_ENTRY(Ffi_asExternalTypedData, 0, 2) {
|
||||
|
||||
@@ -456,76 +456,6 @@ static InstancePtr CreateLibraryDependencyMirror(Thread* thread,
|
||||
prefix_name, is_import, is_deferred);
|
||||
}
|
||||
|
||||
static GrowableObjectArrayPtr CreateBytecodeLibraryDependencies(
|
||||
Thread* thread,
|
||||
const Library& lib,
|
||||
const Instance& lib_mirror) {
|
||||
ASSERT(lib.is_declared_in_bytecode());
|
||||
|
||||
// Make sure top level class (containing annotations) is fully loaded.
|
||||
lib.EnsureTopLevelClassIsFinalized();
|
||||
|
||||
const auto& deps = GrowableObjectArray::Handle(GrowableObjectArray::New());
|
||||
Array& metadata = Array::Handle(lib.GetExtendedMetadata(lib, 1));
|
||||
if (metadata.Length() == 0) {
|
||||
return deps.raw();
|
||||
}
|
||||
|
||||
// Library has the only element in the extended metadata.
|
||||
metadata ^= metadata.At(0);
|
||||
if (metadata.IsNull()) {
|
||||
return deps.raw();
|
||||
}
|
||||
|
||||
auto& desc = Array::Handle();
|
||||
auto& target_uri = String::Handle();
|
||||
auto& importee = Library::Handle();
|
||||
auto& is_export = Bool::Handle();
|
||||
auto& is_deferred = Bool::Handle();
|
||||
auto& prefix_name = String::Handle();
|
||||
auto& show_names = Array::Handle();
|
||||
auto& hide_names = Array::Handle();
|
||||
auto& dep_metadata = Instance::Handle();
|
||||
auto& dep = Instance::Handle();
|
||||
const auto& no_prefix = LibraryPrefix::Handle();
|
||||
|
||||
for (intptr_t i = 0, n = metadata.Length(); i < n; ++i) {
|
||||
desc ^= metadata.At(i);
|
||||
// Each dependency is represented as an array with the following layout:
|
||||
// [0] = target library URI (String)
|
||||
// [1] = is_export (bool)
|
||||
// [2] = is_deferred (bool)
|
||||
// [3] = prefix (String or null)
|
||||
// [4] = list of show names (List<String>)
|
||||
// [5] = list of hide names (List<String>)
|
||||
// [6] = annotations
|
||||
// The library dependencies are encoded by getLibraryAnnotations(),
|
||||
// pkg/vm/lib/bytecode/gen_bytecode.dart.
|
||||
target_uri ^= desc.At(0);
|
||||
is_export ^= desc.At(1);
|
||||
is_deferred ^= desc.At(2);
|
||||
prefix_name ^= desc.At(3);
|
||||
show_names ^= desc.At(4);
|
||||
hide_names ^= desc.At(5);
|
||||
dep_metadata ^= desc.At(6);
|
||||
|
||||
importee = Library::LookupLibrary(thread, target_uri);
|
||||
if (importee.IsNull()) {
|
||||
continue;
|
||||
}
|
||||
ASSERT(importee.Loaded());
|
||||
|
||||
dep = CreateLibraryDependencyMirror(
|
||||
thread, lib_mirror, importee, show_names, hide_names, dep_metadata,
|
||||
no_prefix, prefix_name, !is_export.value(), is_deferred.value());
|
||||
if (!dep.IsNull()) {
|
||||
deps.Add(dep);
|
||||
}
|
||||
}
|
||||
|
||||
return deps.raw();
|
||||
}
|
||||
|
||||
DEFINE_NATIVE_ENTRY(LibraryMirror_fromPrefix, 0, 1) {
|
||||
GET_NON_NULL_NATIVE_ARGUMENT(LibraryPrefix, prefix,
|
||||
arguments->NativeArgAt(0));
|
||||
@@ -541,10 +471,6 @@ DEFINE_NATIVE_ENTRY(LibraryMirror_libraryDependencies, 0, 2) {
|
||||
GET_NON_NULL_NATIVE_ARGUMENT(MirrorReference, ref, arguments->NativeArgAt(1));
|
||||
const Library& lib = Library::Handle(ref.GetLibraryReferent());
|
||||
|
||||
if (lib.is_declared_in_bytecode()) {
|
||||
return CreateBytecodeLibraryDependencies(thread, lib, lib_mirror);
|
||||
}
|
||||
|
||||
Array& ports = Array::Handle();
|
||||
Namespace& ns = Namespace::Handle();
|
||||
Instance& dep = Instance::Handle();
|
||||
|
||||
@@ -141,7 +141,7 @@ DEFINE_NATIVE_ENTRY(StackTrace_asyncStackTraceHelper, 0, 1) {
|
||||
if (!FLAG_causal_async_stacks) {
|
||||
// If causal async stacks are not enabled we should recognize this method
|
||||
// and never call to the NOP runtime.
|
||||
// See kernel_to_il.cc/bytecode_reader.cc/interpreter.cc.
|
||||
// See kernel_to_il.cc.
|
||||
UNREACHABLE();
|
||||
}
|
||||
#if !defined(PRODUCT)
|
||||
@@ -180,7 +180,6 @@ static void AppendFrames(const GrowableObjectArray& code_list,
|
||||
StackFrame* frame = frames.NextFrame();
|
||||
ASSERT(frame != NULL); // We expect to find a dart invocation frame.
|
||||
Code& code = Code::Handle(zone);
|
||||
Bytecode& bytecode = Bytecode::Handle(zone);
|
||||
Smi& offset = Smi::Handle(zone);
|
||||
for (; frame != NULL; frame = frames.NextFrame()) {
|
||||
if (!frame->IsDartFrame()) {
|
||||
@@ -191,18 +190,9 @@ static void AppendFrames(const GrowableObjectArray& code_list,
|
||||
continue;
|
||||
}
|
||||
|
||||
if (frame->is_interpreted()) {
|
||||
bytecode = frame->LookupDartBytecode();
|
||||
if (bytecode.function() == Function::null()) {
|
||||
continue;
|
||||
}
|
||||
offset = Smi::New(frame->pc() - bytecode.PayloadStart());
|
||||
code_list.Add(bytecode);
|
||||
} else {
|
||||
code = frame->LookupDartCode();
|
||||
offset = Smi::New(frame->pc() - code.PayloadStart());
|
||||
code_list.Add(code);
|
||||
}
|
||||
code = frame->LookupDartCode();
|
||||
offset = Smi::New(frame->pc() - code.PayloadStart());
|
||||
code_list.Add(code);
|
||||
pc_offset_list.Add(offset);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,7 +178,7 @@ DEFINE_NATIVE_ENTRY(TypedData_setRange, 0, 7) {
|
||||
}
|
||||
|
||||
// Native methods for typed data allocation are recognized and implemented
|
||||
// both in FlowGraphBuilder::BuildGraphOfRecognizedMethod and interpreter.
|
||||
// in FlowGraphBuilder::BuildGraphOfRecognizedMethod.
|
||||
// These bodies exist only to assert that they are not used.
|
||||
#define TYPED_DATA_NEW(name) \
|
||||
DEFINE_NATIVE_ENTRY(TypedData_##name##_new, 0, 2) { \
|
||||
|
||||
@@ -277,21 +277,6 @@ class FunctionViewElement extends CustomElement implements Renderable {
|
||||
]
|
||||
]);
|
||||
}
|
||||
if (_function.bytecode != null) {
|
||||
members.add(new DivElement()
|
||||
..classes = ['memberItem']
|
||||
..children = <Element>[
|
||||
new DivElement()
|
||||
..classes = ['memberName']
|
||||
..text = 'bytecode',
|
||||
new DivElement()
|
||||
..classes = ['memberName']
|
||||
..children = <Element>[
|
||||
new CodeRefElement(_isolate, _function.bytecode!, queue: _r.queue)
|
||||
.element,
|
||||
]
|
||||
]);
|
||||
}
|
||||
members.add(new DivElement()
|
||||
..classes = ['memberItem']
|
||||
..text = ' ');
|
||||
|
||||
@@ -87,9 +87,6 @@ abstract class ServiceFunction extends Object implements FunctionRef {
|
||||
/// [optional]
|
||||
CodeRef? get unoptimizedCode;
|
||||
|
||||
/// [optional]
|
||||
CodeRef? get bytecode;
|
||||
|
||||
/// [optional]
|
||||
FieldRef? get field;
|
||||
int? get usageCounter;
|
||||
|
||||
@@ -3165,7 +3165,6 @@ class ServiceFunction extends HeapObject implements M.ServiceFunction {
|
||||
SourceLocation? location;
|
||||
Code? code;
|
||||
Code? unoptimizedCode;
|
||||
Code? bytecode;
|
||||
bool? isOptimizable;
|
||||
bool? isInlinable;
|
||||
bool? hasIntrinsic;
|
||||
@@ -3224,7 +3223,6 @@ class ServiceFunction extends HeapObject implements M.ServiceFunction {
|
||||
isInlinable = map['_inlinable'];
|
||||
isRecognized = map['_recognized'];
|
||||
unoptimizedCode = map['_unoptimizedCode'];
|
||||
bytecode = map['_bytecode'];
|
||||
deoptimizations = map['_deoptimizations'];
|
||||
usageCounter = map['_usageCounter'];
|
||||
icDataArray = map['_icDataArray'];
|
||||
|
||||
@@ -577,7 +577,7 @@ IsolateTest checkRecordedStops(
|
||||
expectedStops = removeAdjacentDuplicates(expectedStops);
|
||||
}
|
||||
|
||||
// Single stepping in interpreted bytecode may record extra stops.
|
||||
// Single stepping may record extra stops.
|
||||
// Allow the extra ones as long as the expected ones are recorded.
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
|
||||
@@ -276,21 +276,6 @@ class FunctionViewElement extends CustomElement implements Renderable {
|
||||
]
|
||||
]);
|
||||
}
|
||||
if (_function.bytecode != null) {
|
||||
members.add(new DivElement()
|
||||
..classes = ['memberItem']
|
||||
..children = <Element>[
|
||||
new DivElement()
|
||||
..classes = ['memberName']
|
||||
..text = 'bytecode',
|
||||
new DivElement()
|
||||
..classes = ['memberName']
|
||||
..children = <Element>[
|
||||
new CodeRefElement(_isolate, _function.bytecode, queue: _r.queue)
|
||||
.element,
|
||||
]
|
||||
]);
|
||||
}
|
||||
members.add(new DivElement()
|
||||
..classes = ['memberItem']
|
||||
..text = ' ');
|
||||
|
||||
@@ -87,9 +87,6 @@ abstract class ServiceFunction extends Object implements FunctionRef {
|
||||
/// [optional]
|
||||
CodeRef get unoptimizedCode;
|
||||
|
||||
/// [optional]
|
||||
CodeRef get bytecode;
|
||||
|
||||
/// [optional]
|
||||
FieldRef get field;
|
||||
int get usageCounter;
|
||||
|
||||
@@ -3178,7 +3178,6 @@ class ServiceFunction extends HeapObject implements M.ServiceFunction {
|
||||
SourceLocation location;
|
||||
Code code;
|
||||
Code unoptimizedCode;
|
||||
Code bytecode;
|
||||
bool isOptimizable;
|
||||
bool isInlinable;
|
||||
bool hasIntrinsic;
|
||||
@@ -3237,7 +3236,6 @@ class ServiceFunction extends HeapObject implements M.ServiceFunction {
|
||||
isInlinable = map['_inlinable'];
|
||||
isRecognized = map['_recognized'];
|
||||
unoptimizedCode = map['_unoptimizedCode'];
|
||||
bytecode = map['_bytecode'];
|
||||
deoptimizations = map['_deoptimizations'];
|
||||
usageCounter = map['_usageCounter'];
|
||||
icDataArray = map['_icDataArray'];
|
||||
|
||||
@@ -577,7 +577,7 @@ IsolateTest checkRecordedStops(
|
||||
expectedStops = removeAdjacentDuplicates(expectedStops);
|
||||
}
|
||||
|
||||
// Single stepping in interpreted bytecode may record extra stops.
|
||||
// Single stepping may record extra stops.
|
||||
// Allow the extra ones as long as the expected ones are recorded.
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
|
||||
@@ -28,7 +28,7 @@ class TargetCalls {
|
||||
int unchecked = 0;
|
||||
|
||||
// Leave a little room for some cases which always use the checked entry, like
|
||||
// lazy compile stub or interpreter warm-up.
|
||||
// lazy compile stub.
|
||||
static const int wiggle = 10;
|
||||
|
||||
void expectChecked(int iterations) {
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
// Copyright (c) 2019, 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.
|
||||
//
|
||||
// VMOptions=--optimization-counter-threshold=5 --use-bytecode-compiler
|
||||
//
|
||||
// Test that block merging takes phis into account.
|
||||
//
|
||||
// The problem only reproduces with bytecode compiler (--use-bytecode-compiler)
|
||||
// as bytecode doesn't have backward branches for the redundant loops.
|
||||
// OSR handling code inserts Phi instructions to JoinEntry
|
||||
// even when there is only one predecessor. This results in a flow graph
|
||||
// suitable for block merging with a successor block containing Phi.
|
||||
|
||||
import 'package:expect/expect.dart';
|
||||
|
||||
void testBottomUpInference() {
|
||||
Expect.type<List<int>>([for (; false;) 1]);
|
||||
Expect.type<List<int>>([for (; false;) 1]);
|
||||
Expect.type<List<int>>([for (; false;) 1]);
|
||||
Expect.type<List<int>>([for (; false;) 1]);
|
||||
Expect.type<List<int>>([for (; false;) 1]);
|
||||
Expect.type<List<int>>([for (; false;) 1]);
|
||||
Expect.type<List<int>>([for (; false;) 1]);
|
||||
Expect.type<List<int>>([for (; false;) 1]);
|
||||
Expect.type<List<int>>([for (; false;) 1]);
|
||||
Expect.type<List<int>>([for (; false;) 1]);
|
||||
Expect.type<List<int>>([for (; false;) 1]);
|
||||
Expect.type<List<int>>([for (; false;) 1]);
|
||||
Expect.type<List<int>>([for (; false;) 1]);
|
||||
}
|
||||
|
||||
main() {
|
||||
testBottomUpInference();
|
||||
}
|
||||
@@ -28,7 +28,7 @@ class TargetCalls {
|
||||
int unchecked = 0;
|
||||
|
||||
// Leave a little room for some cases which always use the checked entry, like
|
||||
// lazy compile stub or interpreter warm-up.
|
||||
// lazy compile stub.
|
||||
static const int wiggle = 10;
|
||||
|
||||
void expectChecked(int iterations) {
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
// Copyright (c) 2019, 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.
|
||||
//
|
||||
// VMOptions=--optimization-counter-threshold=5 --use-bytecode-compiler
|
||||
//
|
||||
// Test that block merging takes phis into account.
|
||||
//
|
||||
// The problem only reproduces with bytecode compiler (--use-bytecode-compiler)
|
||||
// as bytecode doesn't have backward branches for the redundant loops.
|
||||
// OSR handling code inserts Phi instructions to JoinEntry
|
||||
// even when there is only one predecessor. This results in a flow graph
|
||||
// suitable for block merging with a successor block containing Phi.
|
||||
|
||||
import 'package:expect/expect.dart';
|
||||
|
||||
void testBottomUpInference() {
|
||||
Expect.type<List<int>>([for (; false;) 1]);
|
||||
Expect.type<List<int>>([for (; false;) 1]);
|
||||
Expect.type<List<int>>([for (; false;) 1]);
|
||||
Expect.type<List<int>>([for (; false;) 1]);
|
||||
Expect.type<List<int>>([for (; false;) 1]);
|
||||
Expect.type<List<int>>([for (; false;) 1]);
|
||||
Expect.type<List<int>>([for (; false;) 1]);
|
||||
Expect.type<List<int>>([for (; false;) 1]);
|
||||
Expect.type<List<int>>([for (; false;) 1]);
|
||||
Expect.type<List<int>>([for (; false;) 1]);
|
||||
Expect.type<List<int>>([for (; false;) 1]);
|
||||
Expect.type<List<int>>([for (; false;) 1]);
|
||||
Expect.type<List<int>>([for (; false;) 1]);
|
||||
}
|
||||
|
||||
main() {
|
||||
testBottomUpInference();
|
||||
}
|
||||
@@ -313,7 +313,6 @@ static void StackFrame_accessFrame(Dart_NativeArguments args) {
|
||||
TransitionNativeToVM transition(thread);
|
||||
const int kNumIterations = 100;
|
||||
Code& code = Code::Handle(thread->zone());
|
||||
Bytecode& bytecode = Bytecode::Handle(thread->zone());
|
||||
for (int i = 0; i < kNumIterations; i++) {
|
||||
StackFrameIterator frames(ValidationPolicy::kDontValidateFrames, thread,
|
||||
StackFrameIterator::kNoCrossThreadIteration);
|
||||
@@ -323,13 +322,8 @@ static void StackFrame_accessFrame(Dart_NativeArguments args) {
|
||||
code = frame->LookupDartCode();
|
||||
EXPECT(code.function() == Function::null());
|
||||
} else if (frame->IsDartFrame()) {
|
||||
if (frame->is_interpreted()) {
|
||||
bytecode = frame->LookupDartBytecode();
|
||||
EXPECT(bytecode.function() != Function::null());
|
||||
} else {
|
||||
code = frame->LookupDartCode();
|
||||
EXPECT(code.function() != Function::null());
|
||||
}
|
||||
code = frame->LookupDartCode();
|
||||
EXPECT(code.function() != Function::null());
|
||||
}
|
||||
frame = frames.NextFrame();
|
||||
}
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include "vm/flags.h"
|
||||
#include "vm/hash_table.h"
|
||||
#include "vm/heap/heap.h"
|
||||
#include "vm/interpreter.h"
|
||||
#include "vm/isolate.h"
|
||||
#include "vm/kernel_loader.h"
|
||||
#include "vm/log.h"
|
||||
@@ -198,19 +197,14 @@ bool ClassFinalizer::ProcessPendingClasses() {
|
||||
#if defined(DEBUG)
|
||||
for (intptr_t i = 0; i < class_array.Length(); i++) {
|
||||
cls ^= class_array.At(i);
|
||||
ASSERT(cls.is_declared_in_bytecode() || cls.is_declaration_loaded());
|
||||
ASSERT(cls.is_declaration_loaded());
|
||||
}
|
||||
#endif
|
||||
|
||||
// Finalize types in all classes.
|
||||
for (intptr_t i = 0; i < class_array.Length(); i++) {
|
||||
cls ^= class_array.At(i);
|
||||
if (cls.is_declared_in_bytecode()) {
|
||||
cls.EnsureDeclarationLoaded();
|
||||
ASSERT(cls.is_type_finalized());
|
||||
} else {
|
||||
FinalizeTypesInClass(cls);
|
||||
}
|
||||
FinalizeTypesInClass(cls);
|
||||
}
|
||||
|
||||
// Clear pending classes array.
|
||||
@@ -1118,14 +1112,9 @@ void ClassFinalizer::FinalizeClass(const Class& cls) {
|
||||
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
// If loading from a kernel, make sure that the class is fully loaded.
|
||||
ASSERT(cls.IsTopLevel() || cls.is_declared_in_bytecode() ||
|
||||
(cls.kernel_offset() > 0));
|
||||
ASSERT(cls.IsTopLevel() || (cls.kernel_offset() > 0));
|
||||
if (!cls.is_loaded()) {
|
||||
if (cls.is_declared_in_bytecode()) {
|
||||
kernel::BytecodeReader::FinishClassLoading(cls);
|
||||
} else {
|
||||
kernel::KernelLoader::FinishLoading(cls);
|
||||
}
|
||||
kernel::KernelLoader::FinishLoading(cls);
|
||||
if (cls.is_finalized()) {
|
||||
return;
|
||||
}
|
||||
@@ -1264,7 +1253,7 @@ void ClassFinalizer::AllocateEnumValues(const Class& enum_cls) {
|
||||
ASSERT(!sentinel.IsNull());
|
||||
sentinel.SetStaticValue(enum_value, true);
|
||||
|
||||
ASSERT(enum_cls.is_declared_in_bytecode() || enum_cls.kernel_offset() > 0);
|
||||
ASSERT(enum_cls.kernel_offset() > 0);
|
||||
Error& error = Error::Handle(zone);
|
||||
for (intptr_t i = 0; i < fields.Length(); i++) {
|
||||
field = Field::RawCast(fields.At(i));
|
||||
@@ -1712,14 +1701,6 @@ void ClassFinalizer::ClearAllCode(bool including_nonchanging_cids) {
|
||||
#ifdef DART_PRECOMPILED_RUNTIME
|
||||
UNREACHABLE();
|
||||
#else
|
||||
Thread* mutator_thread = Isolate::Current()->mutator_thread();
|
||||
if (mutator_thread != nullptr) {
|
||||
Interpreter* interpreter = mutator_thread->interpreter();
|
||||
if (interpreter != nullptr) {
|
||||
interpreter->ClearLookupCache();
|
||||
}
|
||||
}
|
||||
|
||||
auto const thread = Thread::Current();
|
||||
auto const isolate = thread->isolate();
|
||||
StackZone stack_zone(thread);
|
||||
@@ -1730,7 +1711,6 @@ void ClassFinalizer::ClearAllCode(bool including_nonchanging_cids) {
|
||||
public:
|
||||
ClearCodeVisitor(Zone* zone, bool force)
|
||||
: force_(force),
|
||||
bytecode_(Bytecode::Handle(zone)),
|
||||
pool_(ObjectPool::Handle(zone)),
|
||||
entry_(Object::Handle(zone)) {}
|
||||
|
||||
@@ -1741,28 +1721,12 @@ void ClassFinalizer::ClearAllCode(bool including_nonchanging_cids) {
|
||||
}
|
||||
|
||||
void VisitFunction(const Function& function) {
|
||||
bytecode_ = function.bytecode();
|
||||
if (!bytecode_.IsNull()) {
|
||||
pool_ = bytecode_.object_pool();
|
||||
for (intptr_t i = 0; i < pool_.Length(); i++) {
|
||||
ObjectPool::EntryType entry_type = pool_.TypeAt(i);
|
||||
if (entry_type != ObjectPool::EntryType::kTaggedObject) {
|
||||
continue;
|
||||
}
|
||||
entry_ = pool_.ObjectAt(i);
|
||||
if (entry_.IsSubtypeTestCache()) {
|
||||
SubtypeTestCache::Cast(entry_).Reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function.ClearCode();
|
||||
function.ClearICDataArray();
|
||||
}
|
||||
|
||||
private:
|
||||
const bool force_;
|
||||
Bytecode& bytecode_;
|
||||
ObjectPool& pool_;
|
||||
Object& entry_;
|
||||
};
|
||||
|
||||
@@ -31,7 +31,6 @@ typedef uint16_t ClassIdTagType;
|
||||
V(Namespace) \
|
||||
V(KernelProgramInfo) \
|
||||
V(Code) \
|
||||
V(Bytecode) \
|
||||
V(Instructions) \
|
||||
V(InstructionsSection) \
|
||||
V(ObjectPool) \
|
||||
@@ -42,7 +41,6 @@ typedef uint16_t ClassIdTagType;
|
||||
V(ExceptionHandlers) \
|
||||
V(Context) \
|
||||
V(ContextScope) \
|
||||
V(ParameterTypeCheck) \
|
||||
V(SingleTargetCache) \
|
||||
V(UnlinkedCall) \
|
||||
V(MonomorphicSmiableCall) \
|
||||
|
||||
@@ -250,7 +250,7 @@ class ClassSerializationCluster : public SerializationCluster {
|
||||
s->UnexpectedObject(cls, "Class with non mode agnostic constants");
|
||||
}
|
||||
if (s->kind() != Snapshot::kFullAOT) {
|
||||
s->Write<uint32_t>(cls->ptr()->binary_declaration_);
|
||||
s->Write<uint32_t>(cls->ptr()->kernel_offset_);
|
||||
}
|
||||
s->Write<int32_t>(Class::target_instance_size_in_words(cls));
|
||||
s->Write<int32_t>(Class::target_next_field_offset_in_words(cls));
|
||||
@@ -325,7 +325,7 @@ class ClassDeserializationCluster : public DeserializationCluster {
|
||||
cls->ptr()->id_ = class_id;
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
if (d->kind() != Snapshot::kFullAOT) {
|
||||
cls->ptr()->binary_declaration_ = d->Read<uint32_t>();
|
||||
cls->ptr()->kernel_offset_ = d->Read<uint32_t>();
|
||||
}
|
||||
#endif
|
||||
if (!IsInternalVMdefinedClassId(class_id)) {
|
||||
@@ -372,7 +372,7 @@ class ClassDeserializationCluster : public DeserializationCluster {
|
||||
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
if (d->kind() != Snapshot::kFullAOT) {
|
||||
cls->ptr()->binary_declaration_ = d->Read<uint32_t>();
|
||||
cls->ptr()->kernel_offset_ = d->Read<uint32_t>();
|
||||
}
|
||||
#endif
|
||||
cls->ptr()->host_instance_size_in_words_ = d->Read<int32_t>();
|
||||
@@ -598,13 +598,10 @@ class FunctionSerializationCluster : public SerializationCluster {
|
||||
objects_.Add(func);
|
||||
|
||||
PushFromTo(func);
|
||||
if ((kind == Snapshot::kFull) || (kind == Snapshot::kFullCore)) {
|
||||
NOT_IN_PRECOMPILED(s->Push(func->ptr()->bytecode_));
|
||||
} else if (kind == Snapshot::kFullAOT) {
|
||||
if (kind == Snapshot::kFullAOT) {
|
||||
s->Push(func->ptr()->code_);
|
||||
} else if (kind == Snapshot::kFullJIT) {
|
||||
NOT_IN_PRECOMPILED(s->Push(func->ptr()->unoptimized_code_));
|
||||
NOT_IN_PRECOMPILED(s->Push(func->ptr()->bytecode_));
|
||||
s->Push(func->ptr()->code_);
|
||||
s->Push(func->ptr()->ic_data_array_);
|
||||
}
|
||||
@@ -627,13 +624,10 @@ class FunctionSerializationCluster : public SerializationCluster {
|
||||
FunctionPtr func = objects_[i];
|
||||
AutoTraceObjectName(func, MakeDisambiguatedFunctionName(s, func));
|
||||
WriteFromTo(func);
|
||||
if ((kind == Snapshot::kFull) || (kind == Snapshot::kFullCore)) {
|
||||
NOT_IN_PRECOMPILED(WriteField(func, bytecode_));
|
||||
} else if (kind == Snapshot::kFullAOT) {
|
||||
if (kind == Snapshot::kFullAOT) {
|
||||
WriteField(func, code_);
|
||||
} else if (s->kind() == Snapshot::kFullJIT) {
|
||||
NOT_IN_PRECOMPILED(WriteField(func, unoptimized_code_));
|
||||
NOT_IN_PRECOMPILED(WriteField(func, bytecode_));
|
||||
WriteField(func, code_);
|
||||
WriteField(func, ic_data_array_);
|
||||
}
|
||||
@@ -641,7 +635,7 @@ class FunctionSerializationCluster : public SerializationCluster {
|
||||
if (kind != Snapshot::kFullAOT) {
|
||||
s->WriteTokenPosition(func->ptr()->token_pos_);
|
||||
s->WriteTokenPosition(func->ptr()->end_token_pos_);
|
||||
s->Write<uint32_t>(func->ptr()->binary_declaration_);
|
||||
s->Write<uint32_t>(func->ptr()->kernel_offset_);
|
||||
}
|
||||
|
||||
s->Write<uint32_t>(func->ptr()->packed_fields_);
|
||||
@@ -694,16 +688,11 @@ class FunctionDeserializationCluster : public DeserializationCluster {
|
||||
Function::InstanceSize());
|
||||
ReadFromTo(func);
|
||||
|
||||
if ((kind == Snapshot::kFull) || (kind == Snapshot::kFullCore)) {
|
||||
NOT_IN_PRECOMPILED(func->ptr()->bytecode_ =
|
||||
static_cast<BytecodePtr>(d->ReadRef()));
|
||||
} else if (kind == Snapshot::kFullAOT) {
|
||||
if (kind == Snapshot::kFullAOT) {
|
||||
func->ptr()->code_ = static_cast<CodePtr>(d->ReadRef());
|
||||
} else if (kind == Snapshot::kFullJIT) {
|
||||
NOT_IN_PRECOMPILED(func->ptr()->unoptimized_code_ =
|
||||
static_cast<CodePtr>(d->ReadRef()));
|
||||
NOT_IN_PRECOMPILED(func->ptr()->bytecode_ =
|
||||
static_cast<BytecodePtr>(d->ReadRef()));
|
||||
func->ptr()->code_ = static_cast<CodePtr>(d->ReadRef());
|
||||
func->ptr()->ic_data_array_ = static_cast<ArrayPtr>(d->ReadRef());
|
||||
}
|
||||
@@ -717,7 +706,7 @@ class FunctionDeserializationCluster : public DeserializationCluster {
|
||||
if (kind != Snapshot::kFullAOT) {
|
||||
func->ptr()->token_pos_ = d->ReadTokenPosition();
|
||||
func->ptr()->end_token_pos_ = d->ReadTokenPosition();
|
||||
func->ptr()->binary_declaration_ = d->Read<uint32_t>();
|
||||
func->ptr()->kernel_offset_ = d->Read<uint32_t>();
|
||||
}
|
||||
func->ptr()->unboxed_parameters_info_.Reset();
|
||||
#endif
|
||||
@@ -1143,7 +1132,7 @@ class FieldSerializationCluster : public SerializationCluster {
|
||||
s->WriteCid(field->ptr()->guarded_cid_);
|
||||
s->WriteCid(field->ptr()->is_nullable_);
|
||||
s->Write<int8_t>(field->ptr()->static_type_exactness_state_);
|
||||
s->Write<uint32_t>(field->ptr()->binary_declaration_);
|
||||
s->Write<uint32_t>(field->ptr()->kernel_offset_);
|
||||
}
|
||||
s->Write<uint16_t>(field->ptr()->kind_bits_);
|
||||
|
||||
@@ -1213,7 +1202,7 @@ class FieldDeserializationCluster : public DeserializationCluster {
|
||||
field->ptr()->is_nullable_ = d->ReadCid();
|
||||
field->ptr()->static_type_exactness_state_ = d->Read<int8_t>();
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
field->ptr()->binary_declaration_ = d->Read<uint32_t>();
|
||||
field->ptr()->kernel_offset_ = d->Read<uint32_t>();
|
||||
#endif
|
||||
}
|
||||
field->ptr()->kind_bits_ = d->Read<uint16_t>();
|
||||
@@ -1359,7 +1348,7 @@ class LibrarySerializationCluster : public SerializationCluster {
|
||||
s->Write<int8_t>(lib->ptr()->load_state_);
|
||||
s->Write<uint8_t>(lib->ptr()->flags_);
|
||||
if (s->kind() != Snapshot::kFullAOT) {
|
||||
s->Write<uint32_t>(lib->ptr()->binary_declaration_);
|
||||
s->Write<uint32_t>(lib->ptr()->kernel_offset_);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1398,7 +1387,7 @@ class LibraryDeserializationCluster : public DeserializationCluster {
|
||||
LibraryLayout::InFullSnapshotBit::update(true, d->Read<uint8_t>());
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
if (d->kind() != Snapshot::kFullAOT) {
|
||||
lib->ptr()->binary_declaration_ = d->Read<uint32_t>();
|
||||
lib->ptr()->kernel_offset_ = d->Read<uint32_t>();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -1982,88 +1971,6 @@ class CodeDeserializationCluster : public DeserializationCluster {
|
||||
};
|
||||
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
class BytecodeSerializationCluster : public SerializationCluster {
|
||||
public:
|
||||
BytecodeSerializationCluster() : SerializationCluster("Bytecode") {}
|
||||
virtual ~BytecodeSerializationCluster() {}
|
||||
|
||||
void Trace(Serializer* s, ObjectPtr object) {
|
||||
BytecodePtr bytecode = Bytecode::RawCast(object);
|
||||
objects_.Add(bytecode);
|
||||
PushFromTo(bytecode);
|
||||
}
|
||||
|
||||
void WriteAlloc(Serializer* s) {
|
||||
s->WriteCid(kBytecodeCid);
|
||||
const intptr_t count = objects_.length();
|
||||
s->WriteUnsigned(count);
|
||||
for (intptr_t i = 0; i < count; i++) {
|
||||
BytecodePtr bytecode = objects_[i];
|
||||
s->AssignRef(bytecode);
|
||||
}
|
||||
}
|
||||
|
||||
void WriteFill(Serializer* s) {
|
||||
ASSERT(s->kind() != Snapshot::kFullAOT);
|
||||
const intptr_t count = objects_.length();
|
||||
for (intptr_t i = 0; i < count; i++) {
|
||||
BytecodePtr bytecode = objects_[i];
|
||||
s->Write<int32_t>(bytecode->ptr()->instructions_size_);
|
||||
WriteFromTo(bytecode);
|
||||
s->Write<int32_t>(bytecode->ptr()->instructions_binary_offset_);
|
||||
s->Write<int32_t>(bytecode->ptr()->source_positions_binary_offset_);
|
||||
s->Write<int32_t>(bytecode->ptr()->local_variables_binary_offset_);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
GrowableArray<BytecodePtr> objects_;
|
||||
};
|
||||
|
||||
class BytecodeDeserializationCluster : public DeserializationCluster {
|
||||
public:
|
||||
BytecodeDeserializationCluster() : DeserializationCluster("Bytecode") {}
|
||||
virtual ~BytecodeDeserializationCluster() {}
|
||||
|
||||
void ReadAlloc(Deserializer* d, bool is_canonical) {
|
||||
start_index_ = d->next_index();
|
||||
PageSpace* old_space = d->heap()->old_space();
|
||||
const intptr_t count = d->ReadUnsigned();
|
||||
for (intptr_t i = 0; i < count; i++) {
|
||||
d->AssignRef(AllocateUninitialized(old_space, Bytecode::InstanceSize()));
|
||||
}
|
||||
stop_index_ = d->next_index();
|
||||
}
|
||||
|
||||
void ReadFill(Deserializer* d, bool is_canonical) {
|
||||
ASSERT(d->kind() != Snapshot::kFullAOT);
|
||||
|
||||
for (intptr_t id = start_index_; id < stop_index_; id++) {
|
||||
BytecodePtr bytecode = static_cast<BytecodePtr>(d->Ref(id));
|
||||
Deserializer::InitializeHeader(bytecode, kBytecodeCid,
|
||||
Bytecode::InstanceSize());
|
||||
bytecode->ptr()->instructions_ = 0;
|
||||
bytecode->ptr()->instructions_size_ = d->Read<int32_t>();
|
||||
ReadFromTo(bytecode);
|
||||
bytecode->ptr()->instructions_binary_offset_ = d->Read<int32_t>();
|
||||
bytecode->ptr()->source_positions_binary_offset_ = d->Read<int32_t>();
|
||||
bytecode->ptr()->local_variables_binary_offset_ = d->Read<int32_t>();
|
||||
}
|
||||
}
|
||||
|
||||
void PostLoad(Deserializer* d, const Array& refs, bool is_canonical) {
|
||||
Bytecode& bytecode = Bytecode::Handle(d->zone());
|
||||
ExternalTypedData& binary = ExternalTypedData::Handle(d->zone());
|
||||
|
||||
for (intptr_t i = start_index_; i < stop_index_; i++) {
|
||||
bytecode ^= refs.At(i);
|
||||
binary = bytecode.GetBinary(d->zone());
|
||||
bytecode.set_instructions(reinterpret_cast<uword>(
|
||||
binary.DataAddr(bytecode.instructions_binary_offset())));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class ObjectPoolSerializationCluster : public SerializationCluster {
|
||||
public:
|
||||
ObjectPoolSerializationCluster() : SerializationCluster("ObjectPool") {}
|
||||
@@ -2077,8 +1984,7 @@ class ObjectPoolSerializationCluster : public SerializationCluster {
|
||||
uint8_t* entry_bits = pool->ptr()->entry_bits();
|
||||
for (intptr_t i = 0; i < length; i++) {
|
||||
auto entry_type = ObjectPool::TypeBits::decode(entry_bits[i]);
|
||||
if ((entry_type == ObjectPool::EntryType::kTaggedObject) ||
|
||||
(entry_type == ObjectPool::EntryType::kNativeEntryData)) {
|
||||
if (entry_type == ObjectPool::EntryType::kTaggedObject) {
|
||||
s->Push(pool->ptr()->data()[i].raw_obj_);
|
||||
}
|
||||
}
|
||||
@@ -2125,22 +2031,6 @@ class ObjectPoolSerializationCluster : public SerializationCluster {
|
||||
s->Write<intptr_t>(entry.raw_value_);
|
||||
break;
|
||||
}
|
||||
case ObjectPool::EntryType::kNativeEntryData: {
|
||||
ObjectPtr raw = entry.raw_obj_;
|
||||
TypedDataPtr raw_data = static_cast<TypedDataPtr>(raw);
|
||||
// kNativeEntryData object pool entries are for linking natives for
|
||||
// the interpreter. Before writing these entries into the snapshot,
|
||||
// we need to unlink them by nulling out the 'trampoline' and
|
||||
// 'native_function' fields.
|
||||
NativeEntryData::Payload* payload =
|
||||
NativeEntryData::FromTypedArray(raw_data);
|
||||
if (payload->kind == MethodRecognizer::kUnknown) {
|
||||
payload->trampoline = NULL;
|
||||
payload->native_function = NULL;
|
||||
}
|
||||
s->WriteElementRef(raw, j);
|
||||
break;
|
||||
}
|
||||
case ObjectPool::EntryType::kNativeFunction:
|
||||
case ObjectPool::EntryType::kNativeFunctionWrapper: {
|
||||
// Write nothing. Will initialize with the lazy link entry.
|
||||
@@ -2187,7 +2077,6 @@ class ObjectPoolDeserializationCluster : public DeserializationCluster {
|
||||
pool->ptr()->entry_bits()[j] = entry_bits;
|
||||
ObjectPoolLayout::Entry& entry = pool->ptr()->data()[j];
|
||||
switch (ObjectPool::TypeBits::decode(entry_bits)) {
|
||||
case ObjectPool::EntryType::kNativeEntryData:
|
||||
case ObjectPool::EntryType::kTaggedObject:
|
||||
entry.raw_obj_ = d->ReadRef();
|
||||
break;
|
||||
@@ -2755,72 +2644,6 @@ class ContextScopeDeserializationCluster : public DeserializationCluster {
|
||||
}
|
||||
};
|
||||
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
class ParameterTypeCheckSerializationCluster : public SerializationCluster {
|
||||
public:
|
||||
ParameterTypeCheckSerializationCluster()
|
||||
: SerializationCluster("ParameterTypeCheck") {}
|
||||
~ParameterTypeCheckSerializationCluster() {}
|
||||
|
||||
void Trace(Serializer* s, ObjectPtr object) {
|
||||
ParameterTypeCheckPtr unlinked = ParameterTypeCheck::RawCast(object);
|
||||
objects_.Add(unlinked);
|
||||
PushFromTo(unlinked);
|
||||
}
|
||||
|
||||
void WriteAlloc(Serializer* s) {
|
||||
s->WriteCid(kParameterTypeCheckCid);
|
||||
const intptr_t count = objects_.length();
|
||||
s->WriteUnsigned(count);
|
||||
for (intptr_t i = 0; i < count; i++) {
|
||||
ParameterTypeCheckPtr check = objects_[i];
|
||||
s->AssignRef(check);
|
||||
}
|
||||
}
|
||||
|
||||
void WriteFill(Serializer* s) {
|
||||
const intptr_t count = objects_.length();
|
||||
for (intptr_t i = 0; i < count; i++) {
|
||||
ParameterTypeCheckPtr check = objects_[i];
|
||||
s->Write<intptr_t>(check->ptr()->index_);
|
||||
WriteFromTo(check);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
GrowableArray<ParameterTypeCheckPtr> objects_;
|
||||
};
|
||||
#endif // !DART_PRECOMPILED_RUNTIME
|
||||
|
||||
class ParameterTypeCheckDeserializationCluster : public DeserializationCluster {
|
||||
public:
|
||||
ParameterTypeCheckDeserializationCluster()
|
||||
: DeserializationCluster("ParameterTypeCheck") {}
|
||||
~ParameterTypeCheckDeserializationCluster() {}
|
||||
|
||||
void ReadAlloc(Deserializer* d, bool is_canonical) {
|
||||
start_index_ = d->next_index();
|
||||
PageSpace* old_space = d->heap()->old_space();
|
||||
const intptr_t count = d->ReadUnsigned();
|
||||
for (intptr_t i = 0; i < count; i++) {
|
||||
d->AssignRef(
|
||||
AllocateUninitialized(old_space, ParameterTypeCheck::InstanceSize()));
|
||||
}
|
||||
stop_index_ = d->next_index();
|
||||
}
|
||||
|
||||
void ReadFill(Deserializer* d, bool is_canonical) {
|
||||
for (intptr_t id = start_index_; id < stop_index_; id++) {
|
||||
ParameterTypeCheckPtr check =
|
||||
static_cast<ParameterTypeCheckPtr>(d->Ref(id));
|
||||
Deserializer::InitializeHeader(check, kParameterTypeCheckCid,
|
||||
ParameterTypeCheck::InstanceSize());
|
||||
check->ptr()->index_ = d->Read<intptr_t>();
|
||||
ReadFromTo(check);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
class UnlinkedCallSerializationCluster : public SerializationCluster {
|
||||
public:
|
||||
@@ -5024,22 +4847,6 @@ class VMSerializationRoots : public SerializationRoots {
|
||||
"LocalVarDescriptors", "<empty>");
|
||||
s->AddBaseObject(Object::empty_exception_handlers().raw(),
|
||||
"ExceptionHandlers", "<empty>");
|
||||
s->AddBaseObject(Object::implicit_getter_bytecode().raw(), "Bytecode",
|
||||
"<implicit getter>");
|
||||
s->AddBaseObject(Object::implicit_setter_bytecode().raw(), "Bytecode",
|
||||
"<implicit setter>");
|
||||
s->AddBaseObject(Object::implicit_static_getter_bytecode().raw(),
|
||||
"Bytecode", "<implicit static getter>");
|
||||
s->AddBaseObject(Object::method_extractor_bytecode().raw(), "Bytecode",
|
||||
"<method extractor>");
|
||||
s->AddBaseObject(Object::invoke_closure_bytecode().raw(), "Bytecode",
|
||||
"<invoke closure>");
|
||||
s->AddBaseObject(Object::invoke_field_bytecode().raw(), "Bytecode",
|
||||
"<invoke field>");
|
||||
s->AddBaseObject(Object::nsm_dispatcher_bytecode().raw(), "Bytecode",
|
||||
"<nsm dispatcher>");
|
||||
s->AddBaseObject(Object::dynamic_invocation_forwarder_bytecode().raw(),
|
||||
"Bytecode", "<dyn forwarder>");
|
||||
|
||||
for (intptr_t i = 0; i < ArgumentsDescriptor::kCachedDescriptorCount; i++) {
|
||||
s->AddBaseObject(ArgumentsDescriptor::cached_args_descriptors_[i],
|
||||
@@ -5121,14 +4928,6 @@ class VMDeserializationRoots : public DeserializationRoots {
|
||||
d->AddBaseObject(Object::empty_descriptors().raw());
|
||||
d->AddBaseObject(Object::empty_var_descriptors().raw());
|
||||
d->AddBaseObject(Object::empty_exception_handlers().raw());
|
||||
d->AddBaseObject(Object::implicit_getter_bytecode().raw());
|
||||
d->AddBaseObject(Object::implicit_setter_bytecode().raw());
|
||||
d->AddBaseObject(Object::implicit_static_getter_bytecode().raw());
|
||||
d->AddBaseObject(Object::method_extractor_bytecode().raw());
|
||||
d->AddBaseObject(Object::invoke_closure_bytecode().raw());
|
||||
d->AddBaseObject(Object::invoke_field_bytecode().raw());
|
||||
d->AddBaseObject(Object::nsm_dispatcher_bytecode().raw());
|
||||
d->AddBaseObject(Object::dynamic_invocation_forwarder_bytecode().raw());
|
||||
|
||||
for (intptr_t i = 0; i < ArgumentsDescriptor::kCachedDescriptorCount; i++) {
|
||||
d->AddBaseObject(ArgumentsDescriptor::cached_args_descriptors_[i]);
|
||||
@@ -5754,8 +5553,6 @@ SerializationCluster* Serializer::NewClusterForClass(intptr_t cid) {
|
||||
return new (Z) KernelProgramInfoSerializationCluster();
|
||||
case kCodeCid:
|
||||
return new (Z) CodeSerializationCluster(heap_);
|
||||
case kBytecodeCid:
|
||||
return new (Z) BytecodeSerializationCluster();
|
||||
case kObjectPoolCid:
|
||||
return new (Z) ObjectPoolSerializationCluster();
|
||||
case kPcDescriptorsCid:
|
||||
@@ -5766,8 +5563,6 @@ SerializationCluster* Serializer::NewClusterForClass(intptr_t cid) {
|
||||
return new (Z) ContextSerializationCluster();
|
||||
case kContextScopeCid:
|
||||
return new (Z) ContextScopeSerializationCluster();
|
||||
case kParameterTypeCheckCid:
|
||||
return new (Z) ParameterTypeCheckSerializationCluster();
|
||||
case kUnlinkedCallCid:
|
||||
return new (Z) UnlinkedCallSerializationCluster();
|
||||
case kICDataCid:
|
||||
@@ -5934,12 +5729,6 @@ void Serializer::Push(ObjectPtr object) {
|
||||
!Snapshot::IncludesCode(kind_)) {
|
||||
return; // Do not trace, will write null.
|
||||
}
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
if (object->IsHeapObject() && object->IsBytecode() &&
|
||||
!Snapshot::IncludesBytecode(kind_)) {
|
||||
return; // Do not trace, will write null.
|
||||
}
|
||||
#endif // !DART_PRECOMPILED_RUNTIME
|
||||
|
||||
intptr_t id = heap_->GetObjectId(object);
|
||||
if (id == kUnreachableReference) {
|
||||
@@ -6458,10 +6247,6 @@ DeserializationCluster* Deserializer::ReadCluster() {
|
||||
#endif // !DART_PRECOMPILED_RUNTIME
|
||||
case kCodeCid:
|
||||
return new (Z) CodeDeserializationCluster();
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
case kBytecodeCid:
|
||||
return new (Z) BytecodeDeserializationCluster();
|
||||
#endif // !DART_PRECOMPILED_RUNTIME
|
||||
case kObjectPoolCid:
|
||||
return new (Z) ObjectPoolDeserializationCluster();
|
||||
case kPcDescriptorsCid:
|
||||
@@ -6472,8 +6257,6 @@ DeserializationCluster* Deserializer::ReadCluster() {
|
||||
return new (Z) ContextDeserializationCluster();
|
||||
case kContextScopeCid:
|
||||
return new (Z) ContextScopeDeserializationCluster();
|
||||
case kParameterTypeCheckCid:
|
||||
return new (Z) ParameterTypeCheckDeserializationCluster();
|
||||
case kUnlinkedCallCid:
|
||||
return new (Z) UnlinkedCallDeserializationCluster();
|
||||
case kICDataCid:
|
||||
|
||||
@@ -413,11 +413,6 @@ class Serializer : public ThreadStackResource {
|
||||
if (object->IsCode() && !Snapshot::IncludesCode(kind_)) {
|
||||
return RefId(Object::null());
|
||||
}
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
if (object->IsBytecode() && !Snapshot::IncludesBytecode(kind_)) {
|
||||
return RefId(Object::null());
|
||||
}
|
||||
#endif // !DART_PRECOMPILED_RUNTIME
|
||||
FATAL("Missing ref");
|
||||
}
|
||||
|
||||
|
||||
@@ -107,18 +107,6 @@ class CodePatcher : public AllStatic {
|
||||
// Example pattern: `[0x3d, 0x8b, -1, -1]`.
|
||||
bool MatchesPattern(uword end, const int16_t* pattern, intptr_t size);
|
||||
|
||||
class KBCPatcher : public AllStatic {
|
||||
public:
|
||||
static NativeFunctionWrapper GetNativeCallAt(uword return_address,
|
||||
const Bytecode& bytecode,
|
||||
NativeFunction* function);
|
||||
|
||||
static void PatchNativeCallAt(uword return_address,
|
||||
const Bytecode& bytecode,
|
||||
NativeFunction function,
|
||||
NativeFunctionWrapper trampoline);
|
||||
};
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // RUNTIME_VM_CODE_PATCHER_H_
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
// Copyright (c) 2018, 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.
|
||||
|
||||
#include "vm/globals.h"
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
|
||||
#include "vm/code_patcher.h"
|
||||
|
||||
#include "vm/instructions_kbc.h"
|
||||
#include "vm/native_entry.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
void KBCPatcher::PatchNativeCallAt(uword return_address,
|
||||
const Bytecode& bytecode,
|
||||
NativeFunction function,
|
||||
NativeFunctionWrapper trampoline) {
|
||||
ASSERT(bytecode.ContainsInstructionAt(return_address));
|
||||
NativeEntryData native_entry_data(TypedData::Handle(
|
||||
KBCNativeCallPattern::GetNativeEntryDataAt(return_address, bytecode)));
|
||||
native_entry_data.set_trampoline(trampoline);
|
||||
native_entry_data.set_native_function(function);
|
||||
}
|
||||
|
||||
NativeFunctionWrapper KBCPatcher::GetNativeCallAt(uword return_address,
|
||||
const Bytecode& bytecode,
|
||||
NativeFunction* function) {
|
||||
ASSERT(bytecode.ContainsInstructionAt(return_address));
|
||||
NativeEntryData native_entry_data(TypedData::Handle(
|
||||
KBCNativeCallPattern::GetNativeEntryDataAt(return_address, bytecode)));
|
||||
*function = native_entry_data.native_function();
|
||||
return native_entry_data.trampoline();
|
||||
}
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME)
|
||||
@@ -278,7 +278,7 @@ void Precompiler::DoCompileAll() {
|
||||
if (FLAG_use_bare_instructions) {
|
||||
// We use any stub here to get it's object pool (all stubs share the
|
||||
// same object pool in bare instructions mode).
|
||||
const Code& code = StubCode::InterpretCall();
|
||||
const Code& code = StubCode::LazyCompile();
|
||||
const ObjectPool& stub_pool = ObjectPool::Handle(code.object_pool());
|
||||
|
||||
global_object_pool_builder()->Reset();
|
||||
@@ -420,7 +420,6 @@ void Precompiler::DoCompileAll() {
|
||||
I->object_store()->set_async_star_move_next_helper(null_function);
|
||||
I->object_store()->set_complete_on_async_return(null_function);
|
||||
I->object_store()->set_async_star_stream_controller(null_class);
|
||||
I->object_store()->set_bytecode_attributes(Array::null_array());
|
||||
DropMetadata();
|
||||
DropLibraryEntries();
|
||||
}
|
||||
@@ -1745,7 +1744,6 @@ void Precompiler::DropFunctions() {
|
||||
for (intptr_t j = 0; j < functions.Length(); j++) {
|
||||
function ^= functions.At(j);
|
||||
function.DropUncompiledImplicitClosureFunction();
|
||||
function.ClearBytecode();
|
||||
if (functions_to_retain_.ContainsKey(function)) {
|
||||
retained_functions.Add(function);
|
||||
} else {
|
||||
@@ -1795,7 +1793,6 @@ void Precompiler::DropFunctions() {
|
||||
retained_functions = GrowableObjectArray::New();
|
||||
for (intptr_t j = 0; j < closures.Length(); j++) {
|
||||
function ^= closures.At(j);
|
||||
function.ClearBytecode();
|
||||
if (functions_to_retain_.ContainsKey(function)) {
|
||||
retained_functions.Add(function);
|
||||
} else {
|
||||
@@ -1812,7 +1809,6 @@ void Precompiler::DropFields() {
|
||||
Field& field = Field::Handle(Z);
|
||||
GrowableObjectArray& retained_fields = GrowableObjectArray::Handle(Z);
|
||||
AbstractType& type = AbstractType::Handle(Z);
|
||||
Function& initializer_function = Function::Handle(Z);
|
||||
|
||||
SafepointWriteRwLocker ml(T, T->isolate_group()->program_lock());
|
||||
for (intptr_t i = 0; i < libraries_.Length(); i++) {
|
||||
@@ -1825,10 +1821,6 @@ void Precompiler::DropFields() {
|
||||
for (intptr_t j = 0; j < fields.Length(); j++) {
|
||||
field ^= fields.At(j);
|
||||
bool retain = fields_to_retain_.HasKey(&field);
|
||||
if (field.HasInitializerFunction()) {
|
||||
initializer_function = field.InitializerFunction();
|
||||
initializer_function.ClearBytecode();
|
||||
}
|
||||
#if !defined(PRODUCT)
|
||||
if (field.is_instance() && cls.is_allocated()) {
|
||||
// Keep instance fields so their names are available to graph tools.
|
||||
@@ -2228,7 +2220,6 @@ void Precompiler::DropLibraryEntries() {
|
||||
program_info.set_scripts(Array::null_array());
|
||||
program_info.set_libraries_cache(Array::null_array());
|
||||
program_info.set_classes_cache(Array::null_array());
|
||||
program_info.set_bytecode_component(Array::null_array());
|
||||
}
|
||||
script.set_resolved_url(String::null_string());
|
||||
script.set_compile_time_constants(Array::null_array());
|
||||
|
||||
@@ -96,7 +96,7 @@ class FieldKeyValueTrait {
|
||||
if (token_pos.IsReal()) {
|
||||
return token_pos.value();
|
||||
}
|
||||
return key->binary_declaration_offset();
|
||||
return key->kernel_offset();
|
||||
}
|
||||
|
||||
static inline bool IsKeyEqual(Pair pair, Key key) {
|
||||
|
||||
@@ -639,7 +639,7 @@ void Assembler::TransitionNativeToGenerated(Register addr,
|
||||
}
|
||||
|
||||
// Mark that the thread is executing Dart code.
|
||||
LoadImmediate(state, target::Thread::vm_tag_compiled_id());
|
||||
LoadImmediate(state, target::Thread::vm_tag_dart_id());
|
||||
StoreToOffset(kWord, state, THR, target::Thread::vm_tag_offset());
|
||||
LoadImmediate(state, target::Thread::generated_execution_state());
|
||||
StoreToOffset(kWord, state, THR, target::Thread::execution_state_offset());
|
||||
|
||||
@@ -1483,7 +1483,7 @@ void Assembler::TransitionNativeToGenerated(Register state,
|
||||
}
|
||||
|
||||
// Mark that the thread is executing Dart code.
|
||||
LoadImmediate(state, target::Thread::vm_tag_compiled_id());
|
||||
LoadImmediate(state, target::Thread::vm_tag_dart_id());
|
||||
StoreToOffset(state, THR, target::Thread::vm_tag_offset());
|
||||
LoadImmediate(state, target::Thread::generated_execution_state());
|
||||
StoreToOffset(state, THR, target::Thread::execution_state_offset());
|
||||
|
||||
@@ -2288,8 +2288,7 @@ void Assembler::TransitionNativeToGenerated(Register scratch,
|
||||
}
|
||||
|
||||
// Mark that the thread is executing Dart code.
|
||||
movl(Assembler::VMTagAddress(),
|
||||
Immediate(target::Thread::vm_tag_compiled_id()));
|
||||
movl(Assembler::VMTagAddress(), Immediate(target::Thread::vm_tag_dart_id()));
|
||||
movl(Address(THR, target::Thread::execution_state_offset()),
|
||||
Immediate(target::Thread::generated_execution_state()));
|
||||
|
||||
|
||||
@@ -245,8 +245,7 @@ void Assembler::TransitionNativeToGenerated(bool leave_safepoint) {
|
||||
#endif
|
||||
}
|
||||
|
||||
movq(Assembler::VMTagAddress(),
|
||||
Immediate(target::Thread::vm_tag_compiled_id()));
|
||||
movq(Assembler::VMTagAddress(), Immediate(target::Thread::vm_tag_dart_id()));
|
||||
movq(Address(THR, target::Thread::execution_state_offset()),
|
||||
Immediate(target::Thread::generated_execution_state()));
|
||||
|
||||
|
||||
@@ -1,456 +0,0 @@
|
||||
// Copyright (c) 2018, 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.
|
||||
|
||||
#include "vm/globals.h"
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
|
||||
#include "vm/compiler/assembler/disassembler_kbc.h"
|
||||
|
||||
#include "platform/assert.h"
|
||||
#include "vm/compiler/frontend/bytecode_reader.h"
|
||||
#include "vm/constants_kbc.h"
|
||||
#include "vm/cpu.h"
|
||||
#include "vm/instructions.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
static const char* kOpcodeNames[] = {
|
||||
#define BYTECODE_NAME(name, encoding, kind, op1, op2, op3) #name,
|
||||
KERNEL_BYTECODES_LIST(BYTECODE_NAME)
|
||||
#undef BYTECODE_NAME
|
||||
};
|
||||
|
||||
static const size_t kOpcodeCount =
|
||||
sizeof(kOpcodeNames) / sizeof(kOpcodeNames[0]);
|
||||
static_assert(kOpcodeCount <= 256, "Opcode should fit into a byte");
|
||||
|
||||
typedef void (*BytecodeFormatter)(char* buffer,
|
||||
intptr_t size,
|
||||
KernelBytecode::Opcode opcode,
|
||||
const KBCInstr* instr);
|
||||
typedef void (*Fmt)(char** buf,
|
||||
intptr_t* size,
|
||||
const KBCInstr* instr,
|
||||
int32_t value);
|
||||
|
||||
template <typename ValueType>
|
||||
void FormatOperand(char** buf,
|
||||
intptr_t* size,
|
||||
const char* fmt,
|
||||
ValueType value) {
|
||||
intptr_t written = Utils::SNPrint(*buf, *size, fmt, value);
|
||||
if (written < *size) {
|
||||
*buf += written;
|
||||
*size += written;
|
||||
} else {
|
||||
*size = -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void Fmt___(char** buf,
|
||||
intptr_t* size,
|
||||
const KBCInstr* instr,
|
||||
int32_t value) {}
|
||||
|
||||
static void Fmttgt(char** buf,
|
||||
intptr_t* size,
|
||||
const KBCInstr* instr,
|
||||
int32_t value) {
|
||||
if (FLAG_disassemble_relative) {
|
||||
FormatOperand(buf, size, "-> %" Pd, value);
|
||||
} else {
|
||||
FormatOperand(buf, size, "-> %" Px, instr + value);
|
||||
}
|
||||
}
|
||||
|
||||
static void Fmtlit(char** buf,
|
||||
intptr_t* size,
|
||||
const KBCInstr* instr,
|
||||
int32_t value) {
|
||||
FormatOperand(buf, size, "k%d", value);
|
||||
}
|
||||
|
||||
static void Fmtreg(char** buf,
|
||||
intptr_t* size,
|
||||
const KBCInstr* instr,
|
||||
int32_t value) {
|
||||
FormatOperand(buf, size, "r%d", value);
|
||||
}
|
||||
|
||||
static void Fmtxeg(char** buf,
|
||||
intptr_t* size,
|
||||
const KBCInstr* instr,
|
||||
int32_t value) {
|
||||
if (value < 0) {
|
||||
FormatOperand(buf, size, "FP[%d]", value);
|
||||
} else {
|
||||
Fmtreg(buf, size, instr, value);
|
||||
}
|
||||
}
|
||||
|
||||
static void Fmtnum(char** buf,
|
||||
intptr_t* size,
|
||||
const KBCInstr* instr,
|
||||
int32_t value) {
|
||||
FormatOperand(buf, size, "#%d", value);
|
||||
}
|
||||
|
||||
static void Apply(char** buf,
|
||||
intptr_t* size,
|
||||
const KBCInstr* instr,
|
||||
Fmt fmt,
|
||||
int32_t value,
|
||||
const char* suffix) {
|
||||
if (*size <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
fmt(buf, size, instr, value);
|
||||
if (*size > 0) {
|
||||
FormatOperand(buf, size, "%s", suffix);
|
||||
}
|
||||
}
|
||||
|
||||
static void Format0(char* buf,
|
||||
intptr_t size,
|
||||
KernelBytecode::Opcode opcode,
|
||||
const KBCInstr* instr,
|
||||
Fmt op1,
|
||||
Fmt op2,
|
||||
Fmt op3) {}
|
||||
|
||||
static void FormatA(char* buf,
|
||||
intptr_t size,
|
||||
KernelBytecode::Opcode opcode,
|
||||
const KBCInstr* instr,
|
||||
Fmt op1,
|
||||
Fmt op2,
|
||||
Fmt op3) {
|
||||
const int32_t a = KernelBytecode::DecodeA(instr);
|
||||
Apply(&buf, &size, instr, op1, a, "");
|
||||
}
|
||||
|
||||
static void FormatD(char* buf,
|
||||
intptr_t size,
|
||||
KernelBytecode::Opcode opcode,
|
||||
const KBCInstr* instr,
|
||||
Fmt op1,
|
||||
Fmt op2,
|
||||
Fmt op3) {
|
||||
const int32_t bc = KernelBytecode::DecodeD(instr);
|
||||
Apply(&buf, &size, instr, op1, bc, "");
|
||||
}
|
||||
|
||||
static void FormatX(char* buf,
|
||||
intptr_t size,
|
||||
KernelBytecode::Opcode opcode,
|
||||
const KBCInstr* instr,
|
||||
Fmt op1,
|
||||
Fmt op2,
|
||||
Fmt op3) {
|
||||
const int32_t bc = KernelBytecode::DecodeX(instr);
|
||||
Apply(&buf, &size, instr, op1, bc, "");
|
||||
}
|
||||
|
||||
static void FormatT(char* buf,
|
||||
intptr_t size,
|
||||
KernelBytecode::Opcode opcode,
|
||||
const KBCInstr* instr,
|
||||
Fmt op1,
|
||||
Fmt op2,
|
||||
Fmt op3) {
|
||||
const int32_t x = KernelBytecode::DecodeT(instr);
|
||||
Apply(&buf, &size, instr, op1, x, "");
|
||||
}
|
||||
|
||||
static void FormatA_E(char* buf,
|
||||
intptr_t size,
|
||||
KernelBytecode::Opcode opcode,
|
||||
const KBCInstr* instr,
|
||||
Fmt op1,
|
||||
Fmt op2,
|
||||
Fmt op3) {
|
||||
const int32_t a = KernelBytecode::DecodeA(instr);
|
||||
const int32_t e = KernelBytecode::DecodeE(instr);
|
||||
Apply(&buf, &size, instr, op1, a, ", ");
|
||||
Apply(&buf, &size, instr, op2, e, "");
|
||||
}
|
||||
|
||||
static void FormatA_Y(char* buf,
|
||||
intptr_t size,
|
||||
KernelBytecode::Opcode opcode,
|
||||
const KBCInstr* instr,
|
||||
Fmt op1,
|
||||
Fmt op2,
|
||||
Fmt op3) {
|
||||
const int32_t a = KernelBytecode::DecodeA(instr);
|
||||
const int32_t y = KernelBytecode::DecodeY(instr);
|
||||
Apply(&buf, &size, instr, op1, a, ", ");
|
||||
Apply(&buf, &size, instr, op2, y, "");
|
||||
}
|
||||
|
||||
static void FormatD_F(char* buf,
|
||||
intptr_t size,
|
||||
KernelBytecode::Opcode opcode,
|
||||
const KBCInstr* instr,
|
||||
Fmt op1,
|
||||
Fmt op2,
|
||||
Fmt op3) {
|
||||
const int32_t d = KernelBytecode::DecodeD(instr);
|
||||
const int32_t f = KernelBytecode::DecodeF(instr);
|
||||
Apply(&buf, &size, instr, op1, d, ", ");
|
||||
Apply(&buf, &size, instr, op2, f, "");
|
||||
}
|
||||
|
||||
static void FormatA_B_C(char* buf,
|
||||
intptr_t size,
|
||||
KernelBytecode::Opcode opcode,
|
||||
const KBCInstr* instr,
|
||||
Fmt op1,
|
||||
Fmt op2,
|
||||
Fmt op3) {
|
||||
const int32_t a = KernelBytecode::DecodeA(instr);
|
||||
const int32_t b = KernelBytecode::DecodeB(instr);
|
||||
const int32_t c = KernelBytecode::DecodeC(instr);
|
||||
Apply(&buf, &size, instr, op1, a, ", ");
|
||||
Apply(&buf, &size, instr, op2, b, ", ");
|
||||
Apply(&buf, &size, instr, op3, c, "");
|
||||
}
|
||||
|
||||
#define BYTECODE_FORMATTER(name, encoding, kind, op1, op2, op3) \
|
||||
static void Format##name(char* buf, intptr_t size, \
|
||||
KernelBytecode::Opcode opcode, \
|
||||
const KBCInstr* instr) { \
|
||||
Format##encoding(buf, size, opcode, instr, Fmt##op1, Fmt##op2, Fmt##op3); \
|
||||
}
|
||||
KERNEL_BYTECODES_LIST(BYTECODE_FORMATTER)
|
||||
#undef BYTECODE_FORMATTER
|
||||
|
||||
static const BytecodeFormatter kFormatters[] = {
|
||||
#define BYTECODE_FORMATTER(name, encoding, kind, op1, op2, op3) &Format##name,
|
||||
KERNEL_BYTECODES_LIST(BYTECODE_FORMATTER)
|
||||
#undef BYTECODE_FORMATTER
|
||||
};
|
||||
|
||||
static intptr_t GetConstantPoolIndex(const KBCInstr* instr) {
|
||||
switch (KernelBytecode::DecodeOpcode(instr)) {
|
||||
case KernelBytecode::kLoadConstant:
|
||||
case KernelBytecode::kLoadConstant_Wide:
|
||||
case KernelBytecode::kInstantiateTypeArgumentsTOS:
|
||||
case KernelBytecode::kInstantiateTypeArgumentsTOS_Wide:
|
||||
case KernelBytecode::kAssertAssignable:
|
||||
case KernelBytecode::kAssertAssignable_Wide:
|
||||
return KernelBytecode::DecodeE(instr);
|
||||
|
||||
case KernelBytecode::kPushConstant:
|
||||
case KernelBytecode::kPushConstant_Wide:
|
||||
case KernelBytecode::kInitLateField:
|
||||
case KernelBytecode::kInitLateField_Wide:
|
||||
case KernelBytecode::kStoreStaticTOS:
|
||||
case KernelBytecode::kStoreStaticTOS_Wide:
|
||||
case KernelBytecode::kLoadStatic:
|
||||
case KernelBytecode::kLoadStatic_Wide:
|
||||
case KernelBytecode::kAllocate:
|
||||
case KernelBytecode::kAllocate_Wide:
|
||||
case KernelBytecode::kAllocateClosure:
|
||||
case KernelBytecode::kAllocateClosure_Wide:
|
||||
case KernelBytecode::kInstantiateType:
|
||||
case KernelBytecode::kInstantiateType_Wide:
|
||||
case KernelBytecode::kDirectCall:
|
||||
case KernelBytecode::kDirectCall_Wide:
|
||||
case KernelBytecode::kUncheckedDirectCall:
|
||||
case KernelBytecode::kUncheckedDirectCall_Wide:
|
||||
case KernelBytecode::kInterfaceCall:
|
||||
case KernelBytecode::kInterfaceCall_Wide:
|
||||
case KernelBytecode::kInstantiatedInterfaceCall:
|
||||
case KernelBytecode::kInstantiatedInterfaceCall_Wide:
|
||||
case KernelBytecode::kUncheckedClosureCall:
|
||||
case KernelBytecode::kUncheckedClosureCall_Wide:
|
||||
case KernelBytecode::kUncheckedInterfaceCall:
|
||||
case KernelBytecode::kUncheckedInterfaceCall_Wide:
|
||||
case KernelBytecode::kDynamicCall:
|
||||
case KernelBytecode::kDynamicCall_Wide:
|
||||
return KernelBytecode::DecodeD(instr);
|
||||
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static bool GetLoadedObjectAt(uword pc,
|
||||
const ObjectPool& object_pool,
|
||||
Object* obj) {
|
||||
const KBCInstr* instr = reinterpret_cast<const KBCInstr*>(pc);
|
||||
const intptr_t index = GetConstantPoolIndex(instr);
|
||||
if (index >= 0) {
|
||||
if (object_pool.TypeAt(index) == ObjectPool::EntryType::kTaggedObject) {
|
||||
*obj = object_pool.ObjectAt(index);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void KernelBytecodeDisassembler::DecodeInstruction(char* hex_buffer,
|
||||
intptr_t hex_size,
|
||||
char* human_buffer,
|
||||
intptr_t human_size,
|
||||
int* out_instr_size,
|
||||
const Bytecode& bytecode,
|
||||
Object** object,
|
||||
uword pc) {
|
||||
const KBCInstr* instr = reinterpret_cast<const KBCInstr*>(pc);
|
||||
const KernelBytecode::Opcode opcode = KernelBytecode::DecodeOpcode(instr);
|
||||
const intptr_t instr_size = KernelBytecode::kInstructionSize[opcode];
|
||||
|
||||
size_t name_size =
|
||||
Utils::SNPrint(human_buffer, human_size, "%-10s\t", kOpcodeNames[opcode]);
|
||||
human_buffer += name_size;
|
||||
human_size -= name_size;
|
||||
kFormatters[opcode](human_buffer, human_size, opcode, instr);
|
||||
|
||||
const intptr_t kCharactersPerByte = 3;
|
||||
if (hex_size > instr_size * kCharactersPerByte) {
|
||||
for (intptr_t i = 0; i < instr_size; ++i) {
|
||||
Utils::SNPrint(hex_buffer + (i * kCharactersPerByte),
|
||||
hex_size - (i * kCharactersPerByte), " %02x", instr[i]);
|
||||
}
|
||||
}
|
||||
if (out_instr_size != nullptr) {
|
||||
*out_instr_size = instr_size;
|
||||
}
|
||||
|
||||
*object = NULL;
|
||||
if (!bytecode.IsNull()) {
|
||||
*object = &Object::Handle();
|
||||
const ObjectPool& pool = ObjectPool::Handle(bytecode.object_pool());
|
||||
if (!GetLoadedObjectAt(pc, pool, *object)) {
|
||||
*object = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KernelBytecodeDisassembler::Disassemble(uword start,
|
||||
uword end,
|
||||
DisassemblyFormatter* formatter,
|
||||
const Bytecode& bytecode) {
|
||||
#if !defined(PRODUCT)
|
||||
ASSERT(formatter != NULL);
|
||||
char hex_buffer[kHexadecimalBufferSize]; // Instruction in hexadecimal form.
|
||||
char human_buffer[kUserReadableBufferSize]; // Human-readable instruction.
|
||||
uword pc = start;
|
||||
GrowableArray<const Function*> inlined_functions;
|
||||
GrowableArray<TokenPosition> token_positions;
|
||||
while (pc < end) {
|
||||
int instruction_length;
|
||||
Object* object;
|
||||
DecodeInstruction(hex_buffer, sizeof(hex_buffer), human_buffer,
|
||||
sizeof(human_buffer), &instruction_length, bytecode,
|
||||
&object, pc);
|
||||
formatter->ConsumeInstruction(hex_buffer, sizeof(hex_buffer), human_buffer,
|
||||
sizeof(human_buffer), object,
|
||||
FLAG_disassemble_relative ? pc - start : pc);
|
||||
pc += instruction_length;
|
||||
}
|
||||
#else
|
||||
UNREACHABLE();
|
||||
#endif
|
||||
}
|
||||
|
||||
void KernelBytecodeDisassembler::Disassemble(const Function& function) {
|
||||
#if !defined(PRODUCT)
|
||||
ASSERT(function.HasBytecode());
|
||||
const char* function_fullname = function.ToFullyQualifiedCString();
|
||||
Zone* zone = Thread::Current()->zone();
|
||||
const Bytecode& bytecode = Bytecode::Handle(zone, function.bytecode());
|
||||
THR_Print("Bytecode for function '%s' {\n", function_fullname);
|
||||
const uword start = bytecode.PayloadStart();
|
||||
const uword base = FLAG_disassemble_relative ? 0 : start;
|
||||
DisassembleToStdout stdout_formatter;
|
||||
LogBlock lb;
|
||||
Disassemble(start, start + bytecode.Size(), &stdout_formatter, bytecode);
|
||||
THR_Print("}\n");
|
||||
|
||||
const ObjectPool& object_pool =
|
||||
ObjectPool::Handle(zone, bytecode.object_pool());
|
||||
object_pool.DebugPrint();
|
||||
|
||||
THR_Print("PC Descriptors for function '%s' {\n", function_fullname);
|
||||
PcDescriptors::PrintHeaderString();
|
||||
const PcDescriptors& descriptors =
|
||||
PcDescriptors::Handle(zone, bytecode.pc_descriptors());
|
||||
THR_Print("%s}\n", descriptors.ToCString());
|
||||
|
||||
if (bytecode.HasSourcePositions()) {
|
||||
THR_Print("Source positions for function '%s' {\n", function_fullname);
|
||||
// 4 bits per hex digit + 2 for "0x".
|
||||
const int addr_width = (kBitsPerWord / 4) + 2;
|
||||
// "*" in a printf format specifier tells it to read the field width from
|
||||
// the printf argument list.
|
||||
THR_Print("%-*s\tpos\tline\tcolumn\tyield\n", addr_width, "pc");
|
||||
const Script& script = Script::Handle(zone, function.script());
|
||||
kernel::BytecodeSourcePositionsIterator iter(zone, bytecode);
|
||||
while (iter.MoveNext()) {
|
||||
TokenPosition pos = iter.TokenPos();
|
||||
intptr_t line = -1, column = -1;
|
||||
script.GetTokenLocation(pos, &line, &column);
|
||||
THR_Print("%#-*" Px "\t%s\t%" Pd "\t%" Pd "\t%s\n", addr_width,
|
||||
base + iter.PcOffset(), pos.ToCString(), line, column,
|
||||
iter.IsYieldPoint() ? "yield" : "");
|
||||
}
|
||||
THR_Print("}\n");
|
||||
}
|
||||
|
||||
if (FLAG_print_variable_descriptors && bytecode.HasLocalVariablesInfo()) {
|
||||
THR_Print("Local variables info for function '%s' {\n", function_fullname);
|
||||
kernel::BytecodeLocalVariablesIterator iter(zone, bytecode);
|
||||
while (iter.MoveNext()) {
|
||||
switch (iter.Kind()) {
|
||||
case kernel::BytecodeLocalVariablesIterator::kScope: {
|
||||
THR_Print("scope 0x%" Px "-0x%" Px " pos %s-%s\tlev %" Pd "\n",
|
||||
base + iter.StartPC(), base + iter.EndPC(),
|
||||
iter.StartTokenPos().ToCString(),
|
||||
iter.EndTokenPos().ToCString(), iter.ContextLevel());
|
||||
} break;
|
||||
case kernel::BytecodeLocalVariablesIterator::kVariableDeclaration: {
|
||||
THR_Print("var 0x%" Px "-0x%" Px " pos %s-%s\tidx %" Pd
|
||||
"\tdecl %s\t%s %s %s\n",
|
||||
base + iter.StartPC(), base + iter.EndPC(),
|
||||
iter.StartTokenPos().ToCString(),
|
||||
iter.EndTokenPos().ToCString(), iter.Index(),
|
||||
iter.DeclarationTokenPos().ToCString(),
|
||||
String::Handle(
|
||||
zone, AbstractType::Handle(zone, iter.Type()).Name())
|
||||
.ToCString(),
|
||||
String::Handle(zone, iter.Name()).ToCString(),
|
||||
iter.IsCaptured() ? "captured" : "");
|
||||
} break;
|
||||
case kernel::BytecodeLocalVariablesIterator::kContextVariable: {
|
||||
THR_Print("ctxt 0x%" Px "\tidx %" Pd "\n", base + iter.StartPC(),
|
||||
iter.Index());
|
||||
} break;
|
||||
}
|
||||
}
|
||||
THR_Print("}\n");
|
||||
|
||||
THR_Print("Local variable descriptors for function '%s' {\n",
|
||||
function_fullname);
|
||||
const auto& var_descriptors =
|
||||
LocalVarDescriptors::Handle(zone, bytecode.GetLocalVarDescriptors());
|
||||
THR_Print("%s}\n", var_descriptors.ToCString());
|
||||
}
|
||||
|
||||
THR_Print("Exception Handlers for function '%s' {\n", function_fullname);
|
||||
const ExceptionHandlers& handlers =
|
||||
ExceptionHandlers::Handle(zone, bytecode.exception_handlers());
|
||||
THR_Print("%s}\n", handlers.ToCString());
|
||||
|
||||
#else
|
||||
UNREACHABLE();
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME)
|
||||
@@ -1,89 +0,0 @@
|
||||
// Copyright (c) 2018, 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.
|
||||
|
||||
#ifndef RUNTIME_VM_COMPILER_ASSEMBLER_DISASSEMBLER_KBC_H_
|
||||
#define RUNTIME_VM_COMPILER_ASSEMBLER_DISASSEMBLER_KBC_H_
|
||||
|
||||
#include "vm/globals.h"
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
|
||||
#include "vm/compiler/assembler/disassembler.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
// Disassemble instructions.
|
||||
class KernelBytecodeDisassembler : public AllStatic {
|
||||
public:
|
||||
// Disassemble instructions between start and end.
|
||||
// (The assumption is that start is at a valid instruction).
|
||||
// Return true if all instructions were successfully decoded, false otherwise.
|
||||
static void Disassemble(uword start,
|
||||
uword end,
|
||||
DisassemblyFormatter* formatter,
|
||||
const Bytecode& bytecode);
|
||||
|
||||
static void Disassemble(uword start,
|
||||
uword end,
|
||||
DisassemblyFormatter* formatter) {
|
||||
Disassemble(start, end, formatter, Bytecode::Handle());
|
||||
}
|
||||
|
||||
static void Disassemble(uword start, uword end, const Bytecode& bytecode) {
|
||||
#if !defined(PRODUCT)
|
||||
DisassembleToStdout stdout_formatter;
|
||||
LogBlock lb;
|
||||
Disassemble(start, end, &stdout_formatter, bytecode);
|
||||
#else
|
||||
UNREACHABLE();
|
||||
#endif
|
||||
}
|
||||
|
||||
static void Disassemble(uword start, uword end) {
|
||||
#if !defined(PRODUCT)
|
||||
DisassembleToStdout stdout_formatter;
|
||||
LogBlock lb;
|
||||
Disassemble(start, end, &stdout_formatter);
|
||||
#else
|
||||
UNREACHABLE();
|
||||
#endif
|
||||
}
|
||||
|
||||
static void Disassemble(uword start,
|
||||
uword end,
|
||||
char* buffer,
|
||||
uintptr_t buffer_size) {
|
||||
#if !defined(PRODUCT)
|
||||
DisassembleToMemory memory_formatter(buffer, buffer_size);
|
||||
LogBlock lb;
|
||||
Disassemble(start, end, &memory_formatter);
|
||||
#else
|
||||
UNREACHABLE();
|
||||
#endif
|
||||
}
|
||||
|
||||
// Decodes one instruction.
|
||||
// Writes a hexadecimal representation into the hex_buffer and a
|
||||
// human-readable representation into the human_buffer.
|
||||
// Writes the length of the decoded instruction in bytes in out_instr_len.
|
||||
static void DecodeInstruction(char* hex_buffer,
|
||||
intptr_t hex_size,
|
||||
char* human_buffer,
|
||||
intptr_t human_size,
|
||||
int* out_instr_len,
|
||||
const Bytecode& bytecode,
|
||||
Object** object,
|
||||
uword pc);
|
||||
|
||||
static void Disassemble(const Function& function);
|
||||
|
||||
private:
|
||||
static const int kHexadecimalBufferSize = 32;
|
||||
static const int kUserReadableBufferSize = 256;
|
||||
};
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME)
|
||||
|
||||
#endif // RUNTIME_VM_COMPILER_ASSEMBLER_DISASSEMBLER_KBC_H_
|
||||
@@ -30,7 +30,6 @@ struct ObjectPoolBuilderEntry {
|
||||
kImmediate,
|
||||
kNativeFunction,
|
||||
kNativeFunctionWrapper,
|
||||
kNativeEntryData,
|
||||
};
|
||||
|
||||
using TypeBits = BitField<uint8_t, EntryType, 0, 7>;
|
||||
|
||||
@@ -162,10 +162,6 @@ class FlowGraph : public ZoneAllocated {
|
||||
}
|
||||
|
||||
intptr_t CurrentContextEnvIndex() const {
|
||||
if (function().HasBytecode()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return EnvIndex(parsed_function().current_context_var());
|
||||
}
|
||||
|
||||
|
||||
@@ -775,8 +775,7 @@ static intptr_t Usage(const Function& function) {
|
||||
// 'function' is queued for optimized compilation
|
||||
count = FLAG_optimization_counter_threshold;
|
||||
} else {
|
||||
// 'function' is queued for unoptimized compilation
|
||||
count = FLAG_compilation_counter_threshold;
|
||||
count = 0;
|
||||
}
|
||||
} else if (Code::IsOptimized(function.CurrentCode())) {
|
||||
// 'function' was optimized and stopped counting
|
||||
@@ -4834,10 +4833,8 @@ void InstanceCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
|
||||
|
||||
UpdateReceiverSminess(zone);
|
||||
|
||||
if ((compiler->is_optimizing() || compiler->function().HasBytecode()) &&
|
||||
HasICData()) {
|
||||
ASSERT(HasICData());
|
||||
if (compiler->is_optimizing() && (ic_data()->NumberOfUsedChecks() > 0)) {
|
||||
if (compiler->is_optimizing() && HasICData()) {
|
||||
if (ic_data()->NumberOfUsedChecks() > 0) {
|
||||
const ICData& unary_ic_data =
|
||||
ICData::ZoneHandle(zone, ic_data()->AsUnaryClassChecks());
|
||||
compiler->GenerateInstanceCall(deopt_id(), token_pos(), locs(),
|
||||
|
||||
@@ -174,29 +174,14 @@ ISOLATE_UNIT_TEST_CASE(IRTest_InitializingStores) {
|
||||
// which enables us to remove more stores.
|
||||
std::vector<const char*> expected_stores_jit;
|
||||
std::vector<const char*> expected_stores_aot;
|
||||
if (root_library.is_declared_in_bytecode()) {
|
||||
// Bytecode flow graph builder doesn't provide readable
|
||||
// variable names for captured variables. Also, bytecode may omit
|
||||
// stores of context parent in certain cases.
|
||||
expected_stores_jit.insert(
|
||||
expected_stores_jit.end(),
|
||||
{":context_var0", "Context.parent", ":context_var0",
|
||||
"Closure.function_type_arguments", "Closure.function",
|
||||
"Closure.context"});
|
||||
expected_stores_aot.insert(
|
||||
expected_stores_aot.end(),
|
||||
{":context_var0", "Closure.function_type_arguments", "Closure.function",
|
||||
"Closure.context"});
|
||||
} else {
|
||||
// These expectations are for AST-based flow graph builder.
|
||||
expected_stores_jit.insert(expected_stores_jit.end(),
|
||||
{"value", "Context.parent", "Context.parent",
|
||||
"value", "Closure.function_type_arguments",
|
||||
"Closure.function", "Closure.context"});
|
||||
expected_stores_aot.insert(expected_stores_aot.end(),
|
||||
{"value", "Closure.function_type_arguments",
|
||||
"Closure.function", "Closure.context"});
|
||||
}
|
||||
|
||||
expected_stores_jit.insert(expected_stores_jit.end(),
|
||||
{"value", "Context.parent", "Context.parent",
|
||||
"value", "Closure.function_type_arguments",
|
||||
"Closure.function", "Closure.context"});
|
||||
expected_stores_aot.insert(expected_stores_aot.end(),
|
||||
{"value", "Closure.function_type_arguments",
|
||||
"Closure.function", "Closure.context"});
|
||||
|
||||
RunInitializingStoresTest(root_library, "f4", CompilerPass::kJIT,
|
||||
expected_stores_jit);
|
||||
|
||||
@@ -71,12 +71,6 @@ TypeParameterPtr GetFunctionTypeParameter(const Function& fun,
|
||||
}
|
||||
|
||||
ObjectPtr Invoke(const Library& lib, const char* name) {
|
||||
// These tests rely on running unoptimized code to collect type feedback. The
|
||||
// interpreter does not collect type feedback for interface calls, so set
|
||||
// compilation threshold to 0 in order to compile invoked function
|
||||
// immediately and execute compiled code.
|
||||
SetFlagScope<int> sfs(&FLAG_compilation_counter_threshold, 0);
|
||||
|
||||
Thread* thread = Thread::Current();
|
||||
Dart_Handle api_lib = Api::NewHandle(thread, lib.raw());
|
||||
Dart_Handle result;
|
||||
|
||||
@@ -216,74 +216,42 @@ ISOLATE_UNIT_TEST_CASE(Inliner_List_generate) {
|
||||
ILMatcher cursor(flow_graph, entry, /*trace=*/true,
|
||||
ParallelMovesHandling::kSkip);
|
||||
|
||||
if (function.is_declared_in_bytecode()) {
|
||||
RELEASE_ASSERT(cursor.TryMatch({
|
||||
kMoveGlob,
|
||||
kMatchAndMoveCreateArray,
|
||||
kWordSize == 8 ? kMatchAndMoveUnboxInt64 : kNop,
|
||||
kMatchAndMoveGoto,
|
||||
Instruction* unbox1 = nullptr;
|
||||
Instruction* unbox2 = nullptr;
|
||||
|
||||
// Loop header
|
||||
kMatchAndMoveJoinEntry,
|
||||
kMatchAndMoveCheckStackOverflow,
|
||||
kMatchAndMoveUnboxInt64,
|
||||
kMatchAndMoveBranchTrue,
|
||||
RELEASE_ASSERT(cursor.TryMatch({
|
||||
kMoveGlob,
|
||||
kMatchAndMoveCreateArray,
|
||||
kMatchAndMoveUnboxInt64,
|
||||
{kMoveAny, &unbox1},
|
||||
{kMoveAny, &unbox2},
|
||||
kMatchAndMoveGoto,
|
||||
|
||||
// Loop body
|
||||
kMatchAndMoveTargetEntry,
|
||||
kMatchAndMoveGenericCheckBound,
|
||||
kMatchAndMoveStoreIndexed,
|
||||
kMatchAndMoveCheckedSmiOp,
|
||||
kMatchAndMoveGoto,
|
||||
// Loop header
|
||||
kMatchAndMoveJoinEntry,
|
||||
kMatchAndMoveCheckStackOverflow,
|
||||
kMatchAndMoveBranchTrue,
|
||||
|
||||
// Loop header once again
|
||||
kMatchAndMoveJoinEntry,
|
||||
kMatchAndMoveCheckStackOverflow,
|
||||
kMatchAndMoveUnboxInt64,
|
||||
kMatchAndMoveBranchFalse,
|
||||
// Loop body
|
||||
kMatchAndMoveTargetEntry,
|
||||
kWordSize == 4 ? kMatchAndMoveBoxInt64 : kNop,
|
||||
kMatchAndMoveBoxInt64,
|
||||
kMatchAndMoveStoreIndexed,
|
||||
kMatchAndMoveBinaryInt64Op,
|
||||
kMatchAndMoveGoto,
|
||||
|
||||
// After loop
|
||||
kMatchAndMoveTargetEntry,
|
||||
kMatchReturn,
|
||||
}));
|
||||
} else {
|
||||
Instruction* unbox1 = nullptr;
|
||||
Instruction* unbox2 = nullptr;
|
||||
// Loop header once again
|
||||
kMatchAndMoveJoinEntry,
|
||||
kMatchAndMoveCheckStackOverflow,
|
||||
kMatchAndMoveBranchFalse,
|
||||
|
||||
RELEASE_ASSERT(cursor.TryMatch({
|
||||
kMoveGlob,
|
||||
kMatchAndMoveCreateArray,
|
||||
kMatchAndMoveUnboxInt64,
|
||||
{kMoveAny, &unbox1},
|
||||
{kMoveAny, &unbox2},
|
||||
kMatchAndMoveGoto,
|
||||
// After loop
|
||||
kMatchAndMoveTargetEntry,
|
||||
kMatchReturn,
|
||||
}));
|
||||
|
||||
// Loop header
|
||||
kMatchAndMoveJoinEntry,
|
||||
kMatchAndMoveCheckStackOverflow,
|
||||
kMatchAndMoveBranchTrue,
|
||||
|
||||
// Loop body
|
||||
kMatchAndMoveTargetEntry,
|
||||
kWordSize == 4 ? kMatchAndMoveBoxInt64 : kNop,
|
||||
kMatchAndMoveBoxInt64,
|
||||
kMatchAndMoveStoreIndexed,
|
||||
kMatchAndMoveBinaryInt64Op,
|
||||
kMatchAndMoveGoto,
|
||||
|
||||
// Loop header once again
|
||||
kMatchAndMoveJoinEntry,
|
||||
kMatchAndMoveCheckStackOverflow,
|
||||
kMatchAndMoveBranchFalse,
|
||||
|
||||
// After loop
|
||||
kMatchAndMoveTargetEntry,
|
||||
kMatchReturn,
|
||||
}));
|
||||
|
||||
EXPECT(unbox1->IsUnboxedConstant() || unbox1->IsUnboxInt64());
|
||||
EXPECT(unbox2->IsUnboxedConstant() || unbox2->IsUnboxInt64());
|
||||
}
|
||||
EXPECT(unbox1->IsUnboxedConstant() || unbox1->IsUnboxInt64());
|
||||
EXPECT(unbox2->IsUnboxedConstant() || unbox2->IsUnboxInt64());
|
||||
}
|
||||
|
||||
#endif // defined(DART_PRECOMPILER)
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
#include "vm/compiler/backend/loops.h"
|
||||
#include "vm/compiler/backend/type_propagator.h"
|
||||
#include "vm/compiler/compiler_pass.h"
|
||||
#include "vm/compiler/frontend/bytecode_reader.h"
|
||||
#include "vm/compiler/frontend/kernel_to_il.h"
|
||||
#include "vm/compiler/jit/jit_call_specializer.h"
|
||||
#include "vm/flags.h"
|
||||
@@ -60,35 +59,6 @@ static void FlattenScopeIntoEnvironment(FlowGraph* graph,
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(PRODUCT)
|
||||
void PopulateEnvironmentFromBytecodeLocalVariables(
|
||||
const Function& function,
|
||||
FlowGraph* graph,
|
||||
GrowableArray<LocalVariable*>* env) {
|
||||
const auto& bytecode = Bytecode::Handle(function.bytecode());
|
||||
ASSERT(!bytecode.IsNull());
|
||||
|
||||
kernel::BytecodeLocalVariablesIterator iter(Thread::Current()->zone(),
|
||||
bytecode);
|
||||
while (iter.MoveNext()) {
|
||||
if (iter.IsVariableDeclaration() && !iter.IsCaptured()) {
|
||||
LocalVariable* const var = new LocalVariable(
|
||||
TokenPosition::kNoSource, TokenPosition::kNoSource,
|
||||
String::ZoneHandle(graph->zone(), iter.Name()),
|
||||
AbstractType::ZoneHandle(graph->zone(), iter.Type()));
|
||||
if (iter.Index() < 0) { // Parameter.
|
||||
var->set_index(VariableIndex(-iter.Index() - kKBCParamEndSlotFromFp));
|
||||
} else {
|
||||
var->set_index(VariableIndex(-iter.Index()));
|
||||
}
|
||||
const intptr_t env_index = graph->EnvIndex(var);
|
||||
env->EnsureLength(env_index + 1, nullptr);
|
||||
(*env)[env_index] = var;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Run TryCatchAnalyzer optimization on the function foo from the given script
|
||||
// and check that the only variables from the given list are synchronized
|
||||
// on catch entry.
|
||||
@@ -118,17 +88,7 @@ static void TryCatchOptimizerTest(
|
||||
auto scope = graph->parsed_function().scope();
|
||||
|
||||
GrowableArray<LocalVariable*> env;
|
||||
if (function.is_declared_in_bytecode()) {
|
||||
#if defined(PRODUCT)
|
||||
// In product mode information about local variables is not retained in
|
||||
// bytecode, so we can't find variables by names.
|
||||
return;
|
||||
#else
|
||||
PopulateEnvironmentFromBytecodeLocalVariables(function, graph, &env);
|
||||
#endif
|
||||
} else {
|
||||
FlattenScopeIntoEnvironment(graph, scope, &env);
|
||||
}
|
||||
FlattenScopeIntoEnvironment(graph, scope, &env);
|
||||
|
||||
for (intptr_t i = 0; i < env.length(); i++) {
|
||||
bool found = false;
|
||||
|
||||
@@ -111,14 +111,6 @@ compiler_sources = [
|
||||
"ffi/recognized_method.h",
|
||||
"frontend/base_flow_graph_builder.cc",
|
||||
"frontend/base_flow_graph_builder.h",
|
||||
"frontend/bytecode_fingerprints.cc",
|
||||
"frontend/bytecode_fingerprints.h",
|
||||
"frontend/bytecode_flow_graph_builder.cc",
|
||||
"frontend/bytecode_flow_graph_builder.h",
|
||||
"frontend/bytecode_reader.cc",
|
||||
"frontend/bytecode_reader.h",
|
||||
"frontend/bytecode_scope_builder.cc",
|
||||
"frontend/bytecode_scope_builder.h",
|
||||
"frontend/constant_reader.cc",
|
||||
"frontend/constant_reader.h",
|
||||
"frontend/flow_graph_builder.cc",
|
||||
@@ -210,7 +202,5 @@ disassembler_sources = [
|
||||
"assembler/disassembler.h",
|
||||
"assembler/disassembler_arm.cc",
|
||||
"assembler/disassembler_arm64.cc",
|
||||
"assembler/disassembler_kbc.cc",
|
||||
"assembler/disassembler_kbc.h",
|
||||
"assembler/disassembler_x86.cc",
|
||||
]
|
||||
|
||||
@@ -69,15 +69,6 @@ class CompilerState : public ThreadStackResource {
|
||||
|
||||
// Create a dummy list of local variables representing a context object
|
||||
// with the given number of captured variables and given ID.
|
||||
//
|
||||
// Used during bytecode to IL translation because AllocateContext and
|
||||
// CloneContext IL instructions need a list of local varaibles and bytecode
|
||||
// does not record this information.
|
||||
//
|
||||
// TODO(vegorov): create context classes for distinct context IDs and
|
||||
// populate them with slots without creating variables.
|
||||
// Beware that context_id is satured at 8-bits, so multiple contexts may
|
||||
// share id 255.
|
||||
const ZoneGrowableArray<const Slot*>& GetDummyContextSlots(
|
||||
intptr_t context_id,
|
||||
intptr_t num_context_slots);
|
||||
@@ -85,16 +76,8 @@ class CompilerState : public ThreadStackResource {
|
||||
// Create a dummy LocalVariable that represents a captured local variable
|
||||
// at the given index in the context with given ID.
|
||||
//
|
||||
// Used during bytecode to IL translation because StoreInstanceField and
|
||||
// LoadField IL instructions need Slot, which can only be created from a
|
||||
// LocalVariable.
|
||||
//
|
||||
// This function returns the same variable when it is called with the
|
||||
// same index.
|
||||
//
|
||||
// TODO(vegorov): disambiguate slots for different context IDs.
|
||||
// Beware that context_id is saturated at 8-bits, so multiple contexts may
|
||||
// share id 255.
|
||||
LocalVariable* GetDummyCapturedVariable(intptr_t context_id, intptr_t index);
|
||||
|
||||
bool is_aot() const { return is_aot_; }
|
||||
@@ -115,8 +98,7 @@ class CompilerState : public ThreadStackResource {
|
||||
// Cache for Slot objects created during compilation (see slot.h).
|
||||
SlotCache* slot_cache_ = nullptr;
|
||||
|
||||
// Caches for dummy LocalVariables and context Slots created during bytecode
|
||||
// to IL translation.
|
||||
// Caches for dummy LocalVariables and context Slots.
|
||||
ZoneGrowableArray<ZoneGrowableArray<const Slot*>*>* dummy_slots_ = nullptr;
|
||||
ZoneGrowableArray<LocalVariable*>* dummy_captured_vars_ = nullptr;
|
||||
|
||||
|
||||
@@ -465,7 +465,6 @@ class BaseFlowGraphBuilder {
|
||||
const Array& saved_args_desc_array_;
|
||||
|
||||
friend class StreamingFlowGraphBuilder;
|
||||
friend class BytecodeFlowGraphBuilder;
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(BaseFlowGraphBuilder);
|
||||
|
||||
@@ -1,207 +0,0 @@
|
||||
// Copyright (c) 2019, 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.
|
||||
|
||||
#include "vm/compiler/frontend/bytecode_fingerprints.h"
|
||||
|
||||
#include "vm/compiler/frontend/bytecode_reader.h"
|
||||
#include "vm/constants_kbc.h"
|
||||
#include "vm/hash.h"
|
||||
|
||||
namespace dart {
|
||||
namespace kernel {
|
||||
|
||||
static uint32_t CombineObject(uint32_t hash, const Object& obj) {
|
||||
if (obj.IsAbstractType()) {
|
||||
return CombineHashes(hash, AbstractType::Cast(obj).Hash());
|
||||
} else if (obj.IsClass()) {
|
||||
return CombineHashes(hash, Class::Cast(obj).id());
|
||||
} else if (obj.IsFunction()) {
|
||||
return CombineHashes(
|
||||
hash, AbstractType::Handle(Function::Cast(obj).result_type()).Hash());
|
||||
} else if (obj.IsField()) {
|
||||
return CombineHashes(hash,
|
||||
AbstractType::Handle(Field::Cast(obj).type()).Hash());
|
||||
} else {
|
||||
return CombineHashes(hash, static_cast<uint32_t>(obj.GetClassId()));
|
||||
}
|
||||
}
|
||||
|
||||
typedef uint32_t (*Fp)(uint32_t fp,
|
||||
const KBCInstr* instr,
|
||||
const ObjectPool& pool,
|
||||
int32_t value);
|
||||
|
||||
static uint32_t Fp___(uint32_t fp,
|
||||
const KBCInstr* instr,
|
||||
const ObjectPool& pool,
|
||||
int32_t value) {
|
||||
return fp;
|
||||
}
|
||||
|
||||
static uint32_t Fptgt(uint32_t fp,
|
||||
const KBCInstr* instr,
|
||||
const ObjectPool& pool,
|
||||
int32_t value) {
|
||||
return CombineHashes(fp, value);
|
||||
}
|
||||
|
||||
static uint32_t Fplit(uint32_t fp,
|
||||
const KBCInstr* instr,
|
||||
const ObjectPool& pool,
|
||||
int32_t value) {
|
||||
return CombineObject(fp, Object::Handle(pool.ObjectAt(value)));
|
||||
}
|
||||
|
||||
static uint32_t Fpreg(uint32_t fp,
|
||||
const KBCInstr* instr,
|
||||
const ObjectPool& pool,
|
||||
int32_t value) {
|
||||
return CombineHashes(fp, value);
|
||||
}
|
||||
|
||||
static uint32_t Fpxeg(uint32_t fp,
|
||||
const KBCInstr* instr,
|
||||
const ObjectPool& pool,
|
||||
int32_t value) {
|
||||
return CombineHashes(fp, value);
|
||||
}
|
||||
|
||||
static uint32_t Fpnum(uint32_t fp,
|
||||
const KBCInstr* instr,
|
||||
const ObjectPool& pool,
|
||||
int32_t value) {
|
||||
return CombineHashes(fp, value);
|
||||
}
|
||||
|
||||
static uint32_t Fingerprint0(uint32_t fp,
|
||||
const KBCInstr* instr,
|
||||
const ObjectPool& pool,
|
||||
Fp op1,
|
||||
Fp op2,
|
||||
Fp op3) {
|
||||
return fp;
|
||||
}
|
||||
|
||||
static uint32_t FingerprintA(uint32_t fp,
|
||||
const KBCInstr* instr,
|
||||
const ObjectPool& pool,
|
||||
Fp op1,
|
||||
Fp op2,
|
||||
Fp op3) {
|
||||
fp = op1(fp, instr, pool, KernelBytecode::DecodeA(instr));
|
||||
return fp;
|
||||
}
|
||||
|
||||
static uint32_t FingerprintD(uint32_t fp,
|
||||
const KBCInstr* instr,
|
||||
const ObjectPool& pool,
|
||||
Fp op1,
|
||||
Fp op2,
|
||||
Fp op3) {
|
||||
fp = op1(fp, instr, pool, KernelBytecode::DecodeD(instr));
|
||||
return fp;
|
||||
}
|
||||
|
||||
static uint32_t FingerprintX(uint32_t fp,
|
||||
const KBCInstr* instr,
|
||||
const ObjectPool& pool,
|
||||
Fp op1,
|
||||
Fp op2,
|
||||
Fp op3) {
|
||||
fp = op1(fp, instr, pool, KernelBytecode::DecodeX(instr));
|
||||
return fp;
|
||||
}
|
||||
|
||||
static uint32_t FingerprintT(uint32_t fp,
|
||||
const KBCInstr* instr,
|
||||
const ObjectPool& pool,
|
||||
Fp op1,
|
||||
Fp op2,
|
||||
Fp op3) {
|
||||
fp = op1(fp, instr, pool, KernelBytecode::DecodeT(instr));
|
||||
return fp;
|
||||
}
|
||||
|
||||
static uint32_t FingerprintA_E(uint32_t fp,
|
||||
const KBCInstr* instr,
|
||||
const ObjectPool& pool,
|
||||
Fp op1,
|
||||
Fp op2,
|
||||
Fp op3) {
|
||||
fp = op1(fp, instr, pool, KernelBytecode::DecodeA(instr));
|
||||
fp = op2(fp, instr, pool, KernelBytecode::DecodeE(instr));
|
||||
return fp;
|
||||
}
|
||||
|
||||
static uint32_t FingerprintA_Y(uint32_t fp,
|
||||
const KBCInstr* instr,
|
||||
const ObjectPool& pool,
|
||||
Fp op1,
|
||||
Fp op2,
|
||||
Fp op3) {
|
||||
fp = op1(fp, instr, pool, KernelBytecode::DecodeA(instr));
|
||||
fp = op2(fp, instr, pool, KernelBytecode::DecodeY(instr));
|
||||
return fp;
|
||||
}
|
||||
|
||||
static uint32_t FingerprintD_F(uint32_t fp,
|
||||
const KBCInstr* instr,
|
||||
const ObjectPool& pool,
|
||||
Fp op1,
|
||||
Fp op2,
|
||||
Fp op3) {
|
||||
fp = op1(fp, instr, pool, KernelBytecode::DecodeD(instr));
|
||||
fp = op2(fp, instr, pool, KernelBytecode::DecodeF(instr));
|
||||
return fp;
|
||||
}
|
||||
|
||||
static uint32_t FingerprintA_B_C(uint32_t fp,
|
||||
const KBCInstr* instr,
|
||||
const ObjectPool& pool,
|
||||
Fp op1,
|
||||
Fp op2,
|
||||
Fp op3) {
|
||||
fp = op1(fp, instr, pool, KernelBytecode::DecodeA(instr));
|
||||
fp = op2(fp, instr, pool, KernelBytecode::DecodeB(instr));
|
||||
fp = op3(fp, instr, pool, KernelBytecode::DecodeC(instr));
|
||||
return fp;
|
||||
}
|
||||
|
||||
uint32_t BytecodeFingerprintHelper::CalculateFunctionFingerprint(
|
||||
const Function& function) {
|
||||
ASSERT(function.is_declared_in_bytecode());
|
||||
const intptr_t kHashBits = 30;
|
||||
uint32_t fp = 0;
|
||||
fp = CombineHashes(fp, String::Handle(function.UserVisibleName()).Hash());
|
||||
if (function.is_abstract()) {
|
||||
return FinalizeHash(fp, kHashBits);
|
||||
}
|
||||
if (!function.HasBytecode()) {
|
||||
kernel::BytecodeReader::ReadFunctionBytecode(Thread::Current(), function);
|
||||
}
|
||||
const Bytecode& code = Bytecode::Handle(function.bytecode());
|
||||
const ObjectPool& pool = ObjectPool::Handle(code.object_pool());
|
||||
const KBCInstr* const start =
|
||||
reinterpret_cast<const KBCInstr*>(code.instructions());
|
||||
for (const KBCInstr* instr = start; (instr - start) < code.Size();
|
||||
instr = KernelBytecode::Next(instr)) {
|
||||
const KernelBytecode::Opcode opcode = KernelBytecode::DecodeOpcode(instr);
|
||||
fp = CombineHashes(fp, opcode);
|
||||
switch (opcode) {
|
||||
#define FINGERPRINT_BYTECODE(name, encoding, kind, op1, op2, op3) \
|
||||
case KernelBytecode::k##name: \
|
||||
fp = Fingerprint##encoding(fp, instr, pool, Fp##op1, Fp##op2, Fp##op3); \
|
||||
break;
|
||||
KERNEL_BYTECODES_LIST(FINGERPRINT_BYTECODE)
|
||||
#undef FINGERPRINT_BYTECODE
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
return FinalizeHash(fp, kHashBits);
|
||||
}
|
||||
|
||||
} // namespace kernel
|
||||
} // namespace dart
|
||||
@@ -1,26 +0,0 @@
|
||||
// Copyright (c) 2019, 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.
|
||||
|
||||
#ifndef RUNTIME_VM_COMPILER_FRONTEND_BYTECODE_FINGERPRINTS_H_
|
||||
#define RUNTIME_VM_COMPILER_FRONTEND_BYTECODE_FINGERPRINTS_H_
|
||||
|
||||
#if defined(DART_PRECOMPILED_RUNTIME)
|
||||
#error "AOT runtime should not use compiler sources (including header files)"
|
||||
#endif // defined(DART_PRECOMPILED_RUNTIME)
|
||||
|
||||
#include "platform/allocation.h"
|
||||
#include "vm/object.h"
|
||||
|
||||
namespace dart {
|
||||
namespace kernel {
|
||||
|
||||
class BytecodeFingerprintHelper : public AllStatic {
|
||||
public:
|
||||
static uint32_t CalculateFunctionFingerprint(const Function& func);
|
||||
};
|
||||
|
||||
} // namespace kernel
|
||||
} // namespace dart
|
||||
|
||||
#endif // RUNTIME_VM_COMPILER_FRONTEND_BYTECODE_FINGERPRINTS_H_
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,252 +0,0 @@
|
||||
// Copyright (c) 2018, 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.
|
||||
|
||||
#ifndef RUNTIME_VM_COMPILER_FRONTEND_BYTECODE_FLOW_GRAPH_BUILDER_H_
|
||||
#define RUNTIME_VM_COMPILER_FRONTEND_BYTECODE_FLOW_GRAPH_BUILDER_H_
|
||||
|
||||
#if defined(DART_PRECOMPILED_RUNTIME)
|
||||
#error "AOT runtime should not use compiler sources (including header files)"
|
||||
#endif // defined(DART_PRECOMPILED_RUNTIME)
|
||||
|
||||
#include "vm/compiler/backend/il.h"
|
||||
#include "vm/compiler/frontend/base_flow_graph_builder.h"
|
||||
#include "vm/compiler/frontend/kernel_translation_helper.h" // For InferredTypeMetadata
|
||||
#include "vm/constants_kbc.h"
|
||||
|
||||
namespace dart {
|
||||
namespace kernel {
|
||||
|
||||
class BytecodeLocalVariablesIterator;
|
||||
|
||||
// This class builds flow graph from bytecode. It is used either to compile
|
||||
// from bytecode, or generate bytecode interpreter (the latter is not
|
||||
// fully implemented yet).
|
||||
// TODO(alexmarkov): extend this class and IL to generate an interpreter in
|
||||
// addition to compiling bytecode.
|
||||
class BytecodeFlowGraphBuilder {
|
||||
public:
|
||||
BytecodeFlowGraphBuilder(BaseFlowGraphBuilder* flow_graph_builder,
|
||||
ParsedFunction* parsed_function,
|
||||
ZoneGrowableArray<const ICData*>* ic_data_array)
|
||||
: flow_graph_builder_(flow_graph_builder),
|
||||
zone_(flow_graph_builder->zone_),
|
||||
is_generating_interpreter_(
|
||||
false), // TODO(alexmarkov): pass as argument
|
||||
parsed_function_(parsed_function),
|
||||
ic_data_array_(ic_data_array),
|
||||
object_pool_(ObjectPool::Handle(zone_)),
|
||||
bytecode_length_(0),
|
||||
pc_(0),
|
||||
position_(TokenPosition::kNoSource),
|
||||
local_vars_(zone_, 0),
|
||||
parameters_(zone_, 0),
|
||||
exception_var_(nullptr),
|
||||
stacktrace_var_(nullptr),
|
||||
scratch_var_(nullptr),
|
||||
prologue_info_(-1, -1),
|
||||
throw_no_such_method_(nullptr),
|
||||
inferred_types_attribute_(Array::Handle(zone_)) {}
|
||||
|
||||
FlowGraph* BuildGraph();
|
||||
|
||||
// Create parameter variables without building a flow graph.
|
||||
void CreateParameterVariables();
|
||||
|
||||
protected:
|
||||
// Returns `true` if building a flow graph for a bytecode interpreter, or
|
||||
// `false` if compiling a function from bytecode.
|
||||
bool is_generating_interpreter() const { return is_generating_interpreter_; }
|
||||
|
||||
private:
|
||||
// Operand of bytecode instruction, either intptr_t value (if compiling
|
||||
// bytecode) or Definition (if generating interpreter).
|
||||
class Operand {
|
||||
public:
|
||||
explicit Operand(Definition* definition)
|
||||
: definition_(definition), value_(0) {
|
||||
ASSERT(definition != nullptr);
|
||||
}
|
||||
|
||||
explicit Operand(intptr_t value) : definition_(nullptr), value_(value) {}
|
||||
|
||||
Definition* definition() const {
|
||||
ASSERT(definition_ != nullptr);
|
||||
return definition_;
|
||||
}
|
||||
|
||||
intptr_t value() const {
|
||||
ASSERT(definition_ == nullptr);
|
||||
return value_;
|
||||
}
|
||||
|
||||
private:
|
||||
Definition* definition_;
|
||||
intptr_t value_;
|
||||
};
|
||||
|
||||
// Constant from a constant pool.
|
||||
// It is either Object (if compiling bytecode) or Definition
|
||||
// (if generating interpreter).
|
||||
class Constant {
|
||||
public:
|
||||
explicit Constant(Definition* definition)
|
||||
: definition_(definition), value_(Object::null_object()) {
|
||||
ASSERT(definition != nullptr);
|
||||
}
|
||||
|
||||
explicit Constant(Zone* zone, const Object& value)
|
||||
: definition_(nullptr), value_(value) {}
|
||||
|
||||
Definition* definition() const {
|
||||
ASSERT(definition_ != nullptr);
|
||||
return definition_;
|
||||
}
|
||||
|
||||
const Object& value() const {
|
||||
ASSERT(definition_ == nullptr);
|
||||
return value_;
|
||||
}
|
||||
|
||||
private:
|
||||
Definition* definition_;
|
||||
const Object& value_;
|
||||
};
|
||||
|
||||
// Scope declared in bytecode local variables information.
|
||||
class BytecodeScope : public ZoneAllocated {
|
||||
public:
|
||||
BytecodeScope(Zone* zone,
|
||||
intptr_t end_pc,
|
||||
intptr_t context_level,
|
||||
BytecodeScope* parent)
|
||||
: end_pc_(end_pc),
|
||||
context_level_(context_level),
|
||||
parent_(parent),
|
||||
hidden_vars_(zone, 4) {}
|
||||
|
||||
const intptr_t end_pc_;
|
||||
const intptr_t context_level_;
|
||||
BytecodeScope* const parent_;
|
||||
ZoneGrowableArray<LocalVariable*> hidden_vars_;
|
||||
};
|
||||
|
||||
Operand DecodeOperandA();
|
||||
Operand DecodeOperandB();
|
||||
Operand DecodeOperandC();
|
||||
Operand DecodeOperandD();
|
||||
Operand DecodeOperandE();
|
||||
Operand DecodeOperandF();
|
||||
Operand DecodeOperandX();
|
||||
Operand DecodeOperandY();
|
||||
Operand DecodeOperandT();
|
||||
Constant ConstantAt(Operand entry_index, intptr_t add_index = 0);
|
||||
void PushConstant(Constant constant);
|
||||
Constant PopConstant();
|
||||
void LoadStackSlots(intptr_t num_slots);
|
||||
void AllocateLocalVariables(Operand frame_size,
|
||||
intptr_t num_param_locals = 0);
|
||||
LocalVariable* AllocateParameter(intptr_t param_index,
|
||||
VariableIndex var_index);
|
||||
void AllocateFixedParameters();
|
||||
|
||||
// Allocates parameters and local variables in case of EntryOptional.
|
||||
// Returns pointer to the instruction after EntryOptional/LoadConstant/Frame
|
||||
// bytecodes.
|
||||
const KBCInstr* AllocateParametersAndLocalsForEntryOptional();
|
||||
|
||||
LocalVariable* LocalVariableAt(intptr_t local_index);
|
||||
void StoreLocal(Operand local_index);
|
||||
void LoadLocal(Operand local_index);
|
||||
Value* Pop();
|
||||
intptr_t GetStackDepth() const;
|
||||
bool IsStackEmpty() const;
|
||||
InferredTypeMetadata GetInferredType(intptr_t pc);
|
||||
void PropagateStackState(intptr_t target_pc);
|
||||
void DropUnusedValuesFromStack();
|
||||
void BuildJumpIfStrictCompare(Token::Kind cmp_kind);
|
||||
void BuildPrimitiveOp(const String& name,
|
||||
Token::Kind token_kind,
|
||||
const AbstractType& static_receiver_type,
|
||||
int num_args);
|
||||
void BuildIntOp(const String& name, Token::Kind token_kind, int num_args);
|
||||
void BuildDoubleOp(const String& name, Token::Kind token_kind, int num_args);
|
||||
void BuildDirectCallCommon(bool is_unchecked_call);
|
||||
void BuildInterfaceCallCommon(bool is_unchecked_call,
|
||||
bool is_instantiated_call);
|
||||
|
||||
void BuildInstruction(KernelBytecode::Opcode opcode);
|
||||
void BuildFfiAsFunction();
|
||||
void BuildFfiNativeCallbackFunction();
|
||||
void BuildDebugStepCheck();
|
||||
|
||||
#define DECLARE_BUILD_METHOD(name, encoding, kind, op1, op2, op3) \
|
||||
void Build##name();
|
||||
KERNEL_BYTECODES_LIST(DECLARE_BUILD_METHOD)
|
||||
#undef DECLARE_BUILD_METHOD
|
||||
|
||||
intptr_t GetTryIndex(const PcDescriptors& descriptors, intptr_t pc);
|
||||
JoinEntryInstr* EnsureControlFlowJoin(const PcDescriptors& descriptors,
|
||||
intptr_t pc);
|
||||
bool RequiresScratchVar(const KBCInstr* instr);
|
||||
void CollectControlFlow(const PcDescriptors& descriptors,
|
||||
const ExceptionHandlers& handlers,
|
||||
GraphEntryInstr* graph_entry);
|
||||
|
||||
// Update current scope, context level and local variables for the given PC.
|
||||
// Returns next PC where scope might need an update.
|
||||
intptr_t UpdateScope(BytecodeLocalVariablesIterator* iter, intptr_t pc);
|
||||
|
||||
// Figure out entry points style.
|
||||
UncheckedEntryPointStyle ChooseEntryPointStyle(
|
||||
const KBCInstr* jump_if_unchecked);
|
||||
|
||||
Thread* thread() const { return flow_graph_builder_->thread_; }
|
||||
Isolate* isolate() const { return thread()->isolate(); }
|
||||
|
||||
ParsedFunction* parsed_function() const {
|
||||
ASSERT(!is_generating_interpreter());
|
||||
return parsed_function_;
|
||||
}
|
||||
const Function& function() const { return parsed_function()->function(); }
|
||||
|
||||
BaseFlowGraphBuilder* flow_graph_builder_;
|
||||
Zone* zone_;
|
||||
bool is_generating_interpreter_;
|
||||
|
||||
// The following members are available only when compiling bytecode.
|
||||
|
||||
ParsedFunction* parsed_function_;
|
||||
ZoneGrowableArray<const ICData*>* ic_data_array_;
|
||||
ObjectPool& object_pool_;
|
||||
const KBCInstr* raw_bytecode_ = nullptr;
|
||||
intptr_t bytecode_length_;
|
||||
intptr_t pc_;
|
||||
intptr_t next_pc_ = -1;
|
||||
const KBCInstr* bytecode_instr_ = nullptr;
|
||||
TokenPosition position_;
|
||||
intptr_t last_yield_point_pc_ = 0;
|
||||
intptr_t last_yield_point_index_ = 0;
|
||||
Fragment code_;
|
||||
ZoneGrowableArray<LocalVariable*> local_vars_;
|
||||
ZoneGrowableArray<LocalVariable*> parameters_;
|
||||
LocalVariable* exception_var_;
|
||||
LocalVariable* stacktrace_var_;
|
||||
LocalVariable* scratch_var_;
|
||||
IntMap<JoinEntryInstr*> jump_targets_;
|
||||
IntMap<Value*> stack_states_;
|
||||
PrologueInfo prologue_info_;
|
||||
JoinEntryInstr* throw_no_such_method_;
|
||||
GraphEntryInstr* graph_entry_ = nullptr;
|
||||
UncheckedEntryPointStyle entry_point_style_ = UncheckedEntryPointStyle::kNone;
|
||||
bool build_debug_step_checks_ = false;
|
||||
bool seen_parameters_scope_ = false;
|
||||
BytecodeScope* current_scope_ = nullptr;
|
||||
Array& inferred_types_attribute_;
|
||||
intptr_t inferred_types_index_ = 0;
|
||||
};
|
||||
|
||||
} // namespace kernel
|
||||
} // namespace dart
|
||||
|
||||
#endif // RUNTIME_VM_COMPILER_FRONTEND_BYTECODE_FLOW_GRAPH_BUILDER_H_
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,589 +0,0 @@
|
||||
// Copyright (c) 2018, 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.
|
||||
|
||||
#ifndef RUNTIME_VM_COMPILER_FRONTEND_BYTECODE_READER_H_
|
||||
#define RUNTIME_VM_COMPILER_FRONTEND_BYTECODE_READER_H_
|
||||
|
||||
#if defined(DART_PRECOMPILED_RUNTIME)
|
||||
#error "AOT runtime should not use compiler sources (including header files)"
|
||||
#endif // defined(DART_PRECOMPILED_RUNTIME)
|
||||
|
||||
#include "vm/compiler/frontend/kernel_translation_helper.h"
|
||||
#include "vm/constants_kbc.h"
|
||||
#include "vm/object.h"
|
||||
|
||||
namespace dart {
|
||||
namespace kernel {
|
||||
|
||||
class BytecodeComponentData;
|
||||
|
||||
// Helper class which provides access to bytecode metadata.
|
||||
class BytecodeMetadataHelper : public MetadataHelper {
|
||||
public:
|
||||
static const char* tag() { return "vm.bytecode"; }
|
||||
|
||||
explicit BytecodeMetadataHelper(KernelReaderHelper* helper,
|
||||
ActiveClass* active_class);
|
||||
|
||||
void ParseBytecodeFunction(ParsedFunction* parsed_function);
|
||||
|
||||
// Read all library declarations.
|
||||
bool ReadLibraries();
|
||||
|
||||
// Read specific library declaration.
|
||||
void ReadLibrary(const Library& library);
|
||||
|
||||
// Scan through libraries in the bytecode component and figure out if any of
|
||||
// them will replace libraries which are already loaded.
|
||||
// Return true if bytecode component is found.
|
||||
bool FindModifiedLibrariesForHotReload(BitVector* modified_libs,
|
||||
bool* is_empty_program,
|
||||
intptr_t* p_num_classes,
|
||||
intptr_t* p_num_procedures);
|
||||
|
||||
LibraryPtr GetMainLibrary();
|
||||
|
||||
ArrayPtr GetBytecodeComponent();
|
||||
ArrayPtr ReadBytecodeComponent();
|
||||
|
||||
private:
|
||||
ActiveClass* const active_class_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(BytecodeMetadataHelper);
|
||||
};
|
||||
|
||||
// Helper class for reading bytecode.
|
||||
class BytecodeReaderHelper : public ValueObject {
|
||||
public:
|
||||
explicit BytecodeReaderHelper(TranslationHelper* translation_helper,
|
||||
ActiveClass* active_class,
|
||||
BytecodeComponentData* bytecode_component);
|
||||
|
||||
Reader& reader() { return reader_; }
|
||||
|
||||
void ReadCode(const Function& function, intptr_t code_offset);
|
||||
|
||||
ArrayPtr CreateForwarderChecks(const Function& function);
|
||||
|
||||
void ReadMembers(const Class& cls, bool discard_fields);
|
||||
|
||||
void ReadFieldDeclarations(const Class& cls, bool discard_fields);
|
||||
void ReadFunctionDeclarations(const Class& cls);
|
||||
void ReadClassDeclaration(const Class& cls);
|
||||
void ReadLibraryDeclaration(const Library& library, bool lookup_classes);
|
||||
void ReadLibraryDeclarations(intptr_t num_libraries);
|
||||
void FindAndReadSpecificLibrary(const Library& library,
|
||||
intptr_t num_libraries);
|
||||
void FindModifiedLibrariesForHotReload(BitVector* modified_libs,
|
||||
intptr_t num_libraries);
|
||||
|
||||
void ParseBytecodeFunction(ParsedFunction* parsed_function,
|
||||
const Function& function);
|
||||
|
||||
LibraryPtr ReadMain();
|
||||
|
||||
ArrayPtr ReadBytecodeComponent(intptr_t md_offset);
|
||||
void ResetObjects();
|
||||
|
||||
// Fills in [is_covariant] and [is_generic_covariant_impl] vectors
|
||||
// according to covariance attributes of [function] parameters.
|
||||
//
|
||||
// [function] should be declared in bytecode.
|
||||
// [is_covariant] and [is_generic_covariant_impl] should contain bitvectors
|
||||
// of function.NumParameters() length.
|
||||
void ReadParameterCovariance(const Function& function,
|
||||
BitVector* is_covariant,
|
||||
BitVector* is_generic_covariant_impl);
|
||||
|
||||
// Returns an flattened array of tuples {isFinal, defaultValue, metadata},
|
||||
// or an Error.
|
||||
ObjectPtr BuildParameterDescriptor(const Function& function);
|
||||
|
||||
// Read bytecode PackedObject.
|
||||
ObjectPtr ReadObject();
|
||||
|
||||
private:
|
||||
// These constants should match corresponding constants in class ObjectHandle
|
||||
// (pkg/vm/lib/bytecode/object_table.dart).
|
||||
static const int kReferenceBit = 1 << 0;
|
||||
static const int kIndexShift = 1;
|
||||
static const int kKindShift = 1;
|
||||
static const int kKindMask = 0x0f;
|
||||
static const int kFlagBit0 = 1 << 5;
|
||||
static const int kFlagBit1 = 1 << 6;
|
||||
static const int kFlagBit2 = 1 << 7;
|
||||
static const int kFlagBit3 = 1 << 8;
|
||||
static const int kFlagBit4 = 1 << 9;
|
||||
static const int kFlagBit5 = 1 << 10;
|
||||
static const int kTagMask = (kFlagBit0 | kFlagBit1 | kFlagBit2 | kFlagBit3);
|
||||
static const int kNullabilityMask = (kFlagBit4 | kFlagBit5);
|
||||
static const int kFlagsMask = (kTagMask | kNullabilityMask);
|
||||
|
||||
// Code flags, must be in sync with Code constants in
|
||||
// pkg/vm/lib/bytecode/declarations.dart.
|
||||
struct Code {
|
||||
static const int kHasExceptionsTableFlag = 1 << 0;
|
||||
static const int kHasSourcePositionsFlag = 1 << 1;
|
||||
static const int kHasNullableFieldsFlag = 1 << 2;
|
||||
static const int kHasClosuresFlag = 1 << 3;
|
||||
static const int kHasParameterFlagsFlag = 1 << 4;
|
||||
static const int kHasForwardingStubTargetFlag = 1 << 5;
|
||||
static const int kHasDefaultFunctionTypeArgsFlag = 1 << 6;
|
||||
static const int kHasLocalVariablesFlag = 1 << 7;
|
||||
};
|
||||
|
||||
// Closure code flags, must be in sync with ClosureCode constants in
|
||||
// pkg/vm/lib/bytecode/declarations.dart.
|
||||
struct ClosureCode {
|
||||
static const int kHasExceptionsTableFlag = 1 << 0;
|
||||
static const int kHasSourcePositionsFlag = 1 << 1;
|
||||
static const int kHasLocalVariablesFlag = 1 << 2;
|
||||
};
|
||||
|
||||
// Parameter flags, must be in sync with ParameterDeclaration constants in
|
||||
// pkg/vm/lib/bytecode/declarations.dart.
|
||||
struct Parameter {
|
||||
static const int kIsCovariantFlag = 1 << 0;
|
||||
static const int kIsGenericCovariantImplFlag = 1 << 1;
|
||||
static const int kIsFinalFlag = 1 << 2;
|
||||
static const int kIsRequiredFlag = 1 << 3;
|
||||
};
|
||||
|
||||
class FunctionTypeScope : public ValueObject {
|
||||
public:
|
||||
explicit FunctionTypeScope(BytecodeReaderHelper* bytecode_reader)
|
||||
: bytecode_reader_(bytecode_reader),
|
||||
saved_type_parameters_(
|
||||
bytecode_reader->function_type_type_parameters_) {}
|
||||
|
||||
~FunctionTypeScope() {
|
||||
bytecode_reader_->function_type_type_parameters_ = saved_type_parameters_;
|
||||
}
|
||||
|
||||
private:
|
||||
BytecodeReaderHelper* bytecode_reader_;
|
||||
const TypeArguments* const saved_type_parameters_;
|
||||
};
|
||||
|
||||
class FunctionScope : public ValueObject {
|
||||
public:
|
||||
FunctionScope(BytecodeReaderHelper* bytecode_reader,
|
||||
const Function& function,
|
||||
const String& name,
|
||||
const Class& cls)
|
||||
: bytecode_reader_(bytecode_reader) {
|
||||
ASSERT(bytecode_reader_->scoped_function_.IsNull());
|
||||
ASSERT(bytecode_reader_->scoped_function_name_.IsNull());
|
||||
ASSERT(bytecode_reader_->scoped_function_class_.IsNull());
|
||||
ASSERT(name.IsSymbol());
|
||||
bytecode_reader_->scoped_function_ = function.raw();
|
||||
bytecode_reader_->scoped_function_name_ = name.raw();
|
||||
bytecode_reader_->scoped_function_class_ = cls.raw();
|
||||
}
|
||||
|
||||
~FunctionScope() {
|
||||
bytecode_reader_->scoped_function_ = Function::null();
|
||||
bytecode_reader_->scoped_function_name_ = String::null();
|
||||
bytecode_reader_->scoped_function_class_ = Class::null();
|
||||
}
|
||||
|
||||
private:
|
||||
BytecodeReaderHelper* bytecode_reader_;
|
||||
};
|
||||
|
||||
void ReadClosureDeclaration(const Function& function, intptr_t closureIndex);
|
||||
TypePtr ReadFunctionSignature(const Function& func,
|
||||
bool has_optional_positional_params,
|
||||
bool has_optional_named_params,
|
||||
bool has_type_params,
|
||||
bool has_positional_param_names,
|
||||
bool has_parameter_flags,
|
||||
Nullability nullability);
|
||||
void ReadTypeParametersDeclaration(const Class& parameterized_class,
|
||||
const Function& parameterized_function);
|
||||
|
||||
// Read portion of constant pool corresponding to one function/closure.
|
||||
// Start with [start_index], and stop when reaching EndClosureFunctionScope.
|
||||
// Return index of the last read constant pool entry.
|
||||
intptr_t ReadConstantPool(const Function& function,
|
||||
const ObjectPool& pool,
|
||||
intptr_t start_index);
|
||||
|
||||
BytecodePtr ReadBytecode(const ObjectPool& pool);
|
||||
void ReadExceptionsTable(const Bytecode& bytecode, bool has_exceptions_table);
|
||||
void ReadSourcePositions(const Bytecode& bytecode, bool has_source_positions);
|
||||
void ReadLocalVariables(const Bytecode& bytecode, bool has_local_variables);
|
||||
TypedDataPtr NativeEntry(const Function& function,
|
||||
const String& external_name);
|
||||
StringPtr ConstructorName(const Class& cls, const String& name);
|
||||
|
||||
ObjectPtr ReadObjectContents(uint32_t header);
|
||||
ObjectPtr ReadConstObject(intptr_t tag);
|
||||
ObjectPtr ReadType(intptr_t tag, Nullability nullability);
|
||||
StringPtr ReadString(bool is_canonical = true);
|
||||
ScriptPtr ReadSourceFile(const String& uri, intptr_t offset);
|
||||
TypeArgumentsPtr ReadTypeArguments();
|
||||
void ReadAttributes(const Object& key);
|
||||
PatchClassPtr GetPatchClass(const Class& cls, const Script& script);
|
||||
void ParseForwarderFunction(ParsedFunction* parsed_function,
|
||||
const Function& function,
|
||||
const Function& target);
|
||||
|
||||
bool IsExpressionEvaluationLibrary(const Library& library) const {
|
||||
return expression_evaluation_library_ != nullptr &&
|
||||
expression_evaluation_library_->raw() == library.raw();
|
||||
}
|
||||
|
||||
// Similar to cls.EnsureClassDeclaration, but may be more efficient if
|
||||
// class is from the current kernel binary.
|
||||
void LoadReferencedClass(const Class& cls);
|
||||
|
||||
Reader reader_;
|
||||
TranslationHelper& translation_helper_;
|
||||
ActiveClass* const active_class_;
|
||||
Thread* const thread_;
|
||||
Zone* const zone_;
|
||||
BytecodeComponentData* bytecode_component_;
|
||||
Array* closures_ = nullptr;
|
||||
const TypeArguments* function_type_type_parameters_ = nullptr;
|
||||
GrowableObjectArray* pending_recursive_types_ = nullptr;
|
||||
PatchClass* patch_class_ = nullptr;
|
||||
Array* functions_ = nullptr;
|
||||
intptr_t function_index_ = 0;
|
||||
Function& scoped_function_;
|
||||
String& scoped_function_name_;
|
||||
Class& scoped_function_class_;
|
||||
Library* expression_evaluation_library_ = nullptr;
|
||||
bool loading_native_wrappers_library_ = false;
|
||||
bool reading_type_arguments_of_recursive_type_ = false;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(BytecodeReaderHelper);
|
||||
};
|
||||
|
||||
class BytecodeComponentData : ValueObject {
|
||||
public:
|
||||
enum {
|
||||
kVersion,
|
||||
kStringsHeaderOffset,
|
||||
kStringsContentsOffset,
|
||||
kObjectOffsetsOffset,
|
||||
kNumObjects,
|
||||
kObjectsContentsOffset,
|
||||
kMainOffset,
|
||||
kNumLibraries,
|
||||
kLibraryIndexOffset,
|
||||
kLibrariesOffset,
|
||||
kNumClasses,
|
||||
kClassesOffset,
|
||||
kMembersOffset,
|
||||
kNumCodes,
|
||||
kCodesOffset,
|
||||
kSourcePositionsOffset,
|
||||
kSourceFilesOffset,
|
||||
kLineStartsOffset,
|
||||
kLocalVariablesOffset,
|
||||
kAnnotationsOffset,
|
||||
kNumFields
|
||||
};
|
||||
|
||||
explicit BytecodeComponentData(Array* data) : data_(*data) {}
|
||||
|
||||
void Init(const Array& data) { data_ = data.raw(); }
|
||||
|
||||
intptr_t GetVersion() const;
|
||||
intptr_t GetStringsHeaderOffset() const;
|
||||
intptr_t GetStringsContentsOffset() const;
|
||||
intptr_t GetObjectOffsetsOffset() const;
|
||||
intptr_t GetNumObjects() const;
|
||||
intptr_t GetObjectsContentsOffset() const;
|
||||
intptr_t GetMainOffset() const;
|
||||
intptr_t GetNumLibraries() const;
|
||||
intptr_t GetLibraryIndexOffset() const;
|
||||
intptr_t GetLibrariesOffset() const;
|
||||
intptr_t GetNumClasses() const;
|
||||
intptr_t GetClassesOffset() const;
|
||||
intptr_t GetMembersOffset() const;
|
||||
intptr_t GetNumCodes() const;
|
||||
intptr_t GetCodesOffset() const;
|
||||
intptr_t GetSourcePositionsOffset() const;
|
||||
intptr_t GetSourceFilesOffset() const;
|
||||
intptr_t GetLineStartsOffset() const;
|
||||
intptr_t GetLocalVariablesOffset() const;
|
||||
intptr_t GetAnnotationsOffset() const;
|
||||
void SetObject(intptr_t index, const Object& obj) const;
|
||||
ObjectPtr GetObject(intptr_t index) const;
|
||||
|
||||
bool IsNull() const { return data_.IsNull(); }
|
||||
|
||||
static ArrayPtr New(Zone* zone,
|
||||
intptr_t version,
|
||||
intptr_t num_objects,
|
||||
intptr_t strings_header_offset,
|
||||
intptr_t strings_contents_offset,
|
||||
intptr_t object_offsets_offset,
|
||||
intptr_t objects_contents_offset,
|
||||
intptr_t main_offset,
|
||||
intptr_t num_libraries,
|
||||
intptr_t library_index_offset,
|
||||
intptr_t libraries_offset,
|
||||
intptr_t num_classes,
|
||||
intptr_t classes_offset,
|
||||
intptr_t members_offset,
|
||||
intptr_t num_codes,
|
||||
intptr_t codes_offset,
|
||||
intptr_t source_positions_offset,
|
||||
intptr_t source_files_offset,
|
||||
intptr_t line_starts_offset,
|
||||
intptr_t local_variables_offset,
|
||||
intptr_t annotations_offset,
|
||||
Heap::Space space);
|
||||
|
||||
private:
|
||||
Array& data_;
|
||||
};
|
||||
|
||||
class BytecodeReader : public AllStatic {
|
||||
public:
|
||||
// Reads bytecode for the given function and sets its bytecode field.
|
||||
// Returns error (if any), or null.
|
||||
static ErrorPtr ReadFunctionBytecode(Thread* thread,
|
||||
const Function& function);
|
||||
|
||||
// Read annotations for the given annotation field.
|
||||
static ObjectPtr ReadAnnotation(const Field& annotation_field);
|
||||
// Read the |count| annotations following given annotation field.
|
||||
static ArrayPtr ReadExtendedAnnotations(const Field& annotation_field,
|
||||
intptr_t count);
|
||||
|
||||
static void ResetObjectTable(const KernelProgramInfo& info);
|
||||
|
||||
// Read declaration of the given library.
|
||||
static void LoadLibraryDeclaration(const Library& library);
|
||||
|
||||
// Read declaration of the given class.
|
||||
static void LoadClassDeclaration(const Class& cls);
|
||||
|
||||
// Read members of the given class.
|
||||
static void FinishClassLoading(const Class& cls);
|
||||
|
||||
// Value of attribute [name] of Function/Field [key].
|
||||
static ObjectPtr GetBytecodeAttribute(const Object& key, const String& name);
|
||||
|
||||
#if !defined(PRODUCT)
|
||||
// Compute local variable descriptors for [function] with [bytecode].
|
||||
static LocalVarDescriptorsPtr ComputeLocalVarDescriptors(
|
||||
Zone* zone,
|
||||
const Function& function,
|
||||
const Bytecode& bytecode);
|
||||
#endif
|
||||
};
|
||||
|
||||
class InferredTypeBytecodeAttribute : public AllStatic {
|
||||
public:
|
||||
// Number of array elements per entry in InferredType bytecode
|
||||
// attribute (PC, type, flags).
|
||||
static constexpr intptr_t kNumElements = 3;
|
||||
|
||||
// Field type is the first entry with PC = -1.
|
||||
static constexpr intptr_t kFieldTypePC = -1;
|
||||
|
||||
// Returns PC at given index.
|
||||
static intptr_t GetPCAt(const Array& attr, intptr_t index) {
|
||||
return Smi::Value(Smi::RawCast(attr.At(index)));
|
||||
}
|
||||
|
||||
// Returns InferredType metadata at given index.
|
||||
static InferredTypeMetadata GetInferredTypeAt(Zone* zone,
|
||||
const Array& attr,
|
||||
intptr_t index);
|
||||
};
|
||||
|
||||
class BytecodeSourcePositionsIterator : ValueObject {
|
||||
public:
|
||||
// These constants should match corresponding constants in class
|
||||
// SourcePositions (pkg/vm/lib/bytecode/source_positions.dart).
|
||||
static const intptr_t kSyntheticCodeMarker = -1;
|
||||
static const intptr_t kYieldPointMarker = -2;
|
||||
|
||||
BytecodeSourcePositionsIterator(Zone* zone, const Bytecode& bytecode)
|
||||
: reader_(ExternalTypedData::Handle(zone, bytecode.GetBinary(zone))) {
|
||||
if (bytecode.HasSourcePositions()) {
|
||||
reader_.set_offset(bytecode.source_positions_binary_offset());
|
||||
pairs_remaining_ = reader_.ReadUInt();
|
||||
}
|
||||
}
|
||||
|
||||
bool MoveNext() {
|
||||
if (pairs_remaining_ == 0) {
|
||||
return false;
|
||||
}
|
||||
ASSERT(pairs_remaining_ > 0);
|
||||
--pairs_remaining_;
|
||||
cur_bci_ += reader_.ReadUInt();
|
||||
cur_token_pos_ += reader_.ReadSLEB128();
|
||||
is_yield_point_ = false;
|
||||
if (cur_token_pos_ == kYieldPointMarker) {
|
||||
const bool result = MoveNext();
|
||||
is_yield_point_ = true;
|
||||
return result;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
uword PcOffset() const { return cur_bci_; }
|
||||
|
||||
TokenPosition TokenPos() const {
|
||||
return (cur_token_pos_ == kSyntheticCodeMarker)
|
||||
? TokenPosition::kNoSource
|
||||
: TokenPosition(cur_token_pos_);
|
||||
}
|
||||
|
||||
bool IsYieldPoint() const { return is_yield_point_; }
|
||||
|
||||
private:
|
||||
Reader reader_;
|
||||
intptr_t pairs_remaining_ = 0;
|
||||
intptr_t cur_bci_ = 0;
|
||||
intptr_t cur_token_pos_ = 0;
|
||||
bool is_yield_point_ = false;
|
||||
};
|
||||
|
||||
class BytecodeLocalVariablesIterator : ValueObject {
|
||||
public:
|
||||
// These constants should match corresponding constants in
|
||||
// pkg/vm/lib/bytecode/local_variable_table.dart.
|
||||
enum {
|
||||
kInvalid,
|
||||
kScope,
|
||||
kVariableDeclaration,
|
||||
kContextVariable,
|
||||
};
|
||||
|
||||
static const intptr_t kKindMask = 0xF;
|
||||
static const intptr_t kIsCapturedFlag = 1 << 4;
|
||||
|
||||
BytecodeLocalVariablesIterator(Zone* zone, const Bytecode& bytecode)
|
||||
: reader_(ExternalTypedData::Handle(zone, bytecode.GetBinary(zone))),
|
||||
object_pool_(ObjectPool::Handle(zone, bytecode.object_pool())) {
|
||||
if (bytecode.HasLocalVariablesInfo()) {
|
||||
reader_.set_offset(bytecode.local_variables_binary_offset());
|
||||
entries_remaining_ = reader_.ReadUInt();
|
||||
}
|
||||
}
|
||||
|
||||
bool MoveNext() {
|
||||
if (entries_remaining_ <= 0) {
|
||||
// Finished looking at the last entry, now we're done.
|
||||
entries_remaining_ = -1;
|
||||
return false;
|
||||
}
|
||||
--entries_remaining_;
|
||||
cur_kind_and_flags_ = reader_.ReadByte();
|
||||
cur_start_pc_ += reader_.ReadSLEB128();
|
||||
switch (Kind()) {
|
||||
case kScope:
|
||||
cur_end_pc_ = cur_start_pc_ + reader_.ReadUInt();
|
||||
cur_index_ = reader_.ReadSLEB128();
|
||||
cur_token_pos_ = reader_.ReadPosition();
|
||||
cur_end_token_pos_ = reader_.ReadPosition();
|
||||
break;
|
||||
case kVariableDeclaration:
|
||||
cur_index_ = reader_.ReadSLEB128();
|
||||
cur_name_ = reader_.ReadUInt();
|
||||
cur_type_ = reader_.ReadUInt();
|
||||
cur_declaration_token_pos_ = reader_.ReadPosition();
|
||||
cur_token_pos_ = reader_.ReadPosition();
|
||||
break;
|
||||
case kContextVariable:
|
||||
cur_index_ = reader_.ReadSLEB128();
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Returns true after iterator moved past the last entry and
|
||||
// MoveNext() returned false.
|
||||
bool IsDone() const { return entries_remaining_ < 0; }
|
||||
|
||||
intptr_t Kind() const { return cur_kind_and_flags_ & kKindMask; }
|
||||
bool IsScope() const { return Kind() == kScope; }
|
||||
bool IsVariableDeclaration() const { return Kind() == kVariableDeclaration; }
|
||||
bool IsContextVariable() const { return Kind() == kContextVariable; }
|
||||
|
||||
intptr_t StartPC() const { return cur_start_pc_; }
|
||||
intptr_t EndPC() const {
|
||||
ASSERT(IsScope() || IsVariableDeclaration());
|
||||
return cur_end_pc_;
|
||||
}
|
||||
intptr_t ContextLevel() const {
|
||||
ASSERT(IsScope());
|
||||
return cur_index_;
|
||||
}
|
||||
TokenPosition StartTokenPos() const {
|
||||
ASSERT(IsScope() || IsVariableDeclaration());
|
||||
return cur_token_pos_;
|
||||
}
|
||||
TokenPosition EndTokenPos() const {
|
||||
ASSERT(IsScope() || IsVariableDeclaration());
|
||||
return cur_end_token_pos_;
|
||||
}
|
||||
intptr_t Index() const {
|
||||
ASSERT(IsVariableDeclaration() || IsContextVariable());
|
||||
return cur_index_;
|
||||
}
|
||||
StringPtr Name() const {
|
||||
ASSERT(IsVariableDeclaration());
|
||||
return String::RawCast(object_pool_.ObjectAt(cur_name_));
|
||||
}
|
||||
AbstractTypePtr Type() const {
|
||||
ASSERT(IsVariableDeclaration());
|
||||
return AbstractType::RawCast(object_pool_.ObjectAt(cur_type_));
|
||||
}
|
||||
TokenPosition DeclarationTokenPos() const {
|
||||
ASSERT(IsVariableDeclaration());
|
||||
return cur_declaration_token_pos_;
|
||||
}
|
||||
bool IsCaptured() const {
|
||||
ASSERT(IsVariableDeclaration());
|
||||
return (cur_kind_and_flags_ & kIsCapturedFlag) != 0;
|
||||
}
|
||||
|
||||
private:
|
||||
Reader reader_;
|
||||
const ObjectPool& object_pool_;
|
||||
intptr_t entries_remaining_ = 0;
|
||||
intptr_t cur_kind_and_flags_ = 0;
|
||||
intptr_t cur_start_pc_ = 0;
|
||||
intptr_t cur_end_pc_ = 0;
|
||||
intptr_t cur_index_ = -1;
|
||||
intptr_t cur_name_ = -1;
|
||||
intptr_t cur_type_ = -1;
|
||||
TokenPosition cur_token_pos_ = TokenPosition::kNoSource;
|
||||
TokenPosition cur_declaration_token_pos_ = TokenPosition::kNoSource;
|
||||
TokenPosition cur_end_token_pos_ = TokenPosition::kNoSource;
|
||||
};
|
||||
|
||||
class BytecodeAttributesMapTraits {
|
||||
public:
|
||||
static const char* Name() { return "BytecodeAttributesMapTraits"; }
|
||||
static bool ReportStats() { return false; }
|
||||
|
||||
static bool IsMatch(const Object& a, const Object& b) {
|
||||
return a.raw() == b.raw();
|
||||
}
|
||||
|
||||
static uword Hash(const Object& key) {
|
||||
return String::HashRawSymbol(key.IsFunction() ? Function::Cast(key).name()
|
||||
: Field::Cast(key).name());
|
||||
}
|
||||
};
|
||||
typedef UnorderedHashMap<BytecodeAttributesMapTraits> BytecodeAttributesMap;
|
||||
|
||||
bool IsStaticFieldGetterGeneratedAsInitializer(const Function& function,
|
||||
Zone* zone);
|
||||
|
||||
} // namespace kernel
|
||||
} // namespace dart
|
||||
|
||||
#endif // RUNTIME_VM_COMPILER_FRONTEND_BYTECODE_READER_H_
|
||||
@@ -1,194 +0,0 @@
|
||||
// Copyright (c) 2018, 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.
|
||||
|
||||
#include "vm/compiler/frontend/bytecode_scope_builder.h"
|
||||
|
||||
#include "vm/compiler/frontend/bytecode_reader.h"
|
||||
|
||||
namespace dart {
|
||||
namespace kernel {
|
||||
|
||||
#define Z (zone_)
|
||||
|
||||
BytecodeScopeBuilder::BytecodeScopeBuilder(ParsedFunction* parsed_function)
|
||||
: parsed_function_(parsed_function),
|
||||
zone_(parsed_function->zone()),
|
||||
scope_(nullptr) {}
|
||||
|
||||
void BytecodeScopeBuilder::BuildScopes() {
|
||||
if (parsed_function_->scope() != nullptr) {
|
||||
return; // Scopes are already built.
|
||||
}
|
||||
|
||||
const Function& function = parsed_function_->function();
|
||||
|
||||
LocalScope* enclosing_scope = nullptr;
|
||||
if (function.IsImplicitClosureFunction() && !function.is_static()) {
|
||||
// Create artificial enclosing scope for the tear-off that contains
|
||||
// captured receiver value. This ensure that AssertAssignable will correctly
|
||||
// load instantiator type arguments if they are needed.
|
||||
LocalVariable* receiver_variable =
|
||||
MakeReceiverVariable(/* is_parameter = */ false);
|
||||
receiver_variable->set_is_captured();
|
||||
enclosing_scope = new (Z) LocalScope(NULL, 0, 0);
|
||||
enclosing_scope->set_context_level(0);
|
||||
enclosing_scope->AddVariable(receiver_variable);
|
||||
enclosing_scope->AddContextVariable(receiver_variable);
|
||||
}
|
||||
scope_ = new (Z) LocalScope(enclosing_scope, 0, 0);
|
||||
scope_->set_begin_token_pos(function.token_pos());
|
||||
scope_->set_end_token_pos(function.end_token_pos());
|
||||
|
||||
// Add function type arguments variable before current context variable.
|
||||
if ((function.IsGeneric() || function.HasGenericParent())) {
|
||||
LocalVariable* type_args_var = MakeVariable(
|
||||
Symbols::FunctionTypeArgumentsVar(), AbstractType::dynamic_type());
|
||||
scope_->AddVariable(type_args_var);
|
||||
parsed_function_->set_function_type_arguments(type_args_var);
|
||||
}
|
||||
|
||||
bool needs_expr_temp = false;
|
||||
if (parsed_function_->has_arg_desc_var()) {
|
||||
needs_expr_temp = true;
|
||||
scope_->AddVariable(parsed_function_->arg_desc_var());
|
||||
}
|
||||
|
||||
LocalVariable* context_var = parsed_function_->current_context_var();
|
||||
context_var->set_is_forced_stack();
|
||||
scope_->AddVariable(context_var);
|
||||
|
||||
parsed_function_->set_scope(scope_);
|
||||
|
||||
switch (function.kind()) {
|
||||
case FunctionLayout::kImplicitClosureFunction: {
|
||||
ASSERT(function.NumImplicitParameters() == 1);
|
||||
|
||||
const auto& parent = Function::Handle(Z, function.parent_function());
|
||||
const auto& target =
|
||||
Function::Handle(Z, function.ImplicitClosureTarget(Z));
|
||||
|
||||
// For BuildGraphOfNoSuchMethodForwarder, since closures no longer
|
||||
// require arg_desc_var in all cases.
|
||||
if (target.IsNull() ||
|
||||
(parent.num_fixed_parameters() != target.num_fixed_parameters())) {
|
||||
needs_expr_temp = true;
|
||||
}
|
||||
|
||||
LocalVariable* closure_parameter = MakeVariable(
|
||||
Symbols::ClosureParameter(), AbstractType::dynamic_type());
|
||||
closure_parameter->set_is_forced_stack();
|
||||
scope_->InsertParameterAt(0, closure_parameter);
|
||||
|
||||
// Type check all parameters by default.
|
||||
// This may be overridden with parameter flags in
|
||||
// BytecodeReaderHelper::ParseForwarderFunction.
|
||||
AddParameters(function, LocalVariable::kDoTypeCheck);
|
||||
break;
|
||||
}
|
||||
|
||||
case FunctionLayout::kImplicitGetter:
|
||||
case FunctionLayout::kImplicitSetter: {
|
||||
const bool is_setter = function.IsImplicitSetterFunction();
|
||||
const bool is_method = !function.IsStaticFunction();
|
||||
const Field& field = Field::Handle(Z, function.accessor_field());
|
||||
intptr_t pos = 0;
|
||||
if (is_method) {
|
||||
MakeReceiverVariable(/* is_parameter = */ true);
|
||||
++pos;
|
||||
}
|
||||
if (is_setter) {
|
||||
LocalVariable* setter_value = MakeVariable(
|
||||
Symbols::Value(),
|
||||
AbstractType::ZoneHandle(Z, function.ParameterTypeAt(pos)));
|
||||
scope_->InsertParameterAt(pos++, setter_value);
|
||||
|
||||
if (is_method) {
|
||||
if (field.is_covariant()) {
|
||||
setter_value->set_is_explicit_covariant_parameter();
|
||||
} else {
|
||||
const bool needs_type_check =
|
||||
field.is_generic_covariant_impl() &&
|
||||
kernel::ProcedureAttributesOf(field, Z).has_non_this_uses;
|
||||
if (!needs_type_check) {
|
||||
setter_value->set_type_check_mode(
|
||||
LocalVariable::kTypeCheckedByCaller);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FunctionLayout::kImplicitStaticGetter: {
|
||||
ASSERT(!IsStaticFieldGetterGeneratedAsInitializer(function, Z));
|
||||
break;
|
||||
}
|
||||
case FunctionLayout::kDynamicInvocationForwarder: {
|
||||
// Create [this] variable.
|
||||
MakeReceiverVariable(/* is_parameter = */ true);
|
||||
|
||||
// Type check all parameters by default.
|
||||
// This may be overridden with parameter flags in
|
||||
// BytecodeReaderHelper::ParseForwarderFunction.
|
||||
AddParameters(function, LocalVariable::kDoTypeCheck);
|
||||
break;
|
||||
}
|
||||
case FunctionLayout::kMethodExtractor: {
|
||||
// Add a receiver parameter. Though it is captured, we emit code to
|
||||
// explicitly copy it to a fixed offset in a freshly-allocated context
|
||||
// instead of using the generic code for regular functions.
|
||||
// Therefore, it isn't necessary to mark it as captured here.
|
||||
MakeReceiverVariable(/* is_parameter = */ true);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
if (needs_expr_temp) {
|
||||
scope_->AddVariable(parsed_function_->EnsureExpressionTemp());
|
||||
}
|
||||
if (parsed_function_->function().MayHaveUncheckedEntryPoint()) {
|
||||
scope_->AddVariable(parsed_function_->EnsureEntryPointsTemp());
|
||||
}
|
||||
parsed_function_->AllocateVariables();
|
||||
}
|
||||
|
||||
// TODO(alexmarkov): pass bitvectors of parameter covariance to set type
|
||||
// check mode before AllocateVariables.
|
||||
void BytecodeScopeBuilder::AddParameters(const Function& function,
|
||||
LocalVariable::TypeCheckMode mode) {
|
||||
for (intptr_t i = function.NumImplicitParameters(),
|
||||
n = function.NumParameters();
|
||||
i < n; ++i) {
|
||||
// LocalVariable caches handles, so new handles are created for each
|
||||
// parameter.
|
||||
String& name = String::ZoneHandle(Z, function.ParameterNameAt(i));
|
||||
AbstractType& type =
|
||||
AbstractType::ZoneHandle(Z, function.ParameterTypeAt(i));
|
||||
|
||||
LocalVariable* variable = MakeVariable(name, type);
|
||||
variable->set_type_check_mode(mode);
|
||||
scope_->InsertParameterAt(i, variable);
|
||||
}
|
||||
}
|
||||
|
||||
LocalVariable* BytecodeScopeBuilder::MakeVariable(const String& name,
|
||||
const AbstractType& type) {
|
||||
return new (Z) LocalVariable(TokenPosition::kNoSource,
|
||||
TokenPosition::kNoSource, name, type, nullptr);
|
||||
}
|
||||
|
||||
LocalVariable* BytecodeScopeBuilder::MakeReceiverVariable(bool is_parameter) {
|
||||
const auto& cls = Class::Handle(Z, parsed_function_->function().Owner());
|
||||
const auto& type = Type::ZoneHandle(Z, cls.DeclarationType());
|
||||
LocalVariable* receiver_variable = MakeVariable(Symbols::This(), type);
|
||||
parsed_function_->set_receiver_var(receiver_variable);
|
||||
if (is_parameter) {
|
||||
scope_->InsertParameterAt(0, receiver_variable);
|
||||
}
|
||||
return receiver_variable;
|
||||
}
|
||||
|
||||
} // namespace kernel
|
||||
} // namespace dart
|
||||
@@ -1,41 +0,0 @@
|
||||
// Copyright (c) 2019, 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.
|
||||
|
||||
#ifndef RUNTIME_VM_COMPILER_FRONTEND_BYTECODE_SCOPE_BUILDER_H_
|
||||
#define RUNTIME_VM_COMPILER_FRONTEND_BYTECODE_SCOPE_BUILDER_H_
|
||||
|
||||
#if defined(DART_PRECOMPILED_RUNTIME)
|
||||
#error "AOT runtime should not use compiler sources (including header files)"
|
||||
#endif // defined(DART_PRECOMPILED_RUNTIME)
|
||||
|
||||
#include "vm/object.h"
|
||||
#include "vm/parser.h" // For ParsedFunction.
|
||||
#include "vm/scopes.h"
|
||||
|
||||
namespace dart {
|
||||
namespace kernel {
|
||||
|
||||
// Builds scopes, populates parameters and local variables for
|
||||
// certain functions declared in bytecode.
|
||||
class BytecodeScopeBuilder : public ValueObject {
|
||||
public:
|
||||
explicit BytecodeScopeBuilder(ParsedFunction* parsed_function);
|
||||
|
||||
void BuildScopes();
|
||||
|
||||
private:
|
||||
void AddParameters(const Function& function,
|
||||
LocalVariable::TypeCheckMode mode);
|
||||
LocalVariable* MakeVariable(const String& name, const AbstractType& type);
|
||||
LocalVariable* MakeReceiverVariable(bool is_parameter);
|
||||
|
||||
ParsedFunction* parsed_function_;
|
||||
Zone* zone_;
|
||||
LocalScope* scope_;
|
||||
};
|
||||
|
||||
} // namespace kernel
|
||||
} // namespace dart
|
||||
|
||||
#endif // RUNTIME_VM_COMPILER_FRONTEND_BYTECODE_SCOPE_BUILDER_H_
|
||||
@@ -212,7 +212,7 @@ InstancePtr ConstantReader::ReadConstantInternal(intptr_t constant_offset) {
|
||||
case kInstanceConstant: {
|
||||
const NameIndex index = reader.ReadCanonicalNameReference();
|
||||
const auto& klass = Class::Handle(Z, H.LookupClassByKernelClass(index));
|
||||
if (!klass.is_declaration_loaded() && !klass.is_declared_in_bytecode()) {
|
||||
if (!klass.is_declaration_loaded()) {
|
||||
FATAL1(
|
||||
"Trying to evaluate an instance constant whose references class "
|
||||
"%s is not loaded yet.",
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
#include "vm/compiler/frontend/kernel_binary_flowgraph.h"
|
||||
|
||||
#include "vm/compiler/ffi/callback.h"
|
||||
#include "vm/compiler/frontend/bytecode_flow_graph_builder.h"
|
||||
#include "vm/compiler/frontend/bytecode_reader.h"
|
||||
#include "vm/compiler/frontend/flow_graph_builder.h" // For dart::FlowGraphBuilder::SimpleInstanceOfType.
|
||||
#include "vm/compiler/frontend/prologue_builder.h"
|
||||
#include "vm/compiler/jit/compiler.h"
|
||||
@@ -15,9 +13,6 @@
|
||||
#include "vm/stack_frame.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
DECLARE_FLAG(bool, enable_interpreter);
|
||||
|
||||
namespace kernel {
|
||||
|
||||
#define Z (zone_)
|
||||
@@ -1055,55 +1050,6 @@ FlowGraph* StreamingFlowGraphBuilder::BuildGraph() {
|
||||
ActiveMemberScope active_member(active_class(), &outermost_function);
|
||||
ActiveTypeParametersScope active_type_params(active_class(), function, Z);
|
||||
|
||||
if (function.is_declared_in_bytecode()) {
|
||||
bytecode_metadata_helper_.ParseBytecodeFunction(parsed_function());
|
||||
|
||||
switch (function.kind()) {
|
||||
case FunctionLayout::kImplicitClosureFunction:
|
||||
return B->BuildGraphOfImplicitClosureFunction(function);
|
||||
case FunctionLayout::kImplicitGetter:
|
||||
case FunctionLayout::kImplicitSetter:
|
||||
return B->BuildGraphOfFieldAccessor(function);
|
||||
case FunctionLayout::kImplicitStaticGetter: {
|
||||
if (IsStaticFieldGetterGeneratedAsInitializer(function, Z)) {
|
||||
break;
|
||||
}
|
||||
return B->BuildGraphOfFieldAccessor(function);
|
||||
}
|
||||
case FunctionLayout::kDynamicInvocationForwarder:
|
||||
return B->BuildGraphOfDynamicInvocationForwarder(function);
|
||||
case FunctionLayout::kMethodExtractor:
|
||||
return B->BuildGraphOfMethodExtractor(function);
|
||||
case FunctionLayout::kNoSuchMethodDispatcher:
|
||||
return B->BuildGraphOfNoSuchMethodDispatcher(function);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ASSERT(function.HasBytecode());
|
||||
|
||||
BytecodeFlowGraphBuilder bytecode_compiler(
|
||||
flow_graph_builder_, parsed_function(),
|
||||
&(flow_graph_builder_->ic_data_array_));
|
||||
|
||||
if (B->IsRecognizedMethodForFlowGraph(function)) {
|
||||
bytecode_compiler.CreateParameterVariables();
|
||||
return B->BuildGraphOfRecognizedMethod(function);
|
||||
}
|
||||
|
||||
return bytecode_compiler.BuildGraph();
|
||||
}
|
||||
|
||||
// Certain special functions could have a VM-internal bytecode
|
||||
// attached to them.
|
||||
ASSERT((!function.HasBytecode()) ||
|
||||
(function.kind() == FunctionLayout::kImplicitGetter) ||
|
||||
(function.kind() == FunctionLayout::kImplicitSetter) ||
|
||||
(function.kind() == FunctionLayout::kImplicitStaticGetter) ||
|
||||
(function.kind() == FunctionLayout::kMethodExtractor) ||
|
||||
(function.kind() == FunctionLayout::kInvokeFieldDispatcher) ||
|
||||
(function.kind() == FunctionLayout::kNoSuchMethodDispatcher));
|
||||
|
||||
ParseKernelASTFunction();
|
||||
|
||||
switch (function.kind()) {
|
||||
@@ -3174,8 +3120,6 @@ Fragment StreamingFlowGraphBuilder::BuildStaticInvocation(TokenPosition* p) {
|
||||
NULL));
|
||||
|
||||
// Special case identical(x, y) call.
|
||||
// Note: similar optimization is performed in bytecode flow graph builder -
|
||||
// see BytecodeFlowGraphBuilder::BuildDirectCall().
|
||||
// TODO(27590) consider moving this into the inliner and force inline it
|
||||
// there.
|
||||
if (special_case_identical) {
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#error "AOT runtime should not use compiler sources (including header files)"
|
||||
#endif // defined(DART_PRECOMPILED_RUNTIME)
|
||||
|
||||
#include "vm/compiler/frontend/bytecode_reader.h"
|
||||
#include "vm/compiler/frontend/constant_reader.h"
|
||||
#include "vm/compiler/frontend/kernel_to_il.h"
|
||||
#include "vm/compiler/frontend/kernel_translation_helper.h"
|
||||
@@ -41,7 +40,6 @@ class StreamingFlowGraphBuilder : public KernelReaderHelper {
|
||||
&constant_reader_,
|
||||
active_class_,
|
||||
/* finalize= */ true),
|
||||
bytecode_metadata_helper_(this, active_class_),
|
||||
direct_call_metadata_helper_(this),
|
||||
inferred_type_metadata_helper_(this, &constant_reader_),
|
||||
procedure_attributes_metadata_helper_(this),
|
||||
@@ -413,7 +411,6 @@ class StreamingFlowGraphBuilder : public KernelReaderHelper {
|
||||
ActiveClass* const active_class_;
|
||||
ConstantReader constant_reader_;
|
||||
TypeTranslator type_translator_;
|
||||
BytecodeMetadataHelper bytecode_metadata_helper_;
|
||||
DirectCallMetadataHelper direct_call_metadata_helper_;
|
||||
InferredTypeMetadataHelper inferred_type_metadata_helper_;
|
||||
ProcedureAttributesMetadataHelper procedure_attributes_metadata_helper_;
|
||||
|
||||
@@ -743,15 +743,9 @@ FlowGraph* FlowGraphBuilder::BuildGraph() {
|
||||
info.potential_natives() == GrowableObjectArray::null());
|
||||
#endif
|
||||
|
||||
auto& kernel_data = ExternalTypedData::Handle(Z);
|
||||
intptr_t kernel_data_program_offset = 0;
|
||||
if (!function.is_declared_in_bytecode()) {
|
||||
kernel_data = function.KernelData();
|
||||
kernel_data_program_offset = function.KernelDataProgramOffset();
|
||||
}
|
||||
auto& kernel_data = ExternalTypedData::Handle(Z, function.KernelData());
|
||||
intptr_t kernel_data_program_offset = function.KernelDataProgramOffset();
|
||||
|
||||
// TODO(alexmarkov): refactor this - StreamingFlowGraphBuilder should not be
|
||||
// used for bytecode functions.
|
||||
StreamingFlowGraphBuilder streaming_flow_graph_builder(
|
||||
this, kernel_data, kernel_data_program_offset);
|
||||
return streaming_flow_graph_builder.BuildGraph();
|
||||
@@ -837,11 +831,6 @@ bool FlowGraphBuilder::IsRecognizedMethodForFlowGraph(
|
||||
case MethodRecognizer::kFfiStorePointer:
|
||||
case MethodRecognizer::kFfiFromAddress:
|
||||
case MethodRecognizer::kFfiGetAddress:
|
||||
// This list must be kept in sync with BytecodeReaderHelper::NativeEntry in
|
||||
// runtime/vm/compiler/frontend/bytecode_reader.cc and implemented in the
|
||||
// bytecode interpreter in runtime/vm/interpreter.cc. Alternatively, these
|
||||
// methods must work in their original form (a Dart body or native entry) in
|
||||
// the bytecode interpreter.
|
||||
case MethodRecognizer::kObjectEquals:
|
||||
case MethodRecognizer::kStringBaseLength:
|
||||
case MethodRecognizer::kStringBaseIsEmpty:
|
||||
|
||||
@@ -578,9 +578,6 @@ ClassPtr TranslationHelper::LookupClassByKernelClass(NameIndex kernel_class) {
|
||||
Class::Handle(Z, library.LookupClassAllowPrivate(class_name));
|
||||
CheckStaticLookup(klass);
|
||||
ASSERT(!klass.IsNull());
|
||||
if (klass.is_declared_in_bytecode()) {
|
||||
klass.EnsureDeclarationLoaded();
|
||||
}
|
||||
name_index_handle_ = Smi::New(kernel_class);
|
||||
return info_.InsertClass(thread_, name_index_handle_, klass);
|
||||
}
|
||||
@@ -2982,9 +2979,6 @@ void TypeTranslator::BuildInterfaceType(bool simple) {
|
||||
|
||||
const Class& klass = Class::Handle(Z, H.LookupClassByKernelClass(klass_name));
|
||||
ASSERT(!klass.IsNull());
|
||||
if (klass.is_declared_in_bytecode()) {
|
||||
klass.EnsureDeclarationLoaded();
|
||||
}
|
||||
if (simple) {
|
||||
if (finalize_ || klass.is_type_finalized()) {
|
||||
// Fast path for non-generic types: retrieve or populate the class's only
|
||||
|
||||
@@ -194,11 +194,6 @@ class TranslationHelper {
|
||||
const char* format,
|
||||
...) PRINTF_ATTRIBUTE(5, 6);
|
||||
|
||||
ArrayPtr GetBytecodeComponent() const { return info_.bytecode_component(); }
|
||||
void SetBytecodeComponent(const Array& bytecode_component) {
|
||||
info_.set_bytecode_component(bytecode_component);
|
||||
}
|
||||
|
||||
void SetExpressionEvaluationFunction(const Function& function) {
|
||||
ASSERT(expression_evaluation_function_ == nullptr);
|
||||
expression_evaluation_function_ = &Function::Handle(zone_, function.raw());
|
||||
@@ -1260,8 +1255,6 @@ class KernelReaderHelper {
|
||||
// kernel program.
|
||||
intptr_t data_program_offset_;
|
||||
|
||||
friend class BytecodeMetadataHelper;
|
||||
friend class BytecodeReaderHelper;
|
||||
friend class ClassHelper;
|
||||
friend class CallSiteAttributesMetadataHelper;
|
||||
friend class ConstantReader;
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace kernel {
|
||||
bool MethodCanSkipTypeChecksForNonCovariantTypeArguments(
|
||||
const Function& method) {
|
||||
// Dart 2 type system at non-dynamic call sites statically guarantees that
|
||||
// argument values match declarated parameter types for all non-covariant
|
||||
// argument values match declared parameter types for all non-covariant
|
||||
// and non-generic-covariant parameters. The same applies to type parameters
|
||||
// bounds for type parameters of generic functions.
|
||||
//
|
||||
@@ -29,12 +29,7 @@ bool MethodCanSkipTypeChecksForNonCovariantTypeArguments(
|
||||
//
|
||||
// Though for some kinds of methods (e.g. ffi trampolines called from native
|
||||
// code) we do have to perform type checks for all parameters.
|
||||
//
|
||||
// TODO(dartbug.com/40813): Remove the closure case when argument checks have
|
||||
// been fully moved out of closures.
|
||||
return !method.CanReceiveDynamicInvocation() &&
|
||||
!(method.IsClosureFunction() &&
|
||||
Function::ClosureBodiesContainNonCovariantTypeArgumentChecks());
|
||||
return !method.CanReceiveDynamicInvocation();
|
||||
}
|
||||
|
||||
// Returns true if the given method can skip type checks for all arguments
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
#include "vm/compiler/cha.h"
|
||||
#include "vm/compiler/compiler_pass.h"
|
||||
#include "vm/compiler/compiler_state.h"
|
||||
#include "vm/compiler/frontend/bytecode_reader.h"
|
||||
#include "vm/compiler/frontend/flow_graph_builder.h"
|
||||
#include "vm/compiler/frontend/kernel_to_il.h"
|
||||
#include "vm/compiler/jit/jit_call_specializer.h"
|
||||
@@ -84,7 +83,6 @@ DEFINE_FLAG(bool,
|
||||
"Trace only optimizing compiler operations.");
|
||||
DEFINE_FLAG(bool, trace_bailout, false, "Print bailout from ssa compiler.");
|
||||
|
||||
DECLARE_FLAG(bool, enable_interpreter);
|
||||
DECLARE_FLAG(bool, huge_method_cutoff_in_code_size);
|
||||
DECLARE_FLAG(bool, trace_failed_optimization_attempts);
|
||||
|
||||
@@ -215,25 +213,7 @@ DEFINE_RUNTIME_ENTRY(CompileFunction, 1) {
|
||||
ASSERT(thread->IsMutatorThread());
|
||||
const Function& function = Function::CheckedHandle(zone, arguments.ArgAt(0));
|
||||
Object& result = Object::Handle(zone);
|
||||
|
||||
if (FLAG_enable_interpreter && function.IsBytecodeAllowed(zone)) {
|
||||
if (!function.HasBytecode()) {
|
||||
result = kernel::BytecodeReader::ReadFunctionBytecode(thread, function);
|
||||
if (!result.IsNull()) {
|
||||
Exceptions::PropagateError(Error::Cast(result));
|
||||
}
|
||||
}
|
||||
if (function.HasBytecode() && (FLAG_compilation_counter_threshold != 0)) {
|
||||
// If interpreter is enabled and there is bytecode, LazyCompile stub
|
||||
// (which calls CompileFunction) should proceed to InterpretCall in order
|
||||
// to enter interpreter. In such case, compilation is postponed and
|
||||
// triggered by interpreter later via CompileInterpretedFunction.
|
||||
return;
|
||||
}
|
||||
// Fall back to compilation.
|
||||
} else {
|
||||
ASSERT(!function.HasCode());
|
||||
}
|
||||
ASSERT(!function.HasCode());
|
||||
|
||||
result = Compiler::CompileFunction(thread, function);
|
||||
if (result.IsError()) {
|
||||
@@ -495,13 +475,6 @@ void CompileParsedFunctionHelper::CheckIfBackgroundCompilerIsBeingStopped(
|
||||
Compiler::AbortBackgroundCompilation(
|
||||
DeoptId::kNone, "Optimizing Background compilation is being stopped");
|
||||
}
|
||||
} else {
|
||||
if (FLAG_enable_interpreter &&
|
||||
!isolate()->background_compiler()->is_running()) {
|
||||
// The background compiler is being stopped.
|
||||
Compiler::AbortBackgroundCompilation(
|
||||
DeoptId::kNone, "Background compilation is being stopped");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -783,9 +756,8 @@ static ObjectPtr CompileFunctionHelper(CompilationPipeline* pipeline,
|
||||
function.set_is_background_optimizable(false);
|
||||
|
||||
// Trigger another optimization soon on the main thread.
|
||||
function.SetUsageCounter(optimized
|
||||
? FLAG_optimization_counter_threshold
|
||||
: FLAG_compilation_counter_threshold);
|
||||
function.SetUsageCounter(
|
||||
optimized ? FLAG_optimization_counter_threshold : 0);
|
||||
return Error::null();
|
||||
} else if (error.IsLanguageError() &&
|
||||
LanguageError::Cast(error).kind() == Report::kBailout) {
|
||||
@@ -942,8 +914,6 @@ ObjectPtr Compiler::CompileOptimizedFunction(Thread* thread,
|
||||
TIMELINE_FUNCTION_COMPILATION_DURATION(thread, event_name, function);
|
||||
#endif // defined(SUPPORT_TIMELINE)
|
||||
|
||||
ASSERT(function.ShouldCompilerOptimize());
|
||||
|
||||
CompilationPipeline* pipeline =
|
||||
CompilationPipeline::New(thread->zone(), function);
|
||||
return CompileFunctionHelper(pipeline, function, /* optimized = */ true,
|
||||
@@ -978,21 +948,8 @@ void Compiler::ComputeLocalVarDescriptors(const Code& code) {
|
||||
|
||||
auto& var_descs = LocalVarDescriptors::Handle(zone);
|
||||
|
||||
if (function.is_declared_in_bytecode()) {
|
||||
if (function.HasBytecode()) {
|
||||
const auto& bytecode = Bytecode::Handle(zone, function.bytecode());
|
||||
var_descs = bytecode.GetLocalVarDescriptors();
|
||||
LocalVarDescriptorsBuilder builder;
|
||||
builder.AddDeoptIdToContextLevelMappings(context_level_array);
|
||||
builder.AddAll(zone, var_descs);
|
||||
var_descs = builder.Done();
|
||||
} else {
|
||||
var_descs = Object::empty_var_descriptors().raw();
|
||||
}
|
||||
} else {
|
||||
var_descs = parsed_function->scope()->GetVarDescriptors(
|
||||
function, context_level_array);
|
||||
}
|
||||
var_descs = parsed_function->scope()->GetVarDescriptors(
|
||||
function, context_level_array);
|
||||
|
||||
ASSERT(!var_descs.IsNull());
|
||||
code.set_var_descriptors(var_descs);
|
||||
@@ -1026,30 +983,6 @@ ErrorPtr Compiler::CompileAllFunctions(const Class& cls) {
|
||||
return Error::null();
|
||||
}
|
||||
|
||||
ErrorPtr Compiler::ReadAllBytecode(const Class& cls) {
|
||||
Thread* thread = Thread::Current();
|
||||
ASSERT(thread->IsMutatorThread());
|
||||
Zone* zone = thread->zone();
|
||||
Error& error = Error::Handle(zone, cls.EnsureIsFinalized(thread));
|
||||
ASSERT(error.IsNull());
|
||||
Array& functions = Array::Handle(zone, cls.current_functions());
|
||||
Function& func = Function::Handle(zone);
|
||||
// Compile all the regular functions.
|
||||
for (int i = 0; i < functions.Length(); i++) {
|
||||
func ^= functions.At(i);
|
||||
ASSERT(!func.IsNull());
|
||||
if (func.IsBytecodeAllowed(zone) && !func.HasBytecode() &&
|
||||
!func.HasCode()) {
|
||||
ErrorPtr error =
|
||||
kernel::BytecodeReader::ReadFunctionBytecode(thread, func);
|
||||
if (error != Error::null()) {
|
||||
return error;
|
||||
}
|
||||
}
|
||||
}
|
||||
return Error::null();
|
||||
}
|
||||
|
||||
void Compiler::AbortBackgroundCompilation(intptr_t deopt_id, const char* msg) {
|
||||
if (FLAG_trace_compiler) {
|
||||
THR_Print("ABORT background compilation: %s\n", msg);
|
||||
@@ -1209,13 +1142,9 @@ void BackgroundCompiler::Run() {
|
||||
}
|
||||
}
|
||||
while (!function.IsNull()) {
|
||||
if (is_optimizing()) {
|
||||
Compiler::CompileOptimizedFunction(thread, function,
|
||||
Compiler::kNoOSRDeoptId);
|
||||
} else {
|
||||
ASSERT(FLAG_enable_interpreter);
|
||||
Compiler::CompileFunction(thread, function);
|
||||
}
|
||||
ASSERT(is_optimizing());
|
||||
Compiler::CompileOptimizedFunction(thread, function,
|
||||
Compiler::kNoOSRDeoptId);
|
||||
|
||||
QueueElement* qelem = NULL;
|
||||
{
|
||||
|
||||
@@ -84,8 +84,6 @@ class Compiler : public AllStatic {
|
||||
static ObjectPtr CompileFunction(Thread* thread, const Function& function);
|
||||
|
||||
// Generates unoptimized code if not present, current code is unchanged.
|
||||
// Bytecode is considered unoptimized code.
|
||||
// TODO(regis): Revisit when deoptimizing mixed bytecode and jitted code.
|
||||
static ErrorPtr EnsureUnoptimizedCode(Thread* thread,
|
||||
const Function& function);
|
||||
|
||||
@@ -108,9 +106,6 @@ class Compiler : public AllStatic {
|
||||
// Returns Error::null() if there is no compilation error.
|
||||
static ErrorPtr CompileAllFunctions(const Class& cls);
|
||||
|
||||
// Eagerly read all bytecode.
|
||||
static ErrorPtr ReadAllBytecode(const Class& cls);
|
||||
|
||||
// Notify the compiler that background (optimized) compilation has failed
|
||||
// because the mutator thread changed the state (e.g., deoptimization,
|
||||
// deferred loading). The background compilation may retry to compile
|
||||
@@ -129,36 +124,24 @@ class BackgroundCompiler {
|
||||
|
||||
static void Start(Isolate* isolate) {
|
||||
ASSERT(Thread::Current()->IsMutatorThread());
|
||||
if (FLAG_enable_interpreter && isolate->background_compiler() != NULL) {
|
||||
isolate->background_compiler()->Start();
|
||||
}
|
||||
if (isolate->optimizing_background_compiler() != NULL) {
|
||||
isolate->optimizing_background_compiler()->Start();
|
||||
}
|
||||
}
|
||||
static void Stop(Isolate* isolate) {
|
||||
ASSERT(Thread::Current()->IsMutatorThread());
|
||||
if (FLAG_enable_interpreter && isolate->background_compiler() != NULL) {
|
||||
isolate->background_compiler()->Stop();
|
||||
}
|
||||
if (isolate->optimizing_background_compiler() != NULL) {
|
||||
isolate->optimizing_background_compiler()->Stop();
|
||||
}
|
||||
}
|
||||
static void Enable(Isolate* isolate) {
|
||||
ASSERT(Thread::Current()->IsMutatorThread());
|
||||
if (FLAG_enable_interpreter && isolate->background_compiler() != NULL) {
|
||||
isolate->background_compiler()->Enable();
|
||||
}
|
||||
if (isolate->optimizing_background_compiler() != NULL) {
|
||||
isolate->optimizing_background_compiler()->Enable();
|
||||
}
|
||||
}
|
||||
static void Disable(Isolate* isolate) {
|
||||
ASSERT(Thread::Current()->IsMutatorThread());
|
||||
if (FLAG_enable_interpreter && isolate->background_compiler() != NULL) {
|
||||
isolate->background_compiler()->Disable();
|
||||
}
|
||||
if (isolate->optimizing_background_compiler() != NULL) {
|
||||
isolate->optimizing_background_compiler()->Disable();
|
||||
}
|
||||
@@ -169,10 +152,6 @@ class BackgroundCompiler {
|
||||
if (isolate->optimizing_background_compiler() != NULL) {
|
||||
return isolate->optimizing_background_compiler()->IsDisabled();
|
||||
}
|
||||
} else {
|
||||
if (FLAG_enable_interpreter && isolate->background_compiler() != NULL) {
|
||||
return isolate->background_compiler()->IsDisabled();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -727,8 +727,8 @@ uword Thread::vm_execution_state() {
|
||||
return dart::Thread::ExecutionState::kThreadInVM;
|
||||
}
|
||||
|
||||
uword Thread::vm_tag_compiled_id() {
|
||||
return dart::VMTag::kDartCompiledTagId;
|
||||
uword Thread::vm_tag_dart_id() {
|
||||
return dart::VMTag::kDartTagId;
|
||||
}
|
||||
|
||||
uword Thread::exit_through_runtime_call() {
|
||||
@@ -998,10 +998,6 @@ word KernelProgramInfo::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word Bytecode::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word PcDescriptors::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
@@ -1026,10 +1022,6 @@ word ContextScope::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word ParameterTypeCheck::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
word UnlinkedCall::NextFieldOffset() {
|
||||
return -kWordSize;
|
||||
}
|
||||
|
||||
@@ -807,12 +807,6 @@ class KernelProgramInfo : public AllStatic {
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class Bytecode : public AllStatic {
|
||||
public:
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class PcDescriptors : public AllStatic {
|
||||
public:
|
||||
static word HeaderSize();
|
||||
@@ -855,12 +849,6 @@ class ContextScope : public AllStatic {
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class ParameterTypeCheck : public AllStatic {
|
||||
public:
|
||||
static word InstanceSize();
|
||||
static word NextFieldOffset();
|
||||
};
|
||||
|
||||
class UnlinkedCall : public AllStatic {
|
||||
public:
|
||||
static word InstanceSize();
|
||||
@@ -1037,7 +1025,7 @@ class Thread : public AllStatic {
|
||||
static word slow_type_test_entry_point_offset();
|
||||
static word write_barrier_entry_point_offset();
|
||||
static word vm_tag_offset();
|
||||
static uword vm_tag_compiled_id();
|
||||
static uword vm_tag_dart_id();
|
||||
|
||||
static word safepoint_state_offset();
|
||||
static uword safepoint_state_unacquired();
|
||||
@@ -1067,8 +1055,6 @@ class Thread : public AllStatic {
|
||||
static word slow_type_test_stub_offset();
|
||||
static word call_to_runtime_stub_offset();
|
||||
static word invoke_dart_code_stub_offset();
|
||||
static word interpret_call_entry_point_offset();
|
||||
static word invoke_dart_code_from_bytecode_stub_offset();
|
||||
static word late_initialization_error_shared_without_fpu_regs_stub_offset();
|
||||
static word late_initialization_error_shared_with_fpu_regs_stub_offset();
|
||||
static word null_error_shared_without_fpu_regs_stub_offset();
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -208,8 +208,6 @@
|
||||
FIELD(Thread, float_not_address_offset) \
|
||||
FIELD(Thread, float_zerow_address_offset) \
|
||||
FIELD(Thread, global_object_pool_offset) \
|
||||
FIELD(Thread, interpret_call_entry_point_offset) \
|
||||
FIELD(Thread, invoke_dart_code_from_bytecode_stub_offset) \
|
||||
FIELD(Thread, invoke_dart_code_stub_offset) \
|
||||
FIELD(Thread, exit_through_ffi_offset) \
|
||||
FIELD(Thread, isolate_offset) \
|
||||
@@ -301,7 +299,6 @@
|
||||
SIZEOF(Array, InstanceSize, ArrayLayout) \
|
||||
SIZEOF(Array, header_size, ArrayLayout) \
|
||||
SIZEOF(Bool, InstanceSize, BoolLayout) \
|
||||
SIZEOF(Bytecode, InstanceSize, BytecodeLayout) \
|
||||
SIZEOF(Capability, InstanceSize, CapabilityLayout) \
|
||||
SIZEOF(Class, InstanceSize, ClassLayout) \
|
||||
SIZEOF(Closure, InstanceSize, ClosureLayout) \
|
||||
@@ -347,7 +344,6 @@
|
||||
SIZEOF(Object, InstanceSize, ObjectLayout) \
|
||||
SIZEOF(ObjectPool, InstanceSize, ObjectPoolLayout) \
|
||||
SIZEOF(OneByteString, InstanceSize, OneByteStringLayout) \
|
||||
SIZEOF(ParameterTypeCheck, InstanceSize, ParameterTypeCheckLayout) \
|
||||
SIZEOF(PatchClass, InstanceSize, PatchClassLayout) \
|
||||
SIZEOF(PcDescriptors, HeaderSize, PcDescriptorsLayout) \
|
||||
SIZEOF(Pointer, InstanceSize, PointerLayout) \
|
||||
|
||||
@@ -84,14 +84,8 @@ void StubCodeCompiler::GenerateInitLateInstanceFieldStub(Assembler* assembler,
|
||||
if (!FLAG_precompiled_mode || !FLAG_use_bare_instructions) {
|
||||
__ LoadField(CODE_REG,
|
||||
FieldAddress(kFunctionReg, target::Function::code_offset()));
|
||||
if (FLAG_enable_interpreter) {
|
||||
// InterpretCall stub needs arguments descriptor for all function calls.
|
||||
__ LoadObject(ARGS_DESC_REG,
|
||||
CastHandle<Object>(OneArgArgumentsDescriptor()));
|
||||
} else {
|
||||
// Load a GC-safe value for the arguments descriptor (unused but tagged).
|
||||
__ LoadImmediate(ARGS_DESC_REG, 0);
|
||||
}
|
||||
// Load a GC-safe value for the arguments descriptor (unused but tagged).
|
||||
__ LoadImmediate(ARGS_DESC_REG, 0);
|
||||
}
|
||||
__ Call(FieldAddress(kFunctionReg, target::Function::entry_point_offset()));
|
||||
__ Drop(1); // Drop argument.
|
||||
|
||||
@@ -96,7 +96,7 @@ void StubCodeCompiler::GenerateCallToRuntimeStub(Assembler* assembler) {
|
||||
Label ok;
|
||||
// Check that we are always entering from Dart code.
|
||||
__ LoadFromOffset(kWord, R8, THR, target::Thread::vm_tag_offset());
|
||||
__ CompareImmediate(R8, VMTag::kDartCompiledTagId);
|
||||
__ CompareImmediate(R8, VMTag::kDartTagId);
|
||||
__ b(&ok, EQ);
|
||||
__ Stop("Not coming from Dart code.");
|
||||
__ Bind(&ok);
|
||||
@@ -137,7 +137,7 @@ void StubCodeCompiler::GenerateCallToRuntimeStub(Assembler* assembler) {
|
||||
__ blx(R9);
|
||||
|
||||
// Mark that the thread is executing Dart code.
|
||||
__ LoadImmediate(R2, VMTag::kDartCompiledTagId);
|
||||
__ LoadImmediate(R2, VMTag::kDartTagId);
|
||||
__ StoreToOffset(kWord, R2, THR, target::Thread::vm_tag_offset());
|
||||
|
||||
// Mark that the thread has not exited generated Dart code.
|
||||
@@ -540,7 +540,7 @@ static void GenerateCallNativeWithWrapperStub(Assembler* assembler,
|
||||
Label ok;
|
||||
// Check that we are always entering from Dart code.
|
||||
__ LoadFromOffset(kWord, R8, THR, target::Thread::vm_tag_offset());
|
||||
__ CompareImmediate(R8, VMTag::kDartCompiledTagId);
|
||||
__ CompareImmediate(R8, VMTag::kDartTagId);
|
||||
__ b(&ok, EQ);
|
||||
__ Stop("Not coming from Dart code.");
|
||||
__ Bind(&ok);
|
||||
@@ -587,7 +587,7 @@ static void GenerateCallNativeWithWrapperStub(Assembler* assembler,
|
||||
__ blx(LR);
|
||||
|
||||
// Mark that the thread is executing Dart code.
|
||||
__ LoadImmediate(R2, VMTag::kDartCompiledTagId);
|
||||
__ LoadImmediate(R2, VMTag::kDartTagId);
|
||||
__ StoreToOffset(kWord, R2, THR, target::Thread::vm_tag_offset());
|
||||
|
||||
// Mark that the thread has not exited generated Dart code.
|
||||
@@ -1230,7 +1230,7 @@ void StubCodeCompiler::GenerateInvokeDartCodeStub(Assembler* assembler) {
|
||||
|
||||
// Mark that the thread is executing Dart code. Do this after initializing the
|
||||
// exit link for the profiler.
|
||||
__ LoadImmediate(R9, VMTag::kDartCompiledTagId);
|
||||
__ LoadImmediate(R9, VMTag::kDartTagId);
|
||||
__ StoreToOffset(kWord, R9, THR, target::Thread::vm_tag_offset());
|
||||
|
||||
// Load arguments descriptor array into R4, which is passed to Dart code.
|
||||
@@ -1307,160 +1307,6 @@ void StubCodeCompiler::GenerateInvokeDartCodeStub(Assembler* assembler) {
|
||||
__ Ret();
|
||||
}
|
||||
|
||||
// Called when invoking compiled Dart code from interpreted Dart code.
|
||||
// Input parameters:
|
||||
// LR : points to return address.
|
||||
// R0 : raw code object of the Dart function to call.
|
||||
// R1 : arguments raw descriptor array.
|
||||
// R2 : address of first argument.
|
||||
// R3 : current thread.
|
||||
void StubCodeCompiler::GenerateInvokeDartCodeFromBytecodeStub(
|
||||
Assembler* assembler) {
|
||||
if (FLAG_precompiled_mode) {
|
||||
__ Stop("Not using interpreter");
|
||||
return;
|
||||
}
|
||||
|
||||
__ Push(LR); // Marker for the profiler.
|
||||
__ EnterFrame((1 << FP) | (1 << LR), 0);
|
||||
|
||||
// Push code object to PC marker slot.
|
||||
__ ldr(IP,
|
||||
Address(R3,
|
||||
target::Thread::invoke_dart_code_from_bytecode_stub_offset()));
|
||||
__ Push(IP);
|
||||
|
||||
// Save new context and C++ ABI callee-saved registers.
|
||||
__ PushList(kAbiPreservedCpuRegs);
|
||||
|
||||
const DRegister firstd = EvenDRegisterOf(kAbiFirstPreservedFpuReg);
|
||||
if (TargetCPUFeatures::vfp_supported()) {
|
||||
ASSERT(2 * kAbiPreservedFpuRegCount < 16);
|
||||
// Save FPU registers. 2 D registers per Q register.
|
||||
__ vstmd(DB_W, SP, firstd, 2 * kAbiPreservedFpuRegCount);
|
||||
} else {
|
||||
__ sub(SP, SP, Operand(kAbiPreservedFpuRegCount * kFpuRegisterSize));
|
||||
}
|
||||
|
||||
// Set up THR, which caches the current thread in Dart code.
|
||||
if (THR != R3) {
|
||||
__ mov(THR, Operand(R3));
|
||||
}
|
||||
|
||||
#if defined(USING_SHADOW_CALL_STACK)
|
||||
#error Unimplemented
|
||||
#endif
|
||||
|
||||
// Save the current VMTag on the stack.
|
||||
__ LoadFromOffset(kWord, R9, THR, target::Thread::vm_tag_offset());
|
||||
__ Push(R9);
|
||||
|
||||
// Save top resource and top exit frame info. Use R4-6 as temporary registers.
|
||||
// StackFrameIterator reads the top exit frame info saved in this frame.
|
||||
__ LoadFromOffset(kWord, R4, THR, target::Thread::top_resource_offset());
|
||||
__ Push(R4);
|
||||
__ LoadImmediate(R8, 0);
|
||||
__ StoreToOffset(kWord, R8, THR, target::Thread::top_resource_offset());
|
||||
|
||||
__ LoadFromOffset(kWord, R8, THR, target::Thread::exit_through_ffi_offset());
|
||||
__ Push(R8);
|
||||
__ LoadImmediate(R8, 0);
|
||||
__ StoreToOffset(kWord, R8, THR, target::Thread::exit_through_ffi_offset());
|
||||
|
||||
__ LoadFromOffset(kWord, R9, THR,
|
||||
target::Thread::top_exit_frame_info_offset());
|
||||
__ StoreToOffset(kWord, R8, THR,
|
||||
target::Thread::top_exit_frame_info_offset());
|
||||
|
||||
// target::frame_layout.exit_link_slot_from_entry_fp must be kept in sync
|
||||
// with the code below.
|
||||
#if defined(TARGET_OS_MACOS) || defined(TARGET_OS_MACOS_IOS)
|
||||
ASSERT(target::frame_layout.exit_link_slot_from_entry_fp == -27);
|
||||
#else
|
||||
ASSERT(target::frame_layout.exit_link_slot_from_entry_fp == -28);
|
||||
#endif
|
||||
__ Push(R9);
|
||||
|
||||
// Mark that the thread is executing Dart code. Do this after initializing the
|
||||
// exit link for the profiler.
|
||||
__ LoadImmediate(R9, VMTag::kDartCompiledTagId);
|
||||
__ StoreToOffset(kWord, R9, THR, target::Thread::vm_tag_offset());
|
||||
|
||||
// Load arguments descriptor array into R4, which is passed to Dart code.
|
||||
__ mov(R4, Operand(R1));
|
||||
|
||||
// Load number of arguments into R9 and adjust count for type arguments.
|
||||
__ ldr(R3,
|
||||
FieldAddress(R4, target::ArgumentsDescriptor::type_args_len_offset()));
|
||||
__ ldr(R9, FieldAddress(R4, target::ArgumentsDescriptor::count_offset()));
|
||||
__ cmp(R3, Operand(0));
|
||||
__ AddImmediate(R9, R9, target::ToRawSmi(1),
|
||||
NE); // Include the type arguments.
|
||||
__ SmiUntag(R9);
|
||||
|
||||
// R2 points to first argument.
|
||||
// Set up arguments for the Dart call.
|
||||
Label push_arguments;
|
||||
Label done_push_arguments;
|
||||
__ CompareImmediate(R9, 0); // check if there are arguments.
|
||||
__ b(&done_push_arguments, EQ);
|
||||
__ LoadImmediate(R1, 0);
|
||||
__ Bind(&push_arguments);
|
||||
__ ldr(R3, Address(R2));
|
||||
__ Push(R3);
|
||||
__ AddImmediate(R2, target::kWordSize);
|
||||
__ AddImmediate(R1, 1);
|
||||
__ cmp(R1, Operand(R9));
|
||||
__ b(&push_arguments, LT);
|
||||
__ Bind(&done_push_arguments);
|
||||
|
||||
// Call the Dart code entrypoint.
|
||||
__ LoadImmediate(PP, 0); // GC safe value into PP.
|
||||
__ mov(CODE_REG, Operand(R0));
|
||||
__ ldr(R0, FieldAddress(CODE_REG, target::Code::entry_point_offset()));
|
||||
__ blx(R0); // R4 is the arguments descriptor array.
|
||||
|
||||
// Get rid of arguments pushed on the stack.
|
||||
__ AddImmediate(
|
||||
SP, FP,
|
||||
target::frame_layout.exit_link_slot_from_entry_fp * target::kWordSize);
|
||||
|
||||
// Restore the saved top exit frame info and top resource back into the
|
||||
// Isolate structure. Uses R9 as a temporary register for this.
|
||||
__ Pop(R9);
|
||||
__ StoreToOffset(kWord, R9, THR,
|
||||
target::Thread::top_exit_frame_info_offset());
|
||||
__ Pop(R9);
|
||||
__ StoreToOffset(kWord, R9, THR, target::Thread::exit_through_ffi_offset());
|
||||
__ Pop(R9);
|
||||
__ StoreToOffset(kWord, R9, THR, target::Thread::top_resource_offset());
|
||||
|
||||
// Restore the current VMTag from the stack.
|
||||
__ Pop(R4);
|
||||
__ StoreToOffset(kWord, R4, THR, target::Thread::vm_tag_offset());
|
||||
|
||||
// Restore C++ ABI callee-saved registers.
|
||||
if (TargetCPUFeatures::vfp_supported()) {
|
||||
// Restore FPU registers. 2 D registers per Q register.
|
||||
__ vldmd(IA_W, SP, firstd, 2 * kAbiPreservedFpuRegCount);
|
||||
} else {
|
||||
__ AddImmediate(SP, kAbiPreservedFpuRegCount * kFpuRegisterSize);
|
||||
}
|
||||
|
||||
#if defined(USING_SHADOW_CALL_STACK)
|
||||
#error Unimplemented
|
||||
#endif
|
||||
|
||||
// Restore CPU registers.
|
||||
__ PopList(kAbiPreservedCpuRegs);
|
||||
__ set_constant_pool_allowed(false);
|
||||
|
||||
// Restore the frame pointer and return.
|
||||
__ LeaveFrame((1 << FP) | (1 << LR));
|
||||
__ Drop(1);
|
||||
__ Ret();
|
||||
}
|
||||
|
||||
// Helper to generate space allocation of context stub.
|
||||
// This does not initialise the fields of the context.
|
||||
// Input:
|
||||
@@ -2695,94 +2541,10 @@ void StubCodeCompiler::GenerateLazyCompileStub(Assembler* assembler) {
|
||||
__ PopList((1 << R0) | (1 << R4));
|
||||
__ LeaveStubFrame();
|
||||
|
||||
// When using the interpreter, the function's code may now point to the
|
||||
// InterpretCall stub. Make sure R0, R4 and R9 are preserved.
|
||||
__ ldr(CODE_REG, FieldAddress(R0, target::Function::code_offset()));
|
||||
__ Branch(FieldAddress(R0, target::Function::entry_point_offset()));
|
||||
}
|
||||
|
||||
// Stub for interpreting a function call.
|
||||
// R4: Arguments descriptor.
|
||||
// R0: Function.
|
||||
void StubCodeCompiler::GenerateInterpretCallStub(Assembler* assembler) {
|
||||
if (FLAG_precompiled_mode) {
|
||||
__ Stop("Not using interpreter");
|
||||
return;
|
||||
}
|
||||
__ EnterStubFrame();
|
||||
|
||||
#if defined(DEBUG)
|
||||
{
|
||||
Label ok;
|
||||
// Check that we are always entering from Dart code.
|
||||
__ LoadFromOffset(kWord, R8, THR, target::Thread::vm_tag_offset());
|
||||
__ CompareImmediate(R8, VMTag::kDartCompiledTagId);
|
||||
__ b(&ok, EQ);
|
||||
__ Stop("Not coming from Dart code.");
|
||||
__ Bind(&ok);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Adjust arguments count for type arguments vector.
|
||||
__ LoadFieldFromOffset(kWord, R2, R4,
|
||||
target::ArgumentsDescriptor::count_offset());
|
||||
__ SmiUntag(R2);
|
||||
__ LoadFieldFromOffset(kWord, R1, R4,
|
||||
target::ArgumentsDescriptor::type_args_len_offset());
|
||||
__ cmp(R1, Operand(0));
|
||||
__ AddImmediate(R2, R2, 1, NE); // Include the type arguments.
|
||||
|
||||
// Compute argv.
|
||||
__ mov(R3, Operand(R2, LSL, 2));
|
||||
__ add(R3, FP, Operand(R3));
|
||||
__ AddImmediate(R3,
|
||||
target::frame_layout.param_end_from_fp * target::kWordSize);
|
||||
|
||||
// Indicate decreasing memory addresses of arguments with negative argc.
|
||||
__ rsb(R2, R2, Operand(0));
|
||||
|
||||
// Align frame before entering C++ world. Fifth argument passed on the stack.
|
||||
__ ReserveAlignedFrameSpace(1 * target::kWordSize);
|
||||
|
||||
// Pass arguments in registers.
|
||||
// R0: Function.
|
||||
__ mov(R1, Operand(R4)); // Arguments descriptor.
|
||||
// R2: Negative argc.
|
||||
// R3: Argv.
|
||||
__ str(THR, Address(SP, 0)); // Fifth argument: Thread.
|
||||
|
||||
// Save exit frame information to enable stack walking as we are about
|
||||
// to transition to Dart VM C++ code.
|
||||
__ StoreToOffset(kWord, FP, THR,
|
||||
target::Thread::top_exit_frame_info_offset());
|
||||
|
||||
// Mark that the thread exited generated code through a runtime call.
|
||||
__ LoadImmediate(R5, target::Thread::exit_through_runtime_call());
|
||||
__ StoreToOffset(kWord, R5, THR, target::Thread::exit_through_ffi_offset());
|
||||
|
||||
// Mark that the thread is executing VM code.
|
||||
__ LoadFromOffset(kWord, R5, THR,
|
||||
target::Thread::interpret_call_entry_point_offset());
|
||||
__ StoreToOffset(kWord, R5, THR, target::Thread::vm_tag_offset());
|
||||
|
||||
__ blx(R5);
|
||||
|
||||
// Mark that the thread is executing Dart code.
|
||||
__ LoadImmediate(R2, VMTag::kDartCompiledTagId);
|
||||
__ StoreToOffset(kWord, R2, THR, target::Thread::vm_tag_offset());
|
||||
|
||||
// Mark that the thread has not exited generated Dart code.
|
||||
__ LoadImmediate(R2, 0);
|
||||
__ StoreToOffset(kWord, R2, THR, target::Thread::exit_through_ffi_offset());
|
||||
|
||||
// Reset exit frame information in Isolate's mutator thread structure.
|
||||
__ StoreToOffset(kWord, R2, THR,
|
||||
target::Thread::top_exit_frame_info_offset());
|
||||
|
||||
__ LeaveStubFrame();
|
||||
__ Ret();
|
||||
}
|
||||
|
||||
// R9: Contains an ICData.
|
||||
void StubCodeCompiler::GenerateICCallBreakpointStub(Assembler* assembler) {
|
||||
#if defined(PRODUCT)
|
||||
@@ -3318,7 +3080,7 @@ void StubCodeCompiler::GenerateJumpToFrameStub(Assembler* assembler) {
|
||||
__ Bind(&exit_through_non_ffi);
|
||||
|
||||
// Set the tag.
|
||||
__ LoadImmediate(R2, VMTag::kDartCompiledTagId);
|
||||
__ LoadImmediate(R2, VMTag::kDartTagId);
|
||||
__ StoreToOffset(kWord, R2, THR, target::Thread::vm_tag_offset());
|
||||
// Clear top exit frame.
|
||||
__ LoadImmediate(R2, 0);
|
||||
|
||||
@@ -91,7 +91,7 @@ void StubCodeCompiler::GenerateCallToRuntimeStub(Assembler* assembler) {
|
||||
Label ok;
|
||||
// Check that we are always entering from Dart code.
|
||||
__ LoadFromOffset(R8, THR, target::Thread::vm_tag_offset());
|
||||
__ CompareImmediate(R8, VMTag::kDartCompiledTagId);
|
||||
__ CompareImmediate(R8, VMTag::kDartTagId);
|
||||
__ b(&ok, EQ);
|
||||
__ Stop("Not coming from Dart code.");
|
||||
__ Bind(&ok);
|
||||
@@ -154,7 +154,7 @@ void StubCodeCompiler::GenerateCallToRuntimeStub(Assembler* assembler) {
|
||||
|
||||
// Retval is next to 1st argument.
|
||||
// Mark that the thread is executing Dart code.
|
||||
__ LoadImmediate(R2, VMTag::kDartCompiledTagId);
|
||||
__ LoadImmediate(R2, VMTag::kDartTagId);
|
||||
__ StoreToOffset(R2, THR, target::Thread::vm_tag_offset());
|
||||
|
||||
// Mark that the thread has not exited generated Dart code.
|
||||
@@ -622,7 +622,7 @@ static void GenerateCallNativeWithWrapperStub(Assembler* assembler,
|
||||
Label ok;
|
||||
// Check that we are always entering from Dart code.
|
||||
__ LoadFromOffset(R6, THR, target::Thread::vm_tag_offset());
|
||||
__ CompareImmediate(R6, VMTag::kDartCompiledTagId);
|
||||
__ CompareImmediate(R6, VMTag::kDartTagId);
|
||||
__ b(&ok, EQ);
|
||||
__ Stop("Not coming from Dart code.");
|
||||
__ Bind(&ok);
|
||||
@@ -685,7 +685,7 @@ static void GenerateCallNativeWithWrapperStub(Assembler* assembler,
|
||||
__ RestorePinnedRegisters();
|
||||
|
||||
// Mark that the thread is executing Dart code.
|
||||
__ LoadImmediate(R2, VMTag::kDartCompiledTagId);
|
||||
__ LoadImmediate(R2, VMTag::kDartTagId);
|
||||
__ StoreToOffset(R2, THR, target::Thread::vm_tag_offset());
|
||||
|
||||
// Mark that the thread has not exited generated Dart code.
|
||||
@@ -1358,7 +1358,7 @@ void StubCodeCompiler::GenerateInvokeDartCodeStub(Assembler* assembler) {
|
||||
|
||||
// Mark that the thread is executing Dart code. Do this after initializing the
|
||||
// exit link for the profiler.
|
||||
__ LoadImmediate(R6, VMTag::kDartCompiledTagId);
|
||||
__ LoadImmediate(R6, VMTag::kDartTagId);
|
||||
__ StoreToOffset(R6, THR, target::Thread::vm_tag_offset());
|
||||
|
||||
// Load arguments descriptor array into R4, which is passed to Dart code.
|
||||
@@ -1444,157 +1444,6 @@ void StubCodeCompiler::GenerateInvokeDartCodeStub(Assembler* assembler) {
|
||||
__ ret();
|
||||
}
|
||||
|
||||
// Called when invoking compiled Dart code from interpreted Dart code.
|
||||
// Input parameters:
|
||||
// LR : points to return address.
|
||||
// R0 : raw code object of the Dart function to call.
|
||||
// R1 : arguments raw descriptor array.
|
||||
// R2 : address of first argument.
|
||||
// R3 : current thread.
|
||||
void StubCodeCompiler::GenerateInvokeDartCodeFromBytecodeStub(
|
||||
Assembler* assembler) {
|
||||
if (FLAG_precompiled_mode) {
|
||||
__ Stop("Not using interpreter");
|
||||
return;
|
||||
}
|
||||
|
||||
// Copy the C stack pointer (CSP/R31) into the stack pointer we'll actually
|
||||
// use to access the stack (SP/R15) and set the C stack pointer to near the
|
||||
// stack limit, loaded from the Thread held in R3, to prevent signal handlers
|
||||
// from over-writing Dart frames.
|
||||
__ mov(SP, CSP);
|
||||
__ SetupCSPFromThread(R3);
|
||||
__ Push(LR); // Marker for the profiler.
|
||||
__ EnterFrame(0);
|
||||
|
||||
// Push code object to PC marker slot.
|
||||
__ ldr(TMP,
|
||||
Address(R3,
|
||||
target::Thread::invoke_dart_code_from_bytecode_stub_offset()));
|
||||
__ Push(TMP);
|
||||
|
||||
#if defined(TARGET_OS_FUCHSIA)
|
||||
__ str(R18, Address(R3, target::Thread::saved_shadow_call_stack_offset()));
|
||||
#elif defined(USING_SHADOW_CALL_STACK)
|
||||
#error Unimplemented
|
||||
#endif
|
||||
|
||||
__ PushNativeCalleeSavedRegisters();
|
||||
|
||||
// Set up THR, which caches the current thread in Dart code.
|
||||
if (THR != R3) {
|
||||
__ mov(THR, R3);
|
||||
}
|
||||
|
||||
// Refresh pinned registers values (inc. write barrier mask and null object).
|
||||
__ RestorePinnedRegisters();
|
||||
|
||||
// Save the current VMTag on the stack.
|
||||
__ LoadFromOffset(R4, THR, target::Thread::vm_tag_offset());
|
||||
__ Push(R4);
|
||||
|
||||
// Save top resource and top exit frame info. Use R6 as a temporary register.
|
||||
// StackFrameIterator reads the top exit frame info saved in this frame.
|
||||
__ LoadFromOffset(R6, THR, target::Thread::top_resource_offset());
|
||||
__ StoreToOffset(ZR, THR, target::Thread::top_resource_offset());
|
||||
__ Push(R6);
|
||||
|
||||
__ LoadFromOffset(R6, THR, target::Thread::exit_through_ffi_offset());
|
||||
__ Push(R6);
|
||||
__ LoadImmediate(R6, 0);
|
||||
__ StoreToOffset(R6, THR, target::Thread::exit_through_ffi_offset());
|
||||
|
||||
__ LoadFromOffset(R6, THR, target::Thread::top_exit_frame_info_offset());
|
||||
__ StoreToOffset(ZR, THR, target::Thread::top_exit_frame_info_offset());
|
||||
// target::frame_layout.exit_link_slot_from_entry_fp must be kept in sync
|
||||
// with the code below.
|
||||
#if defined(TARGET_OS_FUCHSIA)
|
||||
ASSERT(target::frame_layout.exit_link_slot_from_entry_fp == -24);
|
||||
#else
|
||||
ASSERT(target::frame_layout.exit_link_slot_from_entry_fp == -23);
|
||||
#endif
|
||||
__ Push(R6);
|
||||
|
||||
// Mark that the thread is executing Dart code. Do this after initializing the
|
||||
// exit link for the profiler.
|
||||
__ LoadImmediate(R6, VMTag::kDartCompiledTagId);
|
||||
__ StoreToOffset(R6, THR, target::Thread::vm_tag_offset());
|
||||
|
||||
// Load arguments descriptor array into R4, which is passed to Dart code.
|
||||
__ mov(R4, R1);
|
||||
|
||||
// Load number of arguments into R5 and adjust count for type arguments.
|
||||
__ LoadFieldFromOffset(R5, R4, target::ArgumentsDescriptor::count_offset());
|
||||
__ LoadFieldFromOffset(R3, R4,
|
||||
target::ArgumentsDescriptor::type_args_len_offset());
|
||||
__ AddImmediate(TMP, R5, 1); // Include the type arguments.
|
||||
__ cmp(R3, Operand(0));
|
||||
__ csinc(R5, R5, TMP, EQ); // R5 <- (R3 == 0) ? R5 : TMP + 1 (R5 : R5 + 2).
|
||||
__ SmiUntag(R5);
|
||||
|
||||
// R2 points to first argument.
|
||||
// Set up arguments for the Dart call.
|
||||
Label push_arguments;
|
||||
Label done_push_arguments;
|
||||
__ cmp(R5, Operand(0));
|
||||
__ b(&done_push_arguments, EQ); // check if there are arguments.
|
||||
__ LoadImmediate(R1, 0);
|
||||
__ Bind(&push_arguments);
|
||||
__ ldr(R3, Address(R2));
|
||||
__ Push(R3);
|
||||
__ add(R1, R1, Operand(1));
|
||||
__ add(R2, R2, Operand(target::kWordSize));
|
||||
__ cmp(R1, Operand(R5));
|
||||
__ b(&push_arguments, LT);
|
||||
__ Bind(&done_push_arguments);
|
||||
|
||||
// We now load the pool pointer(PP) with a GC safe value as we are about to
|
||||
// invoke dart code. We don't need a real object pool here.
|
||||
// Smi zero does not work because ARM64 assumes PP to be untagged.
|
||||
__ LoadObject(PP, NullObject());
|
||||
|
||||
// Call the Dart code entrypoint.
|
||||
__ mov(CODE_REG, R0);
|
||||
__ ldr(R0, FieldAddress(CODE_REG, target::Code::entry_point_offset()));
|
||||
__ blr(R0); // R4 is the arguments descriptor array.
|
||||
|
||||
// Get rid of arguments pushed on the stack.
|
||||
__ AddImmediate(
|
||||
SP, FP,
|
||||
target::frame_layout.exit_link_slot_from_entry_fp * target::kWordSize);
|
||||
|
||||
// Restore the saved top exit frame info and top resource back into the
|
||||
// Isolate structure. Uses R6 as a temporary register for this.
|
||||
__ Pop(R6);
|
||||
__ StoreToOffset(R6, THR, target::Thread::top_exit_frame_info_offset());
|
||||
__ Pop(R6);
|
||||
__ StoreToOffset(R6, THR, target::Thread::exit_through_ffi_offset());
|
||||
__ Pop(R6);
|
||||
__ StoreToOffset(R6, THR, target::Thread::top_resource_offset());
|
||||
|
||||
// Restore the current VMTag from the stack.
|
||||
__ Pop(R4);
|
||||
__ StoreToOffset(R4, THR, target::Thread::vm_tag_offset());
|
||||
|
||||
#if defined(TARGET_OS_FUCHSIA)
|
||||
__ mov(R3, THR);
|
||||
#endif
|
||||
|
||||
__ PopNativeCalleeSavedRegisters(); // Clobbers THR
|
||||
|
||||
#if defined(TARGET_OS_FUCHSIA)
|
||||
__ str(R18, Address(R3, target::Thread::saved_shadow_call_stack_offset()));
|
||||
#elif defined(USING_SHADOW_CALL_STACK)
|
||||
#error Unimplemented
|
||||
#endif
|
||||
|
||||
// Restore the frame pointer and C stack pointer and return.
|
||||
__ LeaveFrame();
|
||||
__ Drop(1);
|
||||
__ RestoreCSP();
|
||||
__ ret();
|
||||
}
|
||||
|
||||
// Helper to generate space allocation of context stub.
|
||||
// This does not initialise the fields of the context.
|
||||
// Input:
|
||||
@@ -2858,106 +2707,11 @@ void StubCodeCompiler::GenerateLazyCompileStub(Assembler* assembler) {
|
||||
__ Pop(R4); // Restore arg desc.
|
||||
__ LeaveStubFrame();
|
||||
|
||||
// When using the interpreter, the function's code may now point to the
|
||||
// InterpretCall stub. Make sure R0, R4, and R5 are preserved.
|
||||
__ LoadFieldFromOffset(CODE_REG, R0, target::Function::code_offset());
|
||||
__ LoadFieldFromOffset(R2, R0, target::Function::entry_point_offset());
|
||||
__ br(R2);
|
||||
}
|
||||
|
||||
// Stub for interpreting a function call.
|
||||
// R4: Arguments descriptor.
|
||||
// R0: Function.
|
||||
void StubCodeCompiler::GenerateInterpretCallStub(Assembler* assembler) {
|
||||
if (FLAG_precompiled_mode) {
|
||||
__ Stop("Not using interpreter");
|
||||
return;
|
||||
}
|
||||
|
||||
__ SetPrologueOffset();
|
||||
__ EnterStubFrame();
|
||||
|
||||
#if defined(DEBUG)
|
||||
{
|
||||
Label ok;
|
||||
// Check that we are always entering from Dart code.
|
||||
__ LoadFromOffset(R8, THR, target::Thread::vm_tag_offset());
|
||||
__ CompareImmediate(R8, VMTag::kDartCompiledTagId);
|
||||
__ b(&ok, EQ);
|
||||
__ Stop("Not coming from Dart code.");
|
||||
__ Bind(&ok);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Adjust arguments count for type arguments vector.
|
||||
__ LoadFieldFromOffset(R2, R4, target::ArgumentsDescriptor::count_offset());
|
||||
__ SmiUntag(R2);
|
||||
__ LoadFieldFromOffset(R1, R4,
|
||||
target::ArgumentsDescriptor::type_args_len_offset());
|
||||
__ cmp(R1, Operand(0));
|
||||
__ csinc(R2, R2, R2, EQ); // R2 <- (R1 == 0) ? R2 : R2 + 1.
|
||||
|
||||
// Compute argv.
|
||||
__ add(R3, ZR, Operand(R2, LSL, 3));
|
||||
__ add(R3, FP, Operand(R3));
|
||||
__ AddImmediate(R3,
|
||||
target::frame_layout.param_end_from_fp * target::kWordSize);
|
||||
|
||||
// Indicate decreasing memory addresses of arguments with negative argc.
|
||||
__ neg(R2, R2);
|
||||
|
||||
// Align frame before entering C++ world. No shadow stack space required.
|
||||
__ ReserveAlignedFrameSpace(0 * target::kWordSize);
|
||||
|
||||
// Pass arguments in registers.
|
||||
// R0: Function.
|
||||
__ mov(R1, R4); // Arguments descriptor.
|
||||
// R2: Negative argc.
|
||||
// R3: Argv.
|
||||
__ mov(R4, THR); // Thread.
|
||||
|
||||
// Save exit frame information to enable stack walking as we are about
|
||||
// to transition to Dart VM C++ code.
|
||||
__ StoreToOffset(FP, THR, target::Thread::top_exit_frame_info_offset());
|
||||
|
||||
// Mark that the thread exited generated code through a runtime call.
|
||||
__ LoadImmediate(R5, target::Thread::exit_through_runtime_call());
|
||||
__ StoreToOffset(R5, THR, target::Thread::exit_through_ffi_offset());
|
||||
|
||||
// Mark that the thread is executing VM code.
|
||||
__ LoadFromOffset(R5, THR,
|
||||
target::Thread::interpret_call_entry_point_offset());
|
||||
__ StoreToOffset(R5, THR, target::Thread::vm_tag_offset());
|
||||
|
||||
// We are entering runtime code, so the C stack pointer must be restored from
|
||||
// the stack limit to the top of the stack. We cache the stack limit address
|
||||
// in a callee-saved register.
|
||||
__ mov(R25, CSP);
|
||||
__ mov(CSP, SP);
|
||||
|
||||
__ blr(R5);
|
||||
|
||||
// Restore SP and CSP.
|
||||
__ mov(SP, CSP);
|
||||
__ mov(CSP, R25);
|
||||
|
||||
// Refresh pinned registers values (inc. write barrier mask and null object).
|
||||
__ RestorePinnedRegisters();
|
||||
|
||||
// Mark that the thread is executing Dart code.
|
||||
__ LoadImmediate(R2, VMTag::kDartCompiledTagId);
|
||||
__ StoreToOffset(R2, THR, target::Thread::vm_tag_offset());
|
||||
|
||||
// Mark that the thread has not exited generated Dart code.
|
||||
__ StoreToOffset(ZR, THR, target::Thread::exit_through_ffi_offset());
|
||||
|
||||
// Reset exit frame information in Isolate's mutator thread structure.
|
||||
__ StoreToOffset(ZR, THR, target::Thread::top_exit_frame_info_offset());
|
||||
|
||||
__ LeaveStubFrame();
|
||||
__ ret();
|
||||
}
|
||||
|
||||
// R5: Contains an ICData.
|
||||
void StubCodeCompiler::GenerateICCallBreakpointStub(Assembler* assembler) {
|
||||
#if defined(PRODUCT)
|
||||
@@ -3484,7 +3238,7 @@ void StubCodeCompiler::GenerateJumpToFrameStub(Assembler* assembler) {
|
||||
// Refresh pinned registers values (inc. write barrier mask and null object).
|
||||
__ RestorePinnedRegisters();
|
||||
// Set the tag.
|
||||
__ LoadImmediate(R2, VMTag::kDartCompiledTagId);
|
||||
__ LoadImmediate(R2, VMTag::kDartTagId);
|
||||
__ StoreToOffset(R2, THR, target::Thread::vm_tag_offset());
|
||||
// Clear top exit frame.
|
||||
__ StoreToOffset(ZR, THR, target::Thread::top_exit_frame_info_offset());
|
||||
|
||||
@@ -93,7 +93,7 @@ void StubCodeCompiler::GenerateCallToRuntimeStub(Assembler* assembler) {
|
||||
{
|
||||
Label ok;
|
||||
// Check that we are always entering from Dart code.
|
||||
__ cmpl(Assembler::VMTagAddress(), Immediate(VMTag::kDartCompiledTagId));
|
||||
__ cmpl(Assembler::VMTagAddress(), Immediate(VMTag::kDartTagId));
|
||||
__ j(EQUAL, &ok, Assembler::kNearJump);
|
||||
__ Stop("Not coming from Dart code.");
|
||||
__ Bind(&ok);
|
||||
@@ -126,7 +126,7 @@ void StubCodeCompiler::GenerateCallToRuntimeStub(Assembler* assembler) {
|
||||
__ movl(Address(ESP, retval_offset), EAX); // Set retval in NativeArguments.
|
||||
__ call(ECX);
|
||||
|
||||
__ movl(Assembler::VMTagAddress(), Immediate(VMTag::kDartCompiledTagId));
|
||||
__ movl(Assembler::VMTagAddress(), Immediate(VMTag::kDartTagId));
|
||||
|
||||
// Mark that the thread has not exited generated Dart code.
|
||||
__ movl(Address(THR, target::Thread::exit_through_ffi_offset()),
|
||||
@@ -364,7 +364,7 @@ static void GenerateCallNativeWithWrapperStub(Assembler* assembler,
|
||||
{
|
||||
Label ok;
|
||||
// Check that we are always entering from Dart code.
|
||||
__ cmpl(Assembler::VMTagAddress(), Immediate(VMTag::kDartCompiledTagId));
|
||||
__ cmpl(Assembler::VMTagAddress(), Immediate(VMTag::kDartTagId));
|
||||
__ j(EQUAL, &ok, Assembler::kNearJump);
|
||||
__ Stop("Not coming from Dart code.");
|
||||
__ Bind(&ok);
|
||||
@@ -400,7 +400,7 @@ static void GenerateCallNativeWithWrapperStub(Assembler* assembler,
|
||||
__ movl(Address(ESP, target::kWordSize), ECX); // Function to call.
|
||||
__ call(wrapper_address);
|
||||
|
||||
__ movl(Assembler::VMTagAddress(), Immediate(VMTag::kDartCompiledTagId));
|
||||
__ movl(Assembler::VMTagAddress(), Immediate(VMTag::kDartTagId));
|
||||
|
||||
// Mark that the thread has not exited generated Dart code.
|
||||
__ movl(Address(THR, target::Thread::exit_through_ffi_offset()),
|
||||
@@ -955,7 +955,7 @@ void StubCodeCompiler::GenerateInvokeDartCodeStub(Assembler* assembler) {
|
||||
|
||||
// Mark that the thread is executing Dart code. Do this after initializing the
|
||||
// exit link for the profiler.
|
||||
__ movl(Assembler::VMTagAddress(), Immediate(VMTag::kDartCompiledTagId));
|
||||
__ movl(Assembler::VMTagAddress(), Immediate(VMTag::kDartTagId));
|
||||
|
||||
// Load arguments descriptor array into EDX.
|
||||
__ movl(EDX, Address(EBP, kArgumentsDescOffset));
|
||||
@@ -1029,134 +1029,6 @@ void StubCodeCompiler::GenerateInvokeDartCodeStub(Assembler* assembler) {
|
||||
__ ret();
|
||||
}
|
||||
|
||||
// Called when invoking compiled Dart code from interpreted Dart code.
|
||||
// Input parameters:
|
||||
// ESP : points to return address.
|
||||
// ESP + 4 : target raw code
|
||||
// ESP + 8 : arguments raw descriptor array.
|
||||
// ESP + 12: address of first argument.
|
||||
// ESP + 16 : current thread.
|
||||
void StubCodeCompiler::GenerateInvokeDartCodeFromBytecodeStub(
|
||||
Assembler* assembler) {
|
||||
const intptr_t kTargetCodeOffset = 3 * target::kWordSize;
|
||||
const intptr_t kArgumentsDescOffset = 4 * target::kWordSize;
|
||||
const intptr_t kArgumentsOffset = 5 * target::kWordSize;
|
||||
const intptr_t kThreadOffset = 6 * target::kWordSize;
|
||||
|
||||
__ pushl(Address(ESP, 0)); // Marker for the profiler.
|
||||
__ EnterFrame(0);
|
||||
|
||||
// Push code object to PC marker slot.
|
||||
__ movl(EAX, Address(EBP, kThreadOffset));
|
||||
__ pushl(Address(EAX, target::Thread::invoke_dart_code_stub_offset()));
|
||||
|
||||
// Save C++ ABI callee-saved registers.
|
||||
__ pushl(EBX);
|
||||
__ pushl(ESI);
|
||||
__ pushl(EDI);
|
||||
|
||||
// Set up THR, which caches the current thread in Dart code.
|
||||
__ movl(THR, EAX);
|
||||
|
||||
#if defined(USING_SHADOW_CALL_STACK)
|
||||
#error Unimplemented
|
||||
#endif
|
||||
|
||||
// Save the current VMTag on the stack.
|
||||
__ movl(ECX, Assembler::VMTagAddress());
|
||||
__ pushl(ECX);
|
||||
|
||||
// Save top resource and top exit frame info. Use EDX as a temporary register.
|
||||
// StackFrameIterator reads the top exit frame info saved in this frame.
|
||||
__ movl(EDX, Address(THR, target::Thread::top_resource_offset()));
|
||||
__ pushl(EDX);
|
||||
__ movl(Address(THR, target::Thread::top_resource_offset()), Immediate(0));
|
||||
|
||||
__ movl(EAX, Address(THR, target::Thread::exit_through_ffi_offset()));
|
||||
__ pushl(EAX);
|
||||
__ movl(Address(THR, target::Thread::exit_through_ffi_offset()),
|
||||
Immediate(0));
|
||||
|
||||
// The constant target::frame_layout.exit_link_slot_from_entry_fp must be
|
||||
// kept in sync with the code below.
|
||||
ASSERT(target::frame_layout.exit_link_slot_from_entry_fp == -8);
|
||||
__ movl(EDX, Address(THR, target::Thread::top_exit_frame_info_offset()));
|
||||
__ pushl(EDX);
|
||||
__ movl(Address(THR, target::Thread::top_exit_frame_info_offset()),
|
||||
Immediate(0));
|
||||
|
||||
// Mark that the thread is executing Dart code. Do this after initializing the
|
||||
// exit link for the profiler.
|
||||
__ movl(Assembler::VMTagAddress(), Immediate(VMTag::kDartCompiledTagId));
|
||||
|
||||
// Load arguments descriptor array into EDX.
|
||||
__ movl(EDX, Address(EBP, kArgumentsDescOffset));
|
||||
|
||||
// Load number of arguments into EBX and adjust count for type arguments.
|
||||
__ movl(EBX, FieldAddress(EDX, target::ArgumentsDescriptor::count_offset()));
|
||||
__ cmpl(
|
||||
FieldAddress(EDX, target::ArgumentsDescriptor::type_args_len_offset()),
|
||||
Immediate(0));
|
||||
Label args_count_ok;
|
||||
__ j(EQUAL, &args_count_ok, Assembler::kNearJump);
|
||||
__ addl(EBX, Immediate(target::ToRawSmi(1))); // Include the type arguments.
|
||||
__ Bind(&args_count_ok);
|
||||
// Save number of arguments as Smi on stack, replacing ArgumentsDesc.
|
||||
__ movl(Address(EBP, kArgumentsDescOffset), EBX);
|
||||
__ SmiUntag(EBX);
|
||||
|
||||
// Set up arguments for the dart call.
|
||||
Label push_arguments;
|
||||
Label done_push_arguments;
|
||||
__ testl(EBX, EBX); // check if there are arguments.
|
||||
__ j(ZERO, &done_push_arguments, Assembler::kNearJump);
|
||||
__ movl(EAX, Immediate(0));
|
||||
|
||||
// Compute address of 'arguments array' data area into EDI.
|
||||
__ movl(EDI, Address(EBP, kArgumentsOffset));
|
||||
|
||||
__ Bind(&push_arguments);
|
||||
__ movl(ECX, Address(EDI, EAX, TIMES_4, 0));
|
||||
__ pushl(ECX);
|
||||
__ incl(EAX);
|
||||
__ cmpl(EAX, EBX);
|
||||
__ j(LESS, &push_arguments, Assembler::kNearJump);
|
||||
__ Bind(&done_push_arguments);
|
||||
|
||||
// Call the dart code entrypoint.
|
||||
__ movl(EAX, Address(EBP, kTargetCodeOffset));
|
||||
__ call(FieldAddress(EAX, target::Code::entry_point_offset()));
|
||||
|
||||
// Read the saved number of passed arguments as Smi.
|
||||
__ movl(EDX, Address(EBP, kArgumentsDescOffset));
|
||||
// Get rid of arguments pushed on the stack.
|
||||
__ leal(ESP, Address(ESP, EDX, TIMES_2, 0)); // EDX is a Smi.
|
||||
|
||||
// Restore the saved top exit frame info and top resource back into the
|
||||
// Isolate structure.
|
||||
__ popl(Address(THR, target::Thread::top_exit_frame_info_offset()));
|
||||
__ popl(Address(THR, target::Thread::exit_through_ffi_offset()));
|
||||
__ popl(Address(THR, target::Thread::top_resource_offset()));
|
||||
|
||||
// Restore the current VMTag from the stack.
|
||||
__ popl(Assembler::VMTagAddress());
|
||||
|
||||
#if defined(USING_SHADOW_CALL_STACK)
|
||||
#error Unimplemented
|
||||
#endif
|
||||
|
||||
// Restore C++ ABI callee-saved registers.
|
||||
__ popl(EDI);
|
||||
__ popl(ESI);
|
||||
__ popl(EBX);
|
||||
|
||||
// Restore the frame pointer.
|
||||
__ LeaveFrame();
|
||||
__ popl(ECX);
|
||||
|
||||
__ ret();
|
||||
}
|
||||
|
||||
// Helper to generate space allocation of context stub.
|
||||
// This does not initialise the fields of the context.
|
||||
// Input:
|
||||
@@ -2231,85 +2103,9 @@ void StubCodeCompiler::GenerateLazyCompileStub(Assembler* assembler) {
|
||||
__ popl(EDX); // Restore arguments descriptor array.
|
||||
__ LeaveFrame();
|
||||
|
||||
// When using the interpreter, the function's code may now point to the
|
||||
// InterpretCall stub. Make sure EAX, ECX, and EDX are preserved.
|
||||
__ jmp(FieldAddress(EAX, target::Function::entry_point_offset()));
|
||||
}
|
||||
|
||||
// Stub for interpreting a function call.
|
||||
// EDX: Arguments descriptor.
|
||||
// EAX: Function.
|
||||
void StubCodeCompiler::GenerateInterpretCallStub(Assembler* assembler) {
|
||||
__ EnterStubFrame();
|
||||
|
||||
#if defined(DEBUG)
|
||||
{
|
||||
Label ok;
|
||||
// Check that we are always entering from Dart code.
|
||||
__ cmpl(Assembler::VMTagAddress(), Immediate(VMTag::kDartCompiledTagId));
|
||||
__ j(EQUAL, &ok, Assembler::kNearJump);
|
||||
__ Stop("Not coming from Dart code.");
|
||||
__ Bind(&ok);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Adjust arguments count for type arguments vector.
|
||||
__ movl(ECX, FieldAddress(EDX, target::ArgumentsDescriptor::count_offset()));
|
||||
__ SmiUntag(ECX);
|
||||
__ cmpl(
|
||||
FieldAddress(EDX, target::ArgumentsDescriptor::type_args_len_offset()),
|
||||
Immediate(0));
|
||||
Label args_count_ok;
|
||||
__ j(EQUAL, &args_count_ok, Assembler::kNearJump);
|
||||
__ incl(ECX);
|
||||
__ Bind(&args_count_ok);
|
||||
|
||||
// Compute argv.
|
||||
__ leal(EBX,
|
||||
Address(EBP, ECX, TIMES_4,
|
||||
target::frame_layout.param_end_from_fp * target::kWordSize));
|
||||
|
||||
// Indicate decreasing memory addresses of arguments with negative argc.
|
||||
__ negl(ECX);
|
||||
|
||||
__ pushl(THR); // Arg 4: Thread.
|
||||
__ pushl(EBX); // Arg 3: Argv.
|
||||
__ pushl(ECX); // Arg 2: Negative argc.
|
||||
__ pushl(EDX); // Arg 1: Arguments descriptor
|
||||
__ pushl(EAX); // Arg 0: Function
|
||||
|
||||
// Save exit frame information to enable stack walking as we are about
|
||||
// to transition to Dart VM C++ code.
|
||||
__ movl(Address(THR, target::Thread::top_exit_frame_info_offset()), EBP);
|
||||
|
||||
// Mark that the thread exited generated code through a runtime call.
|
||||
__ movl(Address(THR, target::Thread::exit_through_ffi_offset()),
|
||||
Immediate(target::Thread::exit_through_runtime_call()));
|
||||
|
||||
// Mark that the thread is executing VM code.
|
||||
__ movl(EAX,
|
||||
Address(THR, target::Thread::interpret_call_entry_point_offset()));
|
||||
__ movl(Assembler::VMTagAddress(), EAX);
|
||||
|
||||
__ call(EAX);
|
||||
|
||||
__ Drop(5);
|
||||
|
||||
// Mark that the thread is executing Dart code.
|
||||
__ movl(Assembler::VMTagAddress(), Immediate(VMTag::kDartCompiledTagId));
|
||||
|
||||
// Mark that the thread has not exited generated Dart code.
|
||||
__ movl(Address(THR, target::Thread::exit_through_ffi_offset()),
|
||||
Immediate(0));
|
||||
|
||||
// Reset exit frame information in Isolate's mutator thread structure.
|
||||
__ movl(Address(THR, target::Thread::top_exit_frame_info_offset()),
|
||||
Immediate(0));
|
||||
|
||||
__ LeaveFrame();
|
||||
__ ret();
|
||||
}
|
||||
|
||||
// ECX: Contains an ICData.
|
||||
void StubCodeCompiler::GenerateICCallBreakpointStub(Assembler* assembler) {
|
||||
#if defined(PRODUCT)
|
||||
@@ -2658,7 +2454,7 @@ void StubCodeCompiler::GenerateJumpToFrameStub(Assembler* assembler) {
|
||||
__ Bind(&exit_through_non_ffi);
|
||||
|
||||
// Set tag.
|
||||
__ movl(Assembler::VMTagAddress(), Immediate(VMTag::kDartCompiledTagId));
|
||||
__ movl(Assembler::VMTagAddress(), Immediate(VMTag::kDartTagId));
|
||||
// Clear top exit frame.
|
||||
__ movl(Address(THR, target::Thread::top_exit_frame_info_offset()),
|
||||
Immediate(0));
|
||||
|
||||
@@ -96,7 +96,7 @@ void StubCodeCompiler::GenerateCallToRuntimeStub(Assembler* assembler) {
|
||||
{
|
||||
Label ok;
|
||||
// Check that we are always entering from Dart code.
|
||||
__ movq(RAX, Immediate(VMTag::kDartCompiledTagId));
|
||||
__ movq(RAX, Immediate(VMTag::kDartTagId));
|
||||
__ cmpq(RAX, Assembler::VMTagAddress());
|
||||
__ j(EQUAL, &ok, Assembler::kNearJump);
|
||||
__ Stop("Not coming from Dart code.");
|
||||
@@ -137,7 +137,7 @@ void StubCodeCompiler::GenerateCallToRuntimeStub(Assembler* assembler) {
|
||||
__ CallCFunction(RBX);
|
||||
|
||||
// Mark that the thread is executing Dart code.
|
||||
__ movq(Assembler::VMTagAddress(), Immediate(VMTag::kDartCompiledTagId));
|
||||
__ movq(Assembler::VMTagAddress(), Immediate(VMTag::kDartTagId));
|
||||
|
||||
// Mark that the thread has not exited generated Dart code.
|
||||
__ movq(Address(THR, target::Thread::exit_through_ffi_offset()),
|
||||
@@ -575,7 +575,7 @@ static void GenerateCallNativeWithWrapperStub(Assembler* assembler,
|
||||
{
|
||||
Label ok;
|
||||
// Check that we are always entering from Dart code.
|
||||
__ movq(R8, Immediate(VMTag::kDartCompiledTagId));
|
||||
__ movq(R8, Immediate(VMTag::kDartTagId));
|
||||
__ cmpq(R8, Assembler::VMTagAddress());
|
||||
__ j(EQUAL, &ok, Assembler::kNearJump);
|
||||
__ Stop("Not coming from Dart code.");
|
||||
@@ -614,7 +614,7 @@ static void GenerateCallNativeWithWrapperStub(Assembler* assembler,
|
||||
__ CallCFunction(RAX);
|
||||
|
||||
// Mark that the thread is executing Dart code.
|
||||
__ movq(Assembler::VMTagAddress(), Immediate(VMTag::kDartCompiledTagId));
|
||||
__ movq(Assembler::VMTagAddress(), Immediate(VMTag::kDartTagId));
|
||||
|
||||
// Mark that the thread has not exited generated Dart code.
|
||||
__ movq(Address(THR, target::Thread::exit_through_ffi_offset()),
|
||||
@@ -1287,7 +1287,7 @@ void StubCodeCompiler::GenerateInvokeDartCodeStub(Assembler* assembler) {
|
||||
|
||||
// Mark that the thread is executing Dart code. Do this after initializing the
|
||||
// exit link for the profiler.
|
||||
__ movq(Assembler::VMTagAddress(), Immediate(VMTag::kDartCompiledTagId));
|
||||
__ movq(Assembler::VMTagAddress(), Immediate(VMTag::kDartTagId));
|
||||
|
||||
// Load arguments descriptor array into R10, which is passed to Dart code.
|
||||
__ movq(R10, Address(kArgDescReg, VMHandles::kOffsetOfRawPtrInHandle));
|
||||
@@ -1367,172 +1367,6 @@ void StubCodeCompiler::GenerateInvokeDartCodeStub(Assembler* assembler) {
|
||||
__ ret();
|
||||
}
|
||||
|
||||
// Called when invoking compiled Dart code from interpreted Dart code.
|
||||
// Input parameters:
|
||||
// RSP : points to return address.
|
||||
// RDI : target raw code
|
||||
// RSI : arguments raw descriptor array.
|
||||
// RDX : address of first argument.
|
||||
// RCX : current thread.
|
||||
void StubCodeCompiler::GenerateInvokeDartCodeFromBytecodeStub(
|
||||
Assembler* assembler) {
|
||||
if (FLAG_precompiled_mode) {
|
||||
__ Stop("Not using interpreter");
|
||||
return;
|
||||
}
|
||||
|
||||
__ pushq(Address(RSP, 0)); // Marker for the profiler.
|
||||
__ EnterFrame(0);
|
||||
|
||||
const Register kTargetCodeReg = CallingConventions::kArg1Reg;
|
||||
const Register kArgDescReg = CallingConventions::kArg2Reg;
|
||||
const Register kArg0Reg = CallingConventions::kArg3Reg;
|
||||
const Register kThreadReg = CallingConventions::kArg4Reg;
|
||||
|
||||
// Push code object to PC marker slot.
|
||||
__ pushq(
|
||||
Address(kThreadReg,
|
||||
target::Thread::invoke_dart_code_from_bytecode_stub_offset()));
|
||||
|
||||
// At this point, the stack looks like:
|
||||
// | stub code object
|
||||
// | saved RBP | <-- RBP
|
||||
// | saved PC (return to interpreter's InvokeCompiled) |
|
||||
|
||||
const intptr_t kInitialOffset = 2;
|
||||
// Save arguments descriptor array, later replaced by Smi argument count.
|
||||
const intptr_t kArgumentsDescOffset = -(kInitialOffset)*target::kWordSize;
|
||||
__ pushq(kArgDescReg);
|
||||
|
||||
// Save C++ ABI callee-saved registers.
|
||||
__ PushRegisters(CallingConventions::kCalleeSaveCpuRegisters,
|
||||
CallingConventions::kCalleeSaveXmmRegisters);
|
||||
|
||||
// If any additional (or fewer) values are pushed, the offsets in
|
||||
// target::frame_layout.exit_link_slot_from_entry_fp will need to be changed.
|
||||
|
||||
// Set up THR, which caches the current thread in Dart code.
|
||||
if (THR != kThreadReg) {
|
||||
__ movq(THR, kThreadReg);
|
||||
}
|
||||
|
||||
#if defined(USING_SHADOW_CALL_STACK)
|
||||
#error Unimplemented
|
||||
#endif
|
||||
|
||||
// Save the current VMTag on the stack.
|
||||
__ movq(RAX, Assembler::VMTagAddress());
|
||||
__ pushq(RAX);
|
||||
|
||||
// Save top resource and top exit frame info. Use RAX as a temporary register.
|
||||
// StackFrameIterator reads the top exit frame info saved in this frame.
|
||||
__ movq(RAX, Address(THR, target::Thread::top_resource_offset()));
|
||||
__ pushq(RAX);
|
||||
__ movq(Address(THR, target::Thread::top_resource_offset()), Immediate(0));
|
||||
|
||||
__ movq(RAX, Address(THR, target::Thread::exit_through_ffi_offset()));
|
||||
__ pushq(RAX);
|
||||
__ movq(Address(THR, target::Thread::exit_through_ffi_offset()),
|
||||
Immediate(0));
|
||||
|
||||
__ movq(RAX, Address(THR, target::Thread::top_exit_frame_info_offset()));
|
||||
__ pushq(RAX);
|
||||
__ movq(Address(THR, target::Thread::top_exit_frame_info_offset()),
|
||||
Immediate(0));
|
||||
|
||||
// The constant target::frame_layout.exit_link_slot_from_entry_fp must be kept
|
||||
// in sync with the code below.
|
||||
#if defined(DEBUG)
|
||||
{
|
||||
Label ok;
|
||||
__ leaq(RAX,
|
||||
Address(RBP, target::frame_layout.exit_link_slot_from_entry_fp *
|
||||
target::kWordSize));
|
||||
__ cmpq(RAX, RSP);
|
||||
__ j(EQUAL, &ok);
|
||||
__ Stop("target::frame_layout.exit_link_slot_from_entry_fp mismatch");
|
||||
__ Bind(&ok);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Mark that the thread is executing Dart code. Do this after initializing the
|
||||
// exit link for the profiler.
|
||||
__ movq(Assembler::VMTagAddress(), Immediate(VMTag::kDartCompiledTagId));
|
||||
|
||||
// Load arguments descriptor array into R10, which is passed to Dart code.
|
||||
__ movq(R10, kArgDescReg);
|
||||
|
||||
// Push arguments. At this point we only need to preserve kTargetCodeReg.
|
||||
ASSERT(kTargetCodeReg != RDX);
|
||||
|
||||
// Load number of arguments into RBX and adjust count for type arguments.
|
||||
__ movq(RBX, FieldAddress(R10, target::ArgumentsDescriptor::count_offset()));
|
||||
__ cmpq(
|
||||
FieldAddress(R10, target::ArgumentsDescriptor::type_args_len_offset()),
|
||||
Immediate(0));
|
||||
Label args_count_ok;
|
||||
__ j(EQUAL, &args_count_ok, Assembler::kNearJump);
|
||||
__ addq(RBX, Immediate(target::ToRawSmi(1))); // Include the type arguments.
|
||||
__ Bind(&args_count_ok);
|
||||
// Save number of arguments as Smi on stack, replacing saved ArgumentsDesc.
|
||||
__ movq(Address(RBP, kArgumentsDescOffset), RBX);
|
||||
__ SmiUntag(RBX);
|
||||
|
||||
// Compute address of first argument into RDX.
|
||||
if (kArg0Reg != RDX) { // Different registers on WIN64.
|
||||
__ movq(RDX, kArg0Reg);
|
||||
}
|
||||
|
||||
// Set up arguments for the Dart call.
|
||||
Label push_arguments;
|
||||
Label done_push_arguments;
|
||||
__ j(ZERO, &done_push_arguments, Assembler::kNearJump);
|
||||
__ LoadImmediate(RAX, Immediate(0));
|
||||
__ Bind(&push_arguments);
|
||||
__ pushq(Address(RDX, RAX, TIMES_8, 0));
|
||||
__ incq(RAX);
|
||||
__ cmpq(RAX, RBX);
|
||||
__ j(LESS, &push_arguments, Assembler::kNearJump);
|
||||
__ Bind(&done_push_arguments);
|
||||
|
||||
// Call the Dart code entrypoint.
|
||||
__ xorq(PP, PP); // GC-safe value into PP.
|
||||
__ movq(CODE_REG, kTargetCodeReg);
|
||||
__ movq(kTargetCodeReg,
|
||||
FieldAddress(CODE_REG, target::Code::entry_point_offset()));
|
||||
__ call(kTargetCodeReg); // R10 is the arguments descriptor array.
|
||||
|
||||
// Read the saved number of passed arguments as Smi.
|
||||
__ movq(RDX, Address(RBP, kArgumentsDescOffset));
|
||||
|
||||
// Get rid of arguments pushed on the stack.
|
||||
__ leaq(RSP, Address(RSP, RDX, TIMES_4, 0)); // RDX is a Smi.
|
||||
|
||||
// Restore the saved top exit frame info and top resource back into the
|
||||
// Isolate structure.
|
||||
__ popq(Address(THR, target::Thread::top_exit_frame_info_offset()));
|
||||
__ popq(Address(THR, target::Thread::exit_through_ffi_offset()));
|
||||
__ popq(Address(THR, target::Thread::top_resource_offset()));
|
||||
|
||||
// Restore the current VMTag from the stack.
|
||||
__ popq(Assembler::VMTagAddress());
|
||||
|
||||
#if defined(USING_SHADOW_CALL_STACK)
|
||||
#error Unimplemented
|
||||
#endif
|
||||
|
||||
// Restore C++ ABI callee-saved registers.
|
||||
__ PopRegisters(CallingConventions::kCalleeSaveCpuRegisters,
|
||||
CallingConventions::kCalleeSaveXmmRegisters);
|
||||
__ set_constant_pool_allowed(false);
|
||||
|
||||
// Restore the frame pointer.
|
||||
__ LeaveFrame();
|
||||
__ popq(RCX);
|
||||
|
||||
__ ret();
|
||||
}
|
||||
|
||||
// Helper to generate space allocation of context stub.
|
||||
// This does not initialise the fields of the context.
|
||||
// Input:
|
||||
@@ -2812,101 +2646,11 @@ void StubCodeCompiler::GenerateLazyCompileStub(Assembler* assembler) {
|
||||
__ popq(R10); // Restore arguments descriptor array.
|
||||
__ LeaveStubFrame();
|
||||
|
||||
// When using the interpreter, the function's code may now point to the
|
||||
// InterpretCall stub. Make sure RAX, R10, and RBX are preserved.
|
||||
__ movq(CODE_REG, FieldAddress(RAX, target::Function::code_offset()));
|
||||
__ movq(RCX, FieldAddress(RAX, target::Function::entry_point_offset()));
|
||||
__ jmp(RCX);
|
||||
}
|
||||
|
||||
// Stub for interpreting a function call.
|
||||
// R10: Arguments descriptor.
|
||||
// RAX: Function.
|
||||
void StubCodeCompiler::GenerateInterpretCallStub(Assembler* assembler) {
|
||||
if (FLAG_precompiled_mode) {
|
||||
__ Stop("Not using interpreter");
|
||||
return;
|
||||
}
|
||||
|
||||
__ EnterStubFrame();
|
||||
|
||||
#if defined(DEBUG)
|
||||
{
|
||||
Label ok;
|
||||
// Check that we are always entering from Dart code.
|
||||
__ movq(R8, Immediate(VMTag::kDartCompiledTagId));
|
||||
__ cmpq(R8, Assembler::VMTagAddress());
|
||||
__ j(EQUAL, &ok, Assembler::kNearJump);
|
||||
__ Stop("Not coming from Dart code.");
|
||||
__ Bind(&ok);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Adjust arguments count for type arguments vector.
|
||||
__ movq(R11, FieldAddress(R10, target::ArgumentsDescriptor::count_offset()));
|
||||
__ SmiUntag(R11);
|
||||
__ cmpq(
|
||||
FieldAddress(R10, target::ArgumentsDescriptor::type_args_len_offset()),
|
||||
Immediate(0));
|
||||
Label args_count_ok;
|
||||
__ j(EQUAL, &args_count_ok, Assembler::kNearJump);
|
||||
__ incq(R11);
|
||||
__ Bind(&args_count_ok);
|
||||
|
||||
// Compute argv.
|
||||
__ leaq(R12,
|
||||
Address(RBP, R11, TIMES_8,
|
||||
target::frame_layout.param_end_from_fp * target::kWordSize));
|
||||
|
||||
// Indicate decreasing memory addresses of arguments with negative argc.
|
||||
__ negq(R11);
|
||||
|
||||
// Reserve shadow space for args and align frame before entering C++ world.
|
||||
__ subq(RSP, Immediate(5 * target::kWordSize));
|
||||
if (OS::ActivationFrameAlignment() > 1) {
|
||||
__ andq(RSP, Immediate(~(OS::ActivationFrameAlignment() - 1)));
|
||||
}
|
||||
|
||||
__ movq(CallingConventions::kArg1Reg, RAX); // Function.
|
||||
__ movq(CallingConventions::kArg2Reg, R10); // Arguments descriptor.
|
||||
__ movq(CallingConventions::kArg3Reg, R11); // Negative argc.
|
||||
__ movq(CallingConventions::kArg4Reg, R12); // Argv.
|
||||
|
||||
#if defined(TARGET_OS_WINDOWS)
|
||||
__ movq(Address(RSP, 0 * target::kWordSize), THR); // Thread.
|
||||
#else
|
||||
__ movq(CallingConventions::kArg5Reg, THR); // Thread.
|
||||
#endif
|
||||
// Save exit frame information to enable stack walking as we are about
|
||||
// to transition to Dart VM C++ code.
|
||||
__ movq(Address(THR, target::Thread::top_exit_frame_info_offset()), RBP);
|
||||
|
||||
// Mark that the thread exited generated code through a runtime call.
|
||||
__ movq(Address(THR, target::Thread::exit_through_ffi_offset()),
|
||||
Immediate(target::Thread::exit_through_runtime_call()));
|
||||
|
||||
// Mark that the thread is executing VM code.
|
||||
__ movq(RAX,
|
||||
Address(THR, target::Thread::interpret_call_entry_point_offset()));
|
||||
__ movq(Assembler::VMTagAddress(), RAX);
|
||||
|
||||
__ call(RAX);
|
||||
|
||||
// Mark that the thread is executing Dart code.
|
||||
__ movq(Assembler::VMTagAddress(), Immediate(VMTag::kDartCompiledTagId));
|
||||
|
||||
// Mark that the thread has not exited generated Dart code.
|
||||
__ movq(Address(THR, target::Thread::exit_through_ffi_offset()),
|
||||
Immediate(0));
|
||||
|
||||
// Reset exit frame information in Isolate's mutator thread structure.
|
||||
__ movq(Address(THR, target::Thread::top_exit_frame_info_offset()),
|
||||
Immediate(0));
|
||||
|
||||
__ LeaveStubFrame();
|
||||
__ ret();
|
||||
}
|
||||
|
||||
// RBX: Contains an ICData.
|
||||
// TOS(0): return address (Dart code).
|
||||
void StubCodeCompiler::GenerateICCallBreakpointStub(Assembler* assembler) {
|
||||
@@ -3422,7 +3166,7 @@ void StubCodeCompiler::GenerateJumpToFrameStub(Assembler* assembler) {
|
||||
__ Bind(&exit_through_non_ffi);
|
||||
|
||||
// Set the tag.
|
||||
__ movq(Assembler::VMTagAddress(), Immediate(VMTag::kDartCompiledTagId));
|
||||
__ movq(Assembler::VMTagAddress(), Immediate(VMTag::kDartTagId));
|
||||
// Clear top exit frame.
|
||||
__ movq(Address(THR, target::Thread::top_exit_frame_info_offset()),
|
||||
Immediate(0));
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
#include "platform/assert.h"
|
||||
#include "vm/class_finalizer.h"
|
||||
#include "vm/code_patcher.h"
|
||||
#include "vm/compiler/frontend/bytecode_reader.h"
|
||||
#include "vm/dart_api_impl.h"
|
||||
#include "vm/heap/safepoint.h"
|
||||
#include "vm/kernel_isolate.h"
|
||||
@@ -126,30 +125,8 @@ ISOLATE_UNIT_TEST_CASE(CompileFunctionOnHelperThread) {
|
||||
Function& func =
|
||||
Function::Handle(cls.LookupStaticFunction(function_foo_name));
|
||||
EXPECT(!func.HasCode());
|
||||
if (!FLAG_enable_interpreter) {
|
||||
CompilerTest::TestCompileFunction(func);
|
||||
EXPECT(func.HasCode());
|
||||
return;
|
||||
}
|
||||
// Bytecode loading must happen on the main thread. Ensure the bytecode is
|
||||
// loaded before asking for an unoptimized compile on a background thread.
|
||||
kernel::BytecodeReader::ReadFunctionBytecode(thread, func);
|
||||
#if !defined(PRODUCT)
|
||||
// Constant in product mode.
|
||||
FLAG_background_compilation = true;
|
||||
#endif
|
||||
Isolate* isolate = thread->isolate();
|
||||
BackgroundCompiler::Start(isolate);
|
||||
isolate->background_compiler()->Compile(func);
|
||||
Monitor* m = new Monitor();
|
||||
{
|
||||
MonitorLocker ml(m);
|
||||
while (!func.HasCode()) {
|
||||
ml.WaitWithSafepointCheck(thread, 1);
|
||||
}
|
||||
}
|
||||
delete m;
|
||||
BackgroundCompiler::Stop(isolate);
|
||||
CompilerTest::TestCompileFunction(func);
|
||||
EXPECT(func.HasCode());
|
||||
}
|
||||
|
||||
ISOLATE_UNIT_TEST_CASE(RegenerateAllocStubs) {
|
||||
|
||||
@@ -1,76 +0,0 @@
|
||||
// Copyright (c) 2019, 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.
|
||||
|
||||
#define RUNTIME_VM_CONSTANTS_H_ // To work around include guard.
|
||||
#include "vm/constants_kbc.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
static const intptr_t kInstructionSize0 = 1;
|
||||
static const intptr_t kInstructionSizeA = 2;
|
||||
static const intptr_t kInstructionSizeD = 2;
|
||||
static const intptr_t kInstructionSizeWideD = 5;
|
||||
static const intptr_t kInstructionSizeX = 2;
|
||||
static const intptr_t kInstructionSizeWideX = 5;
|
||||
static const intptr_t kInstructionSizeT = 2;
|
||||
static const intptr_t kInstructionSizeWideT = 4;
|
||||
static const intptr_t kInstructionSizeA_E = 3;
|
||||
static const intptr_t kInstructionSizeWideA_E = 6;
|
||||
static const intptr_t kInstructionSizeA_Y = 3;
|
||||
static const intptr_t kInstructionSizeWideA_Y = 6;
|
||||
static const intptr_t kInstructionSizeD_F = 3;
|
||||
static const intptr_t kInstructionSizeWideD_F = 6;
|
||||
static const intptr_t kInstructionSizeA_B_C = 4;
|
||||
|
||||
const intptr_t KernelBytecode::kInstructionSize[] = {
|
||||
#define SIZE_ORDN(encoding) kInstructionSize##encoding
|
||||
#define SIZE_WIDE(encoding) kInstructionSizeWide##encoding
|
||||
#define SIZE_RESV(encoding) SIZE_ORDN(encoding)
|
||||
#define SIZE(name, encoding, kind, op1, op2, op3) SIZE_##kind(encoding),
|
||||
KERNEL_BYTECODES_LIST(SIZE)
|
||||
#undef SIZE_ORDN
|
||||
#undef SIZE_WIDE
|
||||
#undef SIZE_RESV
|
||||
#undef SIZE
|
||||
};
|
||||
|
||||
#define DECLARE_INSTRUCTIONS(name, fmt, kind, fmta, fmtb, fmtc) \
|
||||
static const KBCInstr k##name##Instructions[] = { \
|
||||
KernelBytecode::k##name, \
|
||||
KernelBytecode::kReturnTOS, \
|
||||
};
|
||||
INTERNAL_KERNEL_BYTECODES_LIST(DECLARE_INSTRUCTIONS)
|
||||
#undef DECLARE_INSTRUCTIONS
|
||||
|
||||
void KernelBytecode::GetVMInternalBytecodeInstructions(
|
||||
Opcode opcode,
|
||||
const KBCInstr** instructions,
|
||||
intptr_t* instructions_size) {
|
||||
switch (opcode) {
|
||||
#define CASE(name, fmt, kind, fmta, fmtb, fmtc) \
|
||||
case k##name: \
|
||||
*instructions = k##name##Instructions; \
|
||||
*instructions_size = sizeof(k##name##Instructions); \
|
||||
return;
|
||||
|
||||
INTERNAL_KERNEL_BYTECODES_LIST(CASE)
|
||||
#undef CASE
|
||||
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
static const KBCInstr kNativeCallToGrowableListReturnTrampoline[] = {
|
||||
KernelBytecode::kDirectCall,
|
||||
0, // target (doesn't matter)
|
||||
KernelBytecode::kNativeCallToGrowableListArgc, // number of arguments
|
||||
KernelBytecode::kReturnTOS,
|
||||
};
|
||||
|
||||
const KBCInstr* KernelBytecode::GetNativeCallToGrowableListReturnTrampoline() {
|
||||
return KernelBytecode::Next(&kNativeCallToGrowableListReturnTrampoline[0]);
|
||||
}
|
||||
|
||||
} // namespace dart
|
||||
File diff suppressed because it is too large
Load Diff
@@ -9,7 +9,6 @@
|
||||
#include "vm/debugger.h"
|
||||
#include "vm/dispatch_table.h"
|
||||
#include "vm/heap/safepoint.h"
|
||||
#include "vm/interpreter.h"
|
||||
#include "vm/object_store.h"
|
||||
#include "vm/resolver.h"
|
||||
#include "vm/runtime_entry.h"
|
||||
@@ -19,13 +18,11 @@
|
||||
#include "vm/zone_text_buffer.h"
|
||||
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
#include "vm/compiler/frontend/bytecode_reader.h"
|
||||
#include "vm/compiler/jit/compiler.h"
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME)
|
||||
|
||||
namespace dart {
|
||||
|
||||
DECLARE_FLAG(bool, enable_interpreter);
|
||||
DECLARE_FLAG(bool, precompiled_mode);
|
||||
|
||||
// A cache of VM heap allocated arguments descriptors.
|
||||
@@ -53,7 +50,6 @@ class ScopedIsolateStackLimits : public ValueObject {
|
||||
thread->SetStackLimit(Simulator::Current()->overflow_stack_limit());
|
||||
#else
|
||||
thread->SetStackLimit(OSThread::Current()->overflow_stack_limit());
|
||||
// TODO(regis): For now, the interpreter is using its own stack limit.
|
||||
#endif
|
||||
|
||||
#if defined(USING_SAFE_STACK)
|
||||
@@ -135,27 +131,6 @@ ObjectPtr DartEntry::InvokeFunction(const Function& function,
|
||||
ScopedIsolateStackLimits stack_limit(thread, current_sp);
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
if (!function.HasCode()) {
|
||||
if (FLAG_enable_interpreter && function.IsBytecodeAllowed(zone)) {
|
||||
if (!function.HasBytecode()) {
|
||||
ErrorPtr error =
|
||||
kernel::BytecodeReader::ReadFunctionBytecode(thread, function);
|
||||
if (error != Error::null()) {
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
// If we have bytecode but no native code then invoke the interpreter.
|
||||
if (function.HasBytecode() && (FLAG_compilation_counter_threshold != 0)) {
|
||||
ASSERT(thread->no_callback_scope_depth() == 0);
|
||||
SuspendLongJumpScope suspend_long_jump_scope(thread);
|
||||
TransitionToGenerated transition(thread);
|
||||
return Interpreter::Current()->Call(function, arguments_descriptor,
|
||||
arguments, thread);
|
||||
}
|
||||
|
||||
// Fall back to compilation.
|
||||
}
|
||||
|
||||
const Object& result =
|
||||
Object::Handle(zone, Compiler::CompileFunction(thread, function));
|
||||
if (result.IsError()) {
|
||||
|
||||
@@ -174,8 +174,6 @@ class ArgumentsDescriptor : public ValueObject {
|
||||
friend class SnapshotWriter;
|
||||
friend class Serializer;
|
||||
friend class Deserializer;
|
||||
friend class Interpreter;
|
||||
friend class InterpreterHelpers;
|
||||
friend class Simulator;
|
||||
friend class SimulatorHelpers;
|
||||
DISALLOW_COPY_AND_ASSIGN(ArgumentsDescriptor);
|
||||
|
||||
+320
-1128
File diff suppressed because it is too large
Load Diff
+8
-70
@@ -7,7 +7,6 @@
|
||||
|
||||
#include "include/dart_tools_api.h"
|
||||
|
||||
#include "vm/constants_kbc.h"
|
||||
#include "vm/kernel_isolate.h"
|
||||
#include "vm/object.h"
|
||||
#include "vm/port.h"
|
||||
@@ -152,21 +151,13 @@ class BreakpointLocation {
|
||||
bool for_over_await);
|
||||
|
||||
bool AnyEnabled() const;
|
||||
bool IsResolved() const {
|
||||
return bytecode_token_pos_.IsReal() || code_token_pos_.IsReal();
|
||||
}
|
||||
bool IsResolved(bool in_bytecode) const {
|
||||
return in_bytecode ? bytecode_token_pos_.IsReal()
|
||||
: code_token_pos_.IsReal();
|
||||
}
|
||||
bool IsResolved() const { return code_token_pos_.IsReal(); }
|
||||
bool IsLatent() const { return !token_pos_.IsReal(); }
|
||||
|
||||
private:
|
||||
void VisitObjectPointers(ObjectPointerVisitor* visitor);
|
||||
|
||||
void SetResolved(bool in_bytecode,
|
||||
const Function& func,
|
||||
TokenPosition token_pos);
|
||||
void SetResolved(const Function& func, TokenPosition token_pos);
|
||||
|
||||
BreakpointLocation* next() const { return this->next_; }
|
||||
void set_next(BreakpointLocation* value) { next_ = value; }
|
||||
@@ -187,14 +178,13 @@ class BreakpointLocation {
|
||||
|
||||
// Valid for resolved breakpoints:
|
||||
FunctionPtr function_;
|
||||
TokenPosition bytecode_token_pos_;
|
||||
TokenPosition code_token_pos_;
|
||||
|
||||
friend class Debugger;
|
||||
DISALLOW_COPY_AND_ASSIGN(BreakpointLocation);
|
||||
};
|
||||
|
||||
// CodeBreakpoint represents a location in compiled or interpreted code.
|
||||
// CodeBreakpoint represents a location in compiled code.
|
||||
// There may be more than one CodeBreakpoint for one BreakpointLocation,
|
||||
// e.g. when a function gets compiled as a regular function and as a closure.
|
||||
class CodeBreakpoint {
|
||||
@@ -203,7 +193,6 @@ class CodeBreakpoint {
|
||||
TokenPosition token_pos,
|
||||
uword pc,
|
||||
PcDescriptorsLayout::Kind kind);
|
||||
CodeBreakpoint(const Bytecode& bytecode, TokenPosition token_pos, uword pc);
|
||||
~CodeBreakpoint();
|
||||
|
||||
FunctionPtr function() const;
|
||||
@@ -217,7 +206,6 @@ class CodeBreakpoint {
|
||||
void Enable();
|
||||
void Disable();
|
||||
bool IsEnabled() const { return is_enabled_; }
|
||||
bool IsInterpreted() const { return bytecode_ != Bytecode::null(); }
|
||||
|
||||
CodePtr OrigStubAddress() const;
|
||||
|
||||
@@ -232,11 +220,8 @@ class CodeBreakpoint {
|
||||
|
||||
void PatchCode();
|
||||
void RestoreCode();
|
||||
void SetBytecodeBreakpoint();
|
||||
void UnsetBytecodeBreakpoint();
|
||||
|
||||
CodePtr code_;
|
||||
BytecodePtr bytecode_;
|
||||
TokenPosition token_pos_;
|
||||
uword pc_;
|
||||
intptr_t line_number_;
|
||||
@@ -273,16 +258,6 @@ class ActivationFrame : public ZoneAllocated {
|
||||
|
||||
ActivationFrame(uword pc, const Code& code);
|
||||
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
ActivationFrame(uword pc,
|
||||
uword fp,
|
||||
uword sp,
|
||||
const Bytecode& bytecode,
|
||||
Kind kind = kRegular);
|
||||
|
||||
ActivationFrame(uword pc, const Bytecode& bytecode);
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME)
|
||||
|
||||
explicit ActivationFrame(Kind kind);
|
||||
|
||||
explicit ActivationFrame(const Closure& async_activation);
|
||||
@@ -291,11 +266,7 @@ class ActivationFrame : public ZoneAllocated {
|
||||
uword fp() const { return fp_; }
|
||||
uword sp() const { return sp_; }
|
||||
|
||||
uword GetCallerSp() const {
|
||||
return fp() +
|
||||
((IsInterpreted() ? kKBCCallerSpSlotFromFp : kCallerSpSlotFromFp) *
|
||||
kWordSize);
|
||||
}
|
||||
uword GetCallerSp() const { return fp() + (kCallerSpSlotFromFp * kWordSize); }
|
||||
|
||||
const Function& function() const {
|
||||
return function_;
|
||||
@@ -304,11 +275,6 @@ class ActivationFrame : public ZoneAllocated {
|
||||
ASSERT(!code_.IsNull());
|
||||
return code_;
|
||||
}
|
||||
const Bytecode& bytecode() const {
|
||||
ASSERT(!bytecode_.IsNull());
|
||||
return bytecode_;
|
||||
}
|
||||
bool IsInterpreted() const { return !bytecode_.IsNull(); }
|
||||
|
||||
enum Relation {
|
||||
kCallee,
|
||||
@@ -316,7 +282,7 @@ class ActivationFrame : public ZoneAllocated {
|
||||
kCaller,
|
||||
};
|
||||
|
||||
Relation CompareTo(uword other_fp, bool other_is_interpreted) const;
|
||||
Relation CompareTo(uword other_fp) const;
|
||||
|
||||
StringPtr QualifiedFunctionName();
|
||||
StringPtr SourceUrl();
|
||||
@@ -430,7 +396,6 @@ class ActivationFrame : public ZoneAllocated {
|
||||
// The anchor of the context chain for this function.
|
||||
Context& ctx_;
|
||||
Code& code_;
|
||||
Bytecode& bytecode_;
|
||||
Function& function_;
|
||||
bool live_frame_; // Is this frame a live frame?
|
||||
bool token_pos_initialized_;
|
||||
@@ -473,7 +438,6 @@ class DebuggerStackTrace : public ZoneAllocated {
|
||||
void AddActivation(ActivationFrame* frame);
|
||||
void AddMarker(ActivationFrame::Kind marker);
|
||||
void AddAsyncCausalFrame(uword pc, const Code& code);
|
||||
void AddAsyncCausalFrame(uword pc, const Bytecode& bytecode);
|
||||
|
||||
ZoneGrowableArray<ActivationFrame*> trace_;
|
||||
|
||||
@@ -508,12 +472,7 @@ class Debugger {
|
||||
|
||||
void OnIsolateRunnable();
|
||||
|
||||
void NotifyCompilation(const Function& func) {
|
||||
HandleCodeChange(/* bytecode_loaded = */ false, func);
|
||||
}
|
||||
void NotifyBytecodeLoaded(const Function& func) {
|
||||
HandleCodeChange(/* bytecode_loaded = */ true, func);
|
||||
}
|
||||
void NotifyCompilation(const Function& func);
|
||||
void NotifyDoneLoading();
|
||||
|
||||
// Set breakpoint at closest location to function entry.
|
||||
@@ -561,10 +520,6 @@ class Debugger {
|
||||
ignore_breakpoints_ = ignore_breakpoints;
|
||||
}
|
||||
|
||||
bool HasEnabledBytecodeBreakpoints() const;
|
||||
// Called from the interpreter. Note that pc already points to next bytecode.
|
||||
bool HasBytecodeBreakpointAt(const KBCInstr* next_pc) const;
|
||||
|
||||
// Put the isolate into single stepping mode when Dart code next runs.
|
||||
//
|
||||
// This is used by the vm service to allow the user to step while
|
||||
@@ -588,7 +543,6 @@ class Debugger {
|
||||
// debugger's zone.
|
||||
bool HasBreakpoint(const Function& func, Zone* zone);
|
||||
bool HasBreakpoint(const Code& code);
|
||||
// A Bytecode version of HasBreakpoint is not needed.
|
||||
|
||||
// Returns true if the call at address pc is patched to point to
|
||||
// a debugger stub.
|
||||
@@ -669,7 +623,6 @@ class Debugger {
|
||||
void FindCompiledFunctions(const Script& script,
|
||||
TokenPosition start_pos,
|
||||
TokenPosition end_pos,
|
||||
GrowableObjectArray* bytecode_function_list,
|
||||
GrowableObjectArray* code_function_list);
|
||||
bool FindBestFit(const Script& script,
|
||||
TokenPosition token_pos,
|
||||
@@ -677,17 +630,14 @@ class Debugger {
|
||||
Function* best_fit);
|
||||
FunctionPtr FindInnermostClosure(const Function& function,
|
||||
TokenPosition token_pos);
|
||||
TokenPosition ResolveBreakpointPos(bool in_bytecode,
|
||||
const Function& func,
|
||||
TokenPosition ResolveBreakpointPos(const Function& func,
|
||||
TokenPosition requested_token_pos,
|
||||
TokenPosition last_token_pos,
|
||||
intptr_t requested_column,
|
||||
TokenPosition exact_token_pos);
|
||||
void DeoptimizeWorld();
|
||||
void NotifySingleStepping(bool value) const;
|
||||
BreakpointLocation* SetCodeBreakpoints(bool in_bytecode,
|
||||
BreakpointLocation* loc,
|
||||
const Script& script,
|
||||
BreakpointLocation* SetCodeBreakpoints(const Script& script,
|
||||
TokenPosition token_pos,
|
||||
TokenPosition last_token_pos,
|
||||
intptr_t requested_line,
|
||||
@@ -714,7 +664,6 @@ class Debugger {
|
||||
TokenPosition token_pos,
|
||||
intptr_t requested_line,
|
||||
intptr_t requested_column,
|
||||
TokenPosition bytecode_token_pos = TokenPosition::kNoSource,
|
||||
TokenPosition code_token_pos = TokenPosition::kNoSource);
|
||||
void MakeCodeBreakpointAt(const Function& func, BreakpointLocation* bpt);
|
||||
// Returns NULL if no breakpoint exists for the given address.
|
||||
@@ -724,8 +673,6 @@ class Debugger {
|
||||
void PrintBreakpointsListToJSONArray(BreakpointLocation* sbpt,
|
||||
JSONArray* jsarr) const;
|
||||
|
||||
void HandleCodeChange(bool bytecode_loaded, const Function& func);
|
||||
|
||||
ActivationFrame* TopDartFrame() const;
|
||||
static ActivationFrame* CollectDartFrame(
|
||||
Isolate* isolate,
|
||||
@@ -736,12 +683,6 @@ class Debugger {
|
||||
intptr_t deopt_frame_offset,
|
||||
ActivationFrame::Kind kind = ActivationFrame::kRegular);
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
static ActivationFrame* CollectDartFrame(
|
||||
Isolate* isolate,
|
||||
uword pc,
|
||||
StackFrame* frame,
|
||||
const Bytecode& bytecode,
|
||||
ActivationFrame::Kind kind = ActivationFrame::kRegular);
|
||||
static ArrayPtr DeoptimizeToArray(Thread* thread,
|
||||
StackFrame* frame,
|
||||
const Code& code);
|
||||
@@ -789,7 +730,6 @@ class Debugger {
|
||||
void RewindToOptimizedFrame(StackFrame* frame,
|
||||
const Code& code,
|
||||
intptr_t post_deopt_frame_index);
|
||||
void RewindToInterpretedFrame(StackFrame* frame, const Bytecode& bytecode);
|
||||
|
||||
void ResetSteppingFramePointers();
|
||||
bool SteppedForSyntheticAsyncBreakpoint() const;
|
||||
@@ -832,7 +772,6 @@ class Debugger {
|
||||
// frame corresponds to this fp value, or if the top frame is
|
||||
// lower on the stack.
|
||||
uword stepping_fp_;
|
||||
bool interpreted_stepping_;
|
||||
|
||||
// When stepping through code, do not stop more than once in the same
|
||||
// token position range.
|
||||
@@ -841,7 +780,6 @@ class Debugger {
|
||||
|
||||
// Used to track the current async/async* function.
|
||||
uword async_stepping_fp_;
|
||||
bool interpreted_async_stepping_;
|
||||
ObjectPtr top_frame_awaiter_;
|
||||
|
||||
// If we step while at a breakpoint, we would hit the same pc twice.
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
// Copyright (c) 2019, 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.
|
||||
|
||||
#include "vm/globals.h"
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
|
||||
#include "vm/debugger.h"
|
||||
#include "vm/instructions_kbc.h"
|
||||
#include "vm/interpreter.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
#ifndef PRODUCT
|
||||
void CodeBreakpoint::SetBytecodeBreakpoint() {
|
||||
ASSERT(!is_enabled_);
|
||||
is_enabled_ = true;
|
||||
Interpreter::Current()->set_is_debugging(true);
|
||||
}
|
||||
|
||||
void CodeBreakpoint::UnsetBytecodeBreakpoint() {
|
||||
ASSERT(is_enabled_);
|
||||
is_enabled_ = false;
|
||||
if (!Isolate::Current()->single_step() &&
|
||||
!Isolate::Current()->debugger()->HasEnabledBytecodeBreakpoints()) {
|
||||
Interpreter::Current()->set_is_debugging(false);
|
||||
}
|
||||
}
|
||||
|
||||
bool Debugger::HasEnabledBytecodeBreakpoints() const {
|
||||
CodeBreakpoint* cbpt = code_breakpoints_;
|
||||
while (cbpt != nullptr) {
|
||||
if (cbpt->IsEnabled() && cbpt->IsInterpreted()) {
|
||||
return true;
|
||||
}
|
||||
cbpt = cbpt->next();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Debugger::HasBytecodeBreakpointAt(const KBCInstr* next_pc) const {
|
||||
CodeBreakpoint* cbpt = code_breakpoints_;
|
||||
while (cbpt != nullptr) {
|
||||
if ((reinterpret_cast<uword>(next_pc)) == cbpt->pc_ && cbpt->IsEnabled()) {
|
||||
ASSERT(cbpt->IsInterpreted());
|
||||
return true;
|
||||
}
|
||||
cbpt = cbpt->next();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif // !PRODUCT
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME)
|
||||
@@ -378,7 +378,6 @@ intptr_t DeoptContext::MaterializeDeferredObjects() {
|
||||
StackFrameIterator::kNoCrossThreadIteration);
|
||||
StackFrame* top_frame = iterator.NextFrame();
|
||||
ASSERT(top_frame != NULL);
|
||||
ASSERT(!top_frame->is_interpreted());
|
||||
const Code& code = Code::Handle(top_frame->LookupDartCode());
|
||||
const Function& top_function = Function::Handle(code.function());
|
||||
const Script& script = Script::Handle(top_function.script());
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
|
||||
namespace dart {
|
||||
|
||||
DECLARE_FLAG(bool, enable_interpreter);
|
||||
DECLARE_FLAG(bool, trace_deoptimization);
|
||||
DEFINE_FLAG(bool,
|
||||
print_stacktrace_at_throw,
|
||||
@@ -129,26 +128,15 @@ static void BuildStackTrace(StackTraceBuilder* builder) {
|
||||
StackFrame* frame = frames.NextFrame();
|
||||
ASSERT(frame != NULL); // We expect to find a dart invocation frame.
|
||||
Code& code = Code::Handle();
|
||||
Bytecode& bytecode = Bytecode::Handle();
|
||||
Smi& offset = Smi::Handle();
|
||||
for (; frame != NULL; frame = frames.NextFrame()) {
|
||||
if (!frame->IsDartFrame()) {
|
||||
continue;
|
||||
}
|
||||
if (frame->is_interpreted()) {
|
||||
bytecode = frame->LookupDartBytecode();
|
||||
ASSERT(bytecode.ContainsInstructionAt(frame->pc()));
|
||||
if (bytecode.function() == Function::null()) {
|
||||
continue;
|
||||
}
|
||||
offset = Smi::New(frame->pc() - bytecode.PayloadStart());
|
||||
builder->AddFrame(bytecode, offset);
|
||||
} else {
|
||||
code = frame->LookupDartCode();
|
||||
ASSERT(code.ContainsInstructionAt(frame->pc()));
|
||||
offset = Smi::New(frame->pc() - code.PayloadStart());
|
||||
builder->AddFrame(code, offset);
|
||||
}
|
||||
code = frame->LookupDartCode();
|
||||
ASSERT(code.ContainsInstructionAt(frame->pc()));
|
||||
offset = Smi::New(frame->pc() - code.PayloadStart());
|
||||
builder->AddFrame(code, offset);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -622,9 +610,7 @@ static void ClearLazyDeopts(Thread* thread, uword frame_pointer) {
|
||||
StackFrameIterator::kNoCrossThreadIteration);
|
||||
for (StackFrame* frame = frames.NextFrame(); frame != nullptr;
|
||||
frame = frames.NextFrame()) {
|
||||
if (frame->is_interpreted()) {
|
||||
continue;
|
||||
} else if (frame->fp() >= frame_pointer) {
|
||||
if (frame->fp() >= frame_pointer) {
|
||||
break;
|
||||
}
|
||||
if (frame->IsMarkedForLazyDeopt()) {
|
||||
@@ -677,18 +663,6 @@ void Exceptions::JumpToFrame(Thread* thread,
|
||||
uword stack_pointer,
|
||||
uword frame_pointer,
|
||||
bool clear_deopt_at_target) {
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
// TODO(regis): We still possibly need to unwind interpreter frames if they
|
||||
// are callee frames of the C++ frame handling the exception.
|
||||
if (FLAG_enable_interpreter) {
|
||||
Interpreter* interpreter = thread->interpreter();
|
||||
if ((interpreter != NULL) && interpreter->HasFrame(frame_pointer)) {
|
||||
interpreter->JumpToFrame(program_counter, stack_pointer, frame_pointer,
|
||||
thread);
|
||||
}
|
||||
}
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME)
|
||||
|
||||
const uword fp_for_clearing =
|
||||
(clear_deopt_at_target ? frame_pointer + 1 : frame_pointer);
|
||||
ClearLazyDeopts(thread, fp_for_clearing);
|
||||
|
||||
@@ -96,9 +96,6 @@ constexpr bool kDartUseBackgroundCompilation = true;
|
||||
"Collects all dynamic function names to identify unique targets") \
|
||||
P(compactor_tasks, int, 2, \
|
||||
"The number of tasks to use for parallel compaction.") \
|
||||
P(compilation_counter_threshold, int, 10, \
|
||||
"Function's usage-counter value before interpreted function is compiled, " \
|
||||
"-1 means never") \
|
||||
P(concurrent_mark, bool, true, "Concurrent mark for old generation.") \
|
||||
P(concurrent_sweep, bool, true, "Concurrent sweep for old generation.") \
|
||||
C(deoptimize_alot, false, false, bool, false, \
|
||||
@@ -219,7 +216,6 @@ constexpr bool kDartUseBackgroundCompilation = true;
|
||||
D(trace_zones, bool, false, "Traces allocation sizes in the zone.") \
|
||||
P(truncating_left_shift, bool, true, \
|
||||
"Optimize left shift to truncate if possible") \
|
||||
P(use_bytecode_compiler, bool, false, "Compile from bytecode") \
|
||||
P(use_compactor, bool, false, "Compact the heap during old-space GC.") \
|
||||
P(use_cha_deopt, bool, true, \
|
||||
"Use class hierarchy analysis even if it can cause deoptimization.") \
|
||||
@@ -242,7 +238,6 @@ constexpr bool kDartUseBackgroundCompilation = true;
|
||||
"Enable magical pragmas for testing purposes. Use at your own risk!") \
|
||||
R(eliminate_type_checks, true, bool, true, \
|
||||
"Eliminate type checks when allowed by static type analysis.") \
|
||||
P(enable_interpreter, bool, false, "Enable interpreting kernel bytecode.") \
|
||||
D(support_rr, bool, false, "Support running within RR.") \
|
||||
P(verify_entry_points, bool, false, \
|
||||
"Throw API error on invalid member access throuh native API. See " \
|
||||
|
||||
@@ -53,26 +53,6 @@ void _printGeneratedStackTrace(uword fp, uword sp, uword pc) {
|
||||
}
|
||||
}
|
||||
|
||||
// Like _printDartStackTrace, but works in the interpreter loop.
|
||||
// Must be called with the current interpreter fp, sp, and pc.
|
||||
// Note that sp[0] is not modified, but sp[1] will be trashed.
|
||||
DART_EXPORT
|
||||
void _printInterpreterStackTrace(ObjectPtr* fp,
|
||||
ObjectPtr* sp,
|
||||
const KBCInstr* pc) {
|
||||
Thread* thread = Thread::Current();
|
||||
sp[1] = Function::null();
|
||||
sp[2] = Bytecode::null();
|
||||
sp[3] = static_cast<ObjectPtr>(reinterpret_cast<uword>(pc));
|
||||
sp[4] = static_cast<ObjectPtr>(reinterpret_cast<uword>(fp));
|
||||
ObjectPtr* exit_fp = sp + 1 + kKBCDartFrameFixedSize;
|
||||
thread->set_top_exit_frame_info(reinterpret_cast<uword>(exit_fp));
|
||||
thread->set_execution_state(Thread::kThreadInVM);
|
||||
_printDartStackTrace();
|
||||
thread->set_execution_state(Thread::kThreadInGenerated);
|
||||
thread->set_top_exit_frame_info(0);
|
||||
}
|
||||
|
||||
class PrintObjectPointersVisitor : public ObjectPointerVisitor {
|
||||
public:
|
||||
PrintObjectPointersVisitor()
|
||||
|
||||
@@ -312,20 +312,6 @@ class MarkingWeakVisitor : public HandleVisitor {
|
||||
|
||||
void GCMarker::Prologue() {
|
||||
isolate_group_->ReleaseStoreBuffers();
|
||||
|
||||
#ifndef DART_PRECOMPILED_RUNTIME
|
||||
isolate_group_->ForEachIsolate(
|
||||
[&](Isolate* isolate) {
|
||||
Thread* mutator_thread = isolate->mutator_thread();
|
||||
if (mutator_thread != NULL) {
|
||||
Interpreter* interpreter = mutator_thread->interpreter();
|
||||
if (interpreter != NULL) {
|
||||
interpreter->ClearLookupCache();
|
||||
}
|
||||
}
|
||||
},
|
||||
/*at_safepoint=*/true);
|
||||
#endif
|
||||
}
|
||||
|
||||
void GCMarker::Epilogue() {}
|
||||
|
||||
@@ -76,12 +76,10 @@ void WeakCodeReferences::DisableCode() {
|
||||
StackFrameIterator::kNoCrossThreadIteration);
|
||||
StackFrame* frame = iterator.NextFrame();
|
||||
while (frame != NULL) {
|
||||
if (!frame->is_interpreted()) {
|
||||
code = frame->LookupDartCode();
|
||||
if (IsOptimizedCode(code_objects, code)) {
|
||||
ReportDeoptimization(code);
|
||||
DeoptimizeAt(code, frame);
|
||||
}
|
||||
code = frame->LookupDartCode();
|
||||
if (IsOptimizedCode(code_objects, code)) {
|
||||
ReportDeoptimization(code);
|
||||
DeoptimizeAt(code, frame);
|
||||
}
|
||||
frame = iterator.NextFrame();
|
||||
}
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
// Copyright (c) 2018, 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.
|
||||
|
||||
#include "vm/globals.h"
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
|
||||
#include "vm/instructions.h"
|
||||
#include "vm/instructions_kbc.h"
|
||||
|
||||
#include "vm/constants_kbc.h"
|
||||
#include "vm/native_entry.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
TypedDataPtr KBCNativeCallPattern::GetNativeEntryDataAt(
|
||||
uword pc,
|
||||
const Bytecode& bytecode) {
|
||||
ASSERT(bytecode.ContainsInstructionAt(pc));
|
||||
|
||||
const KBCInstr* return_addr = reinterpret_cast<const KBCInstr*>(pc);
|
||||
const KBCInstr* instr =
|
||||
reinterpret_cast<const KBCInstr*>(bytecode.PayloadStart());
|
||||
ASSERT(instr < return_addr);
|
||||
while (!KernelBytecode::IsNativeCallOpcode(instr)) {
|
||||
instr = KernelBytecode::Next(instr);
|
||||
if (instr >= return_addr) {
|
||||
FATAL1(
|
||||
"Unable to find NativeCall bytecode instruction"
|
||||
" corresponding to PC %" Px,
|
||||
pc);
|
||||
}
|
||||
}
|
||||
|
||||
intptr_t native_entry_data_pool_index = KernelBytecode::DecodeD(instr);
|
||||
const ObjectPool& obj_pool = ObjectPool::Handle(bytecode.object_pool());
|
||||
TypedData& native_entry_data = TypedData::Handle();
|
||||
native_entry_data ^= obj_pool.ObjectAt(native_entry_data_pool_index);
|
||||
// Native calls to recognized functions should never be patched.
|
||||
ASSERT(NativeEntryData(native_entry_data).kind() ==
|
||||
MethodRecognizer::kUnknown);
|
||||
return native_entry_data.raw();
|
||||
}
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME)
|
||||
@@ -1,25 +0,0 @@
|
||||
// Copyright (c) 2018, 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.
|
||||
// Classes that describe assembly patterns as used by inline caches.
|
||||
|
||||
#ifndef RUNTIME_VM_INSTRUCTIONS_KBC_H_
|
||||
#define RUNTIME_VM_INSTRUCTIONS_KBC_H_
|
||||
|
||||
#include "vm/globals.h"
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
|
||||
#include "vm/object.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
class KBCNativeCallPattern : public AllStatic {
|
||||
public:
|
||||
static TypedDataPtr GetNativeEntryDataAt(uword pc, const Bytecode& bytecode);
|
||||
};
|
||||
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME)
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // RUNTIME_VM_INSTRUCTIONS_KBC_H_
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,281 +0,0 @@
|
||||
// Copyright (c) 2018, 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.
|
||||
|
||||
#ifndef RUNTIME_VM_INTERPRETER_H_
|
||||
#define RUNTIME_VM_INTERPRETER_H_
|
||||
|
||||
#include "vm/globals.h"
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
|
||||
#include "vm/compiler/method_recognizer.h"
|
||||
#include "vm/constants_kbc.h"
|
||||
#include "vm/tagged_pointer.h"
|
||||
|
||||
namespace dart {
|
||||
|
||||
class Array;
|
||||
class Code;
|
||||
class InterpreterSetjmpBuffer;
|
||||
class Isolate;
|
||||
class ObjectPointerVisitor;
|
||||
class Thread;
|
||||
|
||||
class LookupCache : public ValueObject {
|
||||
public:
|
||||
LookupCache() {
|
||||
ASSERT(Utils::IsPowerOfTwo(sizeof(Entry)));
|
||||
ASSERT(Utils::IsPowerOfTwo(sizeof(kNumEntries)));
|
||||
Clear();
|
||||
}
|
||||
|
||||
void Clear();
|
||||
bool Lookup(intptr_t receiver_cid,
|
||||
StringPtr function_name,
|
||||
ArrayPtr arguments_descriptor,
|
||||
FunctionPtr* target) const;
|
||||
void Insert(intptr_t receiver_cid,
|
||||
StringPtr function_name,
|
||||
ArrayPtr arguments_descriptor,
|
||||
FunctionPtr target);
|
||||
|
||||
private:
|
||||
struct Entry {
|
||||
intptr_t receiver_cid;
|
||||
StringPtr function_name;
|
||||
ArrayPtr arguments_descriptor;
|
||||
FunctionPtr target;
|
||||
};
|
||||
|
||||
static const intptr_t kNumEntries = 1024;
|
||||
static const intptr_t kTableMask = kNumEntries - 1;
|
||||
|
||||
Entry entries_[kNumEntries];
|
||||
};
|
||||
|
||||
// Interpreter intrinsic handler. It is invoked on entry to the intrinsified
|
||||
// function via Intrinsic bytecode before the frame is setup.
|
||||
// If the handler returns true then Intrinsic bytecode works as a return
|
||||
// instruction returning the value in result. Otherwise interpreter proceeds to
|
||||
// execute the body of the function.
|
||||
typedef bool (*IntrinsicHandler)(Thread* thread,
|
||||
ObjectPtr* FP,
|
||||
ObjectPtr* result);
|
||||
|
||||
class Interpreter {
|
||||
public:
|
||||
static const uword kInterpreterStackUnderflowSize = 0x80;
|
||||
// The entry frame pc marker must be non-zero (a valid exception handler pc).
|
||||
static const word kEntryFramePcMarker = -1;
|
||||
|
||||
Interpreter();
|
||||
~Interpreter();
|
||||
|
||||
// The currently executing Interpreter instance, which is associated to the
|
||||
// current isolate
|
||||
static Interpreter* Current();
|
||||
|
||||
// Low address (KBC stack grows up).
|
||||
uword stack_base() const { return stack_base_; }
|
||||
// Limit for StackOverflowError.
|
||||
uword overflow_stack_limit() const { return overflow_stack_limit_; }
|
||||
// High address (KBC stack grows up).
|
||||
uword stack_limit() const { return stack_limit_; }
|
||||
|
||||
// Returns true if the interpreter's stack contains the given frame.
|
||||
// TODO(regis): We should rely on a new thread vm_tag to identify an
|
||||
// interpreter frame and not need this HasFrame() method.
|
||||
bool HasFrame(uword frame) const {
|
||||
return frame >= stack_base() && frame < stack_limit();
|
||||
}
|
||||
|
||||
// Identify an entry frame by looking at its pc marker value.
|
||||
static bool IsEntryFrameMarker(const KBCInstr* pc) {
|
||||
return reinterpret_cast<word>(pc) == kEntryFramePcMarker;
|
||||
}
|
||||
|
||||
ObjectPtr Call(const Function& function,
|
||||
const Array& arguments_descriptor,
|
||||
const Array& arguments,
|
||||
Thread* thread);
|
||||
|
||||
ObjectPtr Call(FunctionPtr function,
|
||||
ArrayPtr argdesc,
|
||||
intptr_t argc,
|
||||
ObjectPtr const* argv,
|
||||
Thread* thread);
|
||||
|
||||
void JumpToFrame(uword pc, uword sp, uword fp, Thread* thread);
|
||||
|
||||
uword get_sp() const { return reinterpret_cast<uword>(fp_); } // Yes, fp_.
|
||||
uword get_fp() const { return reinterpret_cast<uword>(fp_); }
|
||||
uword get_pc() const { return reinterpret_cast<uword>(pc_); }
|
||||
|
||||
void Unexit(Thread* thread);
|
||||
|
||||
void VisitObjectPointers(ObjectPointerVisitor* visitor);
|
||||
void ClearLookupCache() { lookup_cache_.Clear(); }
|
||||
|
||||
#ifndef PRODUCT
|
||||
void set_is_debugging(bool value) { is_debugging_ = value; }
|
||||
bool is_debugging() const { return is_debugging_; }
|
||||
#endif // !PRODUCT
|
||||
|
||||
private:
|
||||
uintptr_t* stack_;
|
||||
uword stack_base_;
|
||||
uword overflow_stack_limit_;
|
||||
uword stack_limit_;
|
||||
|
||||
ObjectPtr* volatile fp_;
|
||||
const KBCInstr* volatile pc_;
|
||||
DEBUG_ONLY(uint64_t icount_;)
|
||||
|
||||
InterpreterSetjmpBuffer* last_setjmp_buffer_;
|
||||
|
||||
ObjectPoolPtr pp_; // Pool Pointer.
|
||||
ArrayPtr argdesc_; // Arguments Descriptor: used to pass information between
|
||||
// call instruction and the function entry.
|
||||
ObjectPtr special_[KernelBytecode::kSpecialIndexCount];
|
||||
|
||||
LookupCache lookup_cache_;
|
||||
|
||||
void Exit(Thread* thread,
|
||||
ObjectPtr* base,
|
||||
ObjectPtr* exit_frame,
|
||||
const KBCInstr* pc);
|
||||
|
||||
bool Invoke(Thread* thread,
|
||||
ObjectPtr* call_base,
|
||||
ObjectPtr* call_top,
|
||||
const KBCInstr** pc,
|
||||
ObjectPtr** FP,
|
||||
ObjectPtr** SP);
|
||||
|
||||
bool InvokeCompiled(Thread* thread,
|
||||
FunctionPtr function,
|
||||
ObjectPtr* call_base,
|
||||
ObjectPtr* call_top,
|
||||
const KBCInstr** pc,
|
||||
ObjectPtr** FP,
|
||||
ObjectPtr** SP);
|
||||
|
||||
bool InvokeBytecode(Thread* thread,
|
||||
FunctionPtr function,
|
||||
ObjectPtr* call_base,
|
||||
ObjectPtr* call_top,
|
||||
const KBCInstr** pc,
|
||||
ObjectPtr** FP,
|
||||
ObjectPtr** SP);
|
||||
|
||||
bool InstanceCall(Thread* thread,
|
||||
StringPtr target_name,
|
||||
ObjectPtr* call_base,
|
||||
ObjectPtr* call_top,
|
||||
const KBCInstr** pc,
|
||||
ObjectPtr** FP,
|
||||
ObjectPtr** SP);
|
||||
|
||||
bool CopyParameters(Thread* thread,
|
||||
const KBCInstr** pc,
|
||||
ObjectPtr** FP,
|
||||
ObjectPtr** SP,
|
||||
const intptr_t num_fixed_params,
|
||||
const intptr_t num_opt_pos_params,
|
||||
const intptr_t num_opt_named_params);
|
||||
|
||||
bool AssertAssignable(Thread* thread,
|
||||
const KBCInstr* pc,
|
||||
ObjectPtr* FP,
|
||||
ObjectPtr* call_top,
|
||||
ObjectPtr* args,
|
||||
SubtypeTestCachePtr cache);
|
||||
template <bool is_getter>
|
||||
bool AssertAssignableField(Thread* thread,
|
||||
const KBCInstr* pc,
|
||||
ObjectPtr* FP,
|
||||
ObjectPtr* SP,
|
||||
InstancePtr instance,
|
||||
FieldPtr field,
|
||||
InstancePtr value);
|
||||
|
||||
bool AllocateMint(Thread* thread,
|
||||
int64_t value,
|
||||
const KBCInstr* pc,
|
||||
ObjectPtr* FP,
|
||||
ObjectPtr* SP);
|
||||
bool AllocateDouble(Thread* thread,
|
||||
double value,
|
||||
const KBCInstr* pc,
|
||||
ObjectPtr* FP,
|
||||
ObjectPtr* SP);
|
||||
bool AllocateFloat32x4(Thread* thread,
|
||||
simd128_value_t value,
|
||||
const KBCInstr* pc,
|
||||
ObjectPtr* FP,
|
||||
ObjectPtr* SP);
|
||||
bool AllocateFloat64x2(Thread* thread,
|
||||
simd128_value_t value,
|
||||
const KBCInstr* pc,
|
||||
ObjectPtr* FP,
|
||||
ObjectPtr* SP);
|
||||
bool AllocateArray(Thread* thread,
|
||||
TypeArgumentsPtr type_args,
|
||||
ObjectPtr length,
|
||||
const KBCInstr* pc,
|
||||
ObjectPtr* FP,
|
||||
ObjectPtr* SP);
|
||||
bool AllocateContext(Thread* thread,
|
||||
intptr_t num_variables,
|
||||
const KBCInstr* pc,
|
||||
ObjectPtr* FP,
|
||||
ObjectPtr* SP);
|
||||
bool AllocateClosure(Thread* thread,
|
||||
const KBCInstr* pc,
|
||||
ObjectPtr* FP,
|
||||
ObjectPtr* SP);
|
||||
|
||||
#if defined(DEBUG)
|
||||
// Returns true if tracing of executed instructions is enabled.
|
||||
bool IsTracingExecution() const;
|
||||
|
||||
// Prints bytecode instruction at given pc for instruction tracing.
|
||||
void TraceInstruction(const KBCInstr* pc) const;
|
||||
|
||||
bool IsWritingTraceFile() const;
|
||||
void FlushTraceBuffer();
|
||||
void WriteInstructionToTrace(const KBCInstr* pc);
|
||||
|
||||
void* trace_file_;
|
||||
uint64_t trace_file_bytes_written_;
|
||||
|
||||
static const intptr_t kTraceBufferSizeInBytes = 10 * KB;
|
||||
static const intptr_t kTraceBufferInstrs =
|
||||
kTraceBufferSizeInBytes / sizeof(KBCInstr);
|
||||
KBCInstr* trace_buffer_;
|
||||
intptr_t trace_buffer_idx_;
|
||||
#endif // defined(DEBUG)
|
||||
|
||||
// Longjmp support for exceptions.
|
||||
InterpreterSetjmpBuffer* last_setjmp_buffer() { return last_setjmp_buffer_; }
|
||||
void set_last_setjmp_buffer(InterpreterSetjmpBuffer* buffer) {
|
||||
last_setjmp_buffer_ = buffer;
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
bool is_debugging_ = false;
|
||||
#endif // !PRODUCT
|
||||
|
||||
bool supports_unboxed_doubles_;
|
||||
bool supports_unboxed_simd128_;
|
||||
|
||||
friend class InterpreterSetjmpBuffer;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(Interpreter);
|
||||
};
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // !defined(DART_PRECOMPILED_RUNTIME)
|
||||
|
||||
#endif // RUNTIME_VM_INTERPRETER_H_
|
||||
@@ -26,7 +26,6 @@
|
||||
#include "vm/heap/safepoint.h"
|
||||
#include "vm/heap/verifier.h"
|
||||
#include "vm/image_snapshot.h"
|
||||
#include "vm/interpreter.h"
|
||||
#include "vm/isolate_reload.h"
|
||||
#include "vm/kernel_isolate.h"
|
||||
#include "vm/lockers.h"
|
||||
@@ -1681,10 +1680,6 @@ Isolate::Isolate(IsolateGroup* isolate_group,
|
||||
" See dartbug.com/30524 for more information.\n");
|
||||
}
|
||||
|
||||
if (FLAG_enable_interpreter) {
|
||||
NOT_IN_PRECOMPILED(background_compiler_ = new BackgroundCompiler(
|
||||
this, /* optimizing = */ false));
|
||||
}
|
||||
NOT_IN_PRECOMPILED(optimizing_background_compiler_ =
|
||||
new BackgroundCompiler(this, /* optimizing = */ true));
|
||||
}
|
||||
@@ -1698,11 +1693,6 @@ Isolate::~Isolate() {
|
||||
// RELEASE_ASSERT(reload_context_ == NULL);
|
||||
#endif // !defined(PRODUCT) && !defined(DART_PRECOMPILED_RUNTIME)
|
||||
|
||||
if (FLAG_enable_interpreter) {
|
||||
delete background_compiler_;
|
||||
background_compiler_ = nullptr;
|
||||
}
|
||||
|
||||
delete optimizing_background_compiler_;
|
||||
optimizing_background_compiler_ = nullptr;
|
||||
|
||||
@@ -2602,10 +2592,6 @@ void Isolate::set_forward_table_old(WeakTable* table) {
|
||||
void Isolate::Shutdown() {
|
||||
ASSERT(this == Isolate::Current());
|
||||
BackgroundCompiler::Stop(this);
|
||||
if (FLAG_enable_interpreter) {
|
||||
delete background_compiler_;
|
||||
background_compiler_ = nullptr;
|
||||
}
|
||||
delete optimizing_background_compiler_;
|
||||
optimizing_background_compiler_ = nullptr;
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
#include "platform/atomic.h"
|
||||
#include "vm/base_isolate.h"
|
||||
#include "vm/class_table.h"
|
||||
#include "vm/constants_kbc.h"
|
||||
#include "vm/dispatch_table.h"
|
||||
#include "vm/exceptions.h"
|
||||
#include "vm/field_table.h"
|
||||
@@ -56,9 +55,6 @@ class HandleScope;
|
||||
class HandleVisitor;
|
||||
class Heap;
|
||||
class ICData;
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
class Interpreter;
|
||||
#endif
|
||||
class IsolateObjectStore;
|
||||
class IsolateProfilerData;
|
||||
class IsolateReloadContext;
|
||||
|
||||
@@ -1221,7 +1221,7 @@ void IsolateReloadContext::EnsuredUnoptimizedCodeForStack() {
|
||||
Function& func = Function::Handle();
|
||||
while (it.HasNextFrame()) {
|
||||
StackFrame* frame = it.NextFrame();
|
||||
if (frame->IsDartFrame() && !frame->is_interpreted()) {
|
||||
if (frame->IsDartFrame()) {
|
||||
func = frame->LookupDartFunction();
|
||||
ASSERT(!func.IsNull());
|
||||
// Force-optimized functions don't need unoptimized code because their
|
||||
@@ -1945,31 +1945,25 @@ void IsolateReloadContext::ResetUnoptimizedICsOnStack() {
|
||||
Zone* zone = stack_zone.GetZone();
|
||||
|
||||
Code& code = Code::Handle(zone);
|
||||
Bytecode& bytecode = Bytecode::Handle(zone);
|
||||
Function& function = Function::Handle(zone);
|
||||
CallSiteResetter resetter(zone);
|
||||
DartFrameIterator iterator(thread,
|
||||
StackFrameIterator::kNoCrossThreadIteration);
|
||||
StackFrame* frame = iterator.NextFrame();
|
||||
while (frame != NULL) {
|
||||
if (frame->is_interpreted()) {
|
||||
bytecode = frame->LookupDartBytecode();
|
||||
resetter.RebindStaticTargets(bytecode);
|
||||
code = frame->LookupDartCode();
|
||||
if (code.is_optimized() && !code.is_force_optimized()) {
|
||||
// If this code is optimized, we need to reset the ICs in the
|
||||
// corresponding unoptimized code, which will be executed when the stack
|
||||
// unwinds to the optimized code.
|
||||
function = code.function();
|
||||
code = function.unoptimized_code();
|
||||
ASSERT(!code.IsNull());
|
||||
resetter.ResetSwitchableCalls(code);
|
||||
resetter.ResetCaches(code);
|
||||
} else {
|
||||
code = frame->LookupDartCode();
|
||||
if (code.is_optimized() && !code.is_force_optimized()) {
|
||||
// If this code is optimized, we need to reset the ICs in the
|
||||
// corresponding unoptimized code, which will be executed when the stack
|
||||
// unwinds to the optimized code.
|
||||
function = code.function();
|
||||
code = function.unoptimized_code();
|
||||
ASSERT(!code.IsNull());
|
||||
resetter.ResetSwitchableCalls(code);
|
||||
resetter.ResetCaches(code);
|
||||
} else {
|
||||
resetter.ResetSwitchableCalls(code);
|
||||
resetter.ResetCaches(code);
|
||||
}
|
||||
resetter.ResetSwitchableCalls(code);
|
||||
resetter.ResetCaches(code);
|
||||
}
|
||||
frame = iterator.NextFrame();
|
||||
}
|
||||
@@ -2032,14 +2026,6 @@ void IsolateReloadContext::RunInvalidationVisitors() {
|
||||
StackZone stack_zone(thread);
|
||||
Zone* zone = stack_zone.GetZone();
|
||||
|
||||
Thread* mutator_thread = I->mutator_thread();
|
||||
if (mutator_thread != nullptr) {
|
||||
Interpreter* interpreter = mutator_thread->interpreter();
|
||||
if (interpreter != nullptr) {
|
||||
interpreter->ClearLookupCache();
|
||||
}
|
||||
}
|
||||
|
||||
GrowableArray<const Function*> functions(4 * KB);
|
||||
GrowableArray<const KernelProgramInfo*> kernel_infos(KB);
|
||||
GrowableArray<const Field*> fields(4 * KB);
|
||||
@@ -2084,10 +2070,6 @@ void IsolateReloadContext::InvalidateKernelInfos(
|
||||
table.Clear();
|
||||
info.set_classes_cache(table.Release());
|
||||
}
|
||||
// Clear the bytecode object table.
|
||||
if (info.bytecode_component() != Array::null()) {
|
||||
kernel::BytecodeReader::ResetObjectTable(info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2102,7 +2084,6 @@ void IsolateReloadContext::InvalidateFunctions(
|
||||
Class& owning_class = Class::Handle(zone);
|
||||
Library& owning_lib = Library::Handle(zone);
|
||||
Code& code = Code::Handle(zone);
|
||||
Bytecode& bytecode = Bytecode::Handle(zone);
|
||||
for (intptr_t i = 0; i < functions.length(); i++) {
|
||||
const Function& func = *functions[i];
|
||||
if (func.IsSignatureFunction()) {
|
||||
@@ -2115,7 +2096,6 @@ void IsolateReloadContext::InvalidateFunctions(
|
||||
// Grab the current code.
|
||||
code = func.CurrentCode();
|
||||
ASSERT(!code.IsNull());
|
||||
bytecode = func.bytecode();
|
||||
|
||||
owning_class = func.Owner();
|
||||
owning_lib = owning_class.library();
|
||||
@@ -2126,10 +2106,6 @@ void IsolateReloadContext::InvalidateFunctions(
|
||||
// they're held.
|
||||
resetter.ZeroEdgeCounters(func);
|
||||
|
||||
if (!bytecode.IsNull()) {
|
||||
resetter.RebindStaticTargets(bytecode);
|
||||
}
|
||||
|
||||
if (stub_code) {
|
||||
// Nothing to reset.
|
||||
} else if (clear_code) {
|
||||
|
||||
@@ -435,7 +435,6 @@ class CallSiteResetter : public ValueObject {
|
||||
void ZeroEdgeCounters(const Function& function);
|
||||
void ResetCaches(const Code& code);
|
||||
void ResetCaches(const ObjectPool& pool);
|
||||
void RebindStaticTargets(const Bytecode& code);
|
||||
void Reset(const ICData& ic);
|
||||
void ResetSwitchableCalls(const Code& code);
|
||||
|
||||
|
||||
+23
-200
@@ -7,7 +7,6 @@
|
||||
#include "vm/kernel.h"
|
||||
|
||||
#include "vm/bit_vector.h"
|
||||
#include "vm/compiler/frontend/bytecode_reader.h"
|
||||
#include "vm/compiler/frontend/constant_reader.h"
|
||||
#include "vm/compiler/frontend/kernel_translation_helper.h"
|
||||
#include "vm/compiler/jit/compiler.h"
|
||||
@@ -230,71 +229,6 @@ static void CollectKernelDataTokenPositions(
|
||||
token_position_collector.CollectTokenPositions(kernel_offset);
|
||||
}
|
||||
|
||||
static void CollectTokenPosition(TokenPosition position,
|
||||
GrowableArray<intptr_t>* token_positions) {
|
||||
if (position.IsReal()) {
|
||||
token_positions->Add(position.value());
|
||||
}
|
||||
}
|
||||
|
||||
static void CollectBytecodeSourceTokenPositions(
|
||||
const Bytecode& bytecode,
|
||||
Zone* zone,
|
||||
GrowableArray<intptr_t>* token_positions) {
|
||||
BytecodeSourcePositionsIterator iter(zone, bytecode);
|
||||
while (iter.MoveNext()) {
|
||||
CollectTokenPosition(iter.TokenPos(), token_positions);
|
||||
}
|
||||
}
|
||||
|
||||
static void CollectBytecodeFunctionTokenPositions(
|
||||
const Function& function,
|
||||
GrowableArray<intptr_t>* token_positions) {
|
||||
Thread* thread = Thread::Current();
|
||||
Zone* zone = thread->zone();
|
||||
ASSERT(function.is_declared_in_bytecode());
|
||||
CollectTokenPosition(function.token_pos(), token_positions);
|
||||
CollectTokenPosition(function.end_token_pos(), token_positions);
|
||||
if (!function.HasBytecode()) {
|
||||
const Object& result = Object::Handle(
|
||||
zone, BytecodeReader::ReadFunctionBytecode(thread, function));
|
||||
if (!result.IsNull()) {
|
||||
Exceptions::PropagateError(Error::Cast(result));
|
||||
}
|
||||
}
|
||||
Bytecode& bytecode = Bytecode::Handle(zone, function.bytecode());
|
||||
if (bytecode.IsNull()) {
|
||||
return;
|
||||
}
|
||||
if (bytecode.HasSourcePositions() && !function.IsLocalFunction()) {
|
||||
CollectBytecodeSourceTokenPositions(bytecode, zone, token_positions);
|
||||
// Find closure functions in the object pool.
|
||||
const ObjectPool& pool = ObjectPool::Handle(zone, bytecode.object_pool());
|
||||
Object& object = Object::Handle(zone);
|
||||
Function& closure = Function::Handle(zone);
|
||||
for (intptr_t i = 0; i < pool.Length(); i++) {
|
||||
ObjectPool::EntryType entry_type = pool.TypeAt(i);
|
||||
if (entry_type != ObjectPool::EntryType::kTaggedObject) {
|
||||
continue;
|
||||
}
|
||||
object = pool.ObjectAt(i);
|
||||
if (object.IsFunction()) {
|
||||
closure ^= object.raw();
|
||||
if (closure.kind() == FunctionLayout::kClosureFunction &&
|
||||
closure.IsLocalFunction()) {
|
||||
CollectTokenPosition(closure.token_pos(), token_positions);
|
||||
CollectTokenPosition(closure.end_token_pos(), token_positions);
|
||||
bytecode = closure.bytecode();
|
||||
ASSERT(!bytecode.IsNull());
|
||||
ASSERT(bytecode.function() != Function::null());
|
||||
ASSERT(bytecode.HasSourcePositions());
|
||||
CollectBytecodeSourceTokenPositions(bytecode, zone, token_positions);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CollectTokenPositionsFor(const Script& interesting_script) {
|
||||
Thread* thread = Thread::Current();
|
||||
Zone* zone = thread->zone();
|
||||
@@ -328,22 +262,11 @@ void CollectTokenPositionsFor(const Script& interesting_script) {
|
||||
token_positions.Add(klass.token_pos().value());
|
||||
token_positions.Add(klass.end_token_pos().value());
|
||||
}
|
||||
// If class is declared in bytecode, its members should be loaded
|
||||
// (via class finalization) before their token positions could be
|
||||
// collected.
|
||||
if (klass.is_declared_in_bytecode() && !klass.is_finalized()) {
|
||||
const Error& error =
|
||||
Error::Handle(zone, klass.EnsureIsFinalized(thread));
|
||||
if (!error.IsNull()) {
|
||||
Exceptions::PropagateError(error);
|
||||
}
|
||||
}
|
||||
if (klass.is_finalized()) {
|
||||
temp_array = klass.fields();
|
||||
for (intptr_t i = 0; i < temp_array.Length(); ++i) {
|
||||
temp_field ^= temp_array.At(i);
|
||||
if (!temp_field.is_declared_in_bytecode() &&
|
||||
temp_field.kernel_offset() <= 0) {
|
||||
if (temp_field.kernel_offset() <= 0) {
|
||||
// Skip artificially injected fields.
|
||||
continue;
|
||||
}
|
||||
@@ -351,23 +274,12 @@ void CollectTokenPositionsFor(const Script& interesting_script) {
|
||||
if (entry_script.raw() != interesting_script.raw()) {
|
||||
continue;
|
||||
}
|
||||
if (temp_field.is_declared_in_bytecode()) {
|
||||
token_positions.Add(temp_field.token_pos().value());
|
||||
token_positions.Add(temp_field.end_token_pos().value());
|
||||
if (temp_field.is_static() &&
|
||||
temp_field.has_nontrivial_initializer()) {
|
||||
temp_function = temp_field.EnsureInitializerFunction();
|
||||
CollectBytecodeFunctionTokenPositions(temp_function,
|
||||
&token_positions);
|
||||
}
|
||||
} else {
|
||||
data = temp_field.KernelData();
|
||||
CollectKernelDataTokenPositions(
|
||||
data, interesting_script, entry_script,
|
||||
temp_field.kernel_offset(),
|
||||
temp_field.KernelDataProgramOffset(), zone, &helper,
|
||||
&token_positions);
|
||||
}
|
||||
data = temp_field.KernelData();
|
||||
CollectKernelDataTokenPositions(
|
||||
data, interesting_script, entry_script,
|
||||
temp_field.kernel_offset(),
|
||||
temp_field.KernelDataProgramOffset(), zone, &helper,
|
||||
&token_positions);
|
||||
}
|
||||
temp_array = klass.current_functions();
|
||||
for (intptr_t i = 0; i < temp_array.Length(); ++i) {
|
||||
@@ -376,21 +288,15 @@ void CollectTokenPositionsFor(const Script& interesting_script) {
|
||||
if (entry_script.raw() != interesting_script.raw()) {
|
||||
continue;
|
||||
}
|
||||
if (temp_function.is_declared_in_bytecode()) {
|
||||
CollectBytecodeFunctionTokenPositions(temp_function,
|
||||
&token_positions);
|
||||
} else {
|
||||
data = temp_function.KernelData();
|
||||
CollectKernelDataTokenPositions(
|
||||
data, interesting_script, entry_script,
|
||||
temp_function.kernel_offset(),
|
||||
temp_function.KernelDataProgramOffset(), zone, &helper,
|
||||
&token_positions);
|
||||
}
|
||||
data = temp_function.KernelData();
|
||||
CollectKernelDataTokenPositions(
|
||||
data, interesting_script, entry_script,
|
||||
temp_function.kernel_offset(),
|
||||
temp_function.KernelDataProgramOffset(), zone, &helper,
|
||||
&token_positions);
|
||||
}
|
||||
} else {
|
||||
// Class isn't finalized yet: read the data attached to it.
|
||||
ASSERT(!klass.is_declared_in_bytecode());
|
||||
ASSERT(klass.kernel_offset() > 0);
|
||||
data = lib.kernel_data();
|
||||
ASSERT(!data.IsNull());
|
||||
@@ -412,20 +318,14 @@ void CollectTokenPositionsFor(const Script& interesting_script) {
|
||||
if (entry_script.raw() != interesting_script.raw()) {
|
||||
continue;
|
||||
}
|
||||
if (temp_function.is_declared_in_bytecode()) {
|
||||
CollectBytecodeFunctionTokenPositions(temp_function,
|
||||
&token_positions);
|
||||
} else {
|
||||
data = temp_function.KernelData();
|
||||
CollectKernelDataTokenPositions(
|
||||
data, interesting_script, entry_script,
|
||||
temp_function.kernel_offset(),
|
||||
temp_function.KernelDataProgramOffset(), zone, &helper,
|
||||
&token_positions);
|
||||
}
|
||||
data = temp_function.KernelData();
|
||||
CollectKernelDataTokenPositions(data, interesting_script, entry_script,
|
||||
temp_function.kernel_offset(),
|
||||
temp_function.KernelDataProgramOffset(),
|
||||
zone, &helper, &token_positions);
|
||||
} else if (entry.IsField()) {
|
||||
const Field& field = Field::Cast(entry);
|
||||
if (!field.is_declared_in_bytecode() && field.kernel_offset() <= 0) {
|
||||
if (field.kernel_offset() <= 0) {
|
||||
// Skip artificially injected fields.
|
||||
continue;
|
||||
}
|
||||
@@ -433,20 +333,10 @@ void CollectTokenPositionsFor(const Script& interesting_script) {
|
||||
if (entry_script.raw() != interesting_script.raw()) {
|
||||
continue;
|
||||
}
|
||||
if (field.is_declared_in_bytecode()) {
|
||||
token_positions.Add(field.token_pos().value());
|
||||
token_positions.Add(field.end_token_pos().value());
|
||||
if (field.is_static() && field.has_nontrivial_initializer()) {
|
||||
temp_function = field.EnsureInitializerFunction();
|
||||
CollectBytecodeFunctionTokenPositions(temp_function,
|
||||
&token_positions);
|
||||
}
|
||||
} else {
|
||||
data = field.KernelData();
|
||||
CollectKernelDataTokenPositions(
|
||||
data, interesting_script, entry_script, field.kernel_offset(),
|
||||
field.KernelDataProgramOffset(), zone, &helper, &token_positions);
|
||||
}
|
||||
data = field.KernelData();
|
||||
CollectKernelDataTokenPositions(
|
||||
data, interesting_script, entry_script, field.kernel_offset(),
|
||||
field.KernelDataProgramOffset(), zone, &helper, &token_positions);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -627,15 +517,6 @@ ObjectPtr BuildParameterDescriptor(const Function& function) {
|
||||
Script& script = Script::Handle(zone, function.script());
|
||||
helper.InitFromScript(script);
|
||||
|
||||
if (function.is_declared_in_bytecode()) {
|
||||
BytecodeComponentData bytecode_component(
|
||||
&Array::Handle(zone, helper.GetBytecodeComponent()));
|
||||
ActiveClass active_class;
|
||||
BytecodeReaderHelper bytecode_reader_helper(&helper, &active_class,
|
||||
&bytecode_component);
|
||||
return bytecode_reader_helper.BuildParameterDescriptor(function);
|
||||
}
|
||||
|
||||
const Class& owner_class = Class::Handle(zone, function.Owner());
|
||||
ActiveClass active_class;
|
||||
ActiveClassScope active_class_scope(&active_class, &owner_class);
|
||||
@@ -665,14 +546,6 @@ void ReadParameterCovariance(const Function& function,
|
||||
TranslationHelper translation_helper(thread);
|
||||
translation_helper.InitFromScript(script);
|
||||
|
||||
if (function.is_declared_in_bytecode()) {
|
||||
BytecodeReaderHelper bytecode_reader_helper(&translation_helper, nullptr,
|
||||
nullptr);
|
||||
bytecode_reader_helper.ReadParameterCovariance(function, is_covariant,
|
||||
is_generic_covariant_impl);
|
||||
return;
|
||||
}
|
||||
|
||||
KernelReaderHelper reader_helper(
|
||||
zone, &translation_helper, script,
|
||||
ExternalTypedData::Handle(zone, function.KernelData()),
|
||||
@@ -809,55 +682,8 @@ static ProcedureAttributesMetadata ProcedureAttributesOf(
|
||||
return attrs;
|
||||
}
|
||||
|
||||
static void BytecodeProcedureAttributesError(const Object& function_or_field,
|
||||
const Object& value) {
|
||||
FATAL3("Unexpected value of %s bytecode attribute on %s: %s",
|
||||
Symbols::vm_procedure_attributes_metadata().ToCString(),
|
||||
function_or_field.ToCString(), value.ToCString());
|
||||
}
|
||||
|
||||
static ProcedureAttributesMetadata ProcedureAttributesFromBytecodeAttribute(
|
||||
Zone* zone,
|
||||
const Object& function_or_field) {
|
||||
ProcedureAttributesMetadata attrs;
|
||||
const Object& value = Object::Handle(
|
||||
zone,
|
||||
BytecodeReader::GetBytecodeAttribute(
|
||||
function_or_field, Symbols::vm_procedure_attributes_metadata()));
|
||||
if (!value.IsNull()) {
|
||||
const intptr_t kBytecodeAttributeLength = 3;
|
||||
int32_t elements[kBytecodeAttributeLength];
|
||||
if (!value.IsArray()) {
|
||||
BytecodeProcedureAttributesError(function_or_field, value);
|
||||
}
|
||||
const Array& array = Array::Cast(value);
|
||||
if (array.Length() != kBytecodeAttributeLength) {
|
||||
BytecodeProcedureAttributesError(function_or_field, value);
|
||||
}
|
||||
Object& element = Object::Handle(zone);
|
||||
for (intptr_t i = 0; i < kBytecodeAttributeLength; i++) {
|
||||
element = array.At(i);
|
||||
if (!element.IsSmi()) {
|
||||
BytecodeProcedureAttributesError(function_or_field, value);
|
||||
}
|
||||
elements[i] = Smi::Cast(element).Value();
|
||||
}
|
||||
attrs.InitializeFromFlags(elements[0]);
|
||||
attrs.method_or_setter_selector_id = elements[1];
|
||||
attrs.getter_selector_id = elements[2];
|
||||
}
|
||||
return attrs;
|
||||
}
|
||||
|
||||
ProcedureAttributesMetadata ProcedureAttributesOf(const Function& function,
|
||||
Zone* zone) {
|
||||
if (function.is_declared_in_bytecode()) {
|
||||
if (function.IsImplicitGetterOrSetter()) {
|
||||
const Field& field = Field::Handle(zone, function.accessor_field());
|
||||
return ProcedureAttributesFromBytecodeAttribute(zone, field);
|
||||
}
|
||||
return ProcedureAttributesFromBytecodeAttribute(zone, function);
|
||||
}
|
||||
const Script& script = Script::Handle(zone, function.script());
|
||||
return ProcedureAttributesOf(
|
||||
zone, script, ExternalTypedData::Handle(zone, function.KernelData()),
|
||||
@@ -866,9 +692,6 @@ ProcedureAttributesMetadata ProcedureAttributesOf(const Function& function,
|
||||
|
||||
ProcedureAttributesMetadata ProcedureAttributesOf(const Field& field,
|
||||
Zone* zone) {
|
||||
if (field.is_declared_in_bytecode()) {
|
||||
return ProcedureAttributesFromBytecodeAttribute(zone, field);
|
||||
}
|
||||
const Class& parent = Class::Handle(zone, field.Owner());
|
||||
const Script& script = Script::Handle(zone, parent.script());
|
||||
return ProcedureAttributesOf(
|
||||
|
||||
@@ -214,11 +214,6 @@ void ReadParameterCovariance(const Function& function,
|
||||
// as such function already checks all of its parameters.
|
||||
bool NeedsDynamicInvocationForwarder(const Function& function);
|
||||
|
||||
// Returns a list of ParameterTypeChecks needed by a dynamic invocation
|
||||
// forwarder that targets [function]. Indices in these checks correspond to
|
||||
// bytecode frame indices.
|
||||
ArrayPtr CollectDynamicInvocationChecks(const Function& function);
|
||||
|
||||
ProcedureAttributesMetadata ProcedureAttributesOf(const Function& function,
|
||||
Zone* zone);
|
||||
|
||||
|
||||
@@ -647,11 +647,6 @@ class KernelCompilationRequest : public ValueObject {
|
||||
experimental_flags_object.value.as_array.values = experimental_flags_array;
|
||||
experimental_flags_object.value.as_array.length = num_experimental_flags;
|
||||
|
||||
Dart_CObject bytecode;
|
||||
bytecode.type = Dart_CObject_kBool;
|
||||
bytecode.value.as_bool =
|
||||
FLAG_enable_interpreter || FLAG_use_bytecode_compiler;
|
||||
|
||||
Dart_CObject message;
|
||||
message.type = Dart_CObject_kArray;
|
||||
Dart_CObject* message_arr[] = {&tag,
|
||||
@@ -668,8 +663,7 @@ class KernelCompilationRequest : public ValueObject {
|
||||
&num_blob_loads,
|
||||
&suppress_warnings,
|
||||
&enable_asserts,
|
||||
&experimental_flags_object,
|
||||
&bytecode};
|
||||
&experimental_flags_object};
|
||||
message.value.as_array.values = message_arr;
|
||||
message.value.as_array.length = ARRAY_SIZE(message_arr);
|
||||
|
||||
@@ -813,11 +807,6 @@ class KernelCompilationRequest : public ValueObject {
|
||||
experimental_flags_object.value.as_array.values = experimental_flags_array;
|
||||
experimental_flags_object.value.as_array.length = num_experimental_flags;
|
||||
|
||||
Dart_CObject bytecode;
|
||||
bytecode.type = Dart_CObject_kBool;
|
||||
bytecode.value.as_bool =
|
||||
FLAG_enable_interpreter || FLAG_use_bytecode_compiler;
|
||||
|
||||
Dart_CObject package_config_uri;
|
||||
if (package_config != NULL) {
|
||||
package_config_uri.type = Dart_CObject_kString;
|
||||
@@ -875,7 +864,6 @@ class KernelCompilationRequest : public ValueObject {
|
||||
&suppress_warnings,
|
||||
&enable_asserts,
|
||||
&experimental_flags_object,
|
||||
&bytecode,
|
||||
&package_config_uri,
|
||||
&multiroot_filepaths_object,
|
||||
&multiroot_scheme_object,
|
||||
|
||||
+57
-94
@@ -210,7 +210,6 @@ KernelLoader::KernelLoader(Program* program,
|
||||
&active_class_,
|
||||
/* finalize= */ false),
|
||||
inferred_type_metadata_helper_(&helper_, &constant_reader_),
|
||||
bytecode_metadata_helper_(&helper_, &active_class_),
|
||||
external_name_class_(Class::Handle(Z)),
|
||||
external_name_field_(Field::Handle(Z)),
|
||||
potential_natives_(GrowableObjectArray::Handle(Z)),
|
||||
@@ -450,8 +449,6 @@ void KernelLoader::InitializeFields(UriToSourceTable* uri_to_source_table) {
|
||||
script = LoadScriptAt(index, uri_to_source_table);
|
||||
scripts.SetAt(index, script);
|
||||
}
|
||||
|
||||
bytecode_metadata_helper_.ReadBytecodeComponent();
|
||||
}
|
||||
|
||||
KernelLoader::KernelLoader(const Script& script,
|
||||
@@ -478,7 +475,6 @@ KernelLoader::KernelLoader(const Script& script,
|
||||
&active_class_,
|
||||
/* finalize= */ false),
|
||||
inferred_type_metadata_helper_(&helper_, &constant_reader_),
|
||||
bytecode_metadata_helper_(&helper_, &active_class_),
|
||||
external_name_class_(Class::Handle(Z)),
|
||||
external_name_field_(Field::Handle(Z)),
|
||||
potential_natives_(GrowableObjectArray::Handle(Z)),
|
||||
@@ -653,64 +649,49 @@ void KernelLoader::LoadNativeExtensionLibraries() {
|
||||
for (intptr_t i = 0; i < length; ++i) {
|
||||
library ^= potential_extension_libraries.At(i);
|
||||
|
||||
if (library.is_declared_in_bytecode()) {
|
||||
const auto& imports = Array::Handle(Z, library.imports());
|
||||
auto& ns = Namespace::Handle(Z);
|
||||
auto& importee = Library::Handle(Z);
|
||||
for (intptr_t j = 0; j < imports.Length(); ++j) {
|
||||
ns ^= imports.At(j);
|
||||
if (ns.IsNull()) continue;
|
||||
importee = ns.library();
|
||||
uri_path = importee.url();
|
||||
if (uri_path.StartsWith(Symbols::DartExtensionScheme())) {
|
||||
LoadNativeExtension(library, uri_path);
|
||||
helper_.SetOffset(library.kernel_offset());
|
||||
|
||||
LibraryHelper library_helper(&helper_, kernel_binary_version_);
|
||||
library_helper.ReadUntilExcluding(LibraryHelper::kAnnotations);
|
||||
|
||||
const intptr_t annotation_count = helper_.ReadListLength();
|
||||
for (intptr_t j = 0; j < annotation_count; ++j) {
|
||||
uri_path = String::null();
|
||||
|
||||
const intptr_t tag = helper_.PeekTag();
|
||||
if (tag == kConstantExpression) {
|
||||
helper_.ReadByte(); // Skip the tag.
|
||||
helper_.ReadPosition(); // Skip fileOffset.
|
||||
helper_.SkipDartType(); // Skip type.
|
||||
|
||||
// We have a candidate. Let's look if it's an instance of the
|
||||
// ExternalName class.
|
||||
const intptr_t constant_table_offset = helper_.ReadUInt();
|
||||
if (constant_reader.IsInstanceConstant(constant_table_offset,
|
||||
external_name_class_)) {
|
||||
constant = constant_reader.ReadConstant(constant_table_offset);
|
||||
ASSERT(constant.clazz() == external_name_class_.raw());
|
||||
uri_path ^= constant.GetField(external_name_field_);
|
||||
}
|
||||
} else if (tag == kConstructorInvocation ||
|
||||
tag == kConstConstructorInvocation) {
|
||||
uri_path = DetectExternalNameCtor();
|
||||
} else {
|
||||
helper_.SkipExpression();
|
||||
}
|
||||
} else {
|
||||
helper_.SetOffset(library.kernel_offset());
|
||||
|
||||
LibraryHelper library_helper(&helper_, kernel_binary_version_);
|
||||
library_helper.ReadUntilExcluding(LibraryHelper::kAnnotations);
|
||||
if (uri_path.IsNull()) continue;
|
||||
|
||||
const intptr_t annotation_count = helper_.ReadListLength();
|
||||
for (intptr_t j = 0; j < annotation_count; ++j) {
|
||||
uri_path = String::null();
|
||||
LoadNativeExtension(library, uri_path);
|
||||
|
||||
const intptr_t tag = helper_.PeekTag();
|
||||
if (tag == kConstantExpression) {
|
||||
helper_.ReadByte(); // Skip the tag.
|
||||
helper_.ReadPosition(); // Skip fileOffset.
|
||||
helper_.SkipDartType(); // Skip type.
|
||||
|
||||
// We have a candidate. Let's look if it's an instance of the
|
||||
// ExternalName class.
|
||||
const intptr_t constant_table_offset = helper_.ReadUInt();
|
||||
if (constant_reader.IsInstanceConstant(constant_table_offset,
|
||||
external_name_class_)) {
|
||||
constant = constant_reader.ReadConstant(constant_table_offset);
|
||||
ASSERT(constant.clazz() == external_name_class_.raw());
|
||||
uri_path ^= constant.GetField(external_name_field_);
|
||||
}
|
||||
} else if (tag == kConstructorInvocation ||
|
||||
tag == kConstConstructorInvocation) {
|
||||
uri_path = DetectExternalNameCtor();
|
||||
} else {
|
||||
helper_.SkipExpression();
|
||||
}
|
||||
|
||||
if (uri_path.IsNull()) continue;
|
||||
|
||||
LoadNativeExtension(library, uri_path);
|
||||
|
||||
// Create a dummy library and add it as an import to the current
|
||||
// library. This allows later to discover and reload this native
|
||||
// extension, e.g. when running from an app-jit snapshot.
|
||||
// See Loader::ReloadNativeExtensions(...) which relies on
|
||||
// Dart_GetImportsOfScheme('dart-ext').
|
||||
const auto& native_library = Library::Handle(Library::New(uri_path));
|
||||
library.AddImport(Namespace::Handle(Namespace::New(
|
||||
native_library, Array::null_array(), Array::null_array())));
|
||||
}
|
||||
// Create a dummy library and add it as an import to the current
|
||||
// library. This allows later to discover and reload this native
|
||||
// extension, e.g. when running from an app-jit snapshot.
|
||||
// See Loader::ReloadNativeExtensions(...) which relies on
|
||||
// Dart_GetImportsOfScheme('dart-ext').
|
||||
const auto& native_library = Library::Handle(Library::New(uri_path));
|
||||
library.AddImport(Namespace::Handle(Namespace::New(
|
||||
native_library, Array::null_array(), Array::null_array())));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -745,12 +726,10 @@ ObjectPtr KernelLoader::LoadProgram(bool process_pending_classes) {
|
||||
|
||||
LongJumpScope jump;
|
||||
if (setjmp(*jump.Set()) == 0) {
|
||||
if (!bytecode_metadata_helper_.ReadLibraries()) {
|
||||
// Note that `problemsAsJson` on Component is implicitly skipped.
|
||||
const intptr_t length = program_->library_count();
|
||||
for (intptr_t i = 0; i < length; i++) {
|
||||
LoadLibrary(i);
|
||||
}
|
||||
// Note that `problemsAsJson` on Component is implicitly skipped.
|
||||
const intptr_t length = program_->library_count();
|
||||
for (intptr_t i = 0; i < length; i++) {
|
||||
LoadLibrary(i);
|
||||
}
|
||||
|
||||
// Finalize still pending classes if requested.
|
||||
@@ -780,7 +759,7 @@ ObjectPtr KernelLoader::LoadProgram(bool process_pending_classes) {
|
||||
return LookupLibrary(main_library);
|
||||
}
|
||||
|
||||
return bytecode_metadata_helper_.GetMainLibrary();
|
||||
return Library::null();
|
||||
}
|
||||
|
||||
// Either class finalization failed or we caught a compile error.
|
||||
@@ -791,10 +770,6 @@ ObjectPtr KernelLoader::LoadProgram(bool process_pending_classes) {
|
||||
void KernelLoader::LoadLibrary(const Library& library) {
|
||||
ASSERT(!library.Loaded());
|
||||
|
||||
bytecode_metadata_helper_.ReadLibrary(library);
|
||||
if (library.Loaded()) {
|
||||
return;
|
||||
}
|
||||
const auto& uri = String::Handle(Z, library.url());
|
||||
const intptr_t num_libraries = program_->library_count();
|
||||
for (intptr_t i = 0; i < num_libraries; ++i) {
|
||||
@@ -840,13 +815,10 @@ ObjectPtr KernelLoader::LoadExpressionEvaluationFunction(
|
||||
// Make the expression evaluation function have the right script,
|
||||
// kernel data and parent.
|
||||
const auto& eval_script = Script::Handle(Z, function.script());
|
||||
auto& kernel_data = ExternalTypedData::Handle(Z);
|
||||
intptr_t kernel_offset = -1;
|
||||
if (!function.is_declared_in_bytecode()) {
|
||||
ASSERT(!expression_evaluation_library_.IsNull());
|
||||
kernel_data = expression_evaluation_library_.kernel_data();
|
||||
kernel_offset = expression_evaluation_library_.kernel_offset();
|
||||
}
|
||||
ASSERT(!expression_evaluation_library_.IsNull());
|
||||
auto& kernel_data = ExternalTypedData::Handle(
|
||||
Z, expression_evaluation_library_.kernel_data());
|
||||
intptr_t kernel_offset = expression_evaluation_library_.kernel_offset();
|
||||
function.SetKernelDataAndScript(eval_script, kernel_data, kernel_offset);
|
||||
|
||||
function.set_owner(real_class);
|
||||
@@ -924,10 +896,6 @@ void KernelLoader::walk_incremental_kernel(BitVector* modified_libs,
|
||||
bool* is_empty_program,
|
||||
intptr_t* p_num_classes,
|
||||
intptr_t* p_num_procedures) {
|
||||
if (bytecode_metadata_helper_.FindModifiedLibrariesForHotReload(
|
||||
modified_libs, is_empty_program, p_num_classes, p_num_procedures)) {
|
||||
return;
|
||||
}
|
||||
intptr_t length = program_->library_count();
|
||||
*is_empty_program = *is_empty_program && (length == 0);
|
||||
bool collect_library_stats =
|
||||
@@ -1146,7 +1114,7 @@ LibraryPtr KernelLoader::LoadLibrary(intptr_t index) {
|
||||
if (FLAG_enable_mirrors && annotation_count > 0) {
|
||||
ASSERT(annotations_kernel_offset > 0);
|
||||
library.AddLibraryMetadata(toplevel_class, TokenPosition::kNoSource,
|
||||
annotations_kernel_offset, 0);
|
||||
annotations_kernel_offset);
|
||||
}
|
||||
|
||||
if (register_class) {
|
||||
@@ -1267,8 +1235,7 @@ void KernelLoader::FinishTopLevelClassLoading(
|
||||
}
|
||||
if ((FLAG_enable_mirrors || has_pragma_annotation) &&
|
||||
annotation_count > 0) {
|
||||
library.AddFieldMetadata(field, TokenPosition::kNoSource, field_offset,
|
||||
0);
|
||||
library.AddFieldMetadata(field, TokenPosition::kNoSource, field_offset);
|
||||
}
|
||||
fields_.Add(&field);
|
||||
}
|
||||
@@ -1533,7 +1500,7 @@ void KernelLoader::LoadClass(const Library& library,
|
||||
if ((FLAG_enable_mirrors || has_pragma_annotation) && annotation_count > 0) {
|
||||
library.AddClassMetadata(*out_class, toplevel_class,
|
||||
TokenPosition::kNoSource,
|
||||
class_offset - correction_offset_, 0);
|
||||
class_offset - correction_offset_);
|
||||
}
|
||||
|
||||
// We do not register expression evaluation classes with the VM:
|
||||
@@ -1640,8 +1607,7 @@ void KernelLoader::FinishClassLoading(const Class& klass,
|
||||
}
|
||||
if ((FLAG_enable_mirrors || has_pragma_annotation) &&
|
||||
annotation_count > 0) {
|
||||
library.AddFieldMetadata(field, TokenPosition::kNoSource, field_offset,
|
||||
0);
|
||||
library.AddFieldMetadata(field, TokenPosition::kNoSource, field_offset);
|
||||
}
|
||||
fields_.Add(&field);
|
||||
}
|
||||
@@ -1740,7 +1706,7 @@ void KernelLoader::FinishClassLoading(const Class& klass,
|
||||
if ((FLAG_enable_mirrors || has_pragma_annotation) &&
|
||||
annotation_count > 0) {
|
||||
library.AddFunctionMetadata(function, TokenPosition::kNoSource,
|
||||
constructor_offset, 0);
|
||||
constructor_offset);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1779,7 +1745,6 @@ void KernelLoader::FinishClassLoading(const Class& klass,
|
||||
}
|
||||
|
||||
void KernelLoader::FinishLoading(const Class& klass) {
|
||||
ASSERT(!klass.is_declared_in_bytecode());
|
||||
ASSERT(klass.IsTopLevel() || (klass.kernel_offset() > 0));
|
||||
|
||||
Zone* zone = Thread::Current()->zone();
|
||||
@@ -2087,7 +2052,7 @@ void KernelLoader::LoadProcedure(const Library& library,
|
||||
|
||||
if (annotation_count > 0) {
|
||||
library.AddFunctionMetadata(function, TokenPosition::kNoSource,
|
||||
procedure_offset, 0);
|
||||
procedure_offset);
|
||||
}
|
||||
|
||||
if (has_pragma_annotation) {
|
||||
@@ -2410,11 +2375,9 @@ FunctionPtr CreateFieldInitializerFunction(Thread* thread,
|
||||
const PatchClass& initializer_owner =
|
||||
PatchClass::Handle(zone, PatchClass::New(field_owner, script));
|
||||
const Library& lib = Library::Handle(zone, field_owner.library());
|
||||
if (!lib.is_declared_in_bytecode()) {
|
||||
initializer_owner.set_library_kernel_data(
|
||||
ExternalTypedData::Handle(zone, lib.kernel_data()));
|
||||
initializer_owner.set_library_kernel_offset(lib.kernel_offset());
|
||||
}
|
||||
initializer_owner.set_library_kernel_data(
|
||||
ExternalTypedData::Handle(zone, lib.kernel_data()));
|
||||
initializer_owner.set_library_kernel_offset(lib.kernel_offset());
|
||||
|
||||
// Create a static initializer.
|
||||
const Function& initializer_fun = Function::Handle(
|
||||
@@ -2441,7 +2404,7 @@ FunctionPtr CreateFieldInitializerFunction(Thread* thread,
|
||||
initializer_fun.set_token_pos(field.token_pos());
|
||||
initializer_fun.set_end_token_pos(field.end_token_pos());
|
||||
initializer_fun.set_accessor_field(field);
|
||||
initializer_fun.InheritBinaryDeclarationFrom(field);
|
||||
initializer_fun.InheritKernelOffsetFrom(field);
|
||||
initializer_fun.set_is_extension_member(field.is_extension_member());
|
||||
field.SetInitializerFunction(initializer_fun);
|
||||
return initializer_fun.raw();
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
|
||||
#include "vm/bit_vector.h"
|
||||
#include "vm/compiler/frontend/bytecode_reader.h"
|
||||
#include "vm/compiler/frontend/constant_reader.h"
|
||||
#include "vm/compiler/frontend/kernel_translation_helper.h"
|
||||
#include "vm/hash_map.h"
|
||||
@@ -410,7 +409,6 @@ class KernelLoader : public ValueObject {
|
||||
ConstantReader constant_reader_;
|
||||
TypeTranslator type_translator_;
|
||||
InferredTypeMetadataHelper inferred_type_metadata_helper_;
|
||||
BytecodeMetadataHelper bytecode_metadata_helper_;
|
||||
|
||||
Class& external_name_class_;
|
||||
Field& external_name_field_;
|
||||
|
||||
@@ -207,26 +207,6 @@ DART_EXPORT Dart_Handle Dart_CompileAll() {
|
||||
#endif // defined(DART_PRECOMPILED_RUNTIME)
|
||||
}
|
||||
|
||||
DART_EXPORT Dart_Handle Dart_ReadAllBytecode() {
|
||||
#if defined(DART_PRECOMPILED_RUNTIME)
|
||||
return Api::NewError("%s: Cannot read bytecode on an AOT runtime.",
|
||||
CURRENT_FUNC);
|
||||
#else
|
||||
DARTSCOPE(Thread::Current());
|
||||
API_TIMELINE_DURATION(T);
|
||||
Dart_Handle result = Api::CheckAndFinalizePendingClasses(T);
|
||||
if (Api::IsError(result)) {
|
||||
return result;
|
||||
}
|
||||
CHECK_CALLBACK_STATE(T);
|
||||
const Error& error = Error::Handle(T->zone(), Library::ReadAllBytecode());
|
||||
if (!error.IsNull()) {
|
||||
return Api::NewHandle(T, error.raw());
|
||||
}
|
||||
return Api::Success();
|
||||
#endif // defined(DART_PRECOMPILED_RUNTIME)
|
||||
}
|
||||
|
||||
DART_EXPORT Dart_Handle Dart_FinalizeAllClasses() {
|
||||
#if defined(DART_PRECOMPILED_RUNTIME)
|
||||
return Api::NewError("%s: All classes are already finalized in AOT runtime.",
|
||||
|
||||
@@ -234,10 +234,9 @@ class NativeArguments {
|
||||
: public BitField<intptr_t, bool, kReverseArgOrderBit, 1> {};
|
||||
friend class Api;
|
||||
friend class NativeEntry;
|
||||
friend class Interpreter;
|
||||
friend class Simulator;
|
||||
|
||||
// Allow simulator and interpreter to create NativeArguments in reverse order
|
||||
// Allow simulator to create NativeArguments in reverse order
|
||||
// on the stack.
|
||||
NativeArguments(Thread* thread,
|
||||
int argc_tag,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user