[vm/compiler] Initial implementation of IL binary serialization
This change adds binary serialization/deserialization of flow graphs.
It supports all IL instructions and certain objects which can be
referenced from IL instructions. IL binary serialization is a useful
machanism which would allow us to split compilation into multiple parts
in order to parallelize AOT compilation.
The program structure (libraries/classes/functions/fields) is not
serialized. It is assumed that reader and writer use the same
program structure.
Caveats:
* FFI callbacks are not supported yet.
* Closure functions are not re-created when reading flow graph.
* Flow graph should be in SSA form (unoptimized flow graphs are not
supported).
* JIT mode is not supported (serializer currently assumes lazy
linking of native methods and empty ICData).
In order to test IL serialization, --test_il_serialization VM option is
added to serialize and deserialize flow graph before generating code.
TEST=vm/dart/splay_test now runs with --test_il_serialization.
TEST=Manual run of vm-kernel-precomp-linux-debug-x64-try with
--test_il_serialization enabled (only ffi tests failed).
Issue: https://github.com/dart-lang/sdk/issues/43299
Change-Id: I7bbfd9e3a301e00c9cfbffa06b8f1f6c78a78470
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/254941
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Slava Egorov <vegorov@google.com>
diff --git a/runtime/tests/vm/dart/splay_test.dart b/runtime/tests/vm/dart/splay_test.dart
index ef51ede..25b7d98 100644
--- a/runtime/tests/vm/dart/splay_test.dart
+++ b/runtime/tests/vm/dart/splay_test.dart
@@ -31,6 +31,7 @@
// VMOptions=--no_load_cse
// VMOptions=--no_dead_store_elimination
// VMOptions=--no_load_cse --no_dead_store_elimination
+// VMOptions=--test_il_serialization
import "dart:math";
import 'package:benchmark_harness/benchmark_harness.dart';
diff --git a/runtime/tests/vm/dart_2/splay_test.dart b/runtime/tests/vm/dart_2/splay_test.dart
index 6cd3050..d6a349f 100644
--- a/runtime/tests/vm/dart_2/splay_test.dart
+++ b/runtime/tests/vm/dart_2/splay_test.dart
@@ -35,6 +35,7 @@
// VMOptions=--no_load_cse
// VMOptions=--no_dead_store_elimination
// VMOptions=--no_load_cse --no_dead_store_elimination
+// VMOptions=--test_il_serialization
import "dart:math";
import 'package:benchmark_harness/benchmark_harness.dart';
diff --git a/runtime/vm/bitmap.cc b/runtime/vm/bitmap.cc
index 06119e3..a79912af 100644
--- a/runtime/vm/bitmap.cc
+++ b/runtime/vm/bitmap.cc
@@ -149,4 +149,26 @@
}
}
+void BitmapBuilder::Write(BaseWriteStream* stream) const {
+ const intptr_t payload_size =
+ Utils::Minimum(Utils::RoundUp(Length(), kBitsPerByte) / kBitsPerByte,
+ data_size_in_bytes_);
+ stream->Write<intptr_t>(Length());
+ stream->Write<intptr_t>(payload_size);
+ stream->WriteBytes(BackingStore(), payload_size);
+}
+
+void BitmapBuilder::Read(ReadStream* stream) {
+ length_ = stream->Read<intptr_t>();
+ const intptr_t payload_size = stream->Read<intptr_t>();
+ if (payload_size > data_size_in_bytes_) {
+ data_size_in_bytes_ = payload_size;
+ data_.ptr_ = AllocBackingStore(data_size_in_bytes_);
+ } else {
+ memset(BackingStore() + payload_size, 0,
+ data_size_in_bytes_ - payload_size);
+ }
+ stream->ReadBytes(BackingStore(), payload_size);
+}
+
} // namespace dart
diff --git a/runtime/vm/bitmap.h b/runtime/vm/bitmap.h
index 74c4c5b..2c18ba5 100644
--- a/runtime/vm/bitmap.h
+++ b/runtime/vm/bitmap.h
@@ -54,6 +54,9 @@
void Print() const;
void AppendAsBytesTo(BaseWriteStream* stream) const;
+ void Write(BaseWriteStream* stream) const;
+ void Read(ReadStream* stream);
+
private:
static constexpr intptr_t kIncrementSizeInBytes = 16;
static constexpr intptr_t kInlineCapacityInBytes = 16;
diff --git a/runtime/vm/code_descriptors.h b/runtime/vm/code_descriptors.h
index 47ced6f..6ca2430 100644
--- a/runtime/vm/code_descriptors.h
+++ b/runtime/vm/code_descriptors.h
@@ -107,7 +107,7 @@
ASSERT(list_[try_index].pc_offset == ExceptionHandlers::kInvalidPcOffset);
list_[try_index].pc_offset = pc_offset;
list_[try_index].is_generated = is_generated;
- ASSERT(handler_types.IsZoneHandle());
+ ASSERT(handler_types.IsNotTemporaryScopedHandle());
list_[try_index].handler_types = &handler_types;
list_[try_index].needs_stacktrace |= needs_stacktrace;
}
diff --git a/runtime/vm/compiler/aot/dispatch_table_generator.cc b/runtime/vm/compiler/aot/dispatch_table_generator.cc
index bb5faac..1245c38 100644
--- a/runtime/vm/compiler/aot/dispatch_table_generator.cc
+++ b/runtime/vm/compiler/aot/dispatch_table_generator.cc
@@ -375,6 +375,10 @@
const TableSelector* SelectorMap::GetSelector(
const Function& interface_target) const {
const int32_t sid = SelectorId(interface_target);
+ return GetSelector(sid);
+}
+
+const TableSelector* SelectorMap::GetSelector(int32_t sid) const {
if (sid == kInvalidSelectorId) return nullptr;
const TableSelector* selector = &selectors_[sid];
if (!selector->IsUsed()) return nullptr;
diff --git a/runtime/vm/compiler/aot/dispatch_table_generator.h b/runtime/vm/compiler/aot/dispatch_table_generator.h
index e916a3c..770d880 100644
--- a/runtime/vm/compiler/aot/dispatch_table_generator.h
+++ b/runtime/vm/compiler/aot/dispatch_table_generator.h
@@ -61,6 +61,8 @@
// not have a selector assigned.
const TableSelector* GetSelector(const Function& interface_target) const;
+ const TableSelector* GetSelector(int32_t sid) const;
+
private:
static const int32_t kInvalidSelectorId =
kernel::ProcedureAttributesMetadata::kInvalidSelectorId;
diff --git a/runtime/vm/compiler/backend/compile_type.h b/runtime/vm/compiler/backend/compile_type.h
index 1eeb89c..bc9c6e5 100644
--- a/runtime/vm/compiler/backend/compile_type.h
+++ b/runtime/vm/compiler/backend/compile_type.h
@@ -18,6 +18,8 @@
class AbstractType;
class BaseTextBuffer;
class Definition;
+class FlowGraphDeserializer;
+class FlowGraphSerializer;
template <typename T>
class GrowableArray;
@@ -281,6 +283,9 @@
void set_owner(Definition* owner) { owner_ = owner; }
Definition* owner() const { return owner_; }
+ void Write(FlowGraphSerializer* s) const;
+ explicit CompileType(FlowGraphDeserializer* d);
+
private:
bool can_be_null_;
bool can_be_sentinel_;
diff --git a/runtime/vm/compiler/backend/flow_graph.cc b/runtime/vm/compiler/backend/flow_graph.cc
index fbefe32..2459014 100644
--- a/runtime/vm/compiler/backend/flow_graph.cc
+++ b/runtime/vm/compiler/backend/flow_graph.cc
@@ -2896,4 +2896,120 @@
FlowGraphPrinter::PrintGraph(phase, this);
}
+class SSACompactor : public ValueObject {
+ public:
+ SSACompactor(intptr_t num_blocks,
+ intptr_t num_ssa_vars,
+ ZoneGrowableArray<Definition*>* detached_defs)
+ : block_num_(num_blocks),
+ ssa_num_(num_ssa_vars),
+ detached_defs_(detached_defs) {
+ block_num_.EnsureLength(num_blocks, -1);
+ ssa_num_.EnsureLength(num_ssa_vars, -1);
+ }
+
+ void RenumberGraph(FlowGraph* graph) {
+ for (auto block : graph->reverse_postorder()) {
+ block_num_[block->block_id()] = 1;
+ CollectDetachedMaterializations(block->env());
+
+ if (auto* block_with_idefs = block->AsBlockEntryWithInitialDefs()) {
+ for (Definition* def : *block_with_idefs->initial_definitions()) {
+ RenumberDefinition(def);
+ CollectDetachedMaterializations(def->env());
+ }
+ }
+ if (auto* join = block->AsJoinEntry()) {
+ for (PhiIterator it(join); !it.Done(); it.Advance()) {
+ RenumberDefinition(it.Current());
+ }
+ }
+ for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) {
+ Instruction* instr = it.Current();
+ if (Definition* def = instr->AsDefinition()) {
+ RenumberDefinition(def);
+ }
+ CollectDetachedMaterializations(instr->env());
+ }
+ }
+ for (auto* def : (*detached_defs_)) {
+ RenumberDefinition(def);
+ }
+ graph->set_current_ssa_temp_index(current_ssa_index_);
+
+ // Preserve order between block ids to as predecessors are sorted
+ // by block ids.
+ intptr_t current_block_index = 0;
+ for (intptr_t i = 0, n = block_num_.length(); i < n; ++i) {
+ if (block_num_[i] >= 0) {
+ block_num_[i] = current_block_index++;
+ }
+ }
+ for (auto block : graph->reverse_postorder()) {
+ block->set_block_id(block_num_[block->block_id()]);
+ }
+ graph->set_max_block_id(current_block_index - 1);
+ }
+
+ private:
+ void RenumberDefinition(Definition* def) {
+ if (def->HasSSATemp()) {
+ const intptr_t old_index = def->ssa_temp_index();
+ intptr_t new_index = ssa_num_[old_index];
+ if (new_index < 0) {
+ ssa_num_[old_index] = new_index = current_ssa_index_++;
+ }
+ def->set_ssa_temp_index(new_index);
+ }
+ }
+
+ bool IsDetachedDefinition(Definition* def) {
+ return def->IsMaterializeObject() && (def->next() == nullptr);
+ }
+
+ void AddDetachedDefinition(Definition* def) {
+ for (intptr_t i = 0, n = detached_defs_->length(); i < n; ++i) {
+ if ((*detached_defs_)[i] == def) {
+ return;
+ }
+ }
+ detached_defs_->Add(def);
+ // Follow inputs as detached definitions can reference other
+ // detached definitions.
+ for (intptr_t i = 0, n = def->InputCount(); i < n; ++i) {
+ Definition* input = def->InputAt(i)->definition();
+ if (IsDetachedDefinition(input)) {
+ AddDetachedDefinition(input);
+ }
+ }
+ ASSERT(def->env() == nullptr);
+ }
+
+ void CollectDetachedMaterializations(Environment* env) {
+ if (env == nullptr) {
+ return;
+ }
+ for (Environment::DeepIterator it(env); !it.Done(); it.Advance()) {
+ Definition* def = it.CurrentValue()->definition();
+ if (IsDetachedDefinition(def)) {
+ AddDetachedDefinition(def);
+ }
+ }
+ }
+
+ GrowableArray<intptr_t> block_num_;
+ GrowableArray<intptr_t> ssa_num_;
+ intptr_t current_ssa_index_ = 0;
+ ZoneGrowableArray<Definition*>* detached_defs_;
+};
+
+void FlowGraph::CompactSSA(ZoneGrowableArray<Definition*>* detached_defs) {
+ if (detached_defs == nullptr) {
+ detached_defs = new (Z) ZoneGrowableArray<Definition*>(Z, 0);
+ }
+ SSACompactor compactor(max_block_id() + 1, current_ssa_temp_index(),
+ detached_defs);
+ compactor.RenumberGraph(this);
+}
+
} // namespace dart
diff --git a/runtime/vm/compiler/backend/flow_graph.h b/runtime/vm/compiler/backend/flow_graph.h
index 354e15f..354e2fa 100644
--- a/runtime/vm/compiler/backend/flow_graph.h
+++ b/runtime/vm/compiler/backend/flow_graph.h
@@ -208,6 +208,9 @@
const GrowableArray<BlockEntryInstr*>& reverse_postorder() const {
return reverse_postorder_;
}
+ const GrowableArray<BlockEntryInstr*>& optimized_block_order() const {
+ return optimized_block_order_;
+ }
static bool ShouldReorderBlocks(const Function& function, bool is_optimized);
GrowableArray<BlockEntryInstr*>* CodegenBlockOrder(bool is_optimized);
@@ -533,6 +536,14 @@
const Array& coverage_array() const { return *coverage_array_; }
void set_coverage_array(const Array& array) { coverage_array_ = &array; }
+ // Renumbers SSA values and basic blocks to make numbering dense.
+ // Preserves order among block ids.
+ //
+ // Also collects definitions which are detached from the flow graph
+ // but still referenced (currently only MaterializeObject instructions
+ // can be detached).
+ void CompactSSA(ZoneGrowableArray<Definition*>* detached_defs = nullptr);
+
private:
friend class FlowGraphCompiler; // TODO(ajcbik): restructure
friend class FlowGraphChecker;
diff --git a/runtime/vm/compiler/backend/flow_graph_checker.cc b/runtime/vm/compiler/backend/flow_graph_checker.cc
index e3f8fdd..6fad4a1 100644
--- a/runtime/vm/compiler/backend/flow_graph_checker.cc
+++ b/runtime/vm/compiler/backend/flow_graph_checker.cc
@@ -403,6 +403,13 @@
ASSERT1(def->previous() != nullptr, def);
// Skip checks below for common constants as checking them could be slow.
if (IsCommonConstant(def)) return;
+ } else if (def->IsMaterializeObject()) {
+ // Materializations can be both linked into graph and detached.
+ if (def->next() != nullptr) {
+ ASSERT1(def->previous() != nullptr, def);
+ } else {
+ ASSERT1(def->previous() == nullptr, def);
+ }
} else {
// Others are fully linked into graph.
ASSERT1(def->next() != nullptr, def);
@@ -453,6 +460,14 @@
ASSERT1(instruction->IsGraphEntry() || instruction->next() != nullptr,
instruction);
ASSERT2(DefDominatesUse(def, instruction), def, instruction);
+ } else if (instruction->IsMaterializeObject()) {
+ // Materializations can be both linked into graph and detached.
+ if (instruction->next() != nullptr) {
+ ASSERT1(instruction->previous() != nullptr, instruction);
+ ASSERT2(DefDominatesUse(def, instruction), def, instruction);
+ } else {
+ ASSERT1(instruction->previous() == nullptr, instruction);
+ }
} else {
// Others are fully linked into graph.
ASSERT1(IsControlFlow(instruction) || instruction->next() != nullptr,
diff --git a/runtime/vm/compiler/backend/il.cc b/runtime/vm/compiler/backend/il.cc
index 0dcade7..7182992 100644
--- a/runtime/vm/compiler/backend/il.cc
+++ b/runtime/vm/compiler/backend/il.cc
@@ -1057,6 +1057,11 @@
(needs_number_check() == other_op->needs_number_check());
}
+const RuntimeEntry& CaseInsensitiveCompareInstr::TargetFunction() const {
+ return handle_surrogates_ ? kCaseInsensitiveCompareUTF16RuntimeEntry
+ : kCaseInsensitiveCompareUCS2RuntimeEntry;
+}
+
bool MathMinMaxInstr::AttributesEqual(const Instruction& other) const {
auto const other_op = other.AsMathMinMax();
ASSERT(other_op != NULL);
@@ -3143,10 +3148,10 @@
}
}
- if ((speculative_mode_ == kGuardInputs) && !ComputeCanDeoptimize()) {
+ if ((SpeculativeModeOfInput(0) == kGuardInputs) && !ComputeCanDeoptimize()) {
// Remember if we ever learn out input doesn't require checking, as
// the input Value might be later changed that would make us forget.
- speculative_mode_ = kNotSpeculative;
+ set_speculative_mode(kNotSpeculative);
}
return this;
diff --git a/runtime/vm/compiler/backend/il.h b/runtime/vm/compiler/backend/il.h
index 878c309..e8023e6 100644
--- a/runtime/vm/compiler/backend/il.h
+++ b/runtime/vm/compiler/backend/il.h
@@ -11,11 +11,13 @@
#include <memory>
#include <tuple>
+#include <type_traits>
#include <utility>
#include "vm/allocation.h"
#include "vm/code_descriptors.h"
#include "vm/compiler/backend/compile_type.h"
+#include "vm/compiler/backend/il_serializer.h"
#include "vm/compiler/backend/locations.h"
#include "vm/compiler/backend/slot.h"
#include "vm/compiler/compiler_pass.h"
@@ -588,6 +590,63 @@
DECLARE_INSTRUCTION_NO_BACKEND(type) \
DECLARE_COMPARISON_METHODS
+template <typename T, bool is_enum>
+struct unwrap_enum {};
+
+template <typename T>
+struct unwrap_enum<T, true> {
+ using type = std::underlying_type_t<T>;
+};
+
+template <typename T>
+struct unwrap_enum<T, false> {
+ using type = T;
+};
+
+template <typename T>
+using serializable_type_t =
+ typename unwrap_enum<std::remove_cv_t<T>, std::is_enum<T>::value>::type;
+
+#define WRITE_INSTRUCTION_FIELD(type, name) \
+ s->Write<serializable_type_t<type>>( \
+ static_cast<serializable_type_t<type>>(name));
+#define READ_INSTRUCTION_FIELD(type, name) \
+ , name(static_cast<std::remove_cv_t<type>>( \
+ d->Read<serializable_type_t<type>>()))
+#define DECLARE_INSTRUCTION_FIELD(type, name) type name;
+
+// Every instruction class should declare its serialization via
+// DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS, DECLARE_EMPTY_SERIALIZATION
+// or DECLARE_CUSTOM_SERIALIZATION.
+// If instruction class has fields which reference other instructions,
+// then it should also use DECLARE_EXTRA_SERIALIZATION and serialize
+// those references in WriteExtra/ReadExtra methods.
+#define DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(Instr, BaseClass, FieldList) \
+ public: \
+ virtual void WriteTo(FlowGraphSerializer* s) { \
+ BaseClass::WriteTo(s); \
+ FieldList(WRITE_INSTRUCTION_FIELD) \
+ } \
+ explicit Instr(FlowGraphDeserializer* d) \
+ : BaseClass(d) FieldList(READ_INSTRUCTION_FIELD) {} \
+ \
+ private: \
+ FieldList(DECLARE_INSTRUCTION_FIELD)
+
+#define DECLARE_CUSTOM_SERIALIZATION(Instr) \
+ public: \
+ virtual void WriteTo(FlowGraphSerializer* s); \
+ explicit Instr(FlowGraphDeserializer* d);
+
+#define DECLARE_EMPTY_SERIALIZATION(Instr, BaseClass) \
+ public: \
+ explicit Instr(FlowGraphDeserializer* d) : BaseClass(d) {}
+
+#define DECLARE_EXTRA_SERIALIZATION \
+ public: \
+ virtual void WriteExtra(FlowGraphSerializer* s); \
+ virtual void ReadExtra(FlowGraphDeserializer* d);
+
#if defined(INCLUDE_IL_PRINTER)
#define PRINT_TO_SUPPORT virtual void PrintTo(BaseTextBuffer* f) const;
#define PRINT_OPERANDS_TO_SUPPORT \
@@ -716,6 +775,9 @@
return true;
}
+ void Write(FlowGraphSerializer* s) const;
+ explicit CallTargets(FlowGraphDeserializer* d);
+
private:
void CreateHelper(Zone* zone, const ICData& ic_data);
void MergeIntoRanges();
@@ -1270,6 +1332,9 @@
return Location::kRegister;
}
+ DECLARE_CUSTOM_SERIALIZATION(Instruction)
+ DECLARE_EXTRA_SERIALIZATION
+
protected:
// GetDeoptId and/or CopyDeoptIdFrom.
friend class CallSiteInliner;
@@ -1288,6 +1353,12 @@
deopt_id_ = instr.deopt_id_;
}
+ // Write/read locs and environment, but not inputs.
+ // Used when one instruction embeds another and reuses their inputs
+ // (e.g. Branch/IfThenElse/CheckCondition wrap Comparison).
+ void WriteExtraWithoutInputs(FlowGraphSerializer* s);
+ void ReadExtraWithoutInputs(FlowGraphDeserializer* d);
+
private:
friend class BranchInstr; // For RawSetInputAt.
friend class IfThenElseInstr; // For RawSetInputAt.
@@ -1340,6 +1411,8 @@
virtual bool AllowsCSE() const { return true; }
virtual bool HasUnknownSideEffects() const { return false; }
+
+ DECLARE_EMPTY_SERIALIZATION(PureInstruction, Instruction)
};
// Types to be used as ThrowsTrait for TemplateInstruction/TemplateDefinition.
@@ -1384,6 +1457,8 @@
virtual bool MayThrow() const { return ThrowsTrait::kCanThrow; }
+ DECLARE_EMPTY_SERIALIZATION(TemplateInstruction, BaseClass)
+
protected:
EmbeddedArray<Value*, N> inputs_;
@@ -1484,6 +1559,8 @@
}
PRINT_TO_SUPPORT
+ DECLARE_EMPTY_SERIALIZATION(ParallelMoveInstr, TemplateInstruction)
+ DECLARE_EXTRA_SERIALIZATION
private:
GrowableArray<MoveOperands*> moves_; // Elements cannot be null.
@@ -1624,6 +1701,9 @@
DECLARE_ABSTRACT_INSTRUCTION(BlockEntry)
+ DECLARE_CUSTOM_SERIALIZATION(BlockEntryInstr)
+ DECLARE_EXTRA_SERIALIZATION
+
protected:
BlockEntryInstr(intptr_t block_id,
intptr_t try_index,
@@ -1774,6 +1854,9 @@
return this;
}
+ DECLARE_CUSTOM_SERIALIZATION(BlockEntryWithInitialDefs)
+ DECLARE_EXTRA_SERIALIZATION
+
protected:
void PrintInitialDefinitionsTo(BaseTextBuffer* f) const;
@@ -1856,6 +1939,8 @@
}
PRINT_TO_SUPPORT
+ DECLARE_CUSTOM_SERIALIZATION(GraphEntryInstr)
+ DECLARE_EXTRA_SERIALIZATION
private:
GraphEntryInstr(const ParsedFunction& parsed_function,
@@ -1888,8 +1973,9 @@
intptr_t deopt_id,
intptr_t stack_depth = 0)
: BlockEntryInstr(block_id, try_index, deopt_id, stack_depth),
- predecessors_(2), // Two is the assumed to be the common case.
- phis_(NULL) {}
+ phis_(nullptr),
+ predecessors_(2) // Two is the assumed to be the common case.
+ {}
DECLARE_INSTRUCTION(JoinEntry)
@@ -1913,6 +1999,14 @@
PRINT_TO_SUPPORT
+#define FIELD_LIST(F) F(ZoneGrowableArray<PhiInstr*>*, phis_)
+
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(JoinEntryInstr,
+ BlockEntryInstr,
+ FIELD_LIST)
+#undef FIELD_LIST
+ DECLARE_EXTRA_SERIALIZATION
+
private:
// Classes that have access to predecessors_ when inlining.
friend class BlockEntryInstr;
@@ -1928,7 +2022,6 @@
virtual void AddPredecessor(BlockEntryInstr* predecessor);
GrowableArray<BlockEntryInstr*> predecessors_;
- ZoneGrowableArray<PhiInstr*>* phis_;
DISALLOW_COPY_AND_ASSIGN(JoinEntryInstr);
};
@@ -1961,7 +2054,6 @@
intptr_t deopt_id,
intptr_t stack_depth = 0)
: BlockEntryInstr(block_id, try_index, deopt_id, stack_depth),
- predecessor_(NULL),
edge_weight_(0.0) {}
DECLARE_INSTRUCTION(TargetEntry)
@@ -1980,6 +2072,12 @@
PRINT_TO_SUPPORT
+#define FIELD_LIST(F) F(double, edge_weight_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(TargetEntryInstr,
+ BlockEntryInstr,
+ FIELD_LIST)
+#undef FIELD_LIST
+
private:
friend class BlockEntryInstr; // Access to predecessor_ when inlining.
@@ -1989,8 +2087,8 @@
predecessor_ = predecessor;
}
- BlockEntryInstr* predecessor_;
- double edge_weight_;
+ // Not serialized, set in DiscoverBlocks.
+ BlockEntryInstr* predecessor_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(TargetEntryInstr);
};
@@ -2029,6 +2127,7 @@
GraphEntryInstr* graph_entry() const { return graph_entry_; }
PRINT_TO_SUPPORT
+ DECLARE_CUSTOM_SERIALIZATION(FunctionEntryInstr)
private:
virtual void ClearPredecessors() { graph_entry_ = nullptr; }
@@ -2062,13 +2161,19 @@
PRINT_TO_SUPPORT
+#define FIELD_LIST(F) \
+ F(const intptr_t, callback_id_) \
+ F(const compiler::ffi::CallbackMarshaller&, marshaller_)
+
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(NativeEntryInstr,
+ FunctionEntryInstr,
+ FIELD_LIST)
+#undef FIELD_LIST
+
private:
void SaveArguments(FlowGraphCompiler* compiler) const;
void SaveArgument(FlowGraphCompiler* compiler,
const compiler::ffi::NativeLocation& loc) const;
-
- const intptr_t callback_id_;
- const compiler::ffi::CallbackMarshaller& marshaller_;
};
// Represents an OSR entrypoint to a function.
@@ -2097,6 +2202,7 @@
GraphEntryInstr* graph_entry() const { return graph_entry_; }
PRINT_TO_SUPPORT
+ DECLARE_CUSTOM_SERIALIZATION(OsrEntryInstr)
private:
virtual void ClearPredecessors() { graph_entry_ = nullptr; }
@@ -2125,8 +2231,12 @@
PRINT_TO_SUPPORT
- private:
- const intptr_t indirect_id_;
+#define FIELD_LIST(F) F(const intptr_t, indirect_id_)
+
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(IndirectEntryInstr,
+ JoinEntryInstr,
+ FIELD_LIST)
+#undef FIELD_LIST
};
class CatchBlockEntryInstr : public BlockEntryWithInitialDefs {
@@ -2187,6 +2297,7 @@
intptr_t catch_try_index() const { return catch_try_index_; }
PRINT_TO_SUPPORT
+ DECLARE_CUSTOM_SERIALIZATION(CatchBlockEntryInstr)
private:
friend class BlockEntryInstr; // Access to predecessor_ when inlining.
@@ -2201,7 +2312,6 @@
BlockEntryInstr* predecessor_;
const Array& catch_handler_types_;
const intptr_t catch_try_index_;
- GrowableArray<Definition*> initial_definitions_;
const LocalVariable* exception_var_;
const LocalVariable* stacktrace_var_;
const LocalVariable* raw_exception_var_;
@@ -2266,6 +2376,9 @@
return *this;
}
+ void Write(FlowGraphSerializer* s) const;
+ explicit AliasIdentity(FlowGraphDeserializer* d);
+
private:
explicit AliasIdentity(intptr_t value) : value_(value) {}
@@ -2460,6 +2573,8 @@
virtual Definition* AsDefinition() { return this; }
virtual const Definition* AsDefinition() const { return this; }
+ DECLARE_CUSTOM_SERIALIZATION(Definition)
+
protected:
friend class RangeAnalysis;
friend class Value;
@@ -2510,6 +2625,8 @@
virtual bool AllowsCSE() const { return true; }
virtual bool HasUnknownSideEffects() const { return false; }
+
+ DECLARE_EMPTY_SERIALIZATION(PureDefinition, Definition)
};
template <intptr_t N,
@@ -2530,6 +2647,7 @@
virtual bool MayThrow() const { return ThrowsTrait::kCanThrow; }
+ DECLARE_EMPTY_SERIALIZATION(TemplateDefinition, BaseClass)
protected:
EmbeddedArray<Value*, N> inputs_;
@@ -2572,6 +2690,8 @@
intptr_t InputCount() const { return inputs_.length(); }
Value* InputAt(intptr_t i) const { return inputs_[i]; }
+ DECLARE_CUSTOM_SERIALIZATION(VariadicDefinition)
+
protected:
InputsArray inputs_;
@@ -2648,6 +2768,7 @@
virtual Definition* Canonicalize(FlowGraph* flow_graph);
PRINT_TO_SUPPORT
+ DECLARE_CUSTOM_SERIALIZATION(PhiInstr)
enum ReceiverType { kUnknownReceiver = -1, kNotReceiver = 0, kReceiver = 1 };
@@ -2722,17 +2843,23 @@
PRINT_OPERANDS_TO_SUPPORT
- private:
- const intptr_t index_;
+#define FIELD_LIST(F) \
+ F(const intptr_t, index_) \
+ /* The offset (in words) of the last slot of the parameter, relative */ \
+ /* to the first parameter. */ \
+ /* It is used in the FlowGraphAllocator when it sets the assigned */ \
+ /* location and spill slot for the parameter definition. */ \
+ F(const intptr_t, param_offset_) \
+ F(const Register, base_reg_) \
+ F(const Representation, representation_)
- // The offset (in words) of the last slot of the parameter, relative
- // to the first parameter.
- // It is used in the FlowGraphAllocator when it sets the assigned location
- // and spill slot for the parameter definition.
- const intptr_t param_offset_;
- const Register base_reg_;
- const Representation representation_;
- BlockEntryInstr* block_;
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(ParameterInstr,
+ TemplateDefinition,
+ FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
+ BlockEntryInstr* block_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(ParameterInstr);
};
@@ -2765,10 +2892,16 @@
PRINT_OPERANDS_TO_SUPPORT
- private:
- const compiler::ffi::CallbackMarshaller& marshaller_;
- const intptr_t def_index_;
+#define FIELD_LIST(F) \
+ F(const compiler::ffi::CallbackMarshaller&, marshaller_) \
+ F(const intptr_t, def_index_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(NativeParameterInstr,
+ TemplateDefinition,
+ FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
DISALLOW_COPY_AND_ASSIGN(NativeParameterInstr);
};
@@ -2815,9 +2948,14 @@
PRINT_OPERANDS_TO_SUPPORT
- private:
- const intptr_t offset_;
+#define FIELD_LIST(F) F(const intptr_t, offset_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(StoreIndexedUnsafeInstr,
+ TemplateInstruction,
+ FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
DISALLOW_COPY_AND_ASSIGN(StoreIndexedUnsafeInstr);
};
@@ -2865,10 +3003,16 @@
PRINT_OPERANDS_TO_SUPPORT
- private:
- const intptr_t offset_;
- const Representation representation_;
+#define FIELD_LIST(F) \
+ F(const intptr_t, offset_) \
+ F(const Representation, representation_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(LoadIndexedUnsafeInstr,
+ TemplateDefinition,
+ FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
DISALLOW_COPY_AND_ASSIGN(LoadIndexedUnsafeInstr);
};
@@ -2921,6 +3065,16 @@
Value* dest_start() const { return inputs_[kDestStartPos]; }
Value* length() const { return inputs_[kLengthPos]; }
+#define FIELD_LIST(F) \
+ F(classid_t, src_cid_) \
+ F(classid_t, dest_cid_) \
+ F(intptr_t, element_size_)
+
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(MemoryCopyInstr,
+ TemplateInstruction,
+ FIELD_LIST)
+#undef FIELD_LIST
+
private:
// Set array_reg to point to the index indicated by start (contained in
// start_reg) of the typed data or string in array (contained in array_reg).
@@ -2945,10 +3099,6 @@
}
}
- classid_t src_cid_;
- classid_t dest_cid_;
- intptr_t element_size_;
-
DISALLOW_COPY_AND_ASSIGN(MemoryCopyInstr);
};
@@ -2983,9 +3133,14 @@
PRINT_OPERANDS_TO_SUPPORT
- private:
- const Code& code_;
+#define FIELD_LIST(F) F(const Code&, code_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(TailCallInstr,
+ TemplateInstruction,
+ FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
DISALLOW_COPY_AND_ASSIGN(TailCallInstr);
};
@@ -3019,9 +3174,14 @@
PRINT_OPERANDS_TO_SUPPORT
- private:
- const Representation representation_;
+#define FIELD_LIST(F) F(const Representation, representation_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(PushArgumentInstr,
+ TemplateDefinition,
+ FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
DISALLOW_COPY_AND_ASSIGN(PushArgumentInstr);
};
@@ -3089,11 +3249,17 @@
PRINT_OPERANDS_TO_SUPPORT
- private:
- const TokenPosition token_pos_;
- const intptr_t yield_index_;
- const Representation representation_;
+#define FIELD_LIST(F) \
+ F(const TokenPosition, token_pos_) \
+ F(const intptr_t, yield_index_) \
+ F(const Representation, representation_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(ReturnInstr,
+ TemplateInstruction,
+ FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
const Code& GetReturnStub(FlowGraphCompiler* compiler) const;
DISALLOW_COPY_AND_ASSIGN(ReturnInstr);
@@ -3123,9 +3289,14 @@
return false;
}
- private:
- const compiler::ffi::CallbackMarshaller& marshaller_;
+#define FIELD_LIST(F) F(const compiler::ffi::CallbackMarshaller&, marshaller_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(NativeReturnInstr,
+ ReturnInstr,
+ FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
void EmitReturnMoves(FlowGraphCompiler* compiler);
DISALLOW_COPY_AND_ASSIGN(NativeReturnInstr);
@@ -3151,9 +3322,14 @@
virtual bool HasUnknownSideEffects() const { return false; }
- private:
- const TokenPosition token_pos_;
+#define FIELD_LIST(F) F(const TokenPosition, token_pos_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(ThrowInstr,
+ TemplateInstruction,
+ FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
DISALLOW_COPY_AND_ASSIGN(ThrowInstr);
};
@@ -3186,10 +3362,16 @@
virtual bool HasUnknownSideEffects() const { return false; }
- private:
- const TokenPosition token_pos_;
- const intptr_t catch_try_index_;
+#define FIELD_LIST(F) \
+ F(const TokenPosition, token_pos_) \
+ F(const intptr_t, catch_try_index_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(ReThrowInstr,
+ TemplateInstruction,
+ FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
DISALLOW_COPY_AND_ASSIGN(ReThrowInstr);
};
@@ -3207,9 +3389,14 @@
virtual bool HasUnknownSideEffects() const { return false; }
- private:
- const char* message_;
+#define FIELD_LIST(F) F(const char*, message_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(StopInstr,
+ TemplateInstruction,
+ FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
DISALLOW_COPY_AND_ASSIGN(StopInstr);
};
@@ -3217,10 +3404,9 @@
public:
explicit GotoInstr(JoinEntryInstr* entry, intptr_t deopt_id)
: TemplateInstruction(deopt_id),
- block_(NULL),
- successor_(entry),
edge_weight_(0.0),
- parallel_move_(NULL) {}
+ parallel_move_(nullptr),
+ successor_(entry) {}
DECLARE_INSTRUCTION(Goto)
@@ -3270,14 +3456,23 @@
PRINT_TO_SUPPORT
- private:
- BlockEntryInstr* block_;
- JoinEntryInstr* successor_;
- double edge_weight_;
+#define FIELD_LIST(F) \
+ F(double, edge_weight_) \
+ /* Parallel move that will be used by linear scan register allocator to */ \
+ /* connect live ranges at the end of the block and resolve phis. */ \
+ F(ParallelMoveInstr*, parallel_move_)
- // Parallel move that will be used by linear scan register allocator to
- // connect live ranges at the end of the block and resolve phis.
- ParallelMoveInstr* parallel_move_;
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(GotoInstr,
+ TemplateInstruction,
+ FIELD_LIST)
+#undef FIELD_LIST
+ DECLARE_EXTRA_SERIALIZATION
+
+ private:
+ BlockEntryInstr* block_ = nullptr;
+ JoinEntryInstr* successor_ = nullptr;
+
+ DISALLOW_COPY_AND_ASSIGN(GotoInstr);
};
// IndirectGotoInstr represents a dynamically computed jump. Only
@@ -3339,9 +3534,14 @@
PRINT_TO_SUPPORT
+ DECLARE_CUSTOM_SERIALIZATION(IndirectGotoInstr)
+ DECLARE_EXTRA_SERIALIZATION
+
private:
GrowableArray<TargetEntryInstr*> successors_;
const TypedData& offsets_;
+
+ DISALLOW_COPY_AND_ASSIGN(IndirectGotoInstr);
};
class ComparisonInstr : public Definition {
@@ -3393,6 +3593,17 @@
DECLARE_ABSTRACT_INSTRUCTION(Comparison)
+#define FIELD_LIST(F) \
+ F(const TokenPosition, token_pos_) \
+ F(Token::Kind, kind_) \
+ /* Set by optimizer. */ \
+ F(intptr_t, operation_cid_)
+
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(ComparisonInstr,
+ Definition,
+ FIELD_LIST)
+#undef FIELD_LIST
+
protected:
ComparisonInstr(const InstructionSource& source,
Token::Kind kind,
@@ -3403,10 +3614,6 @@
operation_cid_(kIllegalCid) {}
private:
- const TokenPosition token_pos_;
- Token::Kind kind_;
- intptr_t operation_cid_; // Set by optimizer.
-
DISALLOW_COPY_AND_ASSIGN(ComparisonInstr);
};
@@ -3415,6 +3622,7 @@
virtual bool AllowsCSE() const { return true; }
virtual bool HasUnknownSideEffects() const { return false; }
+ DECLARE_EMPTY_SERIALIZATION(PureComparison, ComparisonInstr)
protected:
PureComparison(const InstructionSource& source,
Token::Kind kind,
@@ -3428,17 +3636,20 @@
class TemplateComparison
: public CSETrait<ComparisonInstr, PureComparison>::Base {
public:
+ using BaseClass = typename CSETrait<ComparisonInstr, PureComparison>::Base;
+
TemplateComparison(const InstructionSource& source,
Token::Kind kind,
intptr_t deopt_id = DeoptId::kNone)
- : CSETrait<ComparisonInstr, PureComparison>::Base(source, kind, deopt_id),
- inputs_() {}
+ : BaseClass(source, kind, deopt_id), inputs_() {}
virtual intptr_t InputCount() const { return N; }
virtual Value* InputAt(intptr_t i) const { return inputs_[i]; }
virtual bool MayThrow() const { return ThrowsTrait::kCanThrow; }
+ DECLARE_EMPTY_SERIALIZATION(TemplateComparison, BaseClass)
+
protected:
EmbeddedArray<Value*, N> inputs_;
@@ -3449,7 +3660,7 @@
class BranchInstr : public Instruction {
public:
explicit BranchInstr(ComparisonInstr* comparison, intptr_t deopt_id)
- : Instruction(deopt_id), comparison_(comparison), constant_target_(NULL) {
+ : Instruction(deopt_id), comparison_(comparison) {
ASSERT(comparison->env() == NULL);
for (intptr_t i = comparison->InputCount() - 1; i >= 0; --i) {
comparison->InputAt(i)->set_instruction(this);
@@ -3529,15 +3740,20 @@
PRINT_TO_SUPPORT
+#define FIELD_LIST(F) F(ComparisonInstr*, comparison_)
+
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(BranchInstr, Instruction, FIELD_LIST)
+#undef FIELD_LIST
+ DECLARE_EXTRA_SERIALIZATION
+
private:
virtual void RawSetInputAt(intptr_t i, Value* value) {
comparison()->RawSetInputAt(i, value);
}
- TargetEntryInstr* true_successor_;
- TargetEntryInstr* false_successor_;
- ComparisonInstr* comparison_;
- TargetEntryInstr* constant_target_;
+ TargetEntryInstr* true_successor_ = nullptr;
+ TargetEntryInstr* false_successor_ = nullptr;
+ TargetEntryInstr* constant_target_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(BranchInstr);
};
@@ -3553,9 +3769,14 @@
DECLARE_INSTRUCTION(Deoptimize)
- private:
- const ICData::DeoptReasonId deopt_reason_;
+#define FIELD_LIST(F) F(const ICData::DeoptReasonId, deopt_reason_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(DeoptimizeInstr,
+ TemplateInstruction,
+ FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
DISALLOW_COPY_AND_ASSIGN(DeoptimizeInstr);
};
@@ -3584,8 +3805,14 @@
PRINT_OPERANDS_TO_SUPPORT
+#define FIELD_LIST(F) F(CompileType*, constrained_type_)
+
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(RedefinitionInstr,
+ TemplateDefinition,
+ FIELD_LIST)
+#undef FIELD_LIST
+
private:
- CompileType* constrained_type_;
DISALLOW_COPY_AND_ASSIGN(RedefinitionInstr);
};
@@ -3609,14 +3836,15 @@
PRINT_OPERANDS_TO_SUPPORT
+ DECLARE_EMPTY_SERIALIZATION(ReachabilityFenceInstr, TemplateInstruction)
+
private:
DISALLOW_COPY_AND_ASSIGN(ReachabilityFenceInstr);
};
class ConstraintInstr : public TemplateDefinition<1, NoThrow> {
public:
- ConstraintInstr(Value* value, Range* constraint)
- : constraint_(constraint), target_(NULL) {
+ ConstraintInstr(Value* value, Range* constraint) : constraint_(constraint) {
SetInputAt(0, value);
}
@@ -3646,9 +3874,16 @@
PRINT_OPERANDS_TO_SUPPORT
+#define FIELD_LIST(F) F(Range*, constraint_)
+
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(ConstraintInstr,
+ TemplateDefinition,
+ FIELD_LIST)
+#undef FIELD_LIST
+ DECLARE_EXTRA_SERIALIZATION
+
private:
- Range* constraint_;
- TargetEntryInstr* target_;
+ TargetEntryInstr* target_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(ConstraintInstr);
};
@@ -3700,10 +3935,16 @@
PRINT_OPERANDS_TO_SUPPORT
- private:
- const Object& value_;
- const TokenPosition token_pos_;
+#define FIELD_LIST(F) \
+ F(const Object&, value_) \
+ F(const TokenPosition, token_pos_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(ConstantInstr,
+ TemplateDefinition,
+ FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
DISALLOW_COPY_AND_ASSIGN(ConstantInstr);
};
@@ -3721,6 +3962,7 @@
uword constant_address() const { return constant_address_; }
DECLARE_INSTRUCTION(UnboxedConstant)
+ DECLARE_CUSTOM_SERIALIZATION(UnboxedConstantInstr)
private:
const Representation representation_;
@@ -3785,9 +4027,14 @@
PRINT_OPERANDS_TO_SUPPORT
- private:
- const TokenPosition token_pos_;
+#define FIELD_LIST(F) F(const TokenPosition, token_pos_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(AssertSubtypeInstr,
+ TemplateInstruction,
+ FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
DISALLOW_COPY_AND_ASSIGN(AssertSubtypeInstr);
};
@@ -3881,11 +4128,17 @@
PRINT_OPERANDS_TO_SUPPORT
- private:
- const TokenPosition token_pos_;
- const String& dst_name_;
- const Kind kind_;
+#define FIELD_LIST(F) \
+ F(const TokenPosition, token_pos_) \
+ F(const String&, dst_name_) \
+ F(const Kind, kind_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(AssertAssignableInstr,
+ TemplateDefinition,
+ FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
DISALLOW_COPY_AND_ASSIGN(AssertAssignableInstr);
};
@@ -3920,9 +4173,14 @@
PRINT_OPERANDS_TO_SUPPORT
- private:
- const TokenPosition token_pos_;
+#define FIELD_LIST(F) F(const TokenPosition, token_pos_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(AssertBooleanInstr,
+ TemplateDefinition,
+ FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
DISALLOW_COPY_AND_ASSIGN(AssertBooleanInstr);
};
@@ -3974,9 +4232,16 @@
PRINT_OPERANDS_TO_SUPPORT
+#define FIELD_LIST(F) F(const SpecialParameterKind, kind_)
+
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(SpecialParameterInstr,
+ TemplateDefinition,
+ FIELD_LIST)
+#undef FIELD_LIST
+ DECLARE_EXTRA_SERIALIZATION
+
private:
- const SpecialParameterKind kind_;
- BlockEntryInstr* block_;
+ BlockEntryInstr* block_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(SpecialParameterInstr);
};
@@ -4083,11 +4348,19 @@
ArgumentsSizeWithoutTypeArgs(), argument_names());
}
+#define FIELD_LIST(F) \
+ F(const intptr_t, type_args_len_) \
+ F(const Array&, argument_names_) \
+ F(const TokenPosition, token_pos_)
+
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(TemplateDartCall,
+ VariadicDefinition,
+ FIELD_LIST)
+#undef FIELD_LIST
+ DECLARE_EXTRA_SERIALIZATION
+
private:
- intptr_t type_args_len_;
- const Array& argument_names_;
PushArgumentsArray* push_arguments_ = nullptr;
- TokenPosition token_pos_;
DISALLOW_COPY_AND_ASSIGN(TemplateDartCall);
};
@@ -4113,6 +4386,7 @@
virtual bool HasUnknownSideEffects() const { return true; }
PRINT_OPERANDS_TO_SUPPORT
+ DECLARE_EMPTY_SERIALIZATION(ClosureCallInstr, TemplateDartCall)
private:
DISALLOW_COPY_AND_ASSIGN(ClosureCallInstr);
@@ -4143,7 +4417,10 @@
interface_target_(interface_target),
tearoff_interface_target_(tearoff_interface_target),
result_type_(nullptr),
- has_unique_selector_(false) {
+ has_unique_selector_(false),
+ entry_kind_(Code::EntryKind::kNormal),
+ receiver_is_not_smi_(false),
+ is_call_on_this_(false) {
ASSERT(function_name.IsNotTemporaryScopedHandle());
ASSERT(interface_target.IsNotTemporaryScopedHandle());
ASSERT(tearoff_interface_target.IsNotTemporaryScopedHandle());
@@ -4238,23 +4515,31 @@
virtual Representation representation() const;
+#define FIELD_LIST(F) \
+ F(const ICData*, ic_data_) \
+ F(const String&, function_name_) \
+ /* Binary op, unary op, kGET or kILLEGAL. */ \
+ F(const Token::Kind, token_kind_) \
+ F(const Function&, interface_target_) \
+ F(const Function&, tearoff_interface_target_) \
+ /* Inferred result type. */ \
+ F(CompileType*, result_type_) \
+ F(bool, has_unique_selector_) \
+ F(Code::EntryKind, entry_kind_) \
+ F(bool, receiver_is_not_smi_) \
+ F(bool, is_call_on_this_)
+
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(InstanceCallBaseInstr,
+ TemplateDartCall,
+ FIELD_LIST)
+#undef FIELD_LIST
+
protected:
friend class CallSpecializer;
void set_ic_data(ICData* value) { ic_data_ = value; }
void set_result_type(CompileType* result_type) { result_type_ = result_type; }
private:
- const ICData* ic_data_;
- const String& function_name_;
- const Token::Kind token_kind_; // Binary op, unary op, kGET or kILLEGAL.
- const Function& interface_target_;
- const Function& tearoff_interface_target_;
- CompileType* result_type_; // Inferred result type.
- bool has_unique_selector_;
- Code::EntryKind entry_kind_ = Code::EntryKind::kNormal;
- bool receiver_is_not_smi_ = false;
- bool is_call_on_this_ = false;
-
DISALLOW_COPY_AND_ASSIGN(InstanceCallBaseInstr);
};
@@ -4283,7 +4568,8 @@
deopt_id,
interface_target,
tearoff_interface_target),
- checked_argument_count_(checked_argument_count) {}
+ checked_argument_count_(checked_argument_count),
+ receivers_static_type_(nullptr) {}
InstanceCallInstr(
const InstructionSource& source,
@@ -4306,7 +4592,8 @@
deopt_id,
interface_target,
tearoff_interface_target),
- checked_argument_count_(checked_argument_count) {}
+ checked_argument_count_(checked_argument_count),
+ receivers_static_type_(nullptr) {}
DECLARE_INSTRUCTION(InstanceCall)
@@ -4335,11 +4622,18 @@
const CallTargets& Targets();
void SetTargets(const CallTargets* targets) { targets_ = targets; }
+#define FIELD_LIST(F) \
+ F(const intptr_t, checked_argument_count_) \
+ F(const AbstractType*, receivers_static_type_)
+
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(InstanceCallInstr,
+ InstanceCallBaseInstr,
+ FIELD_LIST)
+#undef FIELD_LIST
+
private:
const CallTargets* targets_ = nullptr;
const class BinaryFeedback* binary_ = nullptr;
- const intptr_t checked_argument_count_;
- const AbstractType* receivers_static_type_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(InstanceCallInstr);
};
@@ -4402,6 +4696,16 @@
PRINT_OPERANDS_TO_SUPPORT
+#define FIELD_LIST(F) \
+ F(const CallTargets&, targets_) \
+ F(const bool, complete_) \
+ F(intptr_t, total_call_count_)
+
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(PolymorphicInstanceCallInstr,
+ InstanceCallBaseInstr,
+ FIELD_LIST)
+#undef FIELD_LIST
+
private:
PolymorphicInstanceCallInstr(const InstructionSource& source,
const String& function_name,
@@ -4431,10 +4735,6 @@
total_call_count_ = CallCount();
}
- const CallTargets& targets_;
- const bool complete_;
- intptr_t total_call_count_;
-
friend class PolymorphicInliner;
DISALLOW_COPY_AND_ASSIGN(PolymorphicInstanceCallInstr);
@@ -4510,10 +4810,16 @@
PRINT_OPERANDS_TO_SUPPORT
- private:
- const Function& interface_target_;
- const compiler::TableSelector* selector_;
+#define FIELD_LIST(F) \
+ F(const Function&, interface_target_) \
+ F(const compiler::TableSelector*, selector_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(DispatchTableCallInstr,
+ TemplateDartCall,
+ FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
DISALLOW_COPY_AND_ASSIGN(DispatchTableCallInstr);
};
@@ -4543,6 +4849,16 @@
PRINT_OPERANDS_TO_SUPPORT;
+#define FIELD_LIST(F) \
+ /* True if the comparison must check for double or Mint and */ \
+ /* use value comparison instead. */ \
+ F(bool, needs_number_check_)
+
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(StrictCompareInstr,
+ TemplateComparison,
+ FIELD_LIST)
+#undef FIELD_LIST
+
private:
Condition EmitComparisonCodeRegConstant(FlowGraphCompiler* compiler,
BranchLabels labels,
@@ -4554,10 +4870,6 @@
const Object& obj,
Condition* condition_out);
- // True if the comparison must check for double or Mint and
- // use value comparison instead.
- bool needs_number_check_;
-
DISALLOW_COPY_AND_ASSIGN(StrictCompareInstr);
};
@@ -4587,6 +4899,8 @@
return kTagged;
}
+ DECLARE_EMPTY_SERIALIZATION(TestSmiInstr, TemplateComparison)
+
private:
DISALLOW_COPY_AND_ASSIGN(TestSmiInstr);
};
@@ -4632,9 +4946,16 @@
PRINT_OPERANDS_TO_SUPPORT
+#define FIELD_LIST(F) \
+ F(const ZoneGrowableArray<intptr_t>&, cid_results_) \
+ F(bool, licm_hoisted_)
+
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(TestCidsInstr,
+ TemplateComparison,
+ FIELD_LIST)
+#undef FIELD_LIST
+
private:
- const ZoneGrowableArray<intptr_t>& cid_results_;
- bool licm_hoisted_;
DISALLOW_COPY_AND_ASSIGN(TestCidsInstr);
};
@@ -4690,9 +5011,16 @@
PRINT_OPERANDS_TO_SUPPORT
+#define FIELD_LIST(F) \
+ F(bool, null_aware_) \
+ F(const SpeculativeMode, speculative_mode_)
+
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(EqualityCompareInstr,
+ TemplateComparison,
+ FIELD_LIST)
+#undef FIELD_LIST
+
private:
- bool null_aware_;
- const SpeculativeMode speculative_mode_;
DISALLOW_COPY_AND_ASSIGN(EqualityCompareInstr);
};
@@ -4739,8 +5067,14 @@
PRINT_OPERANDS_TO_SUPPORT
+#define FIELD_LIST(F) F(const SpeculativeMode, speculative_mode_)
+
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(RelationalOpInstr,
+ TemplateComparison,
+ FIELD_LIST)
+#undef FIELD_LIST
+
private:
- const SpeculativeMode speculative_mode_;
DISALLOW_COPY_AND_ASSIGN(RelationalOpInstr);
};
@@ -4815,15 +5149,22 @@
PRINT_OPERANDS_TO_SUPPORT
+#define FIELD_LIST(F) \
+ F(ComparisonInstr*, comparison_) \
+ F(const intptr_t, if_true_) \
+ F(const intptr_t, if_false_)
+
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(IfThenElseInstr,
+ Definition,
+ FIELD_LIST)
+#undef FIELD_LIST
+ DECLARE_EXTRA_SERIALIZATION
+
private:
virtual void RawSetInputAt(intptr_t i, Value* value) {
comparison()->RawSetInputAt(i, value);
}
- ComparisonInstr* comparison_;
- const intptr_t if_true_;
- const intptr_t if_false_;
-
DISALLOW_COPY_AND_ASSIGN(IfThenElseInstr);
};
@@ -4848,6 +5189,7 @@
rebind_rule_(rebind_rule),
result_type_(NULL),
is_known_list_constructor_(false),
+ entry_kind_(Code::EntryKind::kNormal),
identity_(AliasIdentity::Unknown()) {
ASSERT(function.IsZoneHandle());
ASSERT(!function.IsNull());
@@ -4872,6 +5214,7 @@
rebind_rule_(rebind_rule),
result_type_(NULL),
is_known_list_constructor_(false),
+ entry_kind_(Code::EntryKind::kNormal),
identity_(AliasIdentity::Unknown()) {
ASSERT(function.IsZoneHandle());
ASSERT(!function.IsNull());
@@ -4990,21 +5333,26 @@
PRINT_OPERANDS_TO_SUPPORT
+#define FIELD_LIST(F) \
+ F(const ICData*, ic_data_) \
+ F(const intptr_t, call_count_) \
+ F(const Function&, function_) \
+ F(const ICData::RebindRule, rebind_rule_) \
+ /* Known or inferred result type. */ \
+ F(CompileType*, result_type_) \
+ /* 'True' for recognized list constructors. */ \
+ F(bool, is_known_list_constructor_) \
+ F(Code::EntryKind, entry_kind_) \
+ F(AliasIdentity, identity_)
+
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(StaticCallInstr,
+ TemplateDartCall,
+ FIELD_LIST)
+#undef FIELD_LIST
+
private:
- const ICData* ic_data_;
const CallTargets* targets_ = nullptr;
const class BinaryFeedback* binary_ = nullptr;
- const intptr_t call_count_;
- const Function& function_;
- const ICData::RebindRule rebind_rule_;
- CompileType* result_type_; // Known or inferred result type.
-
- // 'True' for recognized list constructors.
- bool is_known_list_constructor_;
-
- Code::EntryKind entry_kind_ = Code::EntryKind::kNormal;
-
- AliasIdentity identity_;
DISALLOW_COPY_AND_ASSIGN(StaticCallInstr);
};
@@ -5036,11 +5384,17 @@
PRINT_OPERANDS_TO_SUPPORT
- private:
- const LocalVariable& local_;
- bool is_last_;
- const TokenPosition token_pos_;
+#define FIELD_LIST(F) \
+ F(const LocalVariable&, local_) \
+ F(bool, is_last_) \
+ F(const TokenPosition, token_pos_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(LoadLocalInstr,
+ TemplateDefinition,
+ FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
DISALLOW_COPY_AND_ASSIGN(LoadLocalInstr);
};
@@ -5080,14 +5434,21 @@
PRINT_OPERANDS_TO_SUPPORT
+#define FIELD_LIST(F) \
+ F(const intptr_t, num_temps_) \
+ F(const bool, has_input_)
+
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(DropTempsInstr,
+ Definition,
+ FIELD_LIST)
+#undef FIELD_LIST
+
private:
virtual void RawSetInputAt(intptr_t i, Value* value) {
ASSERT(has_input_);
value_ = value;
}
- const intptr_t num_temps_;
- const bool has_input_;
Value* value_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(DropTempsInstr);
@@ -5129,9 +5490,15 @@
PRINT_OPERANDS_TO_SUPPORT
- private:
- ConstantInstr* null_;
+#define FIELD_LIST(F) F(ConstantInstr*, null_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(MakeTempInstr,
+ TemplateDefinition,
+ FIELD_LIST)
+#undef FIELD_LIST
+ DECLARE_EXTRA_SERIALIZATION
+
+ private:
DISALLOW_COPY_AND_ASSIGN(MakeTempInstr);
};
@@ -5171,12 +5538,18 @@
PRINT_OPERANDS_TO_SUPPORT
- private:
- const LocalVariable& local_;
- bool is_dead_;
- bool is_last_;
- const TokenPosition token_pos_;
+#define FIELD_LIST(F) \
+ F(const LocalVariable&, local_) \
+ F(bool, is_dead_) \
+ F(bool, is_last_) \
+ F(const TokenPosition, token_pos_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(StoreLocalInstr,
+ TemplateDefinition,
+ FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
DISALLOW_COPY_AND_ASSIGN(StoreLocalInstr);
};
@@ -5194,11 +5567,8 @@
source),
native_name_(name),
function_(function),
- native_c_function_(NULL),
- is_bootstrap_native_(false),
- is_auto_scope_(true),
- link_lazily_(link_lazily),
- token_pos_(source.token_pos) {
+ token_pos_(source.token_pos),
+ link_lazily_(link_lazily) {
ASSERT(name.IsZoneHandle());
ASSERT(function.IsZoneHandle());
}
@@ -5224,6 +5594,16 @@
PRINT_OPERANDS_TO_SUPPORT
+#define FIELD_LIST(F) \
+ F(const String&, native_name_) \
+ F(const Function&, function_) \
+ F(const TokenPosition, token_pos_)
+
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(NativeCallInstr,
+ TemplateDartCall,
+ FIELD_LIST)
+#undef FIELD_LIST
+
private:
void set_native_c_function(NativeFunction value) {
native_c_function_ = value;
@@ -5232,13 +5612,12 @@
void set_is_bootstrap_native(bool value) { is_bootstrap_native_ = value; }
void set_is_auto_scope(bool value) { is_auto_scope_ = value; }
- const String& native_name_;
- const Function& function_;
- NativeFunction native_c_function_;
- bool is_bootstrap_native_;
- bool is_auto_scope_;
- bool link_lazily_;
- const TokenPosition token_pos_;
+ // These fields are not serialized.
+ // IL serialization only supports lazy linking of native functions.
+ NativeFunction native_c_function_ = nullptr;
+ bool is_bootstrap_native_ = false;
+ bool is_auto_scope_ = true;
+ bool link_lazily_ = true;
DISALLOW_COPY_AND_ASSIGN(NativeCallInstr);
};
@@ -5303,6 +5682,15 @@
PRINT_OPERANDS_TO_SUPPORT
+#define FIELD_LIST(F) \
+ F(const compiler::ffi::CallMarshaller&, marshaller_) \
+ F(bool, is_leaf_)
+
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(FfiCallInstr,
+ VariadicDefinition,
+ FIELD_LIST)
+#undef FIELD_LIST
+
private:
LocationSummary* MakeLocationSummaryInternal(Zone* zone,
bool is_optimizing,
@@ -5320,9 +5708,6 @@
const Register temp0,
const Register temp1);
- const compiler::ffi::CallMarshaller& marshaller_;
- bool is_leaf_;
-
DISALLOW_COPY_AND_ASSIGN(FfiCallInstr);
};
@@ -5360,9 +5745,15 @@
PRINT_OPERANDS_TO_SUPPORT
- private:
- const compiler::ffi::NativeCallingConvention& native_calling_convention_;
+#define FIELD_LIST(F) \
+ F(const compiler::ffi::NativeCallingConvention&, native_calling_convention_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(CCallInstr,
+ VariadicDefinition,
+ FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
DISALLOW_COPY_AND_ASSIGN(CCallInstr);
};
@@ -5390,9 +5781,14 @@
virtual bool ComputeCanDeoptimize() const { return false; }
virtual bool HasUnknownSideEffects() const { return false; }
- private:
- const int32_t offset_;
+#define FIELD_LIST(F) F(const int32_t, offset_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(RawStoreFieldInstr,
+ TemplateInstruction,
+ FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
DISALLOW_COPY_AND_ASSIGN(RawStoreFieldInstr);
};
@@ -5412,10 +5808,16 @@
virtual bool HasUnknownSideEffects() const { return true; }
virtual Instruction* Canonicalize(FlowGraph* flow_graph);
- private:
- const TokenPosition token_pos_;
- const UntaggedPcDescriptors::Kind stub_kind_;
+#define FIELD_LIST(F) \
+ F(const TokenPosition, token_pos_) \
+ F(const UntaggedPcDescriptors::Kind, stub_kind_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(DebugStepCheckInstr,
+ TemplateInstruction,
+ FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
DISALLOW_COPY_AND_ASSIGN(DebugStepCheckInstr);
};
@@ -5566,6 +5968,19 @@
PRINT_OPERANDS_TO_SUPPORT
+#define FIELD_LIST(F) \
+ F(const Slot&, slot_) \
+ F(StoreBarrierType, emit_store_barrier_) \
+ F(compiler::Assembler::MemoryOrder, memory_order_) \
+ F(const TokenPosition, token_pos_) \
+ /* Marks initializing stores. E.g. in the constructor. */ \
+ F(const bool, is_initialization_)
+
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(StoreFieldInstr,
+ TemplateInstruction,
+ FIELD_LIST)
+#undef FIELD_LIST
+
private:
friend class JitCallSpecializer; // For ASSERT(initialization_).
@@ -5578,13 +5993,6 @@
: compiler::Assembler::kValueIsNotSmi;
}
- const Slot& slot_;
- StoreBarrierType emit_store_barrier_;
- compiler::Assembler::MemoryOrder memory_order_;
- const TokenPosition token_pos_;
- // Marks initializing stores. E.g. in the constructor.
- const bool is_initialization_;
-
DISALLOW_COPY_AND_ASSIGN(StoreFieldInstr);
};
@@ -5608,9 +6016,14 @@
PRINT_OPERANDS_TO_SUPPORT
- private:
- const Field& field_;
+#define FIELD_LIST(F) F(const Field&, field_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(GuardFieldInstr,
+ TemplateInstruction,
+ FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
DISALLOW_COPY_AND_ASSIGN(GuardFieldInstr);
};
@@ -5627,6 +6040,8 @@
virtual bool AttributesEqual(const Instruction& other) const;
+ DECLARE_EMPTY_SERIALIZATION(GuardFieldClassInstr, GuardFieldInstr)
+
private:
DISALLOW_COPY_AND_ASSIGN(GuardFieldClassInstr);
};
@@ -5644,6 +6059,8 @@
virtual bool AttributesEqual(const Instruction& other) const;
+ DECLARE_EMPTY_SERIALIZATION(GuardFieldLengthInstr, GuardFieldInstr)
+
private:
DISALLOW_COPY_AND_ASSIGN(GuardFieldLengthInstr);
};
@@ -5667,6 +6084,8 @@
virtual bool AttributesEqual(const Instruction& other) const;
+ DECLARE_EMPTY_SERIALIZATION(GuardFieldTypeInstr, GuardFieldInstr)
+
private:
DISALLOW_COPY_AND_ASSIGN(GuardFieldTypeInstr);
};
@@ -5725,11 +6144,15 @@
virtual bool CanTriggerGC() const { return calls_initializer(); }
virtual bool MayThrow() const { return calls_initializer(); }
- private:
- const TokenPosition token_pos_;
- const bool throw_exception_on_initialization_;
- bool calls_initializer_;
+#define FIELD_LIST(F) \
+ F(const TokenPosition, token_pos_) \
+ F(const bool, throw_exception_on_initialization_) \
+ F(bool, calls_initializer_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(TemplateLoadField, Base, FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
DISALLOW_COPY_AND_ASSIGN(TemplateLoadField);
};
@@ -5764,9 +6187,14 @@
PRINT_OPERANDS_TO_SUPPORT
- private:
- const Field& field_;
+#define FIELD_LIST(F) F(const Field&, field_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(LoadStaticFieldInstr,
+ TemplateLoadField,
+ FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
DISALLOW_COPY_AND_ASSIGN(LoadStaticFieldInstr);
};
@@ -5801,6 +6229,15 @@
PRINT_OPERANDS_TO_SUPPORT
+#define FIELD_LIST(F) \
+ F(const Field&, field_) \
+ F(const TokenPosition, token_pos_)
+
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(StoreStaticFieldInstr,
+ TemplateDefinition,
+ FIELD_LIST)
+#undef FIELD_LIST
+
private:
compiler::Assembler::CanBeSmi CanValueBeSmi() const {
ASSERT(value()->Type()->ToNullableCid() != kSmiCid);
@@ -5808,9 +6245,6 @@
: compiler::Assembler::kValueIsNotSmi;
}
- const Field& field_;
- const TokenPosition token_pos_;
-
DISALLOW_COPY_AND_ASSIGN(StoreStaticFieldInstr);
};
@@ -5881,14 +6315,21 @@
virtual Definition* Canonicalize(FlowGraph* flow_graph);
- private:
- const bool index_unboxed_;
- const intptr_t index_scale_;
- const intptr_t class_id_;
- const AlignmentType alignment_;
- const TokenPosition token_pos_;
- CompileType* result_type_; // derived from call
+#define FIELD_LIST(F) \
+ F(const bool, index_unboxed_) \
+ F(const intptr_t, index_scale_) \
+ F(const intptr_t, class_id_) \
+ F(const AlignmentType, alignment_) \
+ F(const TokenPosition, token_pos_) \
+ /* derived from call */ \
+ F(CompileType*, result_type_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(LoadIndexedInstr,
+ TemplateDefinition,
+ FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
DISALLOW_COPY_AND_ASSIGN(LoadIndexedInstr);
};
@@ -5962,12 +6403,18 @@
return !can_pack_into_smi() && (representation() == kTagged);
}
- private:
- const intptr_t class_id_;
- const TokenPosition token_pos_;
- const intptr_t element_count_;
- Representation representation_;
+#define FIELD_LIST(F) \
+ F(const intptr_t, class_id_) \
+ F(const TokenPosition, token_pos_) \
+ F(const intptr_t, element_count_) \
+ F(Representation, representation_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(LoadCodeUnitsInstr,
+ TemplateDefinition,
+ FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
DISALLOW_COPY_AND_ASSIGN(LoadCodeUnitsInstr);
};
@@ -5987,6 +6434,9 @@
virtual bool AttributesEqual(const Instruction& other) const { return true; }
+ DECLARE_EMPTY_SERIALIZATION(OneByteStringFromCharCodeInstr,
+ TemplateDefinition)
+
private:
DISALLOW_COPY_AND_ASSIGN(OneByteStringFromCharCodeInstr);
};
@@ -6009,9 +6459,14 @@
return other.AsStringToCharCode()->cid_ == cid_;
}
- private:
- const intptr_t cid_;
+#define FIELD_LIST(F) F(const intptr_t, cid_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(StringToCharCodeInstr,
+ TemplateDefinition,
+ FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
DISALLOW_COPY_AND_ASSIGN(StringToCharCodeInstr);
};
@@ -6083,9 +6538,14 @@
PRINT_TO_SUPPORT
- private:
- const Slot& scan_flags_field_;
+#define FIELD_LIST(F) F(const Slot&, scan_flags_field_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(Utf8ScanInstr,
+ TemplateDefinition,
+ FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
DISALLOW_COPY_AND_ASSIGN(Utf8ScanInstr);
};
@@ -6159,19 +6619,25 @@
virtual Instruction* Canonicalize(FlowGraph* flow_graph);
+#define FIELD_LIST(F) \
+ F(StoreBarrierType, emit_store_barrier_) \
+ F(const bool, index_unboxed_) \
+ F(const intptr_t, index_scale_) \
+ F(const intptr_t, class_id_) \
+ F(const AlignmentType, alignment_) \
+ F(const TokenPosition, token_pos_) \
+ F(const SpeculativeMode, speculative_mode_)
+
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(StoreIndexedInstr,
+ TemplateInstruction,
+ FIELD_LIST)
+#undef FIELD_LIST
+
private:
compiler::Assembler::CanBeSmi CanValueBeSmi() const {
return compiler::Assembler::kValueCanBeSmi;
}
- StoreBarrierType emit_store_barrier_;
- const bool index_unboxed_;
- const intptr_t index_scale_;
- const intptr_t class_id_;
- const AlignmentType alignment_;
- const TokenPosition token_pos_;
- const SpeculativeMode speculative_mode_;
-
DISALLOW_COPY_AND_ASSIGN(StoreIndexedInstr);
};
@@ -6192,11 +6658,17 @@
virtual bool HasUnknownSideEffects() const { return false; }
virtual Instruction* Canonicalize(FlowGraph* flow_graph);
- private:
- const Array& coverage_array_;
- const intptr_t coverage_index_;
- const TokenPosition token_pos_;
+#define FIELD_LIST(F) \
+ F(const Array&, coverage_array_) \
+ F(const intptr_t, coverage_index_) \
+ F(const TokenPosition, token_pos_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(RecordCoverageInstr,
+ TemplateInstruction,
+ FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
DISALLOW_COPY_AND_ASSIGN(RecordCoverageInstr);
};
@@ -6216,6 +6688,8 @@
virtual Definition* Canonicalize(FlowGraph* flow_graph);
+ DECLARE_EMPTY_SERIALIZATION(BooleanNegateInstr, TemplateDefinition)
+
private:
DISALLOW_COPY_AND_ASSIGN(BooleanNegateInstr);
};
@@ -6255,12 +6729,16 @@
PRINT_OPERANDS_TO_SUPPORT
- private:
- const TokenPosition token_pos_;
- Value* value_;
- Value* type_arguments_;
- const AbstractType& type_;
+#define FIELD_LIST(F) \
+ F(const TokenPosition, token_pos_) \
+ F(const AbstractType&, type_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(InstanceOfInstr,
+ TemplateDefinition,
+ FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
DISALLOW_COPY_AND_ASSIGN(InstanceOfInstr);
};
@@ -6324,10 +6802,16 @@
DECLARE_ABSTRACT_INSTRUCTION(Allocation);
- private:
- const TokenPosition token_pos_;
- AliasIdentity identity_;
+#define FIELD_LIST(F) \
+ F(const TokenPosition, token_pos_) \
+ F(AliasIdentity, identity_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(AllocationInstr,
+ Definition,
+ FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
DISALLOW_COPY_AND_ASSIGN(AllocationInstr);
};
@@ -6341,6 +6825,8 @@
virtual intptr_t InputCount() const { return N; }
virtual Value* InputAt(intptr_t i) const { return inputs_[i]; }
+ DECLARE_EMPTY_SERIALIZATION(TemplateAllocation, AllocationInstr)
+
protected:
EmbeddedArray<Value*, N> inputs_;
@@ -6362,6 +6848,7 @@
: AllocationInstr(source, deopt_id),
cls_(cls),
has_type_arguments_(type_arguments != nullptr),
+ type_arguments_slot_(nullptr),
type_arguments_(type_arguments) {
ASSERT(cls.IsZoneHandle());
ASSERT(!cls.IsNull());
@@ -6401,16 +6888,23 @@
PRINT_OPERANDS_TO_SUPPORT
+#define FIELD_LIST(F) \
+ F(const Class&, cls_) \
+ F(const bool, has_type_arguments_) \
+ F(const Slot*, type_arguments_slot_)
+
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(AllocateObjectInstr,
+ AllocationInstr,
+ FIELD_LIST)
+#undef FIELD_LIST
+
private:
virtual void RawSetInputAt(intptr_t i, Value* value) {
ASSERT(has_type_arguments_ && (i == kTypeArgumentsPos));
type_arguments_ = value;
}
- const Class& cls_;
- const bool has_type_arguments_;
- Value* type_arguments_;
- const Slot* type_arguments_slot_ = nullptr;
+ Value* type_arguments_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(AllocateObjectInstr);
};
@@ -6462,6 +6956,8 @@
compiler::target::Closure::InstanceSize());
}
+ DECLARE_EMPTY_SERIALIZATION(AllocateClosureInstr, TemplateAllocation)
+
private:
DISALLOW_COPY_AND_ASSIGN(AllocateClosureInstr);
};
@@ -6488,9 +6984,14 @@
PRINT_OPERANDS_TO_SUPPORT
- private:
- const intptr_t num_context_variables_;
+#define FIELD_LIST(F) F(const intptr_t, num_context_variables_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(AllocateUninitializedContextInstr,
+ TemplateAllocation,
+ FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
DISALLOW_COPY_AND_ASSIGN(AllocateUninitializedContextInstr);
};
@@ -6505,13 +7006,11 @@
const ZoneGrowableArray<const Slot*>& slots,
InputsArray&& values)
: VariadicDefinition(std::move(values)),
- allocation_(allocation),
cls_(cls),
num_elements_(num_elements),
slots_(slots),
- locations_(nullptr),
- visited_for_liveness_(false),
- registers_remapped_(false) {
+ registers_remapped_(false),
+ allocation_(allocation) {
ASSERT(slots_.length() == InputCount());
}
@@ -6524,7 +7023,10 @@
return slots_[i]->offset_in_bytes();
}
- const Location& LocationAt(intptr_t i) { return locations_[i]; }
+ const Location& LocationAt(intptr_t i) {
+ ASSERT(0 <= i && i < InputCount());
+ return locations_[i];
+ }
DECLARE_INSTRUCTION(MaterializeObject)
@@ -6553,15 +7055,24 @@
PRINT_OPERANDS_TO_SUPPORT
- private:
- AllocationInstr* allocation_;
- const Class& cls_;
- intptr_t num_elements_;
- const ZoneGrowableArray<const Slot*>& slots_;
- Location* locations_;
+#define FIELD_LIST(F) \
+ F(const Class&, cls_) \
+ F(intptr_t, num_elements_) \
+ F(const ZoneGrowableArray<const Slot*>&, slots_) \
+ F(bool, registers_remapped_)
- bool visited_for_liveness_;
- bool registers_remapped_;
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(MaterializeObjectInstr,
+ VariadicDefinition,
+ FIELD_LIST)
+#undef FIELD_LIST
+ DECLARE_EXTRA_SERIALIZATION
+
+ private:
+ Location* locations_ = nullptr;
+
+ // Not serialized.
+ AllocationInstr* allocation_ = nullptr;
+ bool visited_for_liveness_ = false;
DISALLOW_COPY_AND_ASSIGN(MaterializeObjectInstr);
};
@@ -6583,6 +7094,8 @@
DECLARE_ABSTRACT_INSTRUCTION(ArrayAllocation);
+ DECLARE_EMPTY_SERIALIZATION(ArrayAllocationInstr, AllocationInstr)
+
private:
DISALLOW_COPY_AND_ASSIGN(ArrayAllocationInstr);
};
@@ -6597,11 +7110,15 @@
virtual intptr_t InputCount() const { return N; }
virtual Value* InputAt(intptr_t i) const { return inputs_[i]; }
+ DECLARE_EMPTY_SERIALIZATION(TemplateArrayAllocation, ArrayAllocationInstr)
+
protected:
EmbeddedArray<Value*, N> inputs_;
private:
virtual void RawSetInputAt(intptr_t i, Value* value) { inputs_[i] = value; }
+
+ DISALLOW_COPY_AND_ASSIGN(TemplateArrayAllocation);
};
class CreateArrayInstr : public TemplateArrayAllocation<2> {
@@ -6643,6 +7160,8 @@
}
}
+ DECLARE_EMPTY_SERIALIZATION(CreateArrayInstr, TemplateArrayAllocation)
+
private:
DISALLOW_COPY_AND_ASSIGN(CreateArrayInstr);
};
@@ -6681,9 +7200,14 @@
}
}
- private:
- const classid_t class_id_;
+#define FIELD_LIST(F) F(const classid_t, class_id_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(AllocateTypedDataInstr,
+ TemplateArrayAllocation,
+ FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
DISALLOW_COPY_AND_ASSIGN(AllocateTypedDataInstr);
};
@@ -6720,9 +7244,14 @@
PRINT_OPERANDS_TO_SUPPORT
- private:
- intptr_t offset_;
+#define FIELD_LIST(F) F(const intptr_t, offset_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(LoadUntaggedInstr,
+ TemplateDefinition,
+ FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
DISALLOW_COPY_AND_ASSIGN(LoadUntaggedInstr);
};
@@ -6754,10 +7283,16 @@
PRINT_OPERANDS_TO_SUPPORT
- private:
- const Representation representation_;
- const bool input_can_be_smi_;
+#define FIELD_LIST(F) \
+ F(const Representation, representation_) \
+ F(const bool, input_can_be_smi_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(LoadClassIdInstr,
+ TemplateDefinition,
+ FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
DISALLOW_COPY_AND_ASSIGN(LoadClassIdInstr);
};
@@ -6837,6 +7372,13 @@
PRINT_OPERANDS_TO_SUPPORT
+#define FIELD_LIST(F) F(const Slot&, slot_)
+
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(LoadFieldInstr,
+ TemplateLoadField,
+ FIELD_LIST)
+#undef FIELD_LIST
+
private:
intptr_t OffsetInBytes() const { return slot().offset_in_bytes(); }
@@ -6844,8 +7386,6 @@
// calls initializer if it is not. Field value is already loaded.
void EmitNativeCodeForInitializerCall(FlowGraphCompiler* compiler);
- const Slot& slot_;
-
DISALLOW_COPY_AND_ASSIGN(LoadFieldInstr);
};
@@ -6883,10 +7423,16 @@
PRINT_OPERANDS_TO_SUPPORT
- private:
- const TokenPosition token_pos_;
- const AbstractType& type_;
+#define FIELD_LIST(F) \
+ F(const TokenPosition, token_pos_) \
+ F(const AbstractType&, type_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(InstantiateTypeInstr,
+ TemplateDefinition,
+ FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
DISALLOW_COPY_AND_ASSIGN(InstantiateTypeInstr);
};
@@ -6969,11 +7515,17 @@
PRINT_OPERANDS_TO_SUPPORT
- private:
- const TokenPosition token_pos_;
- const Class& instantiator_class_;
- const Function& function_;
+#define FIELD_LIST(F) \
+ F(const TokenPosition, token_pos_) \
+ F(const Class&, instantiator_class_) \
+ F(const Function&, function_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(InstantiateTypeArgumentsInstr,
+ TemplateDefinition,
+ FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
DISALLOW_COPY_AND_ASSIGN(InstantiateTypeArgumentsInstr);
};
@@ -7006,9 +7558,14 @@
PRINT_OPERANDS_TO_SUPPORT
- private:
- const ZoneGrowableArray<const Slot*>& context_slots_;
+#define FIELD_LIST(F) F(const ZoneGrowableArray<const Slot*>&, context_slots_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(AllocateContextInstr,
+ TemplateAllocation,
+ FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
DISALLOW_COPY_AND_ASSIGN(AllocateContextInstr);
};
@@ -7049,10 +7606,16 @@
virtual bool HasUnknownSideEffects() const { return false; }
- private:
- const TokenPosition token_pos_;
- const ZoneGrowableArray<const Slot*>& context_slots_;
+#define FIELD_LIST(F) \
+ F(const TokenPosition, token_pos_) \
+ F(const ZoneGrowableArray<const Slot*>&, context_slots_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(CloneContextInstr,
+ TemplateDefinition,
+ FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
DISALLOW_COPY_AND_ASSIGN(CloneContextInstr);
};
@@ -7077,9 +7640,14 @@
void set_licm_hoisted(bool value) { licm_hoisted_ = value; }
- private:
- bool licm_hoisted_;
+#define FIELD_LIST(F) F(bool, licm_hoisted_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(CheckEitherNonSmiInstr,
+ TemplateInstruction,
+ FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
DISALLOW_COPY_AND_ASSIGN(CheckEitherNonSmiInstr);
};
@@ -7130,6 +7698,13 @@
return kNotSpeculative;
}
+#define FIELD_LIST(F) F(const Representation, from_representation_)
+
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(BoxInstr,
+ TemplateDefinition,
+ FIELD_LIST)
+#undef FIELD_LIST
+
protected:
BoxInstr(Representation from_representation, Value* value)
: from_representation_(from_representation) {
@@ -7141,8 +7716,6 @@
return Boxing::ValueOffset(from_representation());
}
- const Representation from_representation_;
-
DISALLOW_COPY_AND_ASSIGN(BoxInstr);
};
@@ -7164,6 +7737,8 @@
DECLARE_ABSTRACT_INSTRUCTION(BoxInteger)
+ DECLARE_EMPTY_SERIALIZATION(BoxIntegerInstr, BoxInstr)
+
private:
DISALLOW_COPY_AND_ASSIGN(BoxIntegerInstr);
};
@@ -7180,6 +7755,8 @@
DECLARE_INSTRUCTION(BoxSmallInt)
+ DECLARE_EMPTY_SERIALIZATION(BoxSmallIntInstr, BoxIntegerInstr)
+
private:
DISALLOW_COPY_AND_ASSIGN(BoxSmallIntInstr);
};
@@ -7191,6 +7768,8 @@
DECLARE_INSTRUCTION_BACKEND()
+ DECLARE_EMPTY_SERIALIZATION(BoxInteger32Instr, BoxIntegerInstr)
+
private:
DISALLOW_COPY_AND_ASSIGN(BoxInteger32Instr);
};
@@ -7202,6 +7781,8 @@
DECLARE_INSTRUCTION_NO_BACKEND(BoxInt32)
+ DECLARE_EMPTY_SERIALIZATION(BoxInt32Instr, BoxInteger32Instr)
+
private:
DISALLOW_COPY_AND_ASSIGN(BoxInt32Instr);
};
@@ -7213,6 +7794,8 @@
DECLARE_INSTRUCTION_NO_BACKEND(BoxUint32)
+ DECLARE_EMPTY_SERIALIZATION(BoxUint32Instr, BoxInteger32Instr)
+
private:
DISALLOW_COPY_AND_ASSIGN(BoxUint32Instr);
};
@@ -7226,6 +7809,8 @@
DECLARE_INSTRUCTION(BoxInt64)
+ DECLARE_EMPTY_SERIALIZATION(BoxInt64Instr, BoxIntegerInstr)
+
private:
DISALLOW_COPY_AND_ASSIGN(BoxInt64Instr);
};
@@ -7279,6 +7864,15 @@
virtual TokenPosition token_pos() const { return TokenPosition::kBox; }
+#define FIELD_LIST(F) \
+ F(const Representation, representation_) \
+ F(SpeculativeMode, speculative_mode_)
+
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(UnboxInstr,
+ TemplateDefinition,
+ FIELD_LIST)
+#undef FIELD_LIST
+
protected:
UnboxInstr(Representation representation,
Value* value,
@@ -7290,6 +7884,10 @@
SetInputAt(0, value);
}
+ void set_speculative_mode(SpeculativeMode value) {
+ speculative_mode_ = value;
+ }
+
private:
bool CanConvertSmi() const;
void EmitLoadFromBox(FlowGraphCompiler* compiler);
@@ -7302,10 +7900,6 @@
intptr_t ValueOffset() const { return Boxing::ValueOffset(representation_); }
- protected:
- const Representation representation_;
- SpeculativeMode speculative_mode_;
-
DISALLOW_COPY_AND_ASSIGN(UnboxInstr);
};
@@ -7339,9 +7933,14 @@
PRINT_OPERANDS_TO_SUPPORT
- private:
- bool is_truncating_;
+#define FIELD_LIST(F) F(bool, is_truncating_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(UnboxIntegerInstr,
+ UnboxInstr,
+ FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
DISALLOW_COPY_AND_ASSIGN(UnboxIntegerInstr);
};
@@ -7360,6 +7959,8 @@
DECLARE_INSTRUCTION_BACKEND()
+ DECLARE_EMPTY_SERIALIZATION(UnboxInteger32Instr, UnboxIntegerInstr)
+
private:
DISALLOW_COPY_AND_ASSIGN(UnboxInteger32Instr);
};
@@ -7383,6 +7984,8 @@
DECLARE_INSTRUCTION_NO_BACKEND(UnboxUint32)
+ DECLARE_EMPTY_SERIALIZATION(UnboxUint32Instr, UnboxInteger32Instr)
+
private:
DISALLOW_COPY_AND_ASSIGN(UnboxUint32Instr);
};
@@ -7407,6 +8010,8 @@
DECLARE_INSTRUCTION_NO_BACKEND(UnboxInt32)
+ DECLARE_EMPTY_SERIALIZATION(UnboxInt32Instr, UnboxInteger32Instr)
+
private:
DISALLOW_COPY_AND_ASSIGN(UnboxInt32Instr);
};
@@ -7436,6 +8041,8 @@
DECLARE_INSTRUCTION_NO_BACKEND(UnboxInt64)
+ DECLARE_EMPTY_SERIALIZATION(UnboxInt64Instr, UnboxIntegerInstr)
+
private:
DISALLOW_COPY_AND_ASSIGN(UnboxInt64Instr);
};
@@ -7494,16 +8101,21 @@
PRINT_OPERANDS_TO_SUPPORT
- private:
- const MathUnaryKind kind_;
+#define FIELD_LIST(F) F(const MathUnaryKind, kind_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(MathUnaryInstr,
+ TemplateDefinition,
+ FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
DISALLOW_COPY_AND_ASSIGN(MathUnaryInstr);
};
// Calls into the runtime and performs a case-insensitive comparison of the
// UTF16 strings (i.e. TwoByteString or ExternalTwoByteString) located at
// str[lhs_index:lhs_index + length] and str[rhs_index:rhs_index + length].
-// Depending on the runtime entry passed, we will treat the strings as either
+// Depending on [handle_surrogates], we will treat the strings as either
// UCS2 (no surrogate handling) or UTF16 (surrogates handled appropriately).
class CaseInsensitiveCompareInstr
: public TemplateDefinition<4, NoThrow, Pure> {
@@ -7512,9 +8124,9 @@
Value* lhs_index,
Value* rhs_index,
Value* length,
- const RuntimeEntry& entry,
+ bool handle_surrogates,
intptr_t cid)
- : entry_(entry), cid_(cid) {
+ : handle_surrogates_(handle_surrogates), cid_(cid) {
ASSERT(cid == kTwoByteStringCid || cid == kExternalTwoByteStringCid);
ASSERT(index_scale() == 2);
SetInputAt(0, str);
@@ -7528,7 +8140,7 @@
Value* rhs_index() const { return inputs_[2]; }
Value* length() const { return inputs_[3]; }
- const RuntimeEntry& TargetFunction() const { return entry_; }
+ const RuntimeEntry& TargetFunction() const;
bool IsExternal() const { return cid_ == kExternalTwoByteStringCid; }
intptr_t class_id() const { return cid_; }
@@ -7544,13 +8156,21 @@
virtual CompileType ComputeType() const;
virtual bool AttributesEqual(const Instruction& other) const {
- return other.AsCaseInsensitiveCompare()->cid_ == cid_;
+ const auto* other_compare = other.AsCaseInsensitiveCompare();
+ return (other_compare->handle_surrogates_ == handle_surrogates_) &&
+ (other_compare->cid_ == cid_);
}
- private:
- const RuntimeEntry& entry_;
- const intptr_t cid_;
+#define FIELD_LIST(F) \
+ F(const bool, handle_surrogates_) \
+ F(const intptr_t, cid_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(CaseInsensitiveCompareInstr,
+ TemplateDefinition,
+ FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
DISALLOW_COPY_AND_ASSIGN(CaseInsensitiveCompareInstr);
};
@@ -7605,10 +8225,16 @@
virtual CompileType ComputeType() const;
virtual bool AttributesEqual(const Instruction& other) const;
- private:
- const MethodRecognizer::Kind op_kind_;
- const intptr_t result_cid_;
+#define FIELD_LIST(F) \
+ F(const MethodRecognizer::Kind, op_kind_) \
+ F(const intptr_t, result_cid_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(MathMinMaxInstr,
+ TemplateDefinition,
+ FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
DISALLOW_COPY_AND_ASSIGN(MathMinMaxInstr);
};
@@ -7667,11 +8293,17 @@
(speculative_mode_ == other_bin_op->speculative_mode_);
}
- private:
- const Token::Kind op_kind_;
- const TokenPosition token_pos_;
- const SpeculativeMode speculative_mode_;
+#define FIELD_LIST(F) \
+ F(const Token::Kind, op_kind_) \
+ F(const TokenPosition, token_pos_) \
+ F(const SpeculativeMode, speculative_mode_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(BinaryDoubleOpInstr,
+ TemplateDefinition,
+ FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
DISALLOW_COPY_AND_ASSIGN(BinaryDoubleOpInstr);
};
@@ -7711,9 +8343,14 @@
virtual ComparisonInstr* CopyWithNewOperands(Value* left, Value* right);
- private:
- const MethodRecognizer::Kind op_kind_;
+#define FIELD_LIST(F) F(const MethodRecognizer::Kind, op_kind_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(DoubleTestOpInstr,
+ TemplateComparison,
+ FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
DISALLOW_COPY_AND_ASSIGN(DoubleTestOpInstr);
};
@@ -7748,8 +8385,15 @@
DECLARE_ABSTRACT_INSTRUCTION(UnaryIntegerOp)
+#define FIELD_LIST(F) F(const Token::Kind, op_kind_)
+
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(UnaryIntegerOpInstr,
+ TemplateDefinition,
+ FIELD_LIST)
+#undef FIELD_LIST
+
private:
- const Token::Kind op_kind_;
+ DISALLOW_COPY_AND_ASSIGN(UnaryIntegerOpInstr);
};
// Handles both Smi operations: BIT_OR and NEGATE.
@@ -7766,6 +8410,8 @@
DECLARE_INSTRUCTION(UnarySmiOp)
+ DECLARE_EMPTY_SERIALIZATION(UnarySmiOpInstr, UnaryIntegerOpInstr)
+
private:
DISALLOW_COPY_AND_ASSIGN(UnarySmiOpInstr);
};
@@ -7794,6 +8440,8 @@
DECLARE_INSTRUCTION(UnaryUint32Op)
+ DECLARE_EMPTY_SERIALIZATION(UnaryUint32OpInstr, UnaryIntegerOpInstr)
+
private:
DISALLOW_COPY_AND_ASSIGN(UnaryUint32OpInstr);
};
@@ -7832,8 +8480,14 @@
DECLARE_INSTRUCTION(UnaryInt64Op)
+#define FIELD_LIST(F) F(const SpeculativeMode, speculative_mode_)
+
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(UnaryInt64OpInstr,
+ UnaryIntegerOpInstr,
+ FIELD_LIST)
+#undef FIELD_LIST
+
private:
- const SpeculativeMode speculative_mode_;
DISALLOW_COPY_AND_ASSIGN(UnaryInt64OpInstr);
};
@@ -7902,6 +8556,16 @@
DECLARE_ABSTRACT_INSTRUCTION(BinaryIntegerOp)
+#define FIELD_LIST(F) \
+ F(const Token::Kind, op_kind_) \
+ F(bool, can_overflow_) \
+ F(bool, is_truncating_)
+
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(BinaryIntegerOpInstr,
+ TemplateDefinition,
+ FIELD_LIST)
+#undef FIELD_LIST
+
protected:
void InferRangeHelper(const Range* left_range,
const Range* right_range,
@@ -7910,11 +8574,6 @@
private:
Definition* CreateConstantResult(FlowGraph* graph, const Integer& result);
- const Token::Kind op_kind_;
-
- bool can_overflow_;
- bool is_truncating_;
-
DISALLOW_COPY_AND_ASSIGN(BinaryIntegerOpInstr);
};
@@ -7938,9 +8597,14 @@
Range* right_range() const { return right_range_; }
- private:
- Range* right_range_;
+#define FIELD_LIST(F) F(Range*, right_range_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(BinarySmiOpInstr,
+ BinaryIntegerOpInstr,
+ FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
DISALLOW_COPY_AND_ASSIGN(BinarySmiOpInstr);
};
@@ -7996,6 +8660,8 @@
DECLARE_INSTRUCTION(BinaryInt32Op)
+ DECLARE_EMPTY_SERIALIZATION(BinaryInt32OpInstr, BinaryIntegerOpInstr)
+
private:
DISALLOW_COPY_AND_ASSIGN(BinaryInt32OpInstr);
};
@@ -8038,6 +8704,8 @@
DECLARE_INSTRUCTION(BinaryUint32Op)
+ DECLARE_EMPTY_SERIALIZATION(BinaryUint32OpInstr, BinaryIntegerOpInstr)
+
private:
DISALLOW_COPY_AND_ASSIGN(BinaryUint32OpInstr);
};
@@ -8083,8 +8751,14 @@
DECLARE_INSTRUCTION(BinaryInt64Op)
+#define FIELD_LIST(F) F(const SpeculativeMode, speculative_mode_)
+
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(BinaryInt64OpInstr,
+ BinaryIntegerOpInstr,
+ FIELD_LIST)
+#undef FIELD_LIST
+
private:
- const SpeculativeMode speculative_mode_;
DISALLOW_COPY_AND_ASSIGN(BinaryInt64OpInstr);
};
@@ -8113,6 +8787,13 @@
DECLARE_ABSTRACT_INSTRUCTION(ShiftIntegerOp)
+#define FIELD_LIST(F) F(Range*, shift_range_)
+
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(ShiftIntegerOpInstr,
+ BinaryIntegerOpInstr,
+ FIELD_LIST)
+#undef FIELD_LIST
+
protected:
static const intptr_t kShiftCountLimit = 63;
@@ -8121,8 +8802,6 @@
bool IsShiftCountInRange(int64_t max = kShiftCountLimit) const;
private:
- Range* shift_range_;
-
DISALLOW_COPY_AND_ASSIGN(ShiftIntegerOpInstr);
};
@@ -8154,6 +8833,8 @@
DECLARE_INSTRUCTION(ShiftInt64Op)
+ DECLARE_EMPTY_SERIALIZATION(ShiftInt64OpInstr, ShiftIntegerOpInstr)
+
private:
DISALLOW_COPY_AND_ASSIGN(ShiftInt64OpInstr);
};
@@ -8185,6 +8866,8 @@
DECLARE_INSTRUCTION(SpeculativeShiftInt64Op)
+ DECLARE_EMPTY_SERIALIZATION(SpeculativeShiftInt64OpInstr, ShiftIntegerOpInstr)
+
private:
DISALLOW_COPY_AND_ASSIGN(SpeculativeShiftInt64OpInstr);
};
@@ -8217,6 +8900,8 @@
DECLARE_INSTRUCTION(ShiftUint32Op)
+ DECLARE_EMPTY_SERIALIZATION(ShiftUint32OpInstr, ShiftIntegerOpInstr)
+
private:
static const intptr_t kUint32ShiftCountLimit = 31;
@@ -8247,6 +8932,9 @@
virtual CompileType ComputeType() const;
+ DECLARE_EMPTY_SERIALIZATION(SpeculativeShiftUint32OpInstr,
+ ShiftIntegerOpInstr)
+
private:
static const intptr_t kUint32ShiftCountLimit = 31;
@@ -8298,10 +8986,16 @@
PRINT_OPERANDS_TO_SUPPORT
- private:
- const Token::Kind op_kind_;
- const SpeculativeMode speculative_mode_;
+#define FIELD_LIST(F) \
+ F(const Token::Kind, op_kind_) \
+ F(const SpeculativeMode, speculative_mode_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(UnaryDoubleOpInstr,
+ TemplateDefinition,
+ FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
DISALLOW_COPY_AND_ASSIGN(UnaryDoubleOpInstr);
};
@@ -8352,12 +9046,18 @@
PRINT_OPERANDS_TO_SUPPORT
- private:
- const TokenPosition token_pos_;
- const intptr_t stack_depth_;
- const intptr_t loop_depth_;
- const Kind kind_;
+#define FIELD_LIST(F) \
+ F(const TokenPosition, token_pos_) \
+ F(const intptr_t, stack_depth_) \
+ F(const intptr_t, loop_depth_) \
+ F(const Kind, kind_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(CheckStackOverflowInstr,
+ TemplateInstruction,
+ FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
DISALLOW_COPY_AND_ASSIGN(CheckStackOverflowInstr);
};
@@ -8381,9 +9081,14 @@
virtual bool AttributesEqual(const Instruction& other) const { return true; }
- private:
- const TokenPosition token_pos_;
+#define FIELD_LIST(F) F(const TokenPosition, token_pos_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(SmiToDoubleInstr,
+ TemplateDefinition,
+ FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
DISALLOW_COPY_AND_ASSIGN(SmiToDoubleInstr);
};
@@ -8407,6 +9112,8 @@
virtual bool AttributesEqual(const Instruction& other) const { return true; }
+ DECLARE_EMPTY_SERIALIZATION(Int32ToDoubleInstr, TemplateDefinition)
+
private:
DISALLOW_COPY_AND_ASSIGN(Int32ToDoubleInstr);
};
@@ -8448,9 +9155,14 @@
return speculative_mode_ == other.AsInt64ToDouble()->speculative_mode_;
}
- private:
- const SpeculativeMode speculative_mode_;
+#define FIELD_LIST(F) F(const SpeculativeMode, speculative_mode_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(Int64ToDoubleInstr,
+ TemplateDefinition,
+ FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
DISALLOW_COPY_AND_ASSIGN(Int64ToDoubleInstr);
};
@@ -8495,9 +9207,14 @@
return other.AsDoubleToInteger()->recognized_kind() == recognized_kind();
}
- private:
- const MethodRecognizer::Kind recognized_kind_;
+#define FIELD_LIST(F) F(const MethodRecognizer::Kind, recognized_kind_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(DoubleToIntegerInstr,
+ TemplateDefinition,
+ FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
DISALLOW_COPY_AND_ASSIGN(DoubleToIntegerInstr);
};
@@ -8526,6 +9243,8 @@
virtual bool AttributesEqual(const Instruction& other) const { return true; }
+ DECLARE_EMPTY_SERIALIZATION(DoubleToSmiInstr, TemplateDefinition)
+
private:
DISALLOW_COPY_AND_ASSIGN(DoubleToSmiInstr);
};
@@ -8569,9 +9288,14 @@
return other.AsDoubleToDouble()->recognized_kind() == recognized_kind();
}
- private:
- const MethodRecognizer::Kind recognized_kind_;
+#define FIELD_LIST(F) F(const MethodRecognizer::Kind, recognized_kind_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(DoubleToDoubleInstr,
+ TemplateDefinition,
+ FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
DISALLOW_COPY_AND_ASSIGN(DoubleToDoubleInstr);
};
@@ -8609,9 +9333,14 @@
virtual Definition* Canonicalize(FlowGraph* flow_graph);
- private:
- const SpeculativeMode speculative_mode_;
+#define FIELD_LIST(F) F(const SpeculativeMode, speculative_mode_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(DoubleToFloatInstr,
+ TemplateDefinition,
+ FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
DISALLOW_COPY_AND_ASSIGN(DoubleToFloatInstr);
};
@@ -8643,6 +9372,8 @@
virtual Definition* Canonicalize(FlowGraph* flow_graph);
+ DECLARE_EMPTY_SERIALIZATION(FloatToDoubleInstr, TemplateDefinition)
+
private:
DISALLOW_COPY_AND_ASSIGN(FloatToDoubleInstr);
};
@@ -8698,10 +9429,16 @@
PRINT_OPERANDS_TO_SUPPORT
- private:
- const MethodRecognizer::Kind recognized_kind_;
- const TokenPosition token_pos_;
+#define FIELD_LIST(F) \
+ F(const MethodRecognizer::Kind, recognized_kind_) \
+ F(const TokenPosition, token_pos_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(InvokeMathCFunctionInstr,
+ VariadicDefinition,
+ FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
DISALLOW_COPY_AND_ASSIGN(InvokeMathCFunctionInstr);
};
@@ -8746,10 +9483,17 @@
PRINT_OPERANDS_TO_SUPPORT
+#define FIELD_LIST(F) \
+ F(const intptr_t, index_) \
+ F(const Representation, definition_rep_) \
+ F(const intptr_t, definition_cid_)
+
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(ExtractNthOutputInstr,
+ TemplateDefinition,
+ FIELD_LIST)
+#undef FIELD_LIST
+
private:
- const intptr_t index_;
- const Representation definition_rep_;
- const intptr_t definition_cid_;
DISALLOW_COPY_AND_ASSIGN(ExtractNthOutputInstr);
};
@@ -8778,6 +9522,8 @@
PRINT_OPERANDS_TO_SUPPORT
+ DECLARE_EMPTY_SERIALIZATION(TruncDivModInstr, TemplateDefinition)
+
private:
Range* divisor_range() const {
// Note: this range is only used to remove check for zero divisor from
@@ -8832,12 +9578,18 @@
PRINT_OPERANDS_TO_SUPPORT
- private:
- const Cids& cids_;
- bool licm_hoisted_;
- bool is_bit_test_;
- const TokenPosition token_pos_;
+#define FIELD_LIST(F) \
+ F(const Cids&, cids_) \
+ F(bool, licm_hoisted_) \
+ F(bool, is_bit_test_) \
+ F(const TokenPosition, token_pos_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(CheckClassInstr,
+ TemplateInstruction,
+ FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
int EmitCheckCid(FlowGraphCompiler* compiler,
int bias,
intptr_t cid_start,
@@ -8881,10 +9633,16 @@
bool licm_hoisted() const { return licm_hoisted_; }
void set_licm_hoisted(bool value) { licm_hoisted_ = value; }
- private:
- const TokenPosition token_pos_;
- bool licm_hoisted_;
+#define FIELD_LIST(F) \
+ F(const TokenPosition, token_pos_) \
+ F(bool, licm_hoisted_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(CheckSmiInstr,
+ TemplateInstruction,
+ FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
DISALLOW_COPY_AND_ASSIGN(CheckSmiInstr);
};
@@ -8944,11 +9702,17 @@
PRINT_OPERANDS_TO_SUPPORT
- private:
- const TokenPosition token_pos_;
- const String& function_name_;
- const ExceptionType exception_type_;
+#define FIELD_LIST(F) \
+ F(const TokenPosition, token_pos_) \
+ F(const String&, function_name_) \
+ F(const ExceptionType, exception_type_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(CheckNullInstr,
+ TemplateDefinition,
+ FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
DISALLOW_COPY_AND_ASSIGN(CheckNullInstr);
};
@@ -8977,11 +9741,16 @@
PRINT_OPERANDS_TO_SUPPORT
+#define FIELD_LIST(F) F(CidRangeValue, cids_)
+
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(CheckClassIdInstr,
+ TemplateInstruction,
+ FIELD_LIST)
+#undef FIELD_LIST
+
private:
bool Contains(intptr_t cid) const;
- CidRangeValue cids_;
-
DISALLOW_COPY_AND_ASSIGN(CheckClassIdInstr);
};
@@ -9011,6 +9780,8 @@
// Give a name to the location/input indices.
enum { kLengthPos = 0, kIndexPos = 1 };
+ DECLARE_EMPTY_SERIALIZATION(CheckBoundBase, TemplateDefinition)
+
private:
DISALLOW_COPY_AND_ASSIGN(CheckBoundBase);
};
@@ -9045,10 +9816,16 @@
void set_licm_hoisted(bool value) { licm_hoisted_ = value; }
- private:
- bool generalized_;
- bool licm_hoisted_;
+#define FIELD_LIST(F) \
+ F(bool, generalized_) \
+ F(bool, licm_hoisted_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(CheckArrayBoundInstr,
+ CheckBoundBase,
+ FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
DISALLOW_COPY_AND_ASSIGN(CheckArrayBoundInstr);
};
@@ -9102,6 +9879,8 @@
return SlowPathSharingSupported(is_optimizing);
}
+ DECLARE_EMPTY_SERIALIZATION(GenericCheckBoundInstr, CheckBoundBase)
+
private:
DISALLOW_COPY_AND_ASSIGN(GenericCheckBoundInstr);
};
@@ -9127,6 +9906,8 @@
virtual bool ComputeCanDeoptimize() const { return false; }
+ DECLARE_EMPTY_SERIALIZATION(CheckWritableInstr, TemplateDefinition)
+
private:
DISALLOW_COPY_AND_ASSIGN(CheckWritableInstr);
};
@@ -9167,13 +9948,19 @@
PRINT_OPERANDS_TO_SUPPORT
+#define FIELD_LIST(F) F(ComparisonInstr*, comparison_)
+
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(CheckConditionInstr,
+ Instruction,
+ FIELD_LIST)
+#undef FIELD_LIST
+ DECLARE_EXTRA_SERIALIZATION
+
private:
virtual void RawSetInputAt(intptr_t i, Value* value) {
comparison()->RawSetInputAt(i, value);
}
- ComparisonInstr* comparison_;
-
DISALLOW_COPY_AND_ASSIGN(CheckConditionInstr);
};
@@ -9238,11 +10025,17 @@
PRINT_OPERANDS_TO_SUPPORT
- private:
- const Representation from_representation_;
- const Representation to_representation_;
- bool is_truncating_;
+#define FIELD_LIST(F) \
+ F(const Representation, from_representation_) \
+ F(const Representation, to_representation_) \
+ F(bool, is_truncating_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(IntConverterInstr,
+ TemplateDefinition,
+ FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
DISALLOW_COPY_AND_ASSIGN(IntConverterInstr);
};
@@ -9289,10 +10082,16 @@
PRINT_OPERANDS_TO_SUPPORT
- private:
- const Representation from_representation_;
- const Representation to_representation_;
+#define FIELD_LIST(F) \
+ F(const Representation, from_representation_) \
+ F(const Representation, to_representation_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(BitCastInstr,
+ TemplateDefinition,
+ FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
DISALLOW_COPY_AND_ASSIGN(BitCastInstr);
};
@@ -9318,6 +10117,8 @@
DECLARE_INSTRUCTION(LoadThread);
+ DECLARE_EMPTY_SERIALIZATION(LoadThreadInstr, TemplateDefinition)
+
private:
DISALLOW_COPY_AND_ASSIGN(LoadThreadInstr);
};
@@ -9526,6 +10327,13 @@
DECLARE_INSTRUCTION(SimdOp)
PRINT_OPERANDS_TO_SUPPORT
+#define FIELD_LIST(F) \
+ F(const Kind, kind_) \
+ F(intptr_t, mask_)
+
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(SimdOpInstr, Definition, FIELD_LIST)
+#undef FIELD_LIST
+
private:
SimdOpInstr(Kind kind, intptr_t deopt_id)
: Definition(deopt_id), kind_(kind) {}
@@ -9549,9 +10357,7 @@
// We consider SimdOpInstr to be very uncommon so we don't optimize them for
// size. Any instance of SimdOpInstr has enough space to fit any variation.
// TODO(dartbug.com/30949) optimize this for size.
- const Kind kind_;
Value* inputs_[4];
- intptr_t mask_;
DISALLOW_COPY_AND_ASSIGN(SimdOpInstr);
};
@@ -9590,10 +10396,16 @@
DECLARE_INSTRUCTION(Call1ArgStub);
PRINT_OPERANDS_TO_SUPPORT
- private:
- const StubId stub_id_;
- const TokenPosition token_pos_;
+#define FIELD_LIST(F) \
+ F(const StubId, stub_id_) \
+ F(const TokenPosition, token_pos_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(Call1ArgStubInstr,
+ TemplateDefinition,
+ FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
DISALLOW_COPY_AND_ASSIGN(Call1ArgStubInstr);
};
@@ -9634,11 +10446,17 @@
DECLARE_INSTRUCTION(Suspend);
PRINT_OPERANDS_TO_SUPPORT
- private:
- const StubId stub_id_;
- const intptr_t resume_deopt_id_;
- const TokenPosition token_pos_;
+#define FIELD_LIST(F) \
+ F(const StubId, stub_id_) \
+ F(const intptr_t, resume_deopt_id_) \
+ F(const TokenPosition, token_pos_)
+ DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS(SuspendInstr,
+ TemplateDefinition,
+ FIELD_LIST)
+#undef FIELD_LIST
+
+ private:
DISALLOW_COPY_AND_ASSIGN(SuspendInstr);
};
@@ -9851,6 +10669,9 @@
// from the copy.
Environment* DeepCopy(Zone* zone, intptr_t length) const;
+ void Write(FlowGraphSerializer* s) const;
+ explicit Environment(FlowGraphDeserializer* d);
+
private:
friend class ShallowIterator;
friend class compiler::BlockBuilder; // For Environment constructor.
@@ -9969,6 +10790,9 @@
ConstantInstr* constant = definition()->AsConstant();
return (constant == nullptr) || constant->value().ptr() == value.ptr();
}
+#undef DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS
+#undef DECLARE_CUSTOM_SERIALIZATION
+#undef DECLARE_EMPTY_SERIALIZATION
} // namespace dart
diff --git a/runtime/vm/compiler/backend/il_serializer.cc b/runtime/vm/compiler/backend/il_serializer.cc
new file mode 100644
index 0000000..6fb76fc
--- /dev/null
+++ b/runtime/vm/compiler/backend/il_serializer.cc
@@ -0,0 +1,2305 @@
+// Copyright (c) 2022, 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/backend/il_serializer.h"
+
+#include "vm/closure_functions_cache.h"
+#if defined(DART_PRECOMPILER)
+#include "vm/compiler/aot/precompiler.h"
+#endif
+#include "vm/compiler/backend/flow_graph.h"
+#include "vm/compiler/backend/il.h"
+#include "vm/compiler/backend/range_analysis.h"
+#include "vm/compiler/ffi/call.h"
+#include "vm/compiler/frontend/flow_graph_builder.h"
+#include "vm/object_store.h"
+#include "vm/parser.h"
+
+#define Z zone_
+
+// This file declares write/read methods for each type,
+// sorted alphabetically by type/class name (case-insensitive).
+// Each "write" method is followed by corresponding "read" method
+// or constructor.
+
+namespace dart {
+
+FlowGraphSerializer::FlowGraphSerializer(NonStreamingWriteStream* stream)
+ : stream_(stream),
+ zone_(Thread::Current()->zone()),
+ isolate_group_(IsolateGroup::Current()),
+ heap_(IsolateGroup::Current()->heap()) {}
+
+FlowGraphSerializer::~FlowGraphSerializer() {
+ heap_->ResetObjectIdTable();
+}
+
+FlowGraphDeserializer::FlowGraphDeserializer(
+ const ParsedFunction& parsed_function,
+ ReadStream* stream)
+ : parsed_function_(parsed_function),
+ stream_(stream),
+ zone_(Thread::Current()->zone()),
+ thread_(Thread::Current()),
+ isolate_group_(IsolateGroup::Current()) {}
+
+ClassPtr FlowGraphDeserializer::GetClassById(classid_t id) const {
+ return isolate_group()->class_table()->At(id);
+}
+
+template <>
+void FlowGraphSerializer::Write<const AbstractType*>(const AbstractType* x) {
+ if (x == nullptr) {
+ Write<bool>(false);
+ } else {
+ Write<bool>(true);
+ Write<const AbstractType&>(*x);
+ }
+}
+
+template <>
+const AbstractType* FlowGraphDeserializer::Read<const AbstractType*>() {
+ if (!Read<bool>()) {
+ return nullptr;
+ }
+ return &Read<const AbstractType&>();
+}
+
+template <>
+void FlowGraphSerializer::Write<AliasIdentity>(AliasIdentity x) {
+ x.Write(this);
+}
+
+template <>
+AliasIdentity FlowGraphDeserializer::Read<AliasIdentity>() {
+ return AliasIdentity(this);
+}
+
+void AliasIdentity::Write(FlowGraphSerializer* s) const {
+ s->Write<intptr_t>(value_);
+}
+
+AliasIdentity::AliasIdentity(FlowGraphDeserializer* d)
+ : value_(d->Read<intptr_t>()) {}
+
+void BlockEntryInstr::WriteTo(FlowGraphSerializer* s) {
+ TemplateInstruction::WriteTo(s);
+ s->Write<intptr_t>(block_id_);
+ s->Write<intptr_t>(try_index_);
+ s->Write<intptr_t>(stack_depth_);
+ s->Write<ParallelMoveInstr*>(parallel_move_);
+}
+
+BlockEntryInstr::BlockEntryInstr(FlowGraphDeserializer* d)
+ : TemplateInstruction(d),
+ block_id_(d->Read<intptr_t>()),
+ try_index_(d->Read<intptr_t>()),
+ stack_depth_(d->Read<intptr_t>()),
+ dominated_blocks_(1),
+ parallel_move_(d->Read<ParallelMoveInstr*>()) {
+ d->set_block(block_id_, this);
+ d->set_current_block(this);
+}
+
+void BlockEntryInstr::WriteExtra(FlowGraphSerializer* s) {
+ TemplateInstruction::WriteExtra(s);
+ s->WriteRef<BlockEntryInstr*>(dominator_);
+ s->WriteGrowableArrayOfRefs<BlockEntryInstr*>(dominated_blocks_);
+ if (parallel_move_ != nullptr) {
+ parallel_move_->WriteExtra(s);
+ }
+}
+
+void BlockEntryInstr::ReadExtra(FlowGraphDeserializer* d) {
+ TemplateInstruction::ReadExtra(d);
+ dominator_ = d->ReadRef<BlockEntryInstr*>();
+ dominated_blocks_ = d->ReadGrowableArrayOfRefs<BlockEntryInstr*>();
+ if (parallel_move_ != nullptr) {
+ parallel_move_->ReadExtra(d);
+ }
+}
+
+template <>
+void FlowGraphSerializer::WriteRef<BlockEntryInstr*>(BlockEntryInstr* x) {
+ ASSERT(can_write_refs());
+ if (x == nullptr) {
+ Write<intptr_t>(-1);
+ return;
+ }
+ const intptr_t id = x->block_id();
+ ASSERT(id >= 0);
+ Write<intptr_t>(id);
+}
+
+template <>
+BlockEntryInstr* FlowGraphDeserializer::ReadRef<BlockEntryInstr*>() {
+ const intptr_t id = Read<intptr_t>();
+ if (id < 0) {
+ return nullptr;
+ }
+ return block(id);
+}
+
+#define INSTRUCTION_REFS_SERIALIZABLE_AS_BLOCK_ENTRY(V) \
+ V(CatchBlockEntry, CatchBlockEntryInstr) \
+ V(FunctionEntry, FunctionEntryInstr) \
+ V(IndirectEntry, IndirectEntryInstr) \
+ V(JoinEntry, JoinEntryInstr) \
+ V(OsrEntry, OsrEntryInstr) \
+ V(TargetEntry, TargetEntryInstr)
+
+#define SERIALIZABLE_AS_BLOCK_ENTRY(name, type) \
+ template <> \
+ void FlowGraphSerializer::WriteRef<type*>(type * x) { \
+ WriteRef<BlockEntryInstr*>(x); \
+ } \
+ template <> \
+ type* FlowGraphDeserializer::ReadRef<type*>() { \
+ BlockEntryInstr* instr = ReadRef<BlockEntryInstr*>(); \
+ ASSERT((instr == nullptr) || instr->Is##name()); \
+ return static_cast<type*>(instr); \
+ }
+
+INSTRUCTION_REFS_SERIALIZABLE_AS_BLOCK_ENTRY(SERIALIZABLE_AS_BLOCK_ENTRY)
+#undef SERIALIZABLE_AS_BLOCK_ENTRY
+#undef INSTRUCTION_REFS_SERIALIZABLE_AS_BLOCK_ENTRY
+
+void BlockEntryWithInitialDefs::WriteTo(FlowGraphSerializer* s) {
+ BlockEntryInstr::WriteTo(s);
+ s->Write<GrowableArray<Definition*>>(initial_definitions_);
+}
+
+BlockEntryWithInitialDefs::BlockEntryWithInitialDefs(FlowGraphDeserializer* d)
+ : BlockEntryInstr(d),
+ initial_definitions_(d->Read<GrowableArray<Definition*>>()) {
+ for (Definition* def : initial_definitions_) {
+ def->set_previous(this);
+ if (auto par = def->AsParameter()) {
+ par->set_block(this);
+ }
+ }
+}
+
+void BlockEntryWithInitialDefs::WriteExtra(FlowGraphSerializer* s) {
+ BlockEntryInstr::WriteExtra(s);
+ for (Definition* def : initial_definitions_) {
+ def->WriteExtra(s);
+ }
+}
+
+void BlockEntryWithInitialDefs::ReadExtra(FlowGraphDeserializer* d) {
+ BlockEntryInstr::ReadExtra(d);
+ for (Definition* def : initial_definitions_) {
+ def->ReadExtra(d);
+ }
+}
+
+template <>
+void FlowGraphSerializer::Write<bool>(bool x) {
+ stream_->Write<uint8_t>(x ? 1 : 0);
+}
+
+template <>
+bool FlowGraphDeserializer::Read<bool>() {
+ return (stream_->Read<uint8_t>() != 0);
+}
+
+void BranchInstr::WriteExtra(FlowGraphSerializer* s) {
+ // Branch reuses inputs from its embedded Comparison.
+ // Instruction::WriteExtra is not called to avoid
+ // writing/reading inputs twice.
+ WriteExtraWithoutInputs(s);
+ comparison_->WriteExtra(s);
+ s->WriteRef<TargetEntryInstr*>(true_successor_);
+ s->WriteRef<TargetEntryInstr*>(false_successor_);
+ s->WriteRef<TargetEntryInstr*>(constant_target_);
+}
+
+void BranchInstr::ReadExtra(FlowGraphDeserializer* d) {
+ ReadExtraWithoutInputs(d);
+ comparison_->ReadExtra(d);
+ for (intptr_t i = comparison_->InputCount() - 1; i >= 0; --i) {
+ comparison_->InputAt(i)->set_instruction(this);
+ }
+ true_successor_ = d->ReadRef<TargetEntryInstr*>();
+ false_successor_ = d->ReadRef<TargetEntryInstr*>();
+ constant_target_ = d->ReadRef<TargetEntryInstr*>();
+}
+
+template <>
+void FlowGraphSerializer::Write<const compiler::ffi::CallbackMarshaller&>(
+ const compiler::ffi::CallbackMarshaller& x) {
+ UNIMPLEMENTED();
+}
+
+template <>
+const compiler::ffi::CallbackMarshaller&
+FlowGraphDeserializer::Read<const compiler::ffi::CallbackMarshaller&>() {
+ UNIMPLEMENTED();
+ return *compiler::ffi::CallbackMarshaller::FromFunction(
+ Z, Function::null_function(), nullptr);
+}
+
+template <>
+void FlowGraphSerializer::Write<const compiler::ffi::CallMarshaller&>(
+ const compiler::ffi::CallMarshaller& x) {
+ Write<const Function&>(x.dart_signature());
+}
+
+template <>
+const compiler::ffi::CallMarshaller&
+FlowGraphDeserializer::Read<const compiler::ffi::CallMarshaller&>() {
+ const Function& dart_signature = Read<const Function&>();
+ const char* error = nullptr;
+ return *compiler::ffi::CallMarshaller::FromFunction(Z, dart_signature,
+ &error);
+}
+
+template <>
+void FlowGraphSerializer::Write<const CallTargets&>(const CallTargets& x) {
+ x.Write(this);
+}
+
+template <>
+const CallTargets& FlowGraphDeserializer::Read<const CallTargets&>() {
+ return *(new (Z) CallTargets(this));
+}
+
+void CallTargets::Write(FlowGraphSerializer* s) const {
+ const intptr_t len = cid_ranges_.length();
+ s->Write<intptr_t>(len);
+ for (intptr_t i = 0; i < len; ++i) {
+ TargetInfo* t = TargetAt(i);
+ s->Write<intptr_t>(t->cid_start);
+ s->Write<intptr_t>(t->cid_end);
+ s->Write<const Function&>(*(t->target));
+ s->Write<intptr_t>(t->count);
+ s->Write<int8_t>(t->exactness.Encode());
+ }
+}
+
+CallTargets::CallTargets(FlowGraphDeserializer* d) : Cids(d->zone()) {
+ const intptr_t len = d->Read<intptr_t>();
+ cid_ranges_.EnsureLength(len, nullptr);
+ for (intptr_t i = 0; i < len; ++i) {
+ const intptr_t cid_start = d->Read<intptr_t>();
+ const intptr_t cid_end = d->Read<intptr_t>();
+ const Function& target = d->Read<const Function&>();
+ const intptr_t count = d->Read<intptr_t>();
+ const StaticTypeExactnessState exactness =
+ StaticTypeExactnessState::Decode(d->Read<int8_t>());
+ TargetInfo* t = new (d->zone())
+ TargetInfo(cid_start, cid_end, &target, count, exactness);
+ cid_ranges_[i] = t;
+ }
+}
+
+void CatchBlockEntryInstr::WriteTo(FlowGraphSerializer* s) {
+ BlockEntryWithInitialDefs::WriteTo(s);
+ s->Write<const Array&>(catch_handler_types_);
+ s->Write<intptr_t>(catch_try_index_);
+ s->Write<bool>(needs_stacktrace_);
+ s->Write<bool>(is_generated_);
+}
+
+CatchBlockEntryInstr::CatchBlockEntryInstr(FlowGraphDeserializer* d)
+ : BlockEntryWithInitialDefs(d),
+ graph_entry_(d->graph_entry()),
+ predecessor_(nullptr),
+ catch_handler_types_(d->Read<const Array&>()),
+ catch_try_index_(d->Read<intptr_t>()),
+ exception_var_(nullptr),
+ stacktrace_var_(nullptr),
+ raw_exception_var_(nullptr),
+ raw_stacktrace_var_(nullptr),
+ needs_stacktrace_(d->Read<bool>()),
+ is_generated_(d->Read<bool>()) {}
+
+template <>
+void FlowGraphSerializer::Write<const char*>(const char* x) {
+ ASSERT(x != nullptr);
+ const intptr_t len = strlen(x);
+ Write<intptr_t>(len);
+ stream_->WriteBytes(x, len);
+}
+
+template <>
+const char* FlowGraphDeserializer::Read<const char*>() {
+ const intptr_t len = Read<intptr_t>();
+ char* str = zone()->Alloc<char>(len + 1);
+ stream_->ReadBytes(str, len);
+ str[len] = 0;
+ return str;
+}
+
+void CheckConditionInstr::WriteExtra(FlowGraphSerializer* s) {
+ // CheckCondition reuses inputs from its embedded Comparison.
+ // Instruction::WriteExtra is not called to avoid
+ // writing/reading inputs twice.
+ WriteExtraWithoutInputs(s);
+ comparison_->WriteExtra(s);
+}
+
+void CheckConditionInstr::ReadExtra(FlowGraphDeserializer* d) {
+ ReadExtraWithoutInputs(d);
+ comparison_->ReadExtra(d);
+ for (intptr_t i = comparison_->InputCount() - 1; i >= 0; --i) {
+ comparison_->InputAt(i)->set_instruction(this);
+ }
+}
+
+template <>
+void FlowGraphSerializer::Write<CidRangeValue>(CidRangeValue x) {
+ Write<intptr_t>(x.cid_start);
+ Write<intptr_t>(x.cid_end);
+}
+
+template <>
+CidRangeValue FlowGraphDeserializer::Read<CidRangeValue>() {
+ const intptr_t cid_start = Read<intptr_t>();
+ const intptr_t cid_end = Read<intptr_t>();
+ return CidRangeValue(cid_start, cid_end);
+}
+
+template <>
+void FlowGraphSerializer::Write<const Cids&>(const Cids& x) {
+ const intptr_t len = x.length();
+ Write<intptr_t>(len);
+ for (intptr_t i = 0; i < len; ++i) {
+ const CidRange* r = x.At(i);
+ Write<intptr_t>(r->cid_start);
+ Write<intptr_t>(r->cid_end);
+ }
+}
+
+template <>
+const Cids& FlowGraphDeserializer::Read<const Cids&>() {
+ Cids* cids = new (Z) Cids(Z);
+ const intptr_t len = Read<intptr_t>();
+ for (intptr_t i = 0; i < len; ++i) {
+ const intptr_t cid_start = Read<intptr_t>();
+ const intptr_t cid_end = Read<intptr_t>();
+ CidRange* r = new (Z) CidRange(cid_start, cid_end);
+ cids->Add(r);
+ }
+ return *cids;
+}
+
+template <>
+void FlowGraphSerializer::Write<const Class&>(const Class& x) {
+ if (x.IsNull()) {
+ Write<classid_t>(kIllegalCid);
+ return;
+ }
+ Write<classid_t>(x.id());
+}
+
+template <>
+const Class& FlowGraphDeserializer::Read<const Class&>() {
+ const classid_t cid = Read<classid_t>();
+ if (cid == kIllegalCid) {
+ return Class::ZoneHandle(Z);
+ }
+ return Class::ZoneHandle(Z, GetClassById(cid));
+}
+
+void ConstraintInstr::WriteExtra(FlowGraphSerializer* s) {
+ TemplateDefinition::WriteExtra(s);
+ s->WriteRef<TargetEntryInstr*>(target_);
+}
+
+void ConstraintInstr::ReadExtra(FlowGraphDeserializer* d) {
+ TemplateDefinition::ReadExtra(d);
+ target_ = d->ReadRef<TargetEntryInstr*>();
+}
+
+template <>
+void FlowGraphSerializer::Write<const Code&>(const Code& x) {
+ ASSERT(!x.IsNull());
+ ASSERT(x.IsStubCode());
+ for (intptr_t i = 0, n = StubCode::NumEntries(); i < n; ++i) {
+ if (StubCode::EntryAt(i).ptr() == x.ptr()) {
+ Write<intptr_t>(i);
+ return;
+ }
+ }
+ intptr_t index = StubCode::NumEntries();
+ ObjectStore* object_store = isolate_group()->object_store();
+#define MATCH(member, name) \
+ if (object_store->member() == x.ptr()) { \
+ Write<intptr_t>(index); \
+ return; \
+ } \
+ ++index;
+ OBJECT_STORE_STUB_CODE_LIST(MATCH)
+#undef MATCH
+ UNIMPLEMENTED();
+}
+
+template <>
+const Code& FlowGraphDeserializer::Read<const Code&>() {
+ const intptr_t stub_id = Read<intptr_t>();
+ if (stub_id < StubCode::NumEntries()) {
+ return StubCode::EntryAt(stub_id);
+ }
+ intptr_t index = StubCode::NumEntries();
+ ObjectStore* object_store = isolate_group()->object_store();
+#define MATCH(member, name) \
+ if (index == stub_id) { \
+ return Code::ZoneHandle(Z, object_store->member()); \
+ } \
+ ++index;
+ OBJECT_STORE_STUB_CODE_LIST(MATCH)
+#undef MATCH
+ UNIMPLEMENTED();
+}
+
+template <>
+void FlowGraphSerializer::Write<CompileType*>(CompileType* x) {
+ if (x == nullptr) {
+ Write<bool>(false);
+ } else {
+ Write<bool>(true);
+ x->Write(this);
+ }
+}
+
+template <>
+CompileType* FlowGraphDeserializer::Read<CompileType*>() {
+ if (!Read<bool>()) {
+ return nullptr;
+ }
+ return new (Z) CompileType(this);
+}
+
+void CompileType::Write(FlowGraphSerializer* s) const {
+ s->Write<bool>(can_be_null_);
+ s->Write<bool>(can_be_sentinel_);
+ s->Write<classid_t>(cid_);
+ if (type_ == nullptr) {
+ s->Write<bool>(false);
+ } else {
+ s->Write<bool>(true);
+ s->Write<const AbstractType&>(*type_);
+ }
+}
+
+CompileType::CompileType(FlowGraphDeserializer* d)
+ : can_be_null_(d->Read<bool>()),
+ can_be_sentinel_(d->Read<bool>()),
+ cid_(d->Read<classid_t>()),
+ type_(nullptr) {
+ if (d->Read<bool>()) {
+ type_ = &d->Read<const AbstractType&>();
+ }
+}
+
+void Definition::WriteTo(FlowGraphSerializer* s) {
+ Instruction::WriteTo(s);
+ s->Write<Range*>(range_);
+ s->Write<intptr_t>(temp_index_);
+ s->Write<intptr_t>(ssa_temp_index_);
+ s->Write<CompileType*>(type_);
+}
+
+Definition::Definition(FlowGraphDeserializer* d)
+ : Instruction(d),
+ range_(d->Read<Range*>()),
+ temp_index_(d->Read<intptr_t>()),
+ ssa_temp_index_(d->Read<intptr_t>()),
+ type_(d->Read<CompileType*>()) {
+ if (HasSSATemp()) {
+ d->set_definition(ssa_temp_index(), this);
+ }
+ if (type_ != nullptr) {
+ type_->set_owner(this);
+ }
+}
+
+template <>
+void FlowGraphSerializer::WriteRef<Definition*>(Definition* x) {
+ if (!x->HasSSATemp()) {
+ if (auto* push_arg = x->AsPushArgument()) {
+ // Environments of the calls can reference PushArgument instructions
+ // and they don't have SSA temps.
+ // Write a reference to the original definition.
+ // When reading it is restored using RepairPushArgsInEnvironment.
+ x = push_arg->value()->definition();
+ } else {
+ UNREACHABLE();
+ }
+ }
+ ASSERT(x->HasSSATemp());
+ ASSERT(can_write_refs());
+ Write<intptr_t>(x->ssa_temp_index());
+}
+
+template <>
+Definition* FlowGraphDeserializer::ReadRef<Definition*>() {
+ return definition(Read<intptr_t>());
+}
+
+template <>
+void FlowGraphSerializer::Write<double>(double x) {
+ stream_->Write<int64_t>(bit_cast<int64_t>(x));
+}
+
+template <>
+double FlowGraphDeserializer::Read<double>() {
+ return bit_cast<double>(stream_->Read<int64_t>());
+}
+
+template <>
+void FlowGraphSerializer::Write<Environment*>(Environment* x) {
+ ASSERT(can_write_refs());
+ if (x == nullptr) {
+ Write<bool>(false);
+ } else {
+ Write<bool>(true);
+ x->Write(this);
+ }
+}
+
+template <>
+Environment* FlowGraphDeserializer::Read<Environment*>() {
+ if (!Read<bool>()) {
+ return nullptr;
+ }
+ return new (Z) Environment(this);
+}
+
+void Environment::Write(FlowGraphSerializer* s) const {
+ s->Write<GrowableArray<Value*>>(values_);
+ s->Write<intptr_t>(fixed_parameter_count_);
+ s->Write<uintptr_t>(bitfield_);
+ s->Write<const Function&>(function_);
+ s->Write<Environment*>(outer_);
+ if (locations_ == nullptr) {
+ s->Write<bool>(false);
+ } else {
+ s->Write<bool>(true);
+ for (intptr_t i = 0, n = values_.length(); i < n; ++i) {
+ locations_[i].Write(s);
+ }
+ }
+}
+
+Environment::Environment(FlowGraphDeserializer* d)
+ : values_(d->Read<GrowableArray<Value*>>()),
+ locations_(nullptr),
+ fixed_parameter_count_(d->Read<intptr_t>()),
+ bitfield_(d->Read<uintptr_t>()),
+ function_(d->Read<const Function&>()),
+ outer_(d->Read<Environment*>()) {
+ for (intptr_t i = 0, n = values_.length(); i < n; ++i) {
+ Value* value = values_[i];
+ value->definition()->AddEnvUse(value);
+ }
+ if (d->Read<bool>()) {
+ locations_ = d->zone()->Alloc<Location>(values_.length());
+ for (intptr_t i = 0, n = values_.length(); i < n; ++i) {
+ locations_[i] = Location::Read(d);
+ }
+ }
+}
+
+void FlowGraphSerializer::WriteFlowGraph(
+ const FlowGraph& flow_graph,
+ const ZoneGrowableArray<Definition*>& detached_defs) {
+ ASSERT(!flow_graph.is_licm_allowed());
+
+ Write<intptr_t>(flow_graph.current_ssa_temp_index());
+ Write<intptr_t>(flow_graph.max_block_id());
+ Write<intptr_t>(flow_graph.inlining_id());
+ Write<const Array&>(flow_graph.coverage_array());
+
+ PrologueInfo prologue_info = flow_graph.prologue_info();
+ Write<intptr_t>(prologue_info.min_block_id);
+ Write<intptr_t>(prologue_info.max_block_id);
+
+ // Write instructions
+ for (auto block : flow_graph.reverse_postorder()) {
+ Write<Instruction*>(block);
+ for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) {
+ Instruction* current = it.Current();
+ Write<Instruction*>(current);
+ }
+ }
+ Write<Instruction*>(nullptr);
+ Write<const ZoneGrowableArray<Definition*>&>(detached_defs);
+ can_write_refs_ = true;
+
+ // Write instructions extra info.
+ // It may contain references to other instructions.
+ for (auto block : flow_graph.reverse_postorder()) {
+ block->WriteExtra(this);
+ for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) {
+ Instruction* current = it.Current();
+ current->WriteExtra(this);
+ }
+ }
+ for (auto* instr : detached_defs) {
+ instr->WriteExtra(this);
+ }
+
+ const auto& optimized_block_order = flow_graph.optimized_block_order();
+ Write<intptr_t>(optimized_block_order.length());
+ for (intptr_t i = 0, n = optimized_block_order.length(); i < n; ++i) {
+ WriteRef<BlockEntryInstr*>(optimized_block_order[i]);
+ }
+
+ const auto* captured_parameters = flow_graph.captured_parameters();
+ if (captured_parameters->IsEmpty()) {
+ Write<bool>(false);
+ } else {
+ Write<bool>(true);
+ // Captured parameters are rare so write their bit numbers
+ // instead of writing BitVector.
+ GrowableArray<intptr_t> indices(Z, 0);
+ for (intptr_t i = 0, n = captured_parameters->length(); i < n; ++i) {
+ if (captured_parameters->Contains(i)) {
+ indices.Add(i);
+ }
+ }
+ Write<GrowableArray<intptr_t>>(indices);
+ }
+}
+
+FlowGraph* FlowGraphDeserializer::ReadFlowGraph() {
+ const intptr_t current_ssa_temp_index = Read<intptr_t>();
+ const intptr_t max_block_id = Read<intptr_t>();
+ const intptr_t inlining_id = Read<intptr_t>();
+ const Array& coverage_array = Read<const Array&>();
+ const PrologueInfo prologue_info(Read<intptr_t>(), Read<intptr_t>());
+
+ definitions_.EnsureLength(current_ssa_temp_index, nullptr);
+ blocks_.EnsureLength(max_block_id + 1, nullptr);
+
+ // Read/create instructions.
+ ZoneGrowableArray<Instruction*> instructions(16);
+ Instruction* prev = nullptr;
+ while (Instruction* instr = Read<Instruction*>()) {
+ instructions.Add(instr);
+ if (!instr->IsBlockEntry()) {
+ ASSERT(prev != nullptr);
+ prev->LinkTo(instr);
+ }
+ prev = instr;
+ }
+ ASSERT(graph_entry_ != nullptr);
+ const auto& detached_defs = Read<const ZoneGrowableArray<Definition*>&>();
+
+ // Read instructions extra info.
+ // It may contain references to other instructions.
+ for (Instruction* instr : instructions) {
+ instr->ReadExtra(this);
+ }
+ for (auto* instr : detached_defs) {
+ instr->ReadExtra(this);
+ }
+
+ FlowGraph* flow_graph = new (Z)
+ FlowGraph(parsed_function(), graph_entry_, max_block_id, prologue_info);
+ flow_graph->set_current_ssa_temp_index(current_ssa_temp_index);
+ flow_graph->CreateCommonConstants();
+ flow_graph->disallow_licm();
+ flow_graph->set_inlining_id(inlining_id);
+ flow_graph->set_coverage_array(coverage_array);
+
+ {
+ const intptr_t num_blocks = Read<intptr_t>();
+ if (num_blocks != 0) {
+ auto* codegen_block_order = flow_graph->CodegenBlockOrder(true);
+ ASSERT(codegen_block_order == &flow_graph->optimized_block_order());
+ for (intptr_t i = 0; i < num_blocks; ++i) {
+ codegen_block_order->Add(ReadRef<BlockEntryInstr*>());
+ }
+ }
+ }
+
+ if (Read<bool>()) {
+ GrowableArray<intptr_t> indices = Read<GrowableArray<intptr_t>>();
+ for (intptr_t i : indices) {
+ flow_graph->captured_parameters()->Add(i);
+ }
+ }
+
+ return flow_graph;
+}
+
+template <>
+void FlowGraphSerializer::Write<const Function&>(const Function& x) {
+ if (x.IsNull()) {
+ Write<int8_t>(-1);
+ return;
+ }
+ Write<int8_t>(x.kind());
+ switch (x.kind()) {
+ case UntaggedFunction::kRegularFunction:
+ case UntaggedFunction::kGetterFunction:
+ case UntaggedFunction::kSetterFunction:
+ case UntaggedFunction::kImplicitGetter:
+ case UntaggedFunction::kImplicitSetter:
+ case UntaggedFunction::kImplicitStaticGetter:
+ case UntaggedFunction::kConstructor: {
+ const auto& owner = Class::Handle(Z, x.Owner());
+ Write<classid_t>(owner.id());
+ const intptr_t function_index = owner.FindFunctionIndex(x);
+ ASSERT(function_index >= 0);
+ Write<intptr_t>(function_index);
+ return;
+ }
+ case UntaggedFunction::kImplicitClosureFunction: {
+ const auto& parent = Function::Handle(Z, x.parent_function());
+ Write<const Function&>(parent);
+ return;
+ }
+ case UntaggedFunction::kFieldInitializer: {
+ const auto& field = Field::Handle(Z, x.accessor_field());
+ Write<const Field&>(field);
+ return;
+ }
+ case UntaggedFunction::kClosureFunction:
+ // TODO(alexmarkov): we cannot rely on ClosureFunctionsCache
+ // as it is lazily populated when compiling functions.
+ // We need to serialize kernel offset and re-create
+ // closure functions when reading as needed.
+ Write<intptr_t>(ClosureFunctionsCache::FindClosureIndex(x));
+ return;
+ case UntaggedFunction::kMethodExtractor: {
+ Function& function = Function::Handle(Z, x.extracted_method_closure());
+ ASSERT(function.IsImplicitClosureFunction());
+ function = function.parent_function();
+ Write<const Function&>(function);
+ Write<const String&>(String::Handle(Z, x.name()));
+ return;
+ }
+ case UntaggedFunction::kInvokeFieldDispatcher: {
+ Write<const Class&>(Class::Handle(Z, x.Owner()));
+ Write<const String&>(String::Handle(Z, x.name()));
+ Write<const Array&>(Array::Handle(Z, x.saved_args_desc()));
+ return;
+ }
+ case UntaggedFunction::kDynamicInvocationForwarder: {
+ const auto& target = Function::Handle(Z, x.ForwardingTarget());
+ Write<const Function&>(target);
+ return;
+ }
+ case UntaggedFunction::kFfiTrampoline: {
+ if (x.FfiCallbackTarget() != Object::null()) {
+ UNIMPLEMENTED();
+ }
+ Write<const String&>(String::Handle(Z, x.name()));
+ Write<const FunctionType&>(FunctionType::Handle(Z, x.signature()));
+ Write<const FunctionType&>(FunctionType::Handle(Z, x.FfiCSignature()));
+ Write<bool>(x.FfiIsLeaf());
+ return;
+ }
+ default:
+ break;
+ }
+ switch (x.kind()) {
+#define UNIMPLEMENTED_FUNCTION_KIND(kind) \
+ case UntaggedFunction::k##kind: \
+ FATAL("Unimplemented Write<const Function&> for " #kind);
+ FOR_EACH_RAW_FUNCTION_KIND(UNIMPLEMENTED_FUNCTION_KIND)
+#undef UNIMPLEMENTED_FUNCTION_KIND
+ }
+ UNREACHABLE();
+}
+
+template <>
+const Function& FlowGraphDeserializer::Read<const Function&>() {
+ const int8_t raw_kind = Read<int8_t>();
+ if (raw_kind < 0) {
+ return Object::null_function();
+ }
+ const auto kind = static_cast<UntaggedFunction::Kind>(raw_kind);
+ switch (kind) {
+ case UntaggedFunction::kRegularFunction:
+ case UntaggedFunction::kGetterFunction:
+ case UntaggedFunction::kSetterFunction:
+ case UntaggedFunction::kImplicitGetter:
+ case UntaggedFunction::kImplicitSetter:
+ case UntaggedFunction::kImplicitStaticGetter:
+ case UntaggedFunction::kConstructor: {
+ const classid_t owner_class_id = Read<classid_t>();
+ const intptr_t function_index = Read<intptr_t>();
+ const auto& owner = Class::Handle(Z, GetClassById(owner_class_id));
+ const auto& result =
+ Function::ZoneHandle(Z, owner.FunctionFromIndex(function_index));
+ ASSERT(!result.IsNull());
+ return result;
+ }
+ case UntaggedFunction::kImplicitClosureFunction: {
+ const auto& parent = Read<const Function&>();
+ return Function::ZoneHandle(Z, parent.ImplicitClosureFunction());
+ }
+ case UntaggedFunction::kFieldInitializer: {
+ const auto& field = Read<const Field&>();
+ return Function::ZoneHandle(Z, field.EnsureInitializerFunction());
+ }
+ case UntaggedFunction::kClosureFunction: {
+ const intptr_t index = Read<intptr_t>();
+ return Function::ZoneHandle(
+ Z, ClosureFunctionsCache::ClosureFunctionFromIndex(index));
+ }
+ case UntaggedFunction::kMethodExtractor: {
+ const Function& function = Read<const Function&>();
+ const String& name = Read<const String&>();
+ return Function::ZoneHandle(Z, function.GetMethodExtractor(name));
+ }
+ case UntaggedFunction::kInvokeFieldDispatcher: {
+ const Class& owner = Read<const Class&>();
+ const String& target_name = Read<const String&>();
+ const Array& args_desc = Read<const Array&>();
+ return Function::ZoneHandle(
+ Z,
+ owner.GetInvocationDispatcher(
+ target_name, args_desc, UntaggedFunction::kInvokeFieldDispatcher,
+ /*create_if_absent=*/true));
+ }
+ case UntaggedFunction::kDynamicInvocationForwarder: {
+ const auto& target = Read<const Function&>();
+ auto& name = String::Handle(Z, target.name());
+ name = Function::CreateDynamicInvocationForwarderName(name);
+ return Function::ZoneHandle(Z,
+ target.GetDynamicInvocationForwarder(name));
+ }
+ case UntaggedFunction::kFfiTrampoline: {
+ const String& name = Read<const String&>();
+ const FunctionType& signature = Read<const FunctionType&>();
+ const FunctionType& c_signature = Read<const FunctionType&>();
+ const bool is_leaf = Read<bool>();
+ return Function::ZoneHandle(
+ Z, compiler::ffi::TrampolineFunction(name, signature, c_signature,
+ is_leaf));
+ }
+ default:
+ UNIMPLEMENTED();
+ return Object::null_function();
+ }
+}
+
+void FunctionEntryInstr::WriteTo(FlowGraphSerializer* s) {
+ BlockEntryWithInitialDefs::WriteTo(s);
+}
+
+FunctionEntryInstr::FunctionEntryInstr(FlowGraphDeserializer* d)
+ : BlockEntryWithInitialDefs(d), graph_entry_(d->graph_entry()) {}
+
+void GraphEntryInstr::WriteTo(FlowGraphSerializer* s) {
+ BlockEntryWithInitialDefs::WriteTo(s);
+ s->Write<intptr_t>(osr_id_);
+ s->Write<intptr_t>(entry_count_);
+ s->Write<intptr_t>(spill_slot_count_);
+ s->Write<intptr_t>(fixed_slot_count_);
+ s->Write<bool>(needs_frame_);
+}
+
+GraphEntryInstr::GraphEntryInstr(FlowGraphDeserializer* d)
+ : BlockEntryWithInitialDefs(d),
+ parsed_function_(d->parsed_function()),
+ osr_id_(d->Read<intptr_t>()),
+ entry_count_(d->Read<intptr_t>()),
+ spill_slot_count_(d->Read<intptr_t>()),
+ fixed_slot_count_(d->Read<intptr_t>()),
+ needs_frame_(d->Read<bool>()) {
+ d->set_graph_entry(this);
+}
+
+void GraphEntryInstr::WriteExtra(FlowGraphSerializer* s) {
+ BlockEntryWithInitialDefs::WriteExtra(s);
+ s->WriteRef<FunctionEntryInstr*>(normal_entry_);
+ s->WriteRef<FunctionEntryInstr*>(unchecked_entry_);
+ s->WriteRef<OsrEntryInstr*>(osr_entry_);
+ s->WriteGrowableArrayOfRefs<CatchBlockEntryInstr*>(catch_entries_);
+ s->WriteGrowableArrayOfRefs<IndirectEntryInstr*>(indirect_entries_);
+}
+
+void GraphEntryInstr::ReadExtra(FlowGraphDeserializer* d) {
+ BlockEntryWithInitialDefs::ReadExtra(d);
+ normal_entry_ = d->ReadRef<FunctionEntryInstr*>();
+ unchecked_entry_ = d->ReadRef<FunctionEntryInstr*>();
+ osr_entry_ = d->ReadRef<OsrEntryInstr*>();
+ catch_entries_ = d->ReadGrowableArrayOfRefs<CatchBlockEntryInstr*>();
+ indirect_entries_ = d->ReadGrowableArrayOfRefs<IndirectEntryInstr*>();
+}
+
+void GotoInstr::WriteExtra(FlowGraphSerializer* s) {
+ TemplateInstruction::WriteExtra(s);
+ if (parallel_move_ != nullptr) {
+ parallel_move_->WriteExtra(s);
+ }
+ s->WriteRef<JoinEntryInstr*>(successor_);
+}
+
+void GotoInstr::ReadExtra(FlowGraphDeserializer* d) {
+ TemplateInstruction::ReadExtra(d);
+ if (parallel_move_ != nullptr) {
+ parallel_move_->ReadExtra(d);
+ }
+ successor_ = d->ReadRef<JoinEntryInstr*>();
+}
+
+template <>
+void FlowGraphSerializer::Write<const ICData*>(const ICData* x) {
+ if (x == nullptr) {
+ Write<bool>(false);
+ } else {
+ Write<bool>(true);
+ ASSERT(!x->IsNull());
+ Write<const Object&>(*x);
+ }
+}
+
+template <>
+const ICData* FlowGraphDeserializer::Read<const ICData*>() {
+ if (!Read<bool>()) {
+ return nullptr;
+ }
+ return &ICData::Cast(Read<const Object&>());
+}
+
+void IfThenElseInstr::WriteExtra(FlowGraphSerializer* s) {
+ // IfThenElse reuses inputs from its embedded Comparison.
+ // Definition::WriteExtra is not called to avoid
+ // writing/reading inputs twice.
+ WriteExtraWithoutInputs(s);
+ comparison_->WriteExtra(s);
+}
+
+void IfThenElseInstr::ReadExtra(FlowGraphDeserializer* d) {
+ ReadExtraWithoutInputs(d);
+ comparison_->ReadExtra(d);
+ for (intptr_t i = comparison_->InputCount() - 1; i >= 0; --i) {
+ comparison_->InputAt(i)->set_instruction(this);
+ }
+}
+
+void IndirectGotoInstr::WriteTo(FlowGraphSerializer* s) {
+ TemplateInstruction::WriteTo(s);
+ s->Write<intptr_t>(offsets_.Length());
+}
+
+IndirectGotoInstr::IndirectGotoInstr(FlowGraphDeserializer* d)
+ : TemplateInstruction(d),
+ offsets_(TypedData::ZoneHandle(d->zone(),
+ TypedData::New(kTypedDataInt32ArrayCid,
+ d->Read<intptr_t>(),
+ Heap::kOld))) {}
+
+void IndirectGotoInstr::WriteExtra(FlowGraphSerializer* s) {
+ TemplateInstruction::WriteExtra(s);
+ s->WriteGrowableArrayOfRefs<TargetEntryInstr*>(successors_);
+}
+
+void IndirectGotoInstr::ReadExtra(FlowGraphDeserializer* d) {
+ TemplateInstruction::ReadExtra(d);
+ successors_ = d->ReadGrowableArrayOfRefs<TargetEntryInstr*>();
+}
+
+template <>
+void FlowGraphSerializer::Write<Instruction*>(Instruction* x) {
+ if (x == nullptr) {
+ Write<uint8_t>(Instruction::kNumInstructions);
+ } else {
+ Write<uint8_t>(static_cast<uint8_t>(x->tag()));
+ x->WriteTo(this);
+ }
+}
+
+template <>
+Instruction* FlowGraphDeserializer::Read<Instruction*>() {
+ const uint8_t tag = Read<uint8_t>();
+ switch (tag) {
+#define READ_INSTRUCTION(type, attrs) \
+ case Instruction::k##type: \
+ return new (Z) type##Instr(this);
+ FOR_EACH_INSTRUCTION(READ_INSTRUCTION)
+#undef READ_INSTRUCTION
+ case Instruction::kNumInstructions:
+ return nullptr;
+ }
+ UNREACHABLE();
+ return nullptr;
+}
+
+void Instruction::WriteTo(FlowGraphSerializer* s) {
+ s->Write<intptr_t>(deopt_id_);
+ s->Write<intptr_t>(inlining_id_);
+}
+
+Instruction::Instruction(FlowGraphDeserializer* d)
+ : deopt_id_(d->Read<intptr_t>()), inlining_id_(d->Read<intptr_t>()) {}
+
+void Instruction::WriteExtra(FlowGraphSerializer* s) {
+ for (intptr_t i = 0, n = InputCount(); i < n; ++i) {
+ s->Write<Value*>(InputAt(i));
+ }
+ WriteExtraWithoutInputs(s);
+}
+
+void Instruction::ReadExtra(FlowGraphDeserializer* d) {
+ for (intptr_t i = 0, n = InputCount(); i < n; ++i) {
+ SetInputAt(i, d->Read<Value*>());
+ }
+ for (intptr_t i = InputCount() - 1; i >= 0; --i) {
+ Value* input = InputAt(i);
+ input->definition()->AddInputUse(input);
+ }
+ ReadExtraWithoutInputs(d);
+}
+
+void Instruction::WriteExtraWithoutInputs(FlowGraphSerializer* s) {
+ s->Write<Environment*>(env_);
+ s->Write<LocationSummary*>(locs_);
+}
+
+void Instruction::ReadExtraWithoutInputs(FlowGraphDeserializer* d) {
+ Environment* env = d->Read<Environment*>();
+ SetEnvironment(env);
+ locs_ = d->Read<LocationSummary*>();
+}
+
+#define INSTRUCTIONS_SERIALIZABLE_AS_INSTRUCTION(V) \
+ V(Comparison, ComparisonInstr) \
+ V(Constant, ConstantInstr) \
+ V(Definition, Definition) \
+ V(ParallelMove, ParallelMoveInstr) \
+ V(Phi, PhiInstr)
+
+#define SERIALIZABLE_AS_INSTRUCTION(name, type) \
+ template <> \
+ void FlowGraphSerializer::Write<type*>(type * x) { \
+ Write<Instruction*>(x); \
+ } \
+ template <> \
+ type* FlowGraphDeserializer::Read<type*>() { \
+ Instruction* instr = Read<Instruction*>(); \
+ ASSERT((instr == nullptr) || instr->Is##name()); \
+ return static_cast<type*>(instr); \
+ }
+
+INSTRUCTIONS_SERIALIZABLE_AS_INSTRUCTION(SERIALIZABLE_AS_INSTRUCTION)
+#undef SERIALIZABLE_AS_INSTRUCTION
+#undef INSTRUCTIONS_SERIALIZABLE_AS_INSTRUCTION
+
+template <>
+void FlowGraphSerializer::Write<int8_t>(int8_t x) {
+ stream_->Write<int8_t>(x);
+}
+
+template <>
+int8_t FlowGraphDeserializer::Read<int8_t>() {
+ return stream_->Read<int8_t>();
+}
+
+template <>
+void FlowGraphSerializer::Write<int16_t>(int16_t x) {
+ stream_->Write<int16_t>(x);
+}
+
+template <>
+int16_t FlowGraphDeserializer::Read<int16_t>() {
+ return stream_->Read<int16_t>();
+}
+
+template <>
+void FlowGraphSerializer::Write<int32_t>(int32_t x) {
+ stream_->Write<int32_t>(x);
+}
+
+template <>
+int32_t FlowGraphDeserializer::Read<int32_t>() {
+ return stream_->Read<int32_t>();
+}
+
+template <>
+void FlowGraphSerializer::Write<int64_t>(int64_t x) {
+ stream_->Write<int64_t>(x);
+}
+
+template <>
+int64_t FlowGraphDeserializer::Read<int64_t>() {
+ return stream_->Read<int64_t>();
+}
+
+void JoinEntryInstr::WriteExtra(FlowGraphSerializer* s) {
+ BlockEntryInstr::WriteExtra(s);
+ if (phis_ != nullptr) {
+ for (PhiInstr* phi : *phis_) {
+ phi->WriteExtra(s);
+ }
+ }
+}
+
+void JoinEntryInstr::ReadExtra(FlowGraphDeserializer* d) {
+ BlockEntryInstr::ReadExtra(d);
+ if (phis_ != nullptr) {
+ for (PhiInstr* phi : *phis_) {
+ phi->ReadExtra(d);
+ }
+ }
+}
+
+template <>
+void FlowGraphSerializer::Write<const LocalVariable&>(const LocalVariable& x) {
+ UNIMPLEMENTED();
+}
+
+template <>
+const LocalVariable& FlowGraphDeserializer::Read<const LocalVariable&>() {
+ UNIMPLEMENTED();
+ return *parsed_function().receiver_var();
+}
+
+void Location::Write(FlowGraphSerializer* s) const {
+ if (IsPairLocation()) {
+ s->Write<uword>(value_ & kLocationTagMask);
+ PairLocation* pair = AsPairLocation();
+ pair->At(0).Write(s);
+ pair->At(1).Write(s);
+ } else if (IsConstant()) {
+ s->Write<uword>(value_ & kLocationTagMask);
+ s->WriteRef<Definition*>(constant_instruction());
+ } else {
+ s->Write<uword>(value_);
+ }
+}
+
+Location Location::Read(FlowGraphDeserializer* d) {
+ const uword value = d->Read<uword>();
+ if (value == kPairLocationTag) {
+ return Location::Pair(Location::Read(d), Location::Read(d));
+ } else if ((value & kConstantTag) == kConstantTag) {
+ ConstantInstr* instr = d->ReadRef<Definition*>()->AsConstant();
+ ASSERT(instr != nullptr);
+ const int pair_index = (value & kPairLocationTag) != 0 ? 1 : 0;
+ return Location::Constant(instr, pair_index);
+ } else {
+ return Location(value);
+ }
+}
+
+template <>
+void FlowGraphSerializer::Write<LocationSummary*>(LocationSummary* x) {
+ ASSERT(can_write_refs());
+ if (x == nullptr) {
+ Write<bool>(false);
+ } else {
+ Write<bool>(true);
+ x->Write(this);
+ }
+}
+
+template <>
+LocationSummary* FlowGraphDeserializer::Read<LocationSummary*>() {
+ if (!Read<bool>()) {
+ return nullptr;
+ }
+ return new (Z) LocationSummary(this);
+}
+
+void LocationSummary::Write(FlowGraphSerializer* s) const {
+ s->Write<intptr_t>(input_count());
+ s->Write<intptr_t>(temp_count());
+ s->Write<int8_t>(static_cast<int8_t>(contains_call_));
+ live_registers_.Write(s);
+
+ for (intptr_t i = 0, n = input_count(); i < n; ++i) {
+ in(i).Write(s);
+ }
+ for (intptr_t i = 0, n = temp_count(); i < n; ++i) {
+ temp(i).Write(s);
+ }
+ ASSERT(output_count() == 1);
+ out(0).Write(s);
+
+ if ((stack_bitmap_ != nullptr) && (stack_bitmap_->Length() != 0)) {
+ s->Write<int8_t>(1);
+ stack_bitmap_->Write(s->stream());
+ } else {
+ s->Write<int8_t>(0);
+ }
+
+#if defined(DEBUG)
+ s->Write<intptr_t>(writable_inputs_);
+#endif
+}
+
+LocationSummary::LocationSummary(FlowGraphDeserializer* d)
+ : num_inputs_(d->Read<intptr_t>()),
+ num_temps_(d->Read<intptr_t>()),
+ output_location_(),
+ stack_bitmap_(nullptr),
+ contains_call_(static_cast<ContainsCall>(d->Read<int8_t>())),
+ live_registers_(d) {
+ input_locations_ = d->zone()->Alloc<Location>(num_inputs_);
+ for (intptr_t i = 0; i < num_inputs_; ++i) {
+ input_locations_[i] = Location::Read(d);
+ }
+ temp_locations_ = d->zone()->Alloc<Location>(num_temps_);
+ for (intptr_t i = 0; i < num_temps_; ++i) {
+ temp_locations_[i] = Location::Read(d);
+ }
+ output_location_ = Location::Read(d);
+
+ if (d->Read<int8_t>() != 0) {
+ EnsureStackBitmap().Read(d->stream());
+ }
+
+#if defined(DEBUG)
+ writable_inputs_ = d->Read<intptr_t>();
+#endif
+}
+
+void MakeTempInstr::WriteExtra(FlowGraphSerializer* s) {
+ TemplateDefinition::WriteExtra(s);
+ null_->WriteExtra(s);
+}
+
+void MakeTempInstr::ReadExtra(FlowGraphDeserializer* d) {
+ TemplateDefinition::ReadExtra(d);
+ null_->ReadExtra(d);
+}
+
+void MaterializeObjectInstr::WriteExtra(FlowGraphSerializer* s) {
+ VariadicDefinition::WriteExtra(s);
+ for (intptr_t i = 0, n = InputCount(); i < n; ++i) {
+ locations_[i].Write(s);
+ }
+}
+
+void MaterializeObjectInstr::ReadExtra(FlowGraphDeserializer* d) {
+ VariadicDefinition::ReadExtra(d);
+ locations_ = d->zone()->Alloc<Location>(InputCount());
+ for (intptr_t i = 0, n = InputCount(); i < n; ++i) {
+ locations_[i] = Location::Read(d);
+ }
+}
+
+template <>
+void FlowGraphSerializer::Write<MoveOperands*>(MoveOperands* x) {
+ ASSERT(x != nullptr);
+ x->src().Write(this);
+ x->dest().Write(this);
+}
+
+template <>
+MoveOperands* FlowGraphDeserializer::Read<MoveOperands*>() {
+ Location src = Location::Read(this);
+ Location dest = Location::Read(this);
+ return new (Z) MoveOperands(dest, src);
+}
+
+template <>
+void FlowGraphSerializer::Write<const compiler::ffi::NativeCallingConvention&>(
+ const compiler::ffi::NativeCallingConvention& x) {
+ // A subset of NativeCallingConvention currently used by CCallInstr.
+ const auto& args = x.argument_locations();
+ for (intptr_t i = 0, n = args.length(); i < n; ++i) {
+ if (args.At(i)->payload_type().AsRepresentation() != kUnboxedFfiIntPtr) {
+ UNIMPLEMENTED();
+ }
+ }
+ if (x.return_location().payload_type().AsRepresentation() !=
+ kUnboxedFfiIntPtr) {
+ UNIMPLEMENTED();
+ }
+ Write<intptr_t>(args.length());
+}
+
+template <>
+const compiler::ffi::NativeCallingConvention&
+FlowGraphDeserializer::Read<const compiler::ffi::NativeCallingConvention&>() {
+ const intptr_t num_args = Read<intptr_t>();
+ const auto& native_function_type =
+ *compiler::ffi::NativeFunctionType::FromUnboxedRepresentation(
+ Z, num_args, kUnboxedFfiIntPtr);
+ return compiler::ffi::NativeCallingConvention::FromSignature(
+ Z, native_function_type);
+}
+
+template <>
+void FlowGraphSerializer::Write<const Object&>(const Object& x) {
+ const intptr_t cid = x.GetClassId();
+ ASSERT(cid != kIllegalCid);
+ // Do not write objects repeatedly.
+ const intptr_t object_id = heap_->GetObjectId(x.ptr());
+ if (object_id != 0) {
+ const intptr_t object_index = object_id - 1;
+ Write<intptr_t>(kIllegalCid);
+ Write<intptr_t>(object_index);
+ return;
+ }
+ const intptr_t object_index = object_counter_++;
+ heap_->SetObjectId(x.ptr(), object_index + 1);
+ Write<intptr_t>(cid);
+ WriteObjectImpl(x, cid, object_index);
+}
+
+template <>
+const Object& FlowGraphDeserializer::Read<const Object&>() {
+ const intptr_t cid = Read<intptr_t>();
+ if (cid == kIllegalCid) {
+ const intptr_t object_index = Read<intptr_t>();
+ return *objects_[object_index];
+ }
+ const intptr_t object_index = object_counter_;
+ object_counter_++;
+ const Object& result = ReadObjectImpl(cid, object_index);
+ SetObjectAt(object_index, result);
+ return result;
+}
+
+void FlowGraphDeserializer::SetObjectAt(intptr_t object_index,
+ const Object& object) {
+ objects_.EnsureLength(object_index + 1, &Object::null_object());
+ objects_[object_index] = &object;
+}
+
+void FlowGraphSerializer::WriteObjectImpl(const Object& x,
+ intptr_t cid,
+ intptr_t object_index) {
+ switch (cid) {
+ case kArrayCid:
+ case kImmutableArrayCid: {
+ const auto& array = Array::Cast(x);
+ const intptr_t len = array.Length();
+ Write<intptr_t>(len);
+ const auto& type_args =
+ TypeArguments::Handle(Z, array.GetTypeArguments());
+ Write<const TypeArguments&>(type_args);
+ if ((len == 0) && type_args.IsNull()) {
+ break;
+ }
+ Write<bool>(array.IsCanonical());
+ auto& elem = Object::Handle(Z);
+ for (intptr_t i = 0; i < len; ++i) {
+ elem = array.At(i);
+ Write<const Object&>(elem);
+ }
+ break;
+ }
+ case kBoolCid:
+ Write<bool>(Bool::Cast(x).value());
+ break;
+ case kClosureCid: {
+ const auto& closure = Closure::Cast(x);
+ if (closure.context() != Object::null()) {
+ UNIMPLEMENTED();
+ }
+ ASSERT(closure.IsCanonical());
+ auto& type_args = TypeArguments::Handle(Z);
+ type_args = closure.instantiator_type_arguments();
+ Write<const TypeArguments&>(type_args);
+ type_args = closure.function_type_arguments();
+ Write<const TypeArguments&>(type_args);
+ type_args = closure.delayed_type_arguments();
+ Write<const TypeArguments&>(type_args);
+ Write<const Function&>(Function::Handle(Z, closure.function()));
+ break;
+ }
+ case kDoubleCid:
+ ASSERT(x.IsCanonical());
+ Write<double>(Double::Cast(x).value());
+ break;
+ case kFieldCid: {
+ const auto& field = Field::Cast(x);
+ const auto& owner = Class::Handle(Z, field.Owner());
+ Write<classid_t>(owner.id());
+ const intptr_t field_index = owner.FindFieldIndex(field);
+ ASSERT(field_index >= 0);
+ Write<intptr_t>(field_index);
+ break;
+ }
+ case kFunctionCid:
+ Write<const Function&>(Function::Cast(x));
+ break;
+ case kFunctionTypeCid: {
+ const auto& type = FunctionType::Cast(x);
+ ASSERT(type.IsFinalized());
+ TypeScope type_scope(this, type.IsRecursive());
+ Write<int8_t>(static_cast<int8_t>(type.nullability()));
+ Write<uint32_t>(type.packed_parameter_counts());
+ Write<uint16_t>(type.packed_type_parameter_counts());
+ Write<const TypeParameters&>(
+ TypeParameters::Handle(Z, type.type_parameters()));
+ AbstractType& t = AbstractType::Handle(Z, type.result_type());
+ Write<const AbstractType&>(t);
+ // Do not write parameter types as Array to avoid eager canonicalization
+ // when reading.
+ const Array& param_types = Array::Handle(Z, type.parameter_types());
+ ASSERT(param_types.Length() == type.NumParameters());
+ for (intptr_t i = 0, n = type.NumParameters(); i < n; ++i) {
+ t ^= param_types.At(i);
+ Write<const AbstractType&>(t);
+ }
+ Write<const Array&>(Array::Handle(Z, type.named_parameter_names()));
+ Write<bool>(type_scope.CanBeCanonicalized());
+ break;
+ }
+ case kICDataCid: {
+ const auto& icdata = ICData::Cast(x);
+ Write<int8_t>(static_cast<int8_t>(icdata.rebind_rule()));
+ Write<const Function&>(Function::Handle(Z, icdata.Owner()));
+ Write<const Array&>(Array::Handle(Z, icdata.arguments_descriptor()));
+ Write<intptr_t>(icdata.deopt_id());
+ Write<intptr_t>(icdata.NumArgsTested());
+ if (icdata.rebind_rule() == ICData::kStatic) {
+ ASSERT(icdata.NumberOfChecks() == 1);
+ Write<const Function&>(Function::Handle(Z, icdata.GetTargetAt(0)));
+ } else if (icdata.rebind_rule() == ICData::kInstance) {
+ if (icdata.NumberOfChecks() != 0) {
+ UNIMPLEMENTED();
+ }
+ Write<const String&>(String::Handle(Z, icdata.target_name()));
+ } else {
+ UNIMPLEMENTED();
+ }
+ break;
+ }
+ case kImmutableLinkedHashMapCid:
+ case kImmutableLinkedHashSetCid: {
+ const auto& map = LinkedHashBase::Cast(x);
+ ASSERT(map.IsCanonical());
+ const intptr_t length = map.Length();
+ Write<intptr_t>(length);
+ Write<const TypeArguments&>(
+ TypeArguments::Handle(Z, map.GetTypeArguments()));
+ const auto& data = Array::Handle(Z, map.data());
+ auto& elem = Object::Handle(Z);
+ intptr_t used_data;
+ if (cid == kImmutableLinkedHashMapCid) {
+ used_data = length << 1;
+ } else {
+ used_data = length;
+ }
+ for (intptr_t i = 0; i < used_data; ++i) {
+ elem = data.At(i);
+ Write<const Object&>(elem);
+ }
+ break;
+ }
+ case kLibraryPrefixCid: {
+ const auto& prefix = LibraryPrefix::Cast(x);
+ const Library& library = Library::Handle(Z, prefix.importer());
+ Write<classid_t>(Class::Handle(Z, library.toplevel_class()).id());
+ Write<const String&>(String::Handle(Z, prefix.name()));
+ break;
+ }
+ case kMintCid:
+ ASSERT(x.IsCanonical());
+ Write<int64_t>(Integer::Cast(x).AsInt64Value());
+ break;
+ case kNullCid:
+ break;
+ case kOneByteStringCid: {
+ ASSERT(x.IsCanonical());
+ const auto& str = String::Cast(x);
+ const intptr_t length = str.Length();
+ Write<intptr_t>(length);
+ NoSafepointScope no_safepoint;
+ uint8_t* latin1 = OneByteString::DataStart(str);
+ stream_->WriteBytes(latin1, length);
+ break;
+ }
+ case kSentinelCid:
+ if (x.ptr() == Object::sentinel().ptr()) {
+ Write<bool>(true);
+ } else if (x.ptr() == Object::transition_sentinel().ptr()) {
+ Write<bool>(false);
+ } else {
+ UNIMPLEMENTED();
+ }
+ break;
+ case kSmiCid:
+ Write<intptr_t>(Smi::Cast(x).Value());
+ break;
+ case kTwoByteStringCid: {
+ ASSERT(x.IsCanonical());
+ const auto& str = String::Cast(x);
+ const intptr_t length = str.Length();
+ Write<intptr_t>(length);
+ NoSafepointScope no_safepoint;
+ uint16_t* utf16 = TwoByteString::DataStart(str);
+ stream_->WriteBytes(reinterpret_cast<const uint8_t*>(utf16),
+ length * sizeof(uint16_t));
+ break;
+ }
+ case kTypeCid: {
+ const auto& type = Type::Cast(x);
+ ASSERT(type.IsFinalized());
+ const auto& cls = Class::Handle(Z, type.type_class());
+ TypeScope type_scope(this, type.IsRecursive() && cls.IsGeneric());
+ Write<int8_t>(static_cast<int8_t>(type.nullability()));
+ Write<classid_t>(type.type_class_id());
+ if (cls.IsGeneric()) {
+ const auto& type_args = TypeArguments::Handle(Z, type.arguments());
+ Write<const TypeArguments&>(type_args);
+ }
+ Write<bool>(type_scope.CanBeCanonicalized());
+ break;
+ }
+ case kTypeArgumentsCid: {
+ const auto& type_args = TypeArguments::Cast(x);
+ ASSERT(type_args.IsFinalized());
+ TypeScope type_scope(this, type_args.IsRecursive());
+ const intptr_t len = type_args.Length();
+ Write<intptr_t>(len);
+ auto& type = AbstractType::Handle(Z);
+ for (intptr_t i = 0; i < len; ++i) {
+ type = type_args.TypeAt(i);
+ Write<const AbstractType&>(type);
+ }
+ Write<bool>(type_scope.CanBeCanonicalized());
+ break;
+ }
+ case kTypeParameterCid: {
+ const auto& tp = TypeParameter::Cast(x);
+ ASSERT(tp.IsFinalized());
+ TypeScope type_scope(this, tp.IsRecursive());
+ Write<classid_t>(tp.parameterized_class_id());
+ Write<intptr_t>(tp.base());
+ Write<intptr_t>(tp.index());
+ Write<int8_t>(static_cast<int8_t>(tp.nullability()));
+ Write<const AbstractType&>(AbstractType::Handle(Z, tp.bound()));
+ Write<bool>(type_scope.CanBeCanonicalized());
+ break;
+ }
+ case kTypeParametersCid: {
+ const auto& tps = TypeParameters::Cast(x);
+ Write<const Array&>(Array::Handle(Z, tps.names()));
+ Write<const Array&>(Array::Handle(Z, tps.flags()));
+ Write<const TypeArguments&>(TypeArguments::Handle(Z, tps.bounds()));
+ Write<const TypeArguments&>(TypeArguments::Handle(Z, tps.defaults()));
+ break;
+ }
+ case kTypeRefCid: {
+ const auto& tr = TypeRef::Cast(x);
+ ASSERT(tr.IsFinalized());
+ TypeScope type_scope(this, tr.IsRecursive());
+ Write<const AbstractType&>(AbstractType::Handle(Z, tr.type()));
+ Write<bool>(type_scope.CanBeCanonicalized());
+ break;
+ }
+ default: {
+ const classid_t cid = x.GetClassId();
+ if ((cid >= kNumPredefinedCids) || (cid == kInstanceCid)) {
+ const auto& instance = Instance::Cast(x);
+ ASSERT(instance.IsCanonical());
+ const auto& cls =
+ Class::Handle(Z, isolate_group()->class_table()->At(cid));
+ const auto unboxed_fields_bitmap =
+ isolate_group()->shared_class_table()->GetUnboxedFieldsMapAt(cid);
+ const intptr_t next_field_offset = cls.host_next_field_offset();
+ auto& obj = Object::Handle(Z);
+ for (intptr_t offset = Instance::NextFieldOffset();
+ offset < next_field_offset; offset += kCompressedWordSize) {
+ if (unboxed_fields_bitmap.Get(offset / kCompressedWordSize)) {
+ if (kCompressedWordSize == 8) {
+ Write<int64_t>(*reinterpret_cast<int64_t*>(
+ instance.RawFieldAddrAtOffset(offset)));
+ } else {
+ Write<int32_t>(*reinterpret_cast<int32_t*>(
+ instance.RawFieldAddrAtOffset(offset)));
+ }
+ } else {
+ obj = instance.RawGetFieldAtOffset(offset);
+ Write<const Object&>(obj);
+ }
+ }
+ break;
+ }
+ FATAL("Unimplemented WriteObjectImpl for %s", x.ToCString());
+ }
+ }
+}
+
+const Object& FlowGraphDeserializer::ReadObjectImpl(intptr_t cid,
+ intptr_t object_index) {
+ switch (cid) {
+ case kArrayCid:
+ case kImmutableArrayCid: {
+ const intptr_t len = Read<intptr_t>();
+ const auto& type_args = Read<const TypeArguments&>();
+ if ((len == 0) && type_args.IsNull()) {
+ return Object::empty_array();
+ }
+ const bool canonicalize = Read<bool>();
+ auto& array = Array::ZoneHandle(
+ Z, Array::New(len, canonicalize ? Heap::kNew : Heap::kOld));
+ if (!type_args.IsNull()) {
+ array.SetTypeArguments(type_args);
+ }
+ for (intptr_t i = 0; i < len; ++i) {
+ array.SetAt(i, Read<const Object&>());
+ }
+ if (cid == kImmutableArrayCid) {
+ array.MakeImmutable();
+ }
+ if (canonicalize) {
+ array ^= array.Canonicalize(thread());
+ }
+ return array;
+ }
+ case kBoolCid:
+ return Bool::Get(Read<bool>());
+ case kClosureCid: {
+ const auto& instantiator_type_arguments = Read<const TypeArguments&>();
+ const auto& function_type_arguments = Read<const TypeArguments&>();
+ const auto& delayed_type_arguments = Read<const TypeArguments&>();
+ const auto& function = Read<const Function&>();
+ auto& closure = Closure::ZoneHandle(
+ Z,
+ Closure::New(instantiator_type_arguments, function_type_arguments,
+ delayed_type_arguments, function, Context::Handle(Z)));
+ closure ^= closure.Canonicalize(thread());
+ return closure;
+ }
+ case kDoubleCid:
+ return Double::ZoneHandle(Z, Double::NewCanonical(Read<double>()));
+ case kFieldCid: {
+ const classid_t owner_class_id = Read<classid_t>();
+ const intptr_t field_index = Read<intptr_t>();
+ const auto& owner = Class::Handle(Z, GetClassById(owner_class_id));
+ auto& result = Field::ZoneHandle(Z, owner.FieldFromIndex(field_index));
+ ASSERT(!result.IsNull());
+ return result;
+ }
+ case kFunctionCid:
+ return Read<const Function&>();
+ case kFunctionTypeCid: {
+ const Nullability nullability = static_cast<Nullability>(Read<int8_t>());
+ auto& result =
+ FunctionType::ZoneHandle(Z, FunctionType::New(0, nullability));
+ SetObjectAt(object_index, result);
+ result.set_packed_parameter_counts(Read<uint32_t>());
+ result.set_packed_type_parameter_counts(Read<uint16_t>());
+ result.SetTypeParameters(Read<const TypeParameters&>());
+ result.set_result_type(Read<const AbstractType&>());
+ const Array& param_types =
+ Array::Handle(Z, Array::New(result.NumParameters(), Heap::kOld));
+ for (intptr_t i = 0, n = result.NumParameters(); i < n; ++i) {
+ param_types.SetAt(i, Read<const AbstractType&>());
+ }
+ result.set_parameter_types(param_types);
+ result.set_named_parameter_names(Read<const Array&>());
+ result.SetIsFinalized();
+ result ^= MaybeCanonicalize(result, object_index, Read<bool>());
+ return result;
+ }
+ case kICDataCid: {
+ const ICData::RebindRule rebind_rule =
+ static_cast<ICData::RebindRule>(Read<int8_t>());
+ const auto& owner = Read<const Function&>();
+ const auto& arguments_descriptor = Read<const Array&>();
+ const intptr_t deopt_id = Read<intptr_t>();
+ const intptr_t num_args_tested = Read<intptr_t>();
+
+ if (rebind_rule == ICData::kStatic) {
+ const auto& target = Read<const Function&>();
+ return ICData::ZoneHandle(
+ Z,
+ ICData::NewForStaticCall(owner, target, arguments_descriptor,
+ deopt_id, num_args_tested, rebind_rule));
+ } else if (rebind_rule == ICData::kInstance) {
+ const auto& target_name = Read<const String&>();
+ return ICData::ZoneHandle(
+ Z, ICData::New(owner, target_name, arguments_descriptor, deopt_id,
+ num_args_tested, rebind_rule));
+ } else {
+ UNIMPLEMENTED();
+ }
+ break;
+ }
+ case kImmutableLinkedHashMapCid:
+ case kImmutableLinkedHashSetCid: {
+ const intptr_t length = Read<intptr_t>();
+ const auto& type_args = Read<const TypeArguments&>();
+ Instance& result = Instance::ZoneHandle(Z);
+ intptr_t used_data;
+ if (cid == kImmutableLinkedHashMapCid) {
+ result = ImmutableLinkedHashMap::NewUninitialized(Heap::kOld);
+ used_data = (length << 1);
+ } else {
+ result = ImmutableLinkedHashSet::NewUninitialized(Heap::kOld);
+ used_data = length;
+ }
+ // LinkedHashBase is not a proper handle type, so
+ // cannot create a LinkedHashBase handle upfront.
+ const LinkedHashBase& map = LinkedHashBase::Cast(result);
+ map.SetTypeArguments(type_args);
+ map.set_used_data(used_data);
+ const auto& data = Array::Handle(Z, Array::New(used_data));
+ map.set_data(data);
+ map.set_deleted_keys(0);
+ map.ComputeAndSetHashMask();
+ for (intptr_t i = 0; i < used_data; ++i) {
+ data.SetAt(i, Read<const Object&>());
+ }
+ result ^= result.Canonicalize(thread());
+ return result;
+ }
+ case kLibraryPrefixCid: {
+ const Class& toplevel_class =
+ Class::Handle(Z, GetClassById(Read<classid_t>()));
+ const Library& library = Library::Handle(Z, toplevel_class.library());
+ const String& name = Read<const String&>();
+ const auto& prefix =
+ LibraryPrefix::ZoneHandle(Z, library.LookupLocalLibraryPrefix(name));
+ ASSERT(!prefix.IsNull());
+ return prefix;
+ }
+ case kMintCid: {
+ const int64_t value = Read<int64_t>();
+ return Integer::ZoneHandle(Z, Integer::NewCanonical(value));
+ }
+ case kNullCid:
+ return Object::null_object();
+ case kOneByteStringCid: {
+ const intptr_t length = Read<intptr_t>();
+ uint8_t* latin1 = Z->Alloc<uint8_t>(length);
+ stream_->ReadBytes(latin1, length);
+ return String::ZoneHandle(Z,
+ Symbols::FromLatin1(thread(), latin1, length));
+ }
+ case kSentinelCid:
+ return Read<bool>() ? Object::sentinel() : Object::transition_sentinel();
+ case kSmiCid:
+ return Smi::ZoneHandle(Z, Smi::New(Read<intptr_t>()));
+ case kTwoByteStringCid: {
+ const intptr_t length = Read<intptr_t>();
+ uint16_t* utf16 = Z->Alloc<uint16_t>(length);
+ stream_->ReadBytes(reinterpret_cast<uint8_t*>(utf16),
+ length * sizeof(uint16_t));
+ return String::ZoneHandle(Z, Symbols::FromUTF16(thread(), utf16, length));
+ }
+ case kTypeCid: {
+ const Nullability nullability = static_cast<Nullability>(Read<int8_t>());
+ const classid_t type_class_id = Read<classid_t>();
+ const auto& cls = Class::Handle(Z, GetClassById(type_class_id));
+ auto& result = Type::ZoneHandle(Z);
+ if (cls.IsGeneric()) {
+ result = Type::New(cls, Object::null_type_arguments(), nullability);
+ SetObjectAt(object_index, result);
+ const auto& type_args = Read<const TypeArguments&>();
+ result.set_arguments(type_args);
+ result.SetIsFinalized();
+ } else {
+ result = cls.DeclarationType();
+ result = result.ToNullability(nullability, Heap::kOld);
+ }
+ result ^= MaybeCanonicalize(result, object_index, Read<bool>());
+ return result;
+ }
+ case kTypeArgumentsCid: {
+ const intptr_t len = Read<intptr_t>();
+ auto& type_args = TypeArguments::ZoneHandle(Z, TypeArguments::New(len));
+ SetObjectAt(object_index, type_args);
+ for (intptr_t i = 0; i < len; ++i) {
+ type_args.SetTypeAt(i, Read<const AbstractType&>());
+ }
+ type_args ^= MaybeCanonicalize(type_args, object_index, Read<bool>());
+ return type_args;
+ }
+ case kTypeParameterCid: {
+ const classid_t parameterized_class_id = Read<classid_t>();
+ const intptr_t base = Read<intptr_t>();
+ const intptr_t index = Read<intptr_t>();
+ const Nullability nullability = static_cast<Nullability>(Read<int8_t>());
+ const auto& parameterized_class =
+ Class::Handle(Z, (parameterized_class_id == kFunctionCid)
+ ? Class::null()
+ : GetClassById(parameterized_class_id));
+ auto& tp = TypeParameter::ZoneHandle(
+ Z, TypeParameter::New(parameterized_class, base, index,
+ /*bound=*/Object::null_abstract_type(),
+ nullability));
+ SetObjectAt(object_index, tp);
+ const auto& bound = Read<const AbstractType&>();
+ tp.set_bound(bound);
+ tp.SetIsFinalized();
+ tp ^= MaybeCanonicalize(tp, object_index, Read<bool>());
+ return tp;
+ }
+ case kTypeParametersCid: {
+ const auto& tps = TypeParameters::ZoneHandle(Z, TypeParameters::New());
+ tps.set_names(Read<const Array&>());
+ tps.set_flags(Read<const Array&>());
+ tps.set_bounds(Read<const TypeArguments&>());
+ tps.set_defaults(Read<const TypeArguments&>());
+ return tps;
+ }
+ case kTypeRefCid: {
+ auto& tr =
+ TypeRef::ZoneHandle(Z, TypeRef::New(Object::null_abstract_type()));
+ SetObjectAt(object_index, tr);
+ const auto& type = Read<const AbstractType&>();
+ ASSERT(!type.IsNull());
+ tr.set_type(type);
+ tr ^= MaybeCanonicalize(tr, object_index, Read<bool>());
+ return tr;
+ }
+ default:
+ if ((cid >= kNumPredefinedCids) || (cid == kInstanceCid)) {
+ const auto& cls = Class::Handle(Z, GetClassById(cid));
+ const auto unboxed_fields_bitmap =
+ isolate_group()->shared_class_table()->GetUnboxedFieldsMapAt(cid);
+ const intptr_t next_field_offset = cls.host_next_field_offset();
+ auto& instance = Instance::ZoneHandle(Z, Instance::New(cls));
+ for (intptr_t offset = Instance::NextFieldOffset();
+ offset < next_field_offset; offset += kCompressedWordSize) {
+ if (unboxed_fields_bitmap.Get(offset / kCompressedWordSize)) {
+ if (kCompressedWordSize == 8) {
+ const int64_t v = Read<int64_t>();
+ *reinterpret_cast<int64_t*>(
+ instance.RawFieldAddrAtOffset(offset)) = v;
+ } else {
+ const int32_t v = Read<int32_t>();
+ *reinterpret_cast<int32_t*>(
+ instance.RawFieldAddrAtOffset(offset)) = v;
+ }
+ } else {
+ const auto& obj = Read<const Object&>();
+ instance.RawSetFieldAtOffset(offset, obj);
+ }
+ }
+ instance = instance.Canonicalize(thread());
+ return instance;
+ }
+ }
+ UNIMPLEMENTED();
+ return Object::null_object();
+}
+
+InstancePtr FlowGraphDeserializer::MaybeCanonicalize(
+ const Instance& obj,
+ intptr_t object_index,
+ bool can_be_canonicalized) {
+ if (can_be_canonicalized) {
+ intptr_t remaining = 0;
+ for (intptr_t idx : pending_canonicalization_) {
+ if (idx < object_index) {
+ pending_canonicalization_[remaining++] = idx;
+ } else {
+ objects_[idx] = &Instance::ZoneHandle(
+ Z, Instance::Cast(*objects_[idx]).Canonicalize(thread()));
+ }
+ }
+ pending_canonicalization_.TruncateTo(remaining);
+ return obj.Canonicalize(thread());
+ } else {
+ ASSERT(objects_[object_index]->ptr() == obj.ptr());
+ pending_canonicalization_.Add(object_index);
+ return obj.ptr();
+ }
+}
+
+#define HANDLES_SERIALIZABLE_AS_OBJECT(V) \
+ V(AbstractType, Object::null_abstract_type()) \
+ V(Array, Object::null_array()) \
+ V(Field, Field::Handle(Z)) \
+ V(FunctionType, Object::null_function_type()) \
+ V(String, Object::null_string()) \
+ V(TypeArguments, Object::null_type_arguments()) \
+ V(TypeParameters, TypeParameters::Handle(Z))
+
+#define SERIALIZE_HANDLE_AS_OBJECT(handle, null_handle) \
+ template <> \
+ void FlowGraphSerializer::Write<const handle&>(const handle& x) { \
+ Write<const Object&>(x); \
+ } \
+ template <> \
+ const handle& FlowGraphDeserializer::Read<const handle&>() { \
+ const Object& result = Read<const Object&>(); \
+ if (result.IsNull()) { \
+ return null_handle; \
+ } \
+ return handle::Cast(result); \
+ }
+
+HANDLES_SERIALIZABLE_AS_OBJECT(SERIALIZE_HANDLE_AS_OBJECT)
+#undef SERIALIZE_HANDLE_AS_OBJECT
+#undef HANDLES_SERIALIZABLE_AS_OBJECT
+
+void OsrEntryInstr::WriteTo(FlowGraphSerializer* s) {
+ BlockEntryWithInitialDefs::WriteTo(s);
+}
+
+OsrEntryInstr::OsrEntryInstr(FlowGraphDeserializer* d)
+ : BlockEntryWithInitialDefs(d), graph_entry_(d->graph_entry()) {}
+
+void ParallelMoveInstr::WriteExtra(FlowGraphSerializer* s) {
+ Instruction::WriteExtra(s);
+ s->Write<GrowableArray<MoveOperands*>>(moves_);
+}
+
+void ParallelMoveInstr::ReadExtra(FlowGraphDeserializer* d) {
+ Instruction::ReadExtra(d);
+ moves_ = d->Read<GrowableArray<MoveOperands*>>();
+}
+
+void PhiInstr::WriteTo(FlowGraphSerializer* s) {
+ VariadicDefinition::WriteTo(s);
+ s->Write<Representation>(representation_);
+ s->Write<bool>(is_alive_);
+ s->Write<int8_t>(is_receiver_);
+}
+
+PhiInstr::PhiInstr(FlowGraphDeserializer* d)
+ : VariadicDefinition(d),
+ block_(d->current_block()->AsJoinEntry()),
+ representation_(d->Read<Representation>()),
+ is_alive_(d->Read<bool>()),
+ is_receiver_(d->Read<int8_t>()) {}
+
+template <>
+void FlowGraphSerializer::Write<Range*>(Range* x) {
+ if (x == nullptr) {
+ Write<bool>(false);
+ } else {
+ Write<bool>(true);
+ x->Write(this);
+ }
+}
+
+template <>
+Range* FlowGraphDeserializer::Read<Range*>() {
+ if (!Read<bool>()) {
+ return nullptr;
+ }
+ return new (Z) Range(this);
+}
+
+void Range::Write(FlowGraphSerializer* s) const {
+ min_.Write(s);
+ max_.Write(s);
+}
+
+Range::Range(FlowGraphDeserializer* d)
+ : min_(RangeBoundary(d)), max_(RangeBoundary(d)) {}
+
+void RangeBoundary::Write(FlowGraphSerializer* s) const {
+ s->Write<int8_t>(kind_);
+ s->Write<int64_t>(value_);
+ s->Write<int64_t>(offset_);
+}
+
+RangeBoundary::RangeBoundary(FlowGraphDeserializer* d)
+ : kind_(static_cast<Kind>(d->Read<int8_t>())),
+ value_(d->Read<int64_t>()),
+ offset_(d->Read<int64_t>()) {}
+
+void RegisterSet::Write(FlowGraphSerializer* s) const {
+ s->Write<uintptr_t>(cpu_registers_.data());
+ s->Write<uintptr_t>(untagged_cpu_registers_.data());
+ s->Write<uintptr_t>(fpu_registers_.data());
+}
+
+RegisterSet::RegisterSet(FlowGraphDeserializer* d)
+ : cpu_registers_(d->Read<uintptr_t>()),
+ untagged_cpu_registers_(d->Read<uintptr_t>()),
+ fpu_registers_(d->Read<uintptr_t>()) {}
+
+template <>
+void FlowGraphSerializer::Write<Representation>(Representation x) {
+ Write<uint8_t>(x);
+}
+
+template <>
+Representation FlowGraphDeserializer::Read<Representation>() {
+ return static_cast<Representation>(Read<uint8_t>());
+}
+
+template <>
+void FlowGraphSerializer::Write<const Slot&>(const Slot& x) {
+ x.Write(this);
+}
+
+template <>
+const Slot& FlowGraphDeserializer::Read<const Slot&>() {
+ return Slot::Read(this);
+}
+
+template <>
+void FlowGraphSerializer::Write<const Slot*>(const Slot* x) {
+ if (x == nullptr) {
+ Write<bool>(false);
+ return;
+ }
+ Write<bool>(true);
+ x->Write(this);
+}
+
+template <>
+const Slot* FlowGraphDeserializer::Read<const Slot*>() {
+ if (!Read<bool>()) {
+ return nullptr;
+ }
+ return &Slot::Read(this);
+}
+
+void Slot::Write(FlowGraphSerializer* s) const {
+ s->Write<serializable_type_t<Kind>>(
+ static_cast<serializable_type_t<Kind>>(kind_));
+
+ switch (kind_) {
+ case Kind::kTypeArguments:
+ s->Write<int8_t>(flags_);
+ s->Write<intptr_t>(offset_in_bytes_);
+ break;
+ case Kind::kTypeArgumentsIndex:
+ s->Write<intptr_t>(offset_in_bytes_);
+ break;
+ case Kind::kArrayElement:
+ s->Write<intptr_t>(offset_in_bytes_);
+ break;
+ case Kind::kCapturedVariable:
+ s->Write<int8_t>(flags_);
+ s->Write<intptr_t>(offset_in_bytes_);
+ s->Write<const String&>(*DataAs<const String>());
+ s->Write<const AbstractType&>(*static_type_);
+ break;
+ case Kind::kDartField:
+ s->Write<const Field&>(field());
+ break;
+ default:
+ break;
+ }
+}
+
+const Slot& Slot::Read(FlowGraphDeserializer* d) {
+ const Kind kind = static_cast<Kind>(d->Read<serializable_type_t<Kind>>());
+ int8_t flags = 0;
+ ClassIdTagType cid = kDynamicCid;
+ intptr_t offset = -1;
+ const void* data = nullptr;
+ const AbstractType* static_type = nullptr;
+ Representation representation = kTagged;
+
+ switch (kind) {
+ case Kind::kTypeArguments:
+ flags = d->Read<int8_t>();
+ offset = d->Read<intptr_t>();
+ cid = kTypeArgumentsCid;
+ data = ":type_arguments";
+ break;
+ case Kind::kTypeArgumentsIndex:
+ flags =
+ IsImmutableBit::encode(true) |
+ IsCompressedBit::encode(TypeArguments::ContainsCompressedPointers());
+ offset = d->Read<intptr_t>();
+ data = ":argument";
+ break;
+ case Kind::kArrayElement:
+ flags = IsNullableBit::encode(true) |
+ IsCompressedBit::encode(Array::ContainsCompressedPointers());
+ offset = d->Read<intptr_t>();
+ data = ":array_element";
+ break;
+ case Kind::kCapturedVariable:
+ flags = d->Read<int8_t>();
+ offset = d->Read<intptr_t>();
+ data = &d->Read<const String&>();
+ static_type = &d->Read<const AbstractType&>();
+ break;
+ case Kind::kDartField: {
+ const Field& field = d->Read<const Field&>();
+ return Slot::Get(field, &d->parsed_function());
+ }
+ default:
+ return Slot::GetNativeSlot(kind);
+ }
+
+ return GetCanonicalSlot(d->thread(), kind, flags, cid, offset, data,
+ static_type, representation);
+}
+
+template <>
+void FlowGraphSerializer::Write<const compiler::TableSelector*>(
+ const compiler::TableSelector* x) {
+#if defined(DART_PRECOMPILER)
+ ASSERT(x != nullptr);
+ Write<int32_t>(x->id);
+#else
+ UNREACHABLE();
+#endif
+}
+
+template <>
+const compiler::TableSelector*
+FlowGraphDeserializer::Read<const compiler::TableSelector*>() {
+#if defined(DART_PRECOMPILER)
+ const int32_t id = Read<int32_t>();
+ const compiler::TableSelector* selector =
+ Precompiler::Instance()->selector_map()->GetSelector(id);
+ ASSERT(selector != nullptr);
+ return selector;
+#else
+ UNREACHABLE();
+#endif
+}
+
+void SpecialParameterInstr::WriteExtra(FlowGraphSerializer* s) {
+ TemplateDefinition::WriteExtra(s);
+ s->WriteRef<BlockEntryInstr*>(block_);
+}
+
+void SpecialParameterInstr::ReadExtra(FlowGraphDeserializer* d) {
+ TemplateDefinition::ReadExtra(d);
+ block_ = d->ReadRef<BlockEntryInstr*>();
+}
+
+template <intptr_t kExtraInputs>
+void TemplateDartCall<kExtraInputs>::WriteExtra(FlowGraphSerializer* s) {
+ VariadicDefinition::WriteExtra(s);
+ if (push_arguments_ == nullptr) {
+ s->Write<intptr_t>(-1);
+ } else {
+ s->Write<intptr_t>(push_arguments_->length());
+#if defined(DEBUG)
+ // Verify that PushArgument instructions are inserted immediately
+ // before this instruction. ReadExtra below relies on
+ // that when restoring push_arguments_.
+ Instruction* instr = this;
+ for (intptr_t i = push_arguments_->length() - 1; i >= 0; --i) {
+ do {
+ instr = instr->previous();
+ ASSERT(instr != nullptr);
+ } while (!instr->IsPushArgument());
+ ASSERT(instr == (*push_arguments_)[i]);
+ }
+#endif
+ }
+}
+
+template <intptr_t kExtraInputs>
+void TemplateDartCall<kExtraInputs>::ReadExtra(FlowGraphDeserializer* d) {
+ VariadicDefinition::ReadExtra(d);
+ const intptr_t num_push_args = d->Read<intptr_t>();
+ if (num_push_args >= 0) {
+ push_arguments_ =
+ new (d->zone()) PushArgumentsArray(d->zone(), num_push_args);
+ push_arguments_->EnsureLength(num_push_args, nullptr);
+ Instruction* instr = this;
+ for (int i = num_push_args - 1; i >= 0; --i) {
+ do {
+ instr = instr->previous();
+ ASSERT(instr != nullptr);
+ } while (!instr->IsPushArgument());
+ (*push_arguments_)[i] = instr->AsPushArgument();
+ }
+ if (env() != nullptr) {
+ RepairPushArgsInEnvironment();
+ }
+ }
+}
+
+// Explicit template instantiations, needed for the methods above.
+template class TemplateDartCall<0>;
+template class TemplateDartCall<1>;
+
+template <>
+void FlowGraphSerializer::Write<TokenPosition>(TokenPosition x) {
+ Write<int32_t>(x.Serialize());
+}
+
+template <>
+TokenPosition FlowGraphDeserializer::Read<TokenPosition>() {
+ return TokenPosition::Deserialize(Read<int32_t>());
+}
+
+template <>
+void FlowGraphSerializer::Write<uint8_t>(uint8_t x) {
+ stream_->Write<uint8_t>(x);
+}
+
+template <>
+uint8_t FlowGraphDeserializer::Read<uint8_t>() {
+ return stream_->Read<uint8_t>();
+}
+
+template <>
+void FlowGraphSerializer::Write<uint16_t>(uint16_t x) {
+ stream_->Write<uint16_t>(x);
+}
+
+template <>
+uint16_t FlowGraphDeserializer::Read<uint16_t>() {
+ return stream_->Read<uint16_t>();
+}
+
+template <>
+void FlowGraphSerializer::Write<uint32_t>(uint32_t x) {
+ stream_->Write<int32_t>(static_cast<int32_t>(x));
+}
+
+template <>
+uint32_t FlowGraphDeserializer::Read<uint32_t>() {
+ return static_cast<uint32_t>(stream_->Read<int32_t>());
+}
+
+template <>
+void FlowGraphSerializer::Write<uint64_t>(uint64_t x) {
+ stream_->Write<int64_t>(static_cast<int64_t>(x));
+}
+
+template <>
+uint64_t FlowGraphDeserializer::Read<uint64_t>() {
+ return static_cast<uint64_t>(stream_->Read<int64_t>());
+}
+
+void UnboxedConstantInstr::WriteTo(FlowGraphSerializer* s) {
+ ConstantInstr::WriteTo(s);
+ s->Write<Representation>(representation_);
+ // constant_address_ is not written - it is restored when reading.
+}
+
+UnboxedConstantInstr::UnboxedConstantInstr(FlowGraphDeserializer* d)
+ : ConstantInstr(d),
+ representation_(d->Read<Representation>()),
+ constant_address_(0) {
+ if (representation_ == kUnboxedDouble) {
+ ASSERT(value().IsDouble());
+ constant_address_ = FindDoubleConstant(Double::Cast(value()).value());
+ }
+}
+
+template <>
+void FlowGraphSerializer::Write<Value*>(Value* x) {
+ ASSERT(can_write_refs());
+ CompileType* reaching_type = x->reaching_type();
+ Definition* def = x->definition();
+ // Omit reaching type if it is the same as definition type.
+ if ((reaching_type != nullptr) && def->HasType() &&
+ (reaching_type == def->Type())) {
+ reaching_type = nullptr;
+ }
+ Write<CompileType*>(reaching_type);
+ WriteRef<Definition*>(def);
+}
+
+template <>
+Value* FlowGraphDeserializer::Read<Value*>() {
+ CompileType* type = Read<CompileType*>();
+ Definition* def = ReadRef<Definition*>();
+ Value* value = new (Z) Value(def);
+ value->SetReachingType(type);
+ return value;
+}
+
+void VariadicDefinition::WriteTo(FlowGraphSerializer* s) {
+ Definition::WriteTo(s);
+ s->Write<intptr_t>(inputs_.length());
+}
+
+VariadicDefinition::VariadicDefinition(FlowGraphDeserializer* d)
+ : Definition(d), inputs_(d->zone(), 0) {
+ const intptr_t num_inputs = d->Read<intptr_t>();
+ inputs_.EnsureLength(num_inputs, nullptr);
+}
+
+} // namespace dart
diff --git a/runtime/vm/compiler/backend/il_serializer.h b/runtime/vm/compiler/backend/il_serializer.h
new file mode 100644
index 0000000..07948c2
--- /dev/null
+++ b/runtime/vm/compiler/backend/il_serializer.h
@@ -0,0 +1,473 @@
+// Copyright (c) 2022, 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_BACKEND_IL_SERIALIZER_H_
+#define RUNTIME_VM_COMPILER_BACKEND_IL_SERIALIZER_H_
+
+#if defined(DART_PRECOMPILED_RUNTIME)
+#error "AOT runtime should not use compiler sources (including header files)"
+#endif // defined(DART_PRECOMPILED_RUNTIME)
+
+#include <utility> // For std::move.
+
+#include "platform/globals.h"
+#include "vm/allocation.h"
+#include "vm/compiler/backend/locations.h"
+
+namespace dart {
+
+class AliasIdentity;
+class BlockEntryInstr;
+class CallTargets;
+class CatchBlockEntryInstr;
+struct CidRangeValue;
+class Cids;
+class Code;
+class ComparisonInstr;
+class CompileType;
+class Definition;
+class Environment;
+class FunctionEntryInstr;
+class Instruction;
+class FlowGraph;
+class GraphEntryInstr;
+class Heap;
+class IndirectEntryInstr;
+class JoinEntryInstr;
+class LocalVariable;
+class LocationSummary;
+class MoveOperands;
+class NonStreamingWriteStream;
+class OsrEntryInstr;
+class ParsedFunction;
+class ParallelMoveInstr;
+class PhiInstr;
+class Range;
+class ReadStream;
+class TargetEntryInstr;
+class TokenPosition;
+
+namespace compiler {
+struct TableSelector;
+
+namespace ffi {
+class CallbackMarshaller;
+class CallMarshaller;
+class NativeCallingConvention;
+} // namespace ffi
+} // namespace compiler
+
+// The list of types which are handled by flow graph serializer/deserializer.
+// For each type there is a corresponding Write<T>(T) and Read<T>() methods.
+//
+// This list includes all types of fields of IL instructions
+// which are serialized via DECLARE_INSTRUCTION_SERIALIZABLE_FIELDS macro,
+// except enum types which are unwrapped with serializable_type_t.
+//
+// The list is sorted alphabetically by type name.
+#define IL_SERIALIZABLE_TYPE_LIST(V) \
+ V(AliasIdentity) \
+ V(const AbstractType&) \
+ V(const AbstractType*) \
+ V(const Array&) \
+ V(bool) \
+ V(const compiler::ffi::CallbackMarshaller&) \
+ V(const compiler::ffi::CallMarshaller&) \
+ V(const CallTargets&) \
+ V(const char*) \
+ V(CidRangeValue) \
+ V(const Cids&) \
+ V(const Class&) \
+ V(const Code&) \
+ V(ComparisonInstr*) \
+ V(CompileType*) \
+ V(ConstantInstr*) \
+ V(Definition*) \
+ V(double) \
+ V(Environment*) \
+ V(const Field&) \
+ V(const ICData*) \
+ V(int8_t) \
+ V(int16_t) \
+ V(int32_t) \
+ V(int64_t) \
+ V(const Function&) \
+ V(const FunctionType&) \
+ V(Instruction*) \
+ V(const LocalVariable&) \
+ V(LocationSummary*) \
+ V(MoveOperands*) \
+ V(const compiler::ffi::NativeCallingConvention&) \
+ V(const Object&) \
+ V(ParallelMoveInstr*) \
+ V(PhiInstr*) \
+ V(Range*) \
+ V(Representation) \
+ V(const Slot&) \
+ V(const Slot*) \
+ V(const String&) \
+ V(const compiler::TableSelector*) \
+ V(TokenPosition) \
+ V(const TypeArguments&) \
+ V(const TypeParameters&) \
+ V(uint8_t) \
+ V(uint16_t) \
+ V(uint32_t) \
+ V(uint64_t) \
+ V(Value*)
+
+// List of types serializable as references.
+#define IL_SERIALIZABLE_REF_TYPE_LIST(V) \
+ V(BlockEntryInstr*) \
+ V(CatchBlockEntryInstr*) \
+ V(Definition*) \
+ V(FunctionEntryInstr*) \
+ V(IndirectEntryInstr*) \
+ V(JoinEntryInstr*) \
+ V(OsrEntryInstr*) \
+ V(TargetEntryInstr*)
+
+// Serializes flow graph, including constants and references
+// to objects of program structure.
+//
+// Each IL instruction is serialized in 2 step:
+// - the main step (T::WriteTo / T::T()) serializes
+// instruction fields, basically everything required to
+// re-create instruction object.
+// - the extra step (T::WriteExtra / T::ReadExtra) serializes
+// references to other instructions, including inputs,
+// environments, locations (may reference constants) and successors.
+//
+class FlowGraphSerializer : public ValueObject {
+ public:
+ explicit FlowGraphSerializer(NonStreamingWriteStream* stream);
+ ~FlowGraphSerializer();
+
+ // Writes [flow_graph] into the stream.
+ // The graph should be compacted via CompactSSA().
+ // [detached_defs] should contain all definitions which are
+ // detached from the graph but can still be referenced from
+ // environments.
+ void WriteFlowGraph(const FlowGraph& flow_graph,
+ const ZoneGrowableArray<Definition*>& detached_defs);
+
+ // Default implementation of 'Write' method, when
+ // specialization for a particular type is not provided.
+ // This struct is used for the partial template instantiations below.
+ template <typename T>
+ struct WriteTrait {
+ using ArgType = T;
+ };
+
+ template <typename T>
+ struct WriteTrait<GrowableArray<T>> {
+ using ArgType = const GrowableArray<T>&;
+ static void Write(FlowGraphSerializer* s, ArgType x) {
+ const intptr_t len = x.length();
+ s->Write<intptr_t>(len);
+ for (intptr_t i = 0; i < len; ++i) {
+ s->Write<T>(x[i]);
+ }
+ }
+ };
+
+ template <typename T>
+ struct WriteTrait<const GrowableArray<T>&> {
+ using ArgType = const GrowableArray<T>&;
+ static void Write(FlowGraphSerializer* s, ArgType x) {
+ WriteTrait<GrowableArray<T>>::Write(s, x);
+ }
+ };
+
+ template <typename T>
+ struct WriteTrait<ZoneGrowableArray<T>*> {
+ using ArgType = const ZoneGrowableArray<T>*;
+ static void Write(FlowGraphSerializer* s, ArgType x) {
+ if (x == nullptr) {
+ s->Write<intptr_t>(-1);
+ return;
+ }
+ const intptr_t len = x->length();
+ s->Write<intptr_t>(len);
+ for (intptr_t i = 0; i < len; ++i) {
+ s->Write<T>((*x)[i]);
+ }
+ }
+ };
+
+ template <typename T>
+ struct WriteTrait<const ZoneGrowableArray<T>&> {
+ using ArgType = const ZoneGrowableArray<T>&;
+ static void Write(FlowGraphSerializer* s, ArgType x) {
+ WriteTrait<ZoneGrowableArray<T>*>::Write(s, &x);
+ }
+ };
+
+ // Specialization in case intptr_t is not mapped to intN_t.
+ template <>
+ struct WriteTrait<intptr_t> {
+ using ArgType = intptr_t;
+ static void Write(FlowGraphSerializer* s, intptr_t x) {
+#ifdef ARCH_IS_64_BIT
+ s->Write<int64_t>(x);
+#else
+ s->Write<int32_t>(x);
+#endif
+ }
+ };
+
+ // Specialization in case uintptr_t is not mapped to uintN_t.
+ template <>
+ struct WriteTrait<uintptr_t> {
+ using ArgType = uintptr_t;
+ static void Write(FlowGraphSerializer* s, uintptr_t x) {
+#ifdef ARCH_IS_64_BIT
+ s->Write<uint64_t>(x);
+#else
+ s->Write<uint32_t>(x);
+#endif
+ }
+ };
+
+ template <typename T>
+ void Write(typename WriteTrait<T>::ArgType x) {
+ WriteTrait<T>::Write(this, x);
+ }
+
+#define DECLARE_WRITE_METHOD(type) \
+ template <> \
+ void Write<type>(type x);
+ IL_SERIALIZABLE_TYPE_LIST(DECLARE_WRITE_METHOD)
+#undef DECLARE_WRITE_METHOD
+
+ template <typename T>
+ void WriteRef(T x);
+
+#define DECLARE_WRITE_REF_METHOD(type) \
+ template <> \
+ void WriteRef<type>(type x);
+ IL_SERIALIZABLE_REF_TYPE_LIST(DECLARE_WRITE_REF_METHOD)
+#undef DECLARE_WRITE_REF_METHOD
+
+ template <typename T>
+ void WriteGrowableArrayOfRefs(const GrowableArray<T>& array) {
+ const intptr_t len = array.length();
+ Write<intptr_t>(len);
+ for (intptr_t i = 0; i < len; ++i) {
+ WriteRef<T>(array[i]);
+ }
+ }
+
+ BaseWriteStream* stream() const { return stream_; }
+ IsolateGroup* isolate_group() const { return isolate_group_; }
+ bool can_write_refs() const { return can_write_refs_; }
+
+ private:
+ void WriteObjectImpl(const Object& x, intptr_t cid, intptr_t object_index);
+
+ // Used to track scopes of recursive types during serialization.
+ struct TypeScope {
+ TypeScope(FlowGraphSerializer* serializer, bool is_recursive)
+ : serializer_(serializer),
+ is_recursive_(is_recursive),
+ was_writing_recursive_type_(serializer->writing_recursive_type_) {
+ serializer->writing_recursive_type_ = is_recursive;
+ }
+
+ ~TypeScope() {
+ serializer_->writing_recursive_type_ = was_writing_recursive_type_;
+ }
+
+ // Returns true if type of the current scope can be canonicalized
+ // during deserialization. Recursive types which were not
+ // fully deserialized should not be canonicalized.
+ bool CanBeCanonicalized() const {
+ return !is_recursive_ || !was_writing_recursive_type_;
+ }
+
+ FlowGraphSerializer* const serializer_;
+ const bool is_recursive_;
+ const bool was_writing_recursive_type_;
+ };
+
+ NonStreamingWriteStream* stream_;
+ Zone* zone_;
+ IsolateGroup* isolate_group_;
+ Heap* heap_;
+ intptr_t object_counter_ = 0;
+ bool can_write_refs_ = false;
+ bool writing_recursive_type_ = false;
+};
+
+// Deserializes flow graph.
+// All constants and types are canonicalized during deserialization.
+class FlowGraphDeserializer : public ValueObject {
+ public:
+ FlowGraphDeserializer(const ParsedFunction& parsed_function,
+ ReadStream* stream);
+
+ const ParsedFunction& parsed_function() const { return parsed_function_; }
+
+ Zone* zone() const { return zone_; }
+ ReadStream* stream() const { return stream_; }
+ Thread* thread() const { return thread_; }
+ IsolateGroup* isolate_group() const { return isolate_group_; }
+
+ GraphEntryInstr* graph_entry() const { return graph_entry_; }
+ void set_graph_entry(GraphEntryInstr* entry) { graph_entry_ = entry; }
+
+ BlockEntryInstr* current_block() const { return current_block_; }
+ void set_current_block(BlockEntryInstr* block) { current_block_ = block; }
+
+ BlockEntryInstr* block(intptr_t block_id) const {
+ BlockEntryInstr* b = blocks_[block_id];
+ ASSERT(b != nullptr);
+ return b;
+ }
+ void set_block(intptr_t block_id, BlockEntryInstr* block) {
+ ASSERT(blocks_[block_id] == nullptr);
+ blocks_[block_id] = block;
+ }
+
+ Definition* definition(intptr_t ssa_temp_index) const {
+ Definition* def = definitions_[ssa_temp_index];
+ ASSERT(def != nullptr);
+ return def;
+ }
+ void set_definition(intptr_t ssa_temp_index, Definition* def) {
+ ASSERT(definitions_[ssa_temp_index] == nullptr);
+ definitions_[ssa_temp_index] = def;
+ }
+
+ FlowGraph* ReadFlowGraph();
+
+ // Default implementation of 'Read' method, when
+ // specialization for a particular type is not provided.
+ // This struct is used for the partial template instantiations below.
+ template <typename T>
+ struct ReadTrait {};
+
+ template <typename T>
+ struct ReadTrait<GrowableArray<T>> {
+ static GrowableArray<T> Read(FlowGraphDeserializer* d) {
+ const intptr_t len = d->Read<intptr_t>();
+ GrowableArray<T> array(len);
+ for (int i = 0; i < len; ++i) {
+ array.Add(d->Read<T>());
+ }
+ return array;
+ }
+ };
+
+ template <typename T>
+ struct ReadTrait<const GrowableArray<T>&> {
+ static const GrowableArray<T>& Read(FlowGraphDeserializer* d) {
+ return ReadTrait<GrowableArray<T>>::Read(d);
+ }
+ };
+
+ template <typename T>
+ struct ReadTrait<ZoneGrowableArray<T>*> {
+ static ZoneGrowableArray<T>* Read(FlowGraphDeserializer* d) {
+ const intptr_t len = d->Read<intptr_t>();
+ if (len < 0) {
+ return nullptr;
+ }
+ auto* array = new (d->zone()) ZoneGrowableArray<T>(d->zone(), len);
+ for (int i = 0; i < len; ++i) {
+ array->Add(d->Read<T>());
+ }
+ return array;
+ }
+ };
+
+ template <typename T>
+ struct ReadTrait<const ZoneGrowableArray<T>&> {
+ static const ZoneGrowableArray<T>& Read(FlowGraphDeserializer* d) {
+ return *ReadTrait<ZoneGrowableArray<T>*>::Read(d);
+ }
+ };
+
+ // Specialization in case intptr_t is not mapped to intN_t.
+ template <>
+ struct ReadTrait<intptr_t> {
+ static intptr_t Read(FlowGraphDeserializer* d) {
+#ifdef ARCH_IS_64_BIT
+ return d->Read<int64_t>();
+#else
+ return d->Read<int32_t>();
+#endif
+ }
+ };
+
+ // Specialization in case uintptr_t is not mapped to uintN_t.
+ template <>
+ struct ReadTrait<uintptr_t> {
+ static uintptr_t Read(FlowGraphDeserializer* d) {
+#ifdef ARCH_IS_64_BIT
+ return d->Read<uint64_t>();
+#else
+ return d->Read<uint32_t>();
+#endif
+ }
+ };
+
+ template <typename T>
+ T Read() {
+ return ReadTrait<T>::Read(this);
+ }
+
+#define DECLARE_READ_METHOD(type) \
+ template <> \
+ type Read<type>();
+ IL_SERIALIZABLE_TYPE_LIST(DECLARE_READ_METHOD)
+#undef DECLARE_READ_METHOD
+
+ template <typename T>
+ T ReadRef();
+
+#define DECLARE_READ_REF_METHOD(type) \
+ template <> \
+ type ReadRef<type>();
+ IL_SERIALIZABLE_REF_TYPE_LIST(DECLARE_READ_REF_METHOD)
+#undef DECLARE_READ_REF_METHOD
+
+ template <typename T>
+ GrowableArray<T> ReadGrowableArrayOfRefs() {
+ const intptr_t len = Read<intptr_t>();
+ GrowableArray<T> array(len);
+ for (int i = 0; i < len; ++i) {
+ array.Add(ReadRef<T>());
+ }
+ return std::move(array);
+ }
+
+ private:
+ ClassPtr GetClassById(classid_t id) const;
+ const Object& ReadObjectImpl(intptr_t cid, intptr_t object_index);
+ void SetObjectAt(intptr_t object_index, const Object& object);
+
+ InstancePtr MaybeCanonicalize(const Instance& obj,
+ intptr_t object_index,
+ bool can_be_canonicalized);
+
+ const ParsedFunction& parsed_function_;
+ ReadStream* stream_;
+ Zone* zone_;
+ Thread* thread_;
+ IsolateGroup* isolate_group_;
+
+ // Deserialized objects.
+ GraphEntryInstr* graph_entry_ = nullptr;
+ BlockEntryInstr* current_block_ = nullptr;
+ GrowableArray<BlockEntryInstr*> blocks_;
+ GrowableArray<Definition*> definitions_;
+ GrowableArray<const Object*> objects_;
+ intptr_t object_counter_ = 0;
+ GrowableArray<intptr_t> pending_canonicalization_;
+};
+
+} // namespace dart
+
+#endif // RUNTIME_VM_COMPILER_BACKEND_IL_SERIALIZER_H_
diff --git a/runtime/vm/compiler/backend/locations.h b/runtime/vm/compiler/backend/locations.h
index aabd12a..c82215f 100644
--- a/runtime/vm/compiler/backend/locations.h
+++ b/runtime/vm/compiler/backend/locations.h
@@ -21,6 +21,8 @@
class BaseTextBuffer;
class ConstantInstr;
class Definition;
+class FlowGraphDeserializer;
+class FlowGraphSerializer;
class PairLocation;
class Value;
@@ -430,8 +432,8 @@
Location Copy() const;
- static Location read(uword value) { return Location(value); }
- uword write() const { return value_; }
+ void Write(FlowGraphSerializer* s) const;
+ static Location Read(FlowGraphDeserializer* d);
private:
explicit Location(uword value) : value_(value) {}
@@ -572,8 +574,7 @@
ASSERT(kNumberOfFpuRegisters <= (kWordSize * kBitsPerByte));
}
- explicit RegisterSet(uintptr_t cpu_register_mask,
- uintptr_t fpu_register_mask = 0)
+ explicit RegisterSet(uintptr_t cpu_register_mask, uintptr_t fpu_register_mask)
: RegisterSet() {
AddTaggedRegisters(cpu_register_mask, fpu_register_mask);
}
@@ -717,6 +718,9 @@
untagged_cpu_registers_.Clear();
}
+ void Write(FlowGraphSerializer* s) const;
+ explicit RegisterSet(FlowGraphDeserializer* d);
+
private:
SmallSet<Register> cpu_registers_;
SmallSet<Register> untagged_cpu_registers_;
@@ -835,6 +839,9 @@
void CheckWritableInputs();
#endif
+ void Write(FlowGraphSerializer* s) const;
+ explicit LocationSummary(FlowGraphDeserializer* d);
+
private:
BitmapBuilder& EnsureStackBitmap() {
if (stack_bitmap_ == NULL) {
diff --git a/runtime/vm/compiler/backend/range_analysis.cc b/runtime/vm/compiler/backend/range_analysis.cc
index f2cf0ab..9025738 100644
--- a/runtime/vm/compiler/backend/range_analysis.cc
+++ b/runtime/vm/compiler/backend/range_analysis.cc
@@ -1815,7 +1815,7 @@
int64_t value = value_boundary.ConstantValue();
if (value == 0) {
- return RangeBoundary(0);
+ return RangeBoundary::FromConstant(0);
} else if (shift_count == 0 ||
(limit > 0 && Utils::IsInt(static_cast<int>(limit), value))) {
// Result stays in 64 bit range.
diff --git a/runtime/vm/compiler/backend/range_analysis.h b/runtime/vm/compiler/backend/range_analysis.h
index aa1f6b9..dc178f6 100644
--- a/runtime/vm/compiler/backend/range_analysis.h
+++ b/runtime/vm/compiler/backend/range_analysis.h
@@ -301,6 +301,9 @@
int64_t SmiLowerBound() const { return LowerBound(kRangeBoundarySmi); }
+ void Write(FlowGraphSerializer* s) const;
+ explicit RangeBoundary(FlowGraphDeserializer* d);
+
private:
RangeBoundary(Kind kind, int64_t value, int64_t offset)
: kind_(kind), value_(value), offset_(offset) {}
@@ -536,6 +539,9 @@
Definition* left_defn,
Range* result);
+ void Write(FlowGraphSerializer* s) const;
+ explicit Range(FlowGraphDeserializer* d);
+
private:
RangeBoundary min_;
RangeBoundary max_;
diff --git a/runtime/vm/compiler/backend/range_analysis_test.cc b/runtime/vm/compiler/backend/range_analysis_test.cc
index ce2d3d5..39b4729 100644
--- a/runtime/vm/compiler/backend/range_analysis_test.cc
+++ b/runtime/vm/compiler/backend/range_analysis_test.cc
@@ -82,13 +82,14 @@
RangeBoundary(compiler::target::kSmiMin),
RangeBoundary(compiler::target::kSmiMax));
}
- TEST_RANGE_OP(Range::Shl, 0, 100, 0, 64, RangeBoundary(0),
+ TEST_RANGE_OP(Range::Shl, 0, 100, 0, 64, RangeBoundary::FromConstant(0),
RangeBoundary::PositiveInfinity());
TEST_RANGE_OP(Range::Shl, -100, 0, 0, 64, RangeBoundary::NegativeInfinity(),
- RangeBoundary(0));
+ RangeBoundary::FromConstant(0));
TEST_RANGE_OP(Range::Shr, -8, 8, 1, 2, RangeBoundary(-4), RangeBoundary(4));
- TEST_RANGE_OP(Range::Shr, 1, 8, 1, 2, RangeBoundary(0), RangeBoundary(4));
+ TEST_RANGE_OP(Range::Shr, 1, 8, 1, 2, RangeBoundary::FromConstant(0),
+ RangeBoundary(4));
TEST_RANGE_OP(Range::Shr, -16, -8, 1, 2, RangeBoundary(-8),
RangeBoundary(-2));
TEST_RANGE_OP(Range::Shr, 2, 4, -1, 1, RangeBoundary(1), RangeBoundary(4));
@@ -466,24 +467,26 @@
// [0xff, 0xfff] & [0xf, 0xf] = [0x0, 0xf].
TEST_RANGE_AND(static_cast<int64_t>(0xff), static_cast<int64_t>(0xfff),
static_cast<int64_t>(0xf), static_cast<int64_t>(0xf),
- RangeBoundary(0), RangeBoundary(0xf));
+ RangeBoundary::FromConstant(0), RangeBoundary(0xf));
// [0xffffffff, 0xffffffff] & [0xfffffffff, 0xfffffffff] = [0x0, 0xfffffffff].
TEST_RANGE_AND(
static_cast<int64_t>(0xffffffff), static_cast<int64_t>(0xffffffff),
static_cast<int64_t>(0xfffffffff), static_cast<int64_t>(0xfffffffff),
- RangeBoundary(0), RangeBoundary(static_cast<int64_t>(0xfffffffff)));
+ RangeBoundary::FromConstant(0),
+ RangeBoundary(static_cast<int64_t>(0xfffffffff)));
// [0xffffffff, 0xffffffff] & [-20, 20] = [0x0, 0xffffffff].
TEST_RANGE_AND(static_cast<int64_t>(0xffffffff),
static_cast<int64_t>(0xffffffff), static_cast<int64_t>(-20),
- static_cast<int64_t>(20), RangeBoundary(0),
+ static_cast<int64_t>(20), RangeBoundary::FromConstant(0),
RangeBoundary(static_cast<int64_t>(0xffffffff)));
// [-20, 20] & [0xffffffff, 0xffffffff] = [0x0, 0xffffffff].
TEST_RANGE_AND(static_cast<int64_t>(-20), static_cast<int64_t>(20),
static_cast<int64_t>(0xffffffff),
- static_cast<int64_t>(0xffffffff), RangeBoundary(0),
+ static_cast<int64_t>(0xffffffff),
+ RangeBoundary::FromConstant(0),
RangeBoundary(static_cast<int64_t>(0xffffffff)));
// Test that [-20, 20] & [-20, 20] = [-32, 31].
diff --git a/runtime/vm/compiler/backend/redundancy_elimination.cc b/runtime/vm/compiler/backend/redundancy_elimination.cc
index c192500..454cae9 100644
--- a/runtime/vm/compiler/backend/redundancy_elimination.cc
+++ b/runtime/vm/compiler/backend/redundancy_elimination.cc
@@ -3676,8 +3676,10 @@
// Remove materializations from the graph. Register allocator will treat them
// as part of the environment not as a real instruction.
void AllocationSinking::DetachMaterializations() {
- for (intptr_t i = 0; i < materializations_.length(); i++) {
- materializations_[i]->previous()->LinkTo(materializations_[i]->next());
+ for (MaterializeObjectInstr* mat : materializations_) {
+ mat->previous()->LinkTo(mat->next());
+ mat->set_next(nullptr);
+ mat->set_previous(nullptr);
}
}
diff --git a/runtime/vm/compiler/backend/slot.cc b/runtime/vm/compiler/backend/slot.cc
index 6554f8b..46acba6 100644
--- a/runtime/vm/compiler/backend/slot.cc
+++ b/runtime/vm/compiler/backend/slot.cc
@@ -302,48 +302,60 @@
const intptr_t offset =
compiler::target::Class::TypeArgumentsFieldOffset(cls);
ASSERT(offset != Class::kNoTypeArguments);
- return SlotCache::Instance(thread).Canonicalize(
- Slot(Kind::kTypeArguments,
- IsImmutableBit::encode(true) |
- IsCompressedBit::encode(
- compiler::target::Class::HasCompressedPointers(cls)),
- kTypeArgumentsCid, offset, ":type_arguments",
- /*static_type=*/nullptr, kTagged));
+ return GetCanonicalSlot(
+ thread, Kind::kTypeArguments,
+ IsImmutableBit::encode(true) |
+ IsCompressedBit::encode(
+ compiler::target::Class::HasCompressedPointers(cls)),
+ kTypeArgumentsCid, offset, ":type_arguments",
+ /*static_type=*/nullptr, kTagged);
}
const Slot& Slot::GetContextVariableSlotFor(Thread* thread,
const LocalVariable& variable) {
ASSERT(variable.is_captured());
- return SlotCache::Instance(thread).Canonicalize(
- Slot(Kind::kCapturedVariable,
- IsImmutableBit::encode(variable.is_final() && !variable.is_late()) |
- IsNullableBit::encode(true) |
- IsCompressedBit::encode(Context::ContainsCompressedPointers()) |
- IsSentinelVisibleBit::encode(variable.is_late()),
- kDynamicCid,
- compiler::target::Context::variable_offset(variable.index().value()),
- &variable.name(), &variable.type(), kTagged));
+ return GetCanonicalSlot(
+ thread, Kind::kCapturedVariable,
+ IsImmutableBit::encode(variable.is_final() && !variable.is_late()) |
+ IsNullableBit::encode(true) |
+ IsCompressedBit::encode(Context::ContainsCompressedPointers()) |
+ IsSentinelVisibleBit::encode(variable.is_late()),
+ kDynamicCid,
+ compiler::target::Context::variable_offset(variable.index().value()),
+ &variable.name(), &variable.type(), kTagged);
}
const Slot& Slot::GetTypeArgumentsIndexSlot(Thread* thread, intptr_t index) {
const intptr_t offset =
compiler::target::TypeArguments::type_at_offset(index);
- const Slot& slot = Slot(
- Kind::kTypeArgumentsIndex,
+ return GetCanonicalSlot(
+ thread, Kind::kTypeArgumentsIndex,
IsImmutableBit::encode(true) |
IsCompressedBit::encode(TypeArguments::ContainsCompressedPointers()),
kDynamicCid, offset, ":argument", /*static_type=*/nullptr, kTagged);
- return SlotCache::Instance(thread).Canonicalize(slot);
}
const Slot& Slot::GetArrayElementSlot(Thread* thread,
intptr_t offset_in_bytes) {
- const Slot& slot =
- Slot(Kind::kArrayElement,
- IsNullableBit::encode(true) |
- IsCompressedBit::encode(Array::ContainsCompressedPointers()),
- kDynamicCid, offset_in_bytes, ":array_element",
- /*static_type=*/nullptr, kTagged);
+ return GetCanonicalSlot(
+ thread, Kind::kArrayElement,
+ IsNullableBit::encode(true) |
+ IsCompressedBit::encode(Array::ContainsCompressedPointers()),
+ kDynamicCid, offset_in_bytes, ":array_element",
+ /*static_type=*/nullptr, kTagged);
+}
+
+const Slot& Slot::GetCanonicalSlot(Thread* thread,
+ Slot::Kind kind,
+ int8_t flags,
+ ClassIdTagType cid,
+ intptr_t offset_in_bytes,
+ const void* data,
+ const AbstractType* static_type,
+ Representation representation,
+ const FieldGuardState& field_guard_state) {
+ const Slot& slot = Slot(kind, flags, cid, offset_in_bytes, data, static_type,
+ representation, field_guard_state);
return SlotCache::Instance(thread).Canonicalize(slot);
}
@@ -456,8 +468,8 @@
}
Class& owner = Class::Handle(zone, field.Owner());
- const Slot& slot = SlotCache::Instance(thread).Canonicalize(Slot(
- Kind::kDartField,
+ const Slot& slot = GetCanonicalSlot(
+ thread, Kind::kDartField,
IsImmutableBit::encode((field.is_final() && !field.is_late()) ||
field.is_const()) |
IsNullableBit::encode(is_nullable) |
@@ -467,7 +479,7 @@
IsSentinelVisibleBit::encode(field.is_late() && field.is_final() &&
!field.has_initializer()),
nullable_cid, compiler::target::Field::OffsetOf(field), &field, &type,
- rep, field_guard_state));
+ rep, field_guard_state);
// If properties of this slot were based on the guarded state make sure
// to add the field to the list of guarded fields. Note that during background
diff --git a/runtime/vm/compiler/backend/slot.h b/runtime/vm/compiler/backend/slot.h
index eb87355..90838c9 100644
--- a/runtime/vm/compiler/backend/slot.h
+++ b/runtime/vm/compiler/backend/slot.h
@@ -357,9 +357,12 @@
bool IsPotentialUnboxed() const;
Representation UnboxedRepresentation() const;
+ void Write(FlowGraphSerializer* s) const;
+ static const Slot& Read(FlowGraphDeserializer* d);
+
private:
Slot(Kind kind,
- int8_t bits,
+ int8_t flags,
ClassIdTagType cid,
intptr_t offset_in_bytes,
const void* data,
@@ -367,7 +370,7 @@
Representation representation,
const FieldGuardState& field_guard_state = FieldGuardState())
: kind_(kind),
- flags_(bits),
+ flags_(flags),
cid_(cid),
offset_in_bytes_(offset_in_bytes),
representation_(representation),
@@ -397,6 +400,17 @@
return static_cast<const T*>(data_);
}
+ static const Slot& GetCanonicalSlot(
+ Thread* thread,
+ Kind kind,
+ int8_t flags,
+ ClassIdTagType cid,
+ intptr_t offset_in_bytes,
+ const void* data,
+ const AbstractType* static_type,
+ Representation representation,
+ const FieldGuardState& field_guard_state = FieldGuardState());
+
// There is a fixed statically known number of native slots so we cache
// them statically.
static AcqRelAtomic<Slot*> native_fields_;
diff --git a/runtime/vm/compiler/compiler_pass.cc b/runtime/vm/compiler/compiler_pass.cc
index f6a4dd3..6486fca 100644
--- a/runtime/vm/compiler/compiler_pass.cc
+++ b/runtime/vm/compiler/compiler_pass.cc
@@ -84,6 +84,7 @@
"Do --compiler-passes=help for more information.");
DECLARE_FLAG(bool, print_flow_graph);
DECLARE_FLAG(bool, print_flow_graph_optimized);
+DEFINE_FLAG(bool, test_il_serialization, false, "Test IL serialization.");
void CompilerPassState::set_flow_graph(FlowGraph* flow_graph) {
flow_graph_ = flow_graph;
@@ -565,6 +566,22 @@
if (state->reorder_blocks) {
BlockScheduler::ReorderBlocks(flow_graph);
}
+
+ // This is the last compiler pass.
+ // Test that round-trip IL serialization works before generating code.
+ if (FLAG_test_il_serialization && CompilerState::Current().is_aot()) {
+ Zone* zone = flow_graph->zone();
+ auto* detached_defs = new (zone) ZoneGrowableArray<Definition*>(zone, 0);
+ flow_graph->CompactSSA(detached_defs);
+
+ ZoneWriteStream write_stream(flow_graph->zone(), 1024);
+ FlowGraphSerializer serializer(&write_stream);
+ serializer.WriteFlowGraph(*flow_graph, *detached_defs);
+ ReadStream read_stream(write_stream.buffer(), write_stream.bytes_written());
+ FlowGraphDeserializer deserializer(flow_graph->parsed_function(),
+ &read_stream);
+ state->set_flow_graph(deserializer.ReadFlowGraph());
+ }
});
COMPILER_PASS(EliminateWriteBarriers, { EliminateWriteBarriers(flow_graph); });
diff --git a/runtime/vm/compiler/compiler_sources.gni b/runtime/vm/compiler/compiler_sources.gni
index ace9914..ed545d6 100644
--- a/runtime/vm/compiler/compiler_sources.gni
+++ b/runtime/vm/compiler/compiler_sources.gni
@@ -65,6 +65,8 @@
"backend/il_printer.cc",
"backend/il_printer.h",
"backend/il_riscv.cc",
+ "backend/il_serializer.cc",
+ "backend/il_serializer.h",
"backend/il_x64.cc",
"backend/inliner.cc",
"backend/inliner.h",
diff --git a/runtime/vm/compiler/ffi/call.cc b/runtime/vm/compiler/ffi/call.cc
index be76d75..0cee4de 100644
--- a/runtime/vm/compiler/ffi/call.cc
+++ b/runtime/vm/compiler/ffi/call.cc
@@ -14,18 +14,15 @@
namespace ffi {
// TODO(dartbug.com/36607): Cache the trampolines.
-FunctionPtr TrampolineFunction(const FunctionType& dart_signature,
+FunctionPtr TrampolineFunction(const String& name,
+ const FunctionType& signature,
const FunctionType& c_signature,
- bool is_leaf,
- const String& function_name) {
+ bool is_leaf) {
+ ASSERT(signature.num_implicit_parameters() == 1);
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
- String& name =
- String::Handle(zone, Symbols::NewFormatted(thread, "FfiTrampoline_%s",
- function_name.ToCString()));
const Library& lib = Library::Handle(zone, Library::FfiLibrary());
const Class& owner_class = Class::Handle(zone, lib.toplevel_class());
- FunctionType& signature = FunctionType::Handle(zone, FunctionType::New());
Function& function = Function::Handle(
zone, Function::New(signature, name, UntaggedFunction::kFfiTrampoline,
/*is_static=*/true,
@@ -35,31 +32,47 @@
/*is_native=*/false, owner_class,
TokenPosition::kMinSource));
function.set_is_debuggable(false);
+
+ // Create unique names for the parameters, as they are used in scope building
+ // and error messages.
+ if (signature.num_fixed_parameters() > 0) {
+ function.CreateNameArray();
+ function.SetParameterNameAt(0, Symbols::ClosureParameter());
+ auto& param_name = String::Handle(zone);
+ for (intptr_t i = 1, n = signature.num_fixed_parameters(); i < n; ++i) {
+ param_name = Symbols::NewFormatted(thread, ":ffi_param%" Pd, i);
+ function.SetParameterNameAt(i, param_name);
+ }
+ }
+
+ function.SetFfiCSignature(c_signature);
+ function.SetFfiIsLeaf(is_leaf);
+
+ return function.ptr();
+}
+
+FunctionPtr TrampolineFunction(const FunctionType& dart_signature,
+ const FunctionType& c_signature,
+ bool is_leaf,
+ const String& function_name) {
+ Thread* thread = Thread::Current();
+ Zone* zone = thread->zone();
+ String& name =
+ String::Handle(zone, Symbols::NewFormatted(thread, "FfiTrampoline_%s",
+ function_name.ToCString()));
+
// Trampolines have no optional arguments.
+ FunctionType& signature = FunctionType::Handle(zone, FunctionType::New());
const intptr_t num_fixed = dart_signature.num_fixed_parameters();
+ signature.set_num_implicit_parameters(1);
signature.set_num_fixed_parameters(num_fixed);
signature.set_result_type(
AbstractType::Handle(zone, dart_signature.result_type()));
signature.set_parameter_types(
Array::Handle(zone, dart_signature.parameter_types()));
-
- // Create unique names for the parameters, as they are used in scope building
- // and error messages.
- if (num_fixed > 0) {
- function.CreateNameArray();
- function.SetParameterNameAt(0, Symbols::ClosureParameter());
- for (intptr_t i = 1; i < num_fixed; i++) {
- name = Symbols::NewFormatted(thread, ":ffi_param%" Pd, i);
- function.SetParameterNameAt(i, name);
- }
- }
- function.SetFfiCSignature(c_signature);
signature ^= ClassFinalizer::FinalizeType(signature);
- function.SetSignature(signature);
- function.SetFfiIsLeaf(is_leaf);
-
- return function.ptr();
+ return TrampolineFunction(name, signature, c_signature, is_leaf);
}
} // namespace ffi
diff --git a/runtime/vm/compiler/ffi/call.h b/runtime/vm/compiler/ffi/call.h
index aecd128..11c328a 100644
--- a/runtime/vm/compiler/ffi/call.h
+++ b/runtime/vm/compiler/ffi/call.h
@@ -19,6 +19,11 @@
namespace ffi {
+FunctionPtr TrampolineFunction(const String& name,
+ const FunctionType& signature,
+ const FunctionType& c_signature,
+ bool is_leaf);
+
FunctionPtr TrampolineFunction(const FunctionType& dart_signature,
const FunctionType& c_signature,
bool is_leaf,
diff --git a/runtime/vm/compiler/ffi/marshaller.h b/runtime/vm/compiler/ffi/marshaller.h
index 175e12e..61eea68 100644
--- a/runtime/vm/compiler/ffi/marshaller.h
+++ b/runtime/vm/compiler/ffi/marshaller.h
@@ -131,6 +131,7 @@
bool ContainsHandles() const;
+ const Function& dart_signature() const { return dart_signature_; }
StringPtr function_name() const { return dart_signature_.name(); }
protected:
diff --git a/runtime/vm/compiler/stub_code_compiler.cc b/runtime/vm/compiler/stub_code_compiler.cc
index 525dc4d..a4c1c5e 100644
--- a/runtime/vm/compiler/stub_code_compiler.cc
+++ b/runtime/vm/compiler/stub_code_compiler.cc
@@ -889,7 +889,8 @@
// Fall through to &is_simple_case
const RegisterSet caller_saved_registers(
- TypeTestABI::kSubtypeTestCacheStubCallerSavedRegisters);
+ TypeTestABI::kSubtypeTestCacheStubCallerSavedRegisters,
+ /*fpu_registers=*/0);
__ Bind(&is_simple_case);
{
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 76817ed..0aca34f 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -3222,6 +3222,28 @@
}
}
+intptr_t Class::FindFunctionIndex(const Function& needle) const {
+ Thread* thread = Thread::Current();
+ if (EnsureIsFinalized(thread) != Error::null()) {
+ return -1;
+ }
+ REUSABLE_ARRAY_HANDLESCOPE(thread);
+ REUSABLE_FUNCTION_HANDLESCOPE(thread);
+ Array& funcs = thread->ArrayHandle();
+ Function& function = thread->FunctionHandle();
+ funcs = current_functions();
+ ASSERT(!funcs.IsNull());
+ const intptr_t len = funcs.Length();
+ for (intptr_t i = 0; i < len; i++) {
+ function ^= funcs.At(i);
+ if (needle.ptr() == function.ptr()) {
+ return i;
+ }
+ }
+ // No function found.
+ return -1;
+}
+
FunctionPtr Class::FunctionFromIndex(intptr_t idx) const {
const Array& funcs = Array::Handle(current_functions());
if ((idx < 0) || (idx >= funcs.Length())) {
@@ -3234,20 +3256,13 @@
}
FunctionPtr Class::ImplicitClosureFunctionFromIndex(intptr_t idx) const {
- const Array& funcs = Array::Handle(current_functions());
- if ((idx < 0) || (idx >= funcs.Length())) {
+ Function& func = Function::Handle(FunctionFromIndex(idx));
+ if (func.IsNull() || !func.HasImplicitClosureFunction()) {
return Function::null();
}
- Function& func = Function::Handle();
- func ^= funcs.At(idx);
+ func = func.ImplicitClosureFunction();
ASSERT(!func.IsNull());
- if (!func.HasImplicitClosureFunction()) {
- return Function::null();
- }
- const Function& closure_func =
- Function::Handle(func.ImplicitClosureFunction());
- ASSERT(!closure_func.IsNull());
- return closure_func.ptr();
+ return func.ptr();
}
intptr_t Class::FindImplicitClosureFunctionIndex(const Function& needle) const {
@@ -4682,6 +4697,35 @@
SetFields(new_arr);
}
+intptr_t Class::FindFieldIndex(const Field& needle) const {
+ Thread* thread = Thread::Current();
+ if (EnsureIsFinalized(thread) != Error::null()) {
+ return -1;
+ }
+ REUSABLE_ARRAY_HANDLESCOPE(thread);
+ REUSABLE_FIELD_HANDLESCOPE(thread);
+ Array& fields = thread->ArrayHandle();
+ Field& field = thread->FieldHandle();
+ fields = this->fields();
+ ASSERT(!fields.IsNull());
+ for (intptr_t i = 0, n = fields.Length(); i < n; ++i) {
+ field ^= fields.At(i);
+ if (needle.ptr() == field.ptr()) {
+ return i;
+ }
+ }
+ // Not found.
+ return -1;
+}
+
+FieldPtr Class::FieldFromIndex(intptr_t idx) const {
+ Array& fields = Array::Handle(this->fields());
+ if ((idx < 0) || (idx >= fields.Length())) {
+ return Field::null();
+ }
+ return Field::RawCast(fields.At(idx));
+}
+
bool Class::InjectCIDFields() const {
if (library() != Library::InternalLibrary() ||
Name() != Symbols::ClassID().ptr()) {
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index ed7f206..555d22c 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -1478,6 +1478,9 @@
void AddField(const Field& field) const;
void AddFields(const GrowableArray<const Field*>& fields) const;
+ intptr_t FindFieldIndex(const Field& needle) const;
+ FieldPtr FieldFromIndex(intptr_t idx) const;
+
// If this is a dart:internal.ClassID class, then inject our own const
// fields. Returns true if synthetic fields are injected and regular
// field declarations should be ignored.
@@ -1505,6 +1508,7 @@
}
void SetFunctions(const Array& value) const;
void AddFunction(const Function& function) const;
+ intptr_t FindFunctionIndex(const Function& needle) const;
FunctionPtr FunctionFromIndex(intptr_t idx) const;
intptr_t FindImplicitClosureFunctionIndex(const Function& needle) const;
FunctionPtr ImplicitClosureFunctionFromIndex(intptr_t idx) const;
@@ -7772,6 +7776,8 @@
friend class Closure;
friend class Pointer;
friend class DeferredObject;
+ friend class FlowGraphSerializer;
+ friend class FlowGraphDeserializer;
friend class RegExp;
friend class StubCode;
friend class TypedDataView;
@@ -7898,6 +7904,8 @@
FINAL_HEAP_OBJECT_IMPLEMENTATION(TypeParameters, Object);
friend class Class;
friend class ClassFinalizer;
+ friend class FlowGraphSerializer;
+ friend class FlowGraphDeserializer;
friend class Function;
friend class FunctionType;
friend class Object;
@@ -9911,6 +9919,7 @@
friend class Class;
friend class ExternalOneByteString;
+ friend class FlowGraphSerializer;
friend class ImageWriter;
friend class String;
friend class StringHasher;
@@ -10031,6 +10040,7 @@
}
friend class Class;
+ friend class FlowGraphSerializer;
friend class ImageWriter;
friend class String;
friend class StringHasher;
diff --git a/runtime/vm/regexp_assembler_ir.cc b/runtime/vm/regexp_assembler_ir.cc
index 2e7a7b4..99440a2 100644
--- a/runtime/vm/regexp_assembler_ir.cc
+++ b/runtime/vm/regexp_assembler_ir.cc
@@ -928,15 +928,9 @@
Definition* is_match_def;
- if (unicode) {
- is_match_def = new (Z) CaseInsensitiveCompareInstr(
- string_value, lhs_index_value, rhs_index_value, length_value,
- kCaseInsensitiveCompareUTF16RuntimeEntry, specialization_cid_);
- } else {
- is_match_def = new (Z) CaseInsensitiveCompareInstr(
- string_value, lhs_index_value, rhs_index_value, length_value,
- kCaseInsensitiveCompareUCS2RuntimeEntry, specialization_cid_);
- }
+ is_match_def = new (Z) CaseInsensitiveCompareInstr(
+ string_value, lhs_index_value, rhs_index_value, length_value,
+ /*handle_surrogates=*/unicode, specialization_cid_);
BranchOrBacktrack(Comparison(kNE, is_match_def, BoolConstant(true)),
on_no_match);
diff --git a/runtime/vm/type_testing_stubs.cc b/runtime/vm/type_testing_stubs.cc
index 41ac9d1..aa79b1d 100644
--- a/runtime/vm/type_testing_stubs.cc
+++ b/runtime/vm/type_testing_stubs.cc
@@ -626,7 +626,7 @@
// c) Then we'll check each value of the type argument.
compiler::Label pop_saved_registers_on_failure;
const RegisterSet saved_registers(
- TTSInternalRegs::kSavedTypeArgumentRegisters);
+ TTSInternalRegs::kSavedTypeArgumentRegisters, /*fpu_registers=*/0);
__ PushRegisters(saved_registers);
AbstractType& type_arg = AbstractType::Handle();