Version 2.13.0-124.0.dev
Merge commit '73f9d0cd26176f128edcde491644bb911f1178c7' into 'dev'
diff --git a/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart b/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart
index fe7cfc1..6c06628 100644
--- a/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart
+++ b/pkg/_fe_analyzer_shared/lib/src/flow_analysis/flow_analysis.dart
@@ -232,11 +232,6 @@
'{${_info.keys.map((k) => '$k (${k.hashCode})').join(',')}}'));
}
- /// Indicates whether information is stored for the given [node].
- bool _hasInfoForNode(Node node) {
- return _info[node] != null;
- }
-
void _printOn(StringBuffer sb) {
sb.write('_info=$_info,');
sb.write('_stack=$_stack,');
@@ -894,11 +889,7 @@
/// Call this method just after visiting a "try/finally" statement.
/// See [tryFinallyStatement_bodyBegin] for details.
- ///
- /// [finallyBlock] should be the same node that was passed to
- /// [AssignedVariables.endNode] for the "finally" part of the try/finally
- /// statement.
- void tryFinallyStatement_end(Node finallyBlock);
+ void tryFinallyStatement_end();
/// Call this method just before visiting the finally block of a "try/finally"
/// statement. See [tryFinallyStatement_bodyBegin] for details.
@@ -1439,9 +1430,9 @@
}
@override
- void tryFinallyStatement_end(Node finallyBlock) {
- return _wrap('tryFinallyStatement_end($finallyBlock)',
- () => _wrapped.tryFinallyStatement_end(finallyBlock));
+ void tryFinallyStatement_end() {
+ return _wrap(
+ 'tryFinallyStatement_end()', () => _wrapped.tryFinallyStatement_end());
}
@override
@@ -4095,10 +4086,7 @@
}
@override
- void tryFinallyStatement_end(Node finallyBlock) {
- // We used to need info for `finally` blocks but we don't anymore.
- assert(!_assignedVariables._hasInfoForNode(finallyBlock),
- 'No assigned variables info should have been stored for $finallyBlock');
+ void tryFinallyStatement_end() {
_TryFinallyContext<Variable, Type> context =
_stack.removeLast() as _TryFinallyContext<Variable, Type>;
_current = context._afterBodyAndCatches!
@@ -4741,7 +4729,7 @@
void tryFinallyStatement_bodyBegin() {}
@override
- void tryFinallyStatement_end(Node finallyBlock) {}
+ void tryFinallyStatement_end() {}
@override
void tryFinallyStatement_finallyBegin(Node body) {}
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_mini_ast.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_mini_ast.dart
index 024a4c6..afd3020 100644
--- a/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_mini_ast.dart
+++ b/pkg/_fe_analyzer_shared/test/flow_analysis/flow_analysis_mini_ast.dart
@@ -1640,7 +1640,6 @@
final List<Statement> body;
final List<Statement> finally_;
final Node _bodyNode = Node._();
- final Node _finallyNode = Node._();
_TryFinally(this.body, this.finally_) : super._();
@@ -1662,7 +1661,7 @@
body._visit(h, flow);
flow.tryFinallyStatement_finallyBegin(_bodyNode);
finally_._visit(h, flow);
- flow.tryFinallyStatement_end(_finallyNode);
+ flow.tryFinallyStatement_end();
}
}
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index b061fe0..e7dd7cf 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -2055,7 +2055,7 @@
flow.tryFinallyStatement_finallyBegin(
catchClauses.isNotEmpty ? node : body);
finallyBlock.accept(this);
- flow.tryFinallyStatement_end(finallyBlock);
+ flow.tryFinallyStatement_end();
}
}
diff --git a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
index 3b061ee..05af526 100644
--- a/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/inference_visitor.dart
@@ -6325,7 +6325,7 @@
inferrer.flowAnalysis.tryFinallyStatement_finallyBegin(
node.catchBlocks.isNotEmpty ? node : tryBodyWithAssignedInfo);
finalizerResult = inferrer.inferStatement(node.finallyBlock);
- inferrer.flowAnalysis.tryFinallyStatement_end(node.finallyBlock);
+ inferrer.flowAnalysis.tryFinallyStatement_end();
}
Statement result =
tryBlockResult.hasChanged ? tryBlockResult.statement : node.tryBlock;
diff --git a/pkg/nnbd_migration/lib/src/edge_builder.dart b/pkg/nnbd_migration/lib/src/edge_builder.dart
index 850669e..5b97ce5 100644
--- a/pkg/nnbd_migration/lib/src/edge_builder.dart
+++ b/pkg/nnbd_migration/lib/src/edge_builder.dart
@@ -1776,7 +1776,7 @@
_flowAnalysis.tryFinallyStatement_finallyBegin(
catchClauses.isNotEmpty ? node : body);
_dispatch(finallyBlock);
- _flowAnalysis.tryFinallyStatement_end(finallyBlock);
+ _flowAnalysis.tryFinallyStatement_end();
}
return null;
}
diff --git a/runtime/tests/vm/dart/base_il_serialization_test.dart b/runtime/tests/vm/dart/base_il_serialization_test.dart
deleted file mode 100644
index 569b661..0000000
--- a/runtime/tests/vm/dart/base_il_serialization_test.dart
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// VMOptions=--serialize_flow_graphs_to=il_tmp.txt
-// VMOptions=--serialize_flow_graphs_to=il_tmp.txt --populate_llvm_constant_pool
-// VMOptions=--serialize_flow_graphs_to=il_tmp.txt --no_serialize_flow_graph_types
-// VMOptions=--serialize_flow_graphs_to=il_tmp.txt --verbose_flow_graph_serialization
-// VMOptions=--serialize_flow_graphs_to=il_tmp.txt --no_serialize_flow_graph_types --verbose_flow_graph_serialization
-
-// Just use the existing hello world test.
-import 'hello_world_test.dart' as test;
-
-main(args) {
- test.main();
-}
diff --git a/runtime/tests/vm/dart/regress_38661_test.dart b/runtime/tests/vm/dart/regress_38661_test.dart
deleted file mode 100644
index 2e1ba13..0000000
--- a/runtime/tests/vm/dart/regress_38661_test.dart
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// VMOptions=--serialize_flow_graphs_to=il_tmp.txt
-// VMOptions=--serialize_flow_graphs_to=il_tmp.txt --populate_llvm_constant_pool
-// VMOptions=--serialize_flow_graphs_to=il_tmp.txt --no_serialize_flow_graph_types
-// VMOptions=--serialize_flow_graphs_to=il_tmp.txt --verbose_flow_graph_serialization
-// VMOptions=--serialize_flow_graphs_to=il_tmp.txt --no_serialize_flow_graph_types --verbose_flow_graph_serialization
-
-class A {
- const A();
-}
-
-class B {
- Object a = const A();
-}
-
-foo(int i) {
- if (i == 3) {
- new B();
- }
-}
-
-main(args) {
- foo(4);
-}
diff --git a/runtime/tests/vm/dart_2/base_il_serialization_test.dart b/runtime/tests/vm/dart_2/base_il_serialization_test.dart
deleted file mode 100644
index 569b661..0000000
--- a/runtime/tests/vm/dart_2/base_il_serialization_test.dart
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// VMOptions=--serialize_flow_graphs_to=il_tmp.txt
-// VMOptions=--serialize_flow_graphs_to=il_tmp.txt --populate_llvm_constant_pool
-// VMOptions=--serialize_flow_graphs_to=il_tmp.txt --no_serialize_flow_graph_types
-// VMOptions=--serialize_flow_graphs_to=il_tmp.txt --verbose_flow_graph_serialization
-// VMOptions=--serialize_flow_graphs_to=il_tmp.txt --no_serialize_flow_graph_types --verbose_flow_graph_serialization
-
-// Just use the existing hello world test.
-import 'hello_world_test.dart' as test;
-
-main(args) {
- test.main();
-}
diff --git a/runtime/tests/vm/dart_2/regress_38661_test.dart b/runtime/tests/vm/dart_2/regress_38661_test.dart
deleted file mode 100644
index 2e1ba13..0000000
--- a/runtime/tests/vm/dart_2/regress_38661_test.dart
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// VMOptions=--serialize_flow_graphs_to=il_tmp.txt
-// VMOptions=--serialize_flow_graphs_to=il_tmp.txt --populate_llvm_constant_pool
-// VMOptions=--serialize_flow_graphs_to=il_tmp.txt --no_serialize_flow_graph_types
-// VMOptions=--serialize_flow_graphs_to=il_tmp.txt --verbose_flow_graph_serialization
-// VMOptions=--serialize_flow_graphs_to=il_tmp.txt --no_serialize_flow_graph_types --verbose_flow_graph_serialization
-
-class A {
- const A();
-}
-
-class B {
- Object a = const A();
-}
-
-foo(int i) {
- if (i == 3) {
- new B();
- }
-}
-
-main(args) {
- foo(4);
-}
diff --git a/runtime/vm/compiler/aot/precompiler.cc b/runtime/vm/compiler/aot/precompiler.cc
index 460c9e0..abb8ad0 100644
--- a/runtime/vm/compiler/aot/precompiler.cc
+++ b/runtime/vm/compiler/aot/precompiler.cc
@@ -18,7 +18,6 @@
#include "vm/compiler/backend/flow_graph.h"
#include "vm/compiler/backend/flow_graph_compiler.h"
#include "vm/compiler/backend/il_printer.h"
-#include "vm/compiler/backend/il_serializer.h"
#include "vm/compiler/backend/inliner.h"
#include "vm/compiler/backend/linearscan.h"
#include "vm/compiler/backend/range_analysis.h"
@@ -87,17 +86,6 @@
DECLARE_FLAG(int, inlining_constant_arguments_min_size_threshold);
DECLARE_FLAG(bool, print_instruction_stats);
-DEFINE_FLAG(charp,
- serialize_flow_graphs_to,
- nullptr,
- "Serialize flow graphs to the given file");
-
-DEFINE_FLAG(bool,
- populate_llvm_constant_pool,
- false,
- "Add constant pool entries from flow graphs to a special pool "
- "serialized in AOT snapshots (with --serialize_flow_graphs_to)");
-
Precompiler* Precompiler::singleton_ = nullptr;
#if defined(DART_PRECOMPILER) && !defined(TARGET_ARCH_IA32)
@@ -234,8 +222,7 @@
consts_to_retain_(),
seen_table_selectors_(),
error_(Error::Handle()),
- get_runtime_type_is_unique_(false),
- il_serialization_stream_(nullptr) {
+ get_runtime_type_is_unique_(false) {
ASSERT(Precompiler::singleton_ == NULL);
Precompiler::singleton_ = this;
}
@@ -307,32 +294,6 @@
ClassFinalizer::ClearAllCode(
/*including_nonchanging_cids=*/FLAG_use_bare_instructions);
- // After this point, it should be safe to serialize flow graphs produced
- // during compilation and add constants to the LLVM constant pool.
- //
- // Check that both the file open and write callbacks are available, though
- // we only use the latter during IL processing.
- if (FLAG_serialize_flow_graphs_to != nullptr &&
- Dart::file_write_callback() != nullptr) {
- if (auto file_open = Dart::file_open_callback()) {
- auto file = file_open(FLAG_serialize_flow_graphs_to, /*write=*/true);
- set_il_serialization_stream(file);
- }
- if (FLAG_populate_llvm_constant_pool) {
- auto const object_store = IG->object_store();
- auto& llvm_constants = GrowableObjectArray::Handle(
- Z, GrowableObjectArray::New(16, Heap::kOld));
- auto& llvm_functions = GrowableObjectArray::Handle(
- Z, GrowableObjectArray::New(16, Heap::kOld));
- auto& llvm_constant_hash_table = Array::Handle(
- Z, HashTables::New<FlowGraphSerializer::LLVMPoolMap>(16,
- Heap::kOld));
- object_store->set_llvm_constant_pool(llvm_constants);
- object_store->set_llvm_function_pool(llvm_functions);
- object_store->set_llvm_constant_hash_table(llvm_constant_hash_table);
- }
- }
-
tracer_ = PrecompilerTracer::StartTracingIfRequested(this);
// All stubs have already been generated, all of them share the same pool.
@@ -412,45 +373,6 @@
}
}
- if (FLAG_serialize_flow_graphs_to != nullptr &&
- Dart::file_write_callback() != nullptr) {
- if (auto file_close = Dart::file_close_callback()) {
- file_close(il_serialization_stream());
- }
- set_il_serialization_stream(nullptr);
- if (FLAG_populate_llvm_constant_pool) {
- // We don't want the Array backing for any mappings in the snapshot,
- // only the pools themselves.
- IG->object_store()->set_llvm_constant_hash_table(Array::null_array());
-
- // Keep any functions, classes, etc. referenced from the LLVM pools,
- // even if they could have been dropped due to not being otherwise
- // needed at runtime.
- const auto& constant_pool = GrowableObjectArray::Handle(
- Z, IG->object_store()->llvm_constant_pool());
- auto& object = Object::Handle(Z);
- for (intptr_t i = 0; i < constant_pool.Length(); i++) {
- object = constant_pool.At(i);
- if (object.IsNull()) continue;
- if (object.IsInstance()) {
- AddConstObject(Instance::Cast(object));
- } else if (object.IsField()) {
- AddField(Field::Cast(object));
- } else if (object.IsFunction()) {
- AddFunction(Function::Cast(object), RetainReasons::kLLVMPool);
- }
- }
-
- const auto& function_pool = GrowableObjectArray::Handle(
- Z, IG->object_store()->llvm_function_pool());
- auto& function = Function::Handle(Z);
- for (intptr_t i = 0; i < function_pool.Length(); i++) {
- function ^= function_pool.At(i);
- AddFunction(function, RetainReasons::kLLVMPool);
- }
- }
- }
-
if (tracer_ != nullptr) {
tracer_->Finalize();
tracer_ = nullptr;
diff --git a/runtime/vm/compiler/aot/precompiler.h b/runtime/vm/compiler/aot/precompiler.h
index 01e2892..48613ee 100644
--- a/runtime/vm/compiler/aot/precompiler.h
+++ b/runtime/vm/compiler/aot/precompiler.h
@@ -250,8 +250,6 @@
return dispatch_table_generator_->selector_map();
}
- void* il_serialization_stream() const { return il_serialization_stream_; }
-
static Precompiler* Instance() { return singleton_; }
void AddField(const Field& field);
@@ -348,10 +346,6 @@
void FinalizeAllClasses();
- void set_il_serialization_stream(void* file) {
- il_serialization_stream_ = file;
- }
-
Thread* thread() const { return thread_; }
Zone* zone() const { return zone_; }
Isolate* isolate() const { return isolate_; }
@@ -431,7 +425,6 @@
compiler::DispatchTableGenerator* dispatch_table_generator_;
bool get_runtime_type_is_unique_;
- void* il_serialization_stream_;
Phase phase_ = Phase::kPreparation;
PrecompilerTracer* tracer_ = nullptr;
diff --git a/runtime/vm/compiler/backend/compile_type.h b/runtime/vm/compiler/backend/compile_type.h
index 3a7d6aa..192d541 100644
--- a/runtime/vm/compiler/backend/compile_type.h
+++ b/runtime/vm/compiler/backend/compile_type.h
@@ -18,9 +18,6 @@
class AbstractType;
class BaseTextBuffer;
class Definition;
-class FlowGraphSerializer;
-class SExpression;
-class SExpList;
template <typename T>
class GrowableArray;
@@ -248,8 +245,6 @@
bool Specialize(GrowableArray<intptr_t>* class_ids);
void PrintTo(BaseTextBuffer* f) const;
- SExpression* ToSExpression(FlowGraphSerializer* s) const;
- void AddExtraInfoToSExpression(SExpList* sexp, FlowGraphSerializer* s) const;
const char* ToCString() const;
diff --git a/runtime/vm/compiler/backend/il.h b/runtime/vm/compiler/backend/il.h
index 38006b2..3cf8ffc 100644
--- a/runtime/vm/compiler/backend/il.h
+++ b/runtime/vm/compiler/backend/il.h
@@ -49,7 +49,6 @@
class Environment;
class FlowGraph;
class FlowGraphCompiler;
-class FlowGraphSerializer;
class FlowGraphVisitor;
class ForwardInstructionIterator;
class Instruction;
@@ -59,8 +58,6 @@
class Range;
class RangeAnalysis;
class RangeBoundary;
-class SExpList;
-class SExpression;
class SuccessorsIterable;
class TypeUsageInfo;
class UnboxIntegerInstr;
@@ -150,8 +147,6 @@
void PrintTo(BaseTextBuffer* f) const;
#endif // defined(INCLUDE_IL_PRINTER)
- SExpression* ToSExpression(FlowGraphSerializer* s) const;
-
const char* ToCString() const;
bool IsSmiValue() { return Type()->ToCid() == kSmiCid; }
@@ -569,17 +564,6 @@
#define PRINT_OPERANDS_TO_SUPPORT
#endif // defined(INCLUDE_IL_PRINTER)
-#define TO_S_EXPRESSION_SUPPORT \
- virtual SExpression* ToSExpression(FlowGraphSerializer* s) const;
-
-#define ADD_OPERANDS_TO_S_EXPRESSION_SUPPORT \
- virtual void AddOperandsToSExpression(SExpList* sexp, \
- FlowGraphSerializer* s) const;
-
-#define ADD_EXTRA_INFO_TO_S_EXPRESSION_SUPPORT \
- virtual void AddExtraInfoToSExpression(SExpList* sexp, \
- FlowGraphSerializer* s) const;
-
// Together with CidRange, this represents a mapping from a range of class-ids
// to a method for a given selector (method name). Also can contain an
// indication of how frequently a given method has been called at a call site.
@@ -932,11 +916,6 @@
const char* ToCString() const;
PRINT_TO_SUPPORT
PRINT_OPERANDS_TO_SUPPORT
- virtual SExpression* ToSExpression(FlowGraphSerializer* s) const;
- virtual void AddOperandsToSExpression(SExpList* sexp,
- FlowGraphSerializer* s) const;
- virtual void AddExtraInfoToSExpression(SExpList* sexp,
- FlowGraphSerializer* s) const;
#define DECLARE_INSTRUCTION_TYPE_CHECK(Name, Type) \
bool Is##Name() const { return (As##Name() != nullptr); } \
@@ -1519,9 +1498,6 @@
DEFINE_INSTRUCTION_TYPE_CHECK(BlockEntry)
- TO_S_EXPRESSION_SUPPORT
- ADD_OPERANDS_TO_S_EXPRESSION_SUPPORT
- ADD_EXTRA_INFO_TO_S_EXPRESSION_SUPPORT
protected:
BlockEntryInstr(intptr_t block_id,
@@ -1822,7 +1798,6 @@
virtual bool HasUnknownSideEffects() const { return false; }
PRINT_TO_SUPPORT
- ADD_OPERANDS_TO_S_EXPRESSION_SUPPORT
private:
// Classes that have access to predecessors_ when inlining.
@@ -2269,7 +2244,6 @@
PRINT_OPERANDS_TO_SUPPORT
PRINT_TO_SUPPORT
- TO_S_EXPRESSION_SUPPORT
bool UpdateType(CompileType new_type) {
if (type_ == nullptr) {
@@ -2382,7 +2356,6 @@
protected:
friend class RangeAnalysis;
friend class Value;
- friend class FlowGraphSerializer; // To access type_ directly.
Range* range_ = nullptr;
@@ -2617,7 +2590,6 @@
virtual bool MayThrow() const { return false; }
PRINT_OPERANDS_TO_SUPPORT
- ADD_OPERANDS_TO_S_EXPRESSION_SUPPORT
private:
virtual void RawSetInputAt(intptr_t i, Value* value) { UNREACHABLE(); }
@@ -2723,7 +2695,6 @@
intptr_t offset() const { return offset_; }
PRINT_OPERANDS_TO_SUPPORT
- ADD_EXTRA_INFO_TO_S_EXPRESSION_SUPPORT
private:
const intptr_t offset_;
@@ -2774,7 +2745,6 @@
intptr_t offset() const { return offset_; }
PRINT_OPERANDS_TO_SUPPORT
- ADD_EXTRA_INFO_TO_S_EXPRESSION_SUPPORT
private:
const intptr_t offset_;
@@ -2906,7 +2876,6 @@
virtual bool ComputeCanDeoptimize() const { return false; }
PRINT_OPERANDS_TO_SUPPORT
- ADD_OPERANDS_TO_S_EXPRESSION_SUPPORT
private:
const Code& code_;
@@ -3188,7 +3157,6 @@
}
PRINT_TO_SUPPORT
- ADD_OPERANDS_TO_S_EXPRESSION_SUPPORT
private:
BlockEntryInstr* block_;
@@ -3299,7 +3267,6 @@
(operation_cid() == other_comparison->operation_cid());
}
- ADD_OPERANDS_TO_S_EXPRESSION_SUPPORT
DEFINE_INSTRUCTION_TYPE_CHECK(Comparison)
@@ -3438,7 +3405,6 @@
virtual BlockEntryInstr* SuccessorAt(intptr_t index) const;
PRINT_TO_SUPPORT
- ADD_OPERANDS_TO_S_EXPRESSION_SUPPORT
private:
virtual void RawSetInputAt(intptr_t i, Value* value) {
@@ -3592,7 +3558,6 @@
Register tmp = kNoRegister);
PRINT_OPERANDS_TO_SUPPORT
- ADD_OPERANDS_TO_S_EXPRESSION_SUPPORT
private:
const Object& value_;
@@ -3759,7 +3724,6 @@
virtual Value* RedefinedValue() const;
PRINT_OPERANDS_TO_SUPPORT
- ADD_EXTRA_INFO_TO_S_EXPRESSION_SUPPORT
private:
const TokenPosition token_pos_;
@@ -3850,7 +3814,6 @@
const char* ToCString() const;
PRINT_OPERANDS_TO_SUPPORT
- ADD_OPERANDS_TO_S_EXPRESSION_SUPPORT
private:
const SpecialParameterKind kind_;
@@ -3960,7 +3923,6 @@
ArgumentsSizeWithoutTypeArgs(), argument_names());
}
- ADD_EXTRA_INFO_TO_S_EXPRESSION_SUPPORT
private:
virtual void RawSetInputAt(intptr_t i, Value* value) {
@@ -4005,7 +3967,6 @@
Code::EntryKind entry_kind() const { return entry_kind_; }
PRINT_OPERANDS_TO_SUPPORT
- ADD_EXTRA_INFO_TO_S_EXPRESSION_SUPPORT
private:
const Code::EntryKind entry_kind_;
@@ -4103,8 +4064,6 @@
Code::EntryKind entry_kind() const { return entry_kind_; }
void set_entry_kind(Code::EntryKind value) { entry_kind_ = value; }
- ADD_OPERANDS_TO_S_EXPRESSION_SUPPORT
- ADD_EXTRA_INFO_TO_S_EXPRESSION_SUPPORT
DEFINE_INSTRUCTION_TYPE_CHECK(InstanceCallBase);
bool receiver_is_not_smi() const { return receiver_is_not_smi_; }
@@ -4220,7 +4179,6 @@
virtual Definition* Canonicalize(FlowGraph* flow_graph);
PRINT_OPERANDS_TO_SUPPORT
- ADD_EXTRA_INFO_TO_S_EXPRESSION_SUPPORT
bool MatchesCoreName(const String& name);
@@ -4295,7 +4253,6 @@
static TypePtr ComputeRuntimeType(const CallTargets& targets);
PRINT_OPERANDS_TO_SUPPORT
- ADD_EXTRA_INFO_TO_S_EXPRESSION_SUPPORT
private:
PolymorphicInstanceCallInstr(const InstructionSource& source,
@@ -4434,8 +4391,7 @@
bool AttributesEqual(Instruction* other) const;
- PRINT_OPERANDS_TO_SUPPORT
- ADD_EXTRA_INFO_TO_S_EXPRESSION_SUPPORT;
+ PRINT_OPERANDS_TO_SUPPORT;
private:
Condition EmitComparisonCodeRegConstant(FlowGraphCompiler* compiler,
@@ -4868,8 +4824,6 @@
const class BinaryFeedback& BinaryFeedback();
PRINT_OPERANDS_TO_SUPPORT
- ADD_OPERANDS_TO_S_EXPRESSION_SUPPORT
- ADD_EXTRA_INFO_TO_S_EXPRESSION_SUPPORT
private:
const ICData* ic_data_;
@@ -4916,7 +4870,6 @@
virtual TokenPosition token_pos() const { return token_pos_; }
PRINT_OPERANDS_TO_SUPPORT
- ADD_OPERANDS_TO_S_EXPRESSION_SUPPORT
private:
const LocalVariable& local_;
@@ -5048,7 +5001,6 @@
virtual TokenPosition token_pos() const { return token_pos_; }
PRINT_OPERANDS_TO_SUPPORT
- ADD_OPERANDS_TO_S_EXPRESSION_SUPPORT
private:
const LocalVariable& local_;
@@ -5098,8 +5050,6 @@
void SetupNative();
PRINT_OPERANDS_TO_SUPPORT
- ADD_OPERANDS_TO_S_EXPRESSION_SUPPORT
- ADD_EXTRA_INFO_TO_S_EXPRESSION_SUPPORT
private:
void set_native_c_function(NativeFunction value) {
@@ -5292,7 +5242,6 @@
virtual bool HasUnknownSideEffects() const { return true; }
virtual Instruction* Canonicalize(FlowGraph* flow_graph);
- ADD_EXTRA_INFO_TO_S_EXPRESSION_SUPPORT
private:
const TokenPosition token_pos_;
@@ -5423,8 +5372,6 @@
virtual Instruction* Canonicalize(FlowGraph* flow_graph);
PRINT_OPERANDS_TO_SUPPORT
- ADD_OPERANDS_TO_S_EXPRESSION_SUPPORT
- ADD_EXTRA_INFO_TO_S_EXPRESSION_SUPPORT
private:
friend class JitCallSpecializer; // For ASSERT(initialization_).
@@ -5684,7 +5631,6 @@
virtual Definition* Canonicalize(FlowGraph* flow_graph);
- ADD_EXTRA_INFO_TO_S_EXPRESSION_SUPPORT
private:
const bool index_unboxed_;
@@ -5988,7 +5934,6 @@
virtual Instruction* Canonicalize(FlowGraph* flow_graph);
- ADD_EXTRA_INFO_TO_S_EXPRESSION_SUPPORT
private:
compiler::Assembler::CanBeSmi CanValueBeSmi() const {
@@ -6170,8 +6115,6 @@
}
PRINT_OPERANDS_TO_SUPPORT
- ADD_OPERANDS_TO_S_EXPRESSION_SUPPORT
- ADD_EXTRA_INFO_TO_S_EXPRESSION_SUPPORT
private:
virtual void RawSetInputAt(intptr_t i, Value* value) {
@@ -6639,8 +6582,6 @@
virtual bool AttributesEqual(Instruction* other) const;
PRINT_OPERANDS_TO_SUPPORT
- ADD_OPERANDS_TO_S_EXPRESSION_SUPPORT
- ADD_EXTRA_INFO_TO_S_EXPRESSION_SUPPORT
private:
intptr_t OffsetInBytes() const { return slot().offset_in_bytes(); }
@@ -7469,7 +7410,6 @@
}
PRINT_OPERANDS_TO_SUPPORT
- ADD_OPERANDS_TO_S_EXPRESSION_SUPPORT
DECLARE_COMPARISON_INSTRUCTION(DoubleTestOp)
@@ -7642,7 +7582,6 @@
virtual Definition* Canonicalize(FlowGraph* flow_graph);
PRINT_OPERANDS_TO_SUPPORT
- ADD_OPERANDS_TO_S_EXPRESSION_SUPPORT
DECLARE_INSTRUCTION(CheckedSmiOp)
@@ -7767,7 +7706,6 @@
virtual void InferRange(RangeAnalysis* analysis, Range* range);
PRINT_OPERANDS_TO_SUPPORT
- ADD_OPERANDS_TO_S_EXPRESSION_SUPPORT
DEFINE_INSTRUCTION_TYPE_CHECK(BinaryIntegerOp)
@@ -8220,7 +8158,6 @@
}
PRINT_OPERANDS_TO_SUPPORT
- ADD_EXTRA_INFO_TO_S_EXPRESSION_SUPPORT
private:
const TokenPosition token_pos_;
@@ -8792,7 +8729,6 @@
virtual Value* RedefinedValue() const;
- ADD_EXTRA_INFO_TO_S_EXPRESSION_SUPPORT
PRINT_OPERANDS_TO_SUPPORT
@@ -9323,8 +9259,6 @@
DECLARE_INSTRUCTION(SimdOp)
PRINT_OPERANDS_TO_SUPPORT
- ADD_OPERANDS_TO_S_EXPRESSION_SUPPORT
- ADD_EXTRA_INFO_TO_S_EXPRESSION_SUPPORT
private:
SimdOpInstr(Kind kind, intptr_t deopt_id)
@@ -9539,7 +9473,6 @@
Definition* result) const;
void PrintTo(BaseTextBuffer* f) const;
- SExpression* ToSExpression(FlowGraphSerializer* s) const;
const char* ToCString() const;
// Deep copy an environment. The 'length' parameter may be less than the
diff --git a/runtime/vm/compiler/backend/il_deserializer.cc b/runtime/vm/compiler/backend/il_deserializer.cc
deleted file mode 100644
index eb7f1fa..0000000
--- a/runtime/vm/compiler/backend/il_deserializer.cc
+++ /dev/null
@@ -1,2520 +0,0 @@
-// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#include "vm/compiler/backend/il_deserializer.h"
-
-#include "vm/compiler/backend/il_serializer.h"
-#include "vm/compiler/backend/range_analysis.h"
-#include "vm/compiler/call_specializer.h"
-#include "vm/compiler/frontend/base_flow_graph_builder.h"
-#include "vm/compiler/jit/compiler.h"
-#include "vm/flags.h"
-#include "vm/json_writer.h"
-#include "vm/os.h"
-
-namespace dart {
-
-DEFINE_FLAG(bool,
- trace_round_trip_serialization,
- false,
- "Print out tracing information during round trip serialization.");
-DEFINE_FLAG(bool,
- print_json_round_trip_results,
- false,
- "Print out results of each round trip serialization in JSON form.");
-
-// Contains the contents of a single round-trip result.
-struct RoundTripResults : public ValueObject {
- explicit RoundTripResults(Zone* zone, const Function& func)
- : function(func), unhandled(zone, 2) {}
-
- // The function for which a flow graph was being parsed.
- const Function& function;
- // Whether the round trip succeeded.
- bool success = false;
- // An array of unhandled instructions found in the flow graph.
- GrowableArray<Instruction*> unhandled;
- // The serialized form of the flow graph, if computed.
- SExpression* serialized = nullptr;
- // The error information from the deserializer, if an error occurred.
- const char* error_message = nullptr;
- SExpression* error_sexp = nullptr;
-};
-
-// Return a textual description of how to find the sub-expression [to_find]
-// inside a [root] S-Expression.
-static const char* GetSExpressionPosition(Zone* zone,
- SExpression* root,
- SExpression* to_find) {
- // The S-expression to find _is_ the root, so no description is needed.
- if (root == to_find) return "";
- // The S-expression to find cannot be a sub-expression of the given root,
- // so return nullptr to signal this.
- if (!root->IsList()) return nullptr;
- auto const list = root->AsList();
- for (intptr_t i = 0, n = list->Length(); i < n; i++) {
- if (auto const str = GetSExpressionPosition(zone, list->At(i), to_find)) {
- return OS::SCreate(zone, "element %" Pd "%s%s", i,
- *str == '\0' ? "" : " -> ", str);
- }
- }
- auto it = list->ExtraIterator();
- while (auto kv = it.Next()) {
- if (auto const str = GetSExpressionPosition(zone, kv->value, to_find)) {
- return OS::SCreate(zone, "label %s%s%s", kv->key,
- *str == '\0' ? "" : " -> ", str);
- }
- }
- return nullptr;
-}
-
-static void PrintRoundTripResults(Zone* zone, const RoundTripResults& results) {
- // A few checks to make sure we'll print out enough info. First, if there are
- // no unhandled instructions, then we should have serialized the flow graph.
- ASSERT(!results.unhandled.is_empty() || results.serialized != nullptr);
- // If we failed, then either there are unhandled instructions or we have
- // an appropriate error message and sexp from the FlowGraphDeserializer.
- ASSERT(results.success || !results.unhandled.is_empty() ||
- (results.error_message != nullptr && results.error_sexp != nullptr));
-
- JSONWriter js;
-
- js.OpenObject();
- js.PrintProperty("function", results.function.ToFullyQualifiedCString());
- js.PrintPropertyBool("success", results.success);
-
- if (!results.unhandled.is_empty()) {
- CStringMap<intptr_t> count_map(zone);
- for (auto inst : results.unhandled) {
- auto const name = inst->DebugName();
- auto const old_count = count_map.LookupValue(name);
- count_map.Update({name, old_count + 1});
- }
-
- auto count_it = count_map.GetIterator();
- js.OpenObject("unhandled");
- while (auto kv = count_it.Next()) {
- js.PrintProperty64(kv->key, kv->value);
- }
- js.CloseObject();
- }
-
- if (results.serialized != nullptr) {
- TextBuffer buf(1000);
- results.serialized->SerializeTo(zone, &buf, "");
- js.PrintProperty("serialized", buf.buffer());
- }
-
- if (results.error_message != nullptr) {
- js.OpenObject("error");
- js.PrintProperty("message", results.error_message);
-
- ASSERT(results.error_sexp != nullptr);
- TextBuffer buf(1000);
- results.error_sexp->SerializeTo(zone, &buf, "");
- js.PrintProperty("expression", buf.buffer());
-
- auto const sexp_position =
- GetSExpressionPosition(zone, results.serialized, results.error_sexp);
- js.PrintProperty("path", sexp_position);
- js.CloseObject();
- }
-
- js.CloseObject();
- THR_Print("Results of round trip serialization: %s\n", js.buffer()->buffer());
-}
-
-void FlowGraphDeserializer::RoundTripSerialization(CompilerPassState* state) {
- auto const flow_graph = state->flow_graph();
-
- // The deserialized flow graph must be in the same zone as the original flow
- // graph, to ensure it has the right lifetime. Thus, we leave an explicit
- // use of [flow_graph->zone()] in the deserializer construction.
- //
- // Otherwise, it would be nice to use a StackZone to limit the lifetime of the
- // serialized form (and other values created with this [zone] variable), since
- // it only needs to live for the dynamic extent of this method.
- //
- // However, creating a StackZone for it also changes the zone associated with
- // the thread. Also, some parts of the VM used in later updates to the
- // deserializer implicitly pick up the zone to use either from a passed-in
- // thread or the current thread instead of taking an explicit zone.
- //
- // For now, just serialize into the same zone as the original flow graph, and
- // we can revisit this if this causes a performance issue or if we can ensure
- // that those VM parts mentioned can be passed an explicit zone.
- Zone* const zone = flow_graph->zone();
-
- // Final flow graph, if we successfully serialize and deserialize.
- FlowGraph* new_graph = nullptr;
-
- // Stored information for printing results if requested.
- RoundTripResults results(zone, flow_graph->function());
-
- FlowGraphDeserializer::AllUnhandledInstructions(flow_graph,
- &results.unhandled);
- if (results.unhandled.is_empty()) {
- results.serialized = FlowGraphSerializer::SerializeToSExp(zone, flow_graph);
-
- if (FLAG_trace_round_trip_serialization && results.serialized != nullptr) {
- TextBuffer buf(1000);
- results.serialized->SerializeTo(zone, &buf, "");
- THR_Print("Serialized flow graph:\n%s\n", buf.buffer());
- }
-
- // For the deserializer, use the thread from the compiler pass and zone
- // associated with the existing flow graph to make sure the new flow graph
- // has the right lifetime.
- FlowGraphDeserializer d(state->thread, flow_graph->zone(),
- results.serialized, &flow_graph->parsed_function());
- new_graph = d.ParseFlowGraph();
- if (new_graph == nullptr) {
- ASSERT(d.error_message() != nullptr && d.error_sexp() != nullptr);
- if (FLAG_trace_round_trip_serialization) {
- THR_Print("Failure during deserialization: %s\n", d.error_message());
- THR_Print("At S-expression %s\n", d.error_sexp()->ToCString(zone));
- if (auto const pos = GetSExpressionPosition(zone, results.serialized,
- d.error_sexp())) {
- THR_Print("Path from root: %s\n", pos);
- }
- }
- results.error_message = d.error_message();
- results.error_sexp = d.error_sexp();
- } else {
- if (FLAG_trace_round_trip_serialization) {
- THR_Print("Successfully deserialized graph for %s\n",
- results.serialized->AsList()->At(1)->AsSymbol()->value());
- }
- results.success = true;
- }
- } else if (FLAG_trace_round_trip_serialization) {
- THR_Print("Cannot serialize graph due to instruction: %s\n",
- results.unhandled.At(0)->DebugName());
- }
-
- if (FLAG_print_json_round_trip_results) PrintRoundTripResults(zone, results);
-
- if (new_graph != nullptr) {
- state->set_flow_graph(new_graph);
- }
-}
-
-#define HANDLED_CASE(name) \
- if (inst->Is##name()) return true;
-bool FlowGraphDeserializer::IsHandledInstruction(Instruction* inst) {
- if (auto const const_inst = inst->AsConstant()) {
- return IsHandledConstant(const_inst->value());
- }
- FOR_EACH_HANDLED_BLOCK_TYPE_IN_DESERIALIZER(HANDLED_CASE)
- FOR_EACH_HANDLED_INSTRUCTION_IN_DESERIALIZER(HANDLED_CASE)
- return false;
-}
-#undef HANDLED_CASE
-
-void FlowGraphDeserializer::AllUnhandledInstructions(
- const FlowGraph* graph,
- GrowableArray<Instruction*>* unhandled) {
- ASSERT(graph != nullptr);
- ASSERT(unhandled != nullptr);
- for (auto block_it = graph->reverse_postorder_iterator(); !block_it.Done();
- block_it.Advance()) {
- auto const entry = block_it.Current();
- if (!IsHandledInstruction(entry)) unhandled->Add(entry);
- // Check that the Phi instructions in JoinEntrys do not have pair
- // representation.
- if (auto const join_block = entry->AsJoinEntry()) {
- auto const phis = join_block->phis();
- auto const length = ((phis == nullptr) ? 0 : phis->length());
- for (intptr_t i = 0; i < length; i++) {
- auto const current = phis->At(i);
- for (intptr_t j = 0; j < current->InputCount(); j++) {
- if (current->InputAt(j)->definition()->HasPairRepresentation()) {
- unhandled->Add(current);
- }
- }
- }
- }
- if (auto const def_block = entry->AsBlockEntryWithInitialDefs()) {
- auto const defs = def_block->initial_definitions();
- for (intptr_t i = 0; i < defs->length(); i++) {
- auto const current = defs->At(i);
- if (!IsHandledInstruction(current)) unhandled->Add(current);
- }
- }
- for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) {
- auto current = it.Current();
- // We handle branches, so we need to check the comparison instruction.
- if (current->IsBranch()) current = current->AsBranch()->comparison();
- if (!IsHandledInstruction(current)) unhandled->Add(current);
- }
- }
-}
-
-// Keep in sync with work in ParseDartValue. Right now, this is just a shallow
-// check, not a deep one.
-bool FlowGraphDeserializer::IsHandledConstant(const Object& obj) {
- if (obj.IsArray()) return Array::Cast(obj).IsImmutable();
- return obj.IsNull() || obj.IsClass() || obj.IsFunction() || obj.IsField() ||
- obj.IsInstance();
-}
-
-SExpression* FlowGraphDeserializer::Retrieve(SExpList* list, intptr_t index) {
- if (list == nullptr) return nullptr;
- if (list->Length() <= index) {
- StoreError(list, "expected at least %" Pd " element(s) in list", index + 1);
- return nullptr;
- }
- auto const elem = list->At(index);
- if (elem == nullptr) {
- StoreError(list, "null value at index %" Pd "", index);
- }
- return elem;
-}
-
-SExpression* FlowGraphDeserializer::Retrieve(SExpList* list, const char* key) {
- if (list == nullptr) return nullptr;
- if (!list->ExtraHasKey(key)) {
- StoreError(list, "expected an extra info entry for key %s", key);
- return nullptr;
- }
- auto const elem = list->ExtraLookupValue(key);
- if (elem == nullptr) {
- StoreError(list, "null value for key %s", key);
- }
- return elem;
-}
-
-FlowGraph* FlowGraphDeserializer::ParseFlowGraph() {
- auto const root = CheckTaggedList(root_sexp_, "FlowGraph");
- if (root == nullptr) return nullptr;
-
- intptr_t deopt_id = DeoptId::kNone;
- if (auto const deopt_id_sexp =
- CheckInteger(root->ExtraLookupValue("deopt_id"))) {
- deopt_id = deopt_id_sexp->value();
- }
- EntryInfo common_info = {0, kInvalidTryIndex, deopt_id};
-
- auto const graph = DeserializeGraphEntry(root, common_info);
-
- PrologueInfo pi(-1, -1);
- flow_graph_ = new (zone()) FlowGraph(*parsed_function_, graph, 0, pi);
- flow_graph_->CreateCommonConstants();
-
- intptr_t pos = 2;
- if (auto const pool = CheckTaggedList(Retrieve(root, pos), "Constants")) {
- if (!ParseConstantPool(pool)) return nullptr;
- pos++;
- }
-
- // The deopt environment for the graph entry may use entries from the
- // constant pool, so that must be parsed first.
- if (auto const env_sexp = CheckList(root->ExtraLookupValue("env"))) {
- current_block_ = graph;
- auto const env = ParseEnvironment(env_sexp);
- if (env == nullptr) return nullptr;
- env->DeepCopyTo(zone(), graph);
- }
-
- auto const entries_sexp = CheckTaggedList(Retrieve(root, pos), "Entries");
- if (!ParseEntries(entries_sexp)) return nullptr;
- pos++;
-
- // Now prime the block worklist with entries. We keep the block worklist
- // in reverse order so that we can just pop the next block for content
- // parsing off the end.
- BlockWorklist block_worklist(zone(), entries_sexp->Length() - 1);
-
- const auto& indirect_entries = graph->indirect_entries();
- for (auto indirect_entry : indirect_entries) {
- block_worklist.Add(indirect_entry->block_id());
- }
-
- const auto& catch_entries = graph->catch_entries();
- for (auto catch_entry : catch_entries) {
- block_worklist.Add(catch_entry->block_id());
- }
-
- if (auto const osr_entry = graph->osr_entry()) {
- block_worklist.Add(osr_entry->block_id());
- }
- if (auto const unchecked_entry = graph->unchecked_entry()) {
- block_worklist.Add(unchecked_entry->block_id());
- }
- if (auto const normal_entry = graph->normal_entry()) {
- block_worklist.Add(normal_entry->block_id());
- }
-
- if (!ParseBlocks(root, pos, &block_worklist)) return nullptr;
-
- // Before we return the new graph, make sure all definitions were found for
- // all pending values.
- if (values_map_.Length() > 0) {
- auto it = values_map_.GetIterator();
- auto const kv = it.Next();
- ASSERT(kv->value->length() > 0);
- const auto& value_info = kv->value->At(0);
- StoreError(value_info.sexp, "no definition found for use in flow graph");
- return nullptr;
- }
-
- flow_graph_->set_max_block_id(max_block_id_);
- // The highest numbered SSA temp might need two slots (e.g. for unboxed
- // integers on 32-bit platforms), so we add 2 to the highest seen SSA temp
- // index to get to the new current SSA temp index. In cases where the highest
- // numbered SSA temp originally had only one slot assigned, this can result
- // in different SSA temp numbering in later passes between the original and
- // deserialized graphs.
- flow_graph_->set_current_ssa_temp_index(max_ssa_index_ + 2);
- // Now that the deserializer has finished re-creating all the blocks in the
- // flow graph, the blocks must be rediscovered. In addition, if ComputeSSA
- // has already been run, dominators must be recomputed as well.
- flow_graph_->DiscoverBlocks();
- // Currently we only handle SSA graphs, so always do this.
- GrowableArray<BitVector*> dominance_frontier;
- flow_graph_->ComputeDominators(&dominance_frontier);
-
- return flow_graph_;
-}
-
-bool FlowGraphDeserializer::ParseConstantPool(SExpList* pool) {
- ASSERT(flow_graph_ != nullptr);
- if (pool == nullptr) return false;
- // Definitions in the constant pool may refer to later definitions. However,
- // there should be no cycles possible between constant objects, so using a
- // worklist algorithm we should always be able to make progress.
- // Since we will not be adding new definitions, we make the initial size of
- // the worklist the number of definitions in the constant pool.
- GrowableArray<SExpList*> worklist(zone(), pool->Length() - 1);
- // In order to ensure that the definition order is the same in the original
- // flow graph, we can't just simply call GetConstant() whenever we
- // successfully parse a constant. Instead, we'll create a stand-in
- // ConstantInstr that we can temporarily stick in the definition_map_, and
- // then once finished we'll go back through, add the constants via
- // GetConstant() and parse any extra information.
- DirectChainedHashMap<RawPointerKeyValueTrait<SExpList, ConstantInstr*>>
- parsed_constants(zone());
- // We keep old_worklist in reverse order so that we can just RemoveLast
- // to get elements in their original order.
- for (intptr_t i = pool->Length() - 1; i > 0; i--) {
- const auto def_sexp = CheckTaggedList(pool->At(i), "def");
- if (def_sexp == nullptr) return false;
- worklist.Add(def_sexp);
- }
- while (true) {
- const intptr_t worklist_len = worklist.length();
- GrowableArray<SExpList*> parse_failures(zone(), worklist_len);
- while (!worklist.is_empty()) {
- const auto def_sexp = worklist.RemoveLast();
- auto& obj = Object::ZoneHandle(zone());
- if (!ParseDartValue(Retrieve(def_sexp, 2), &obj)) {
- parse_failures.Add(def_sexp);
- continue;
- }
- ConstantInstr* def = new (zone()) ConstantInstr(obj);
- // Instead of parsing the whole definition, just get the SSA index so
- // we can insert it into the definition_map_.
- intptr_t index;
- auto const name_sexp = CheckSymbol(Retrieve(def_sexp, 1));
- if (!ParseSSATemp(name_sexp, &index)) return false;
- def->set_ssa_temp_index(index);
- ASSERT(!definition_map_.HasKey(index));
- definition_map_.Insert(index, def);
- parsed_constants.Insert({def_sexp, def});
- }
- if (parse_failures.is_empty()) break;
- // We've gone through the whole worklist without success, so return
- // the last error we encountered.
- if (parse_failures.length() == worklist_len) return false;
- // worklist was added to in order, so we need to reverse its contents
- // when we add them to old_worklist.
- while (!parse_failures.is_empty()) {
- worklist.Add(parse_failures.RemoveLast());
- }
- }
- // Now loop back through the constant pool definition S-expressions and
- // get the real ConstantInstrs the flow graph will be using and finish
- // parsing.
- for (intptr_t i = 1; i < pool->Length(); i++) {
- auto const def_sexp = CheckTaggedList(pool->At(i));
- auto const temp_def = parsed_constants.LookupValue(def_sexp);
- ASSERT(temp_def != nullptr);
- // Remove the temporary definition from definition_map_ so this doesn't get
- // flagged as a redefinition.
- definition_map_.Remove(temp_def->ssa_temp_index());
- ConstantInstr* real_def = flow_graph_->GetConstant(temp_def->value());
- if (!ParseDefinitionWithParsedBody(def_sexp, real_def)) return false;
- ASSERT(temp_def->ssa_temp_index() == real_def->ssa_temp_index());
- }
- return true;
-}
-
-bool FlowGraphDeserializer::ParseEntries(SExpList* list) {
- ASSERT(flow_graph_ != nullptr);
- if (list == nullptr) return false;
- for (intptr_t i = 1; i < list->Length(); i++) {
- const auto entry = CheckTaggedList(Retrieve(list, i));
- if (entry == nullptr) return false;
- intptr_t block_id;
- if (!ParseBlockId(CheckSymbol(Retrieve(entry, 1)), &block_id)) {
- return false;
- }
- if (block_map_.LookupValue(block_id) != nullptr) {
- StoreError(entry->At(1), "multiple entries for block found");
- return false;
- }
- const auto tag = entry->Tag();
- if (ParseBlockHeader(entry, block_id, tag) == nullptr) return false;
- }
- return true;
-}
-
-bool FlowGraphDeserializer::ParseBlocks(SExpList* list,
- intptr_t pos,
- BlockWorklist* worklist) {
- // First, ensure that all the block headers have been parsed. Set up a
- // map from block IDs to S-expressions and the max_block_id while we're at it.
- IntMap<SExpList*> block_sexp_map(zone());
- for (intptr_t i = pos, n = list->Length(); i < n; i++) {
- auto const block_sexp = CheckTaggedList(Retrieve(list, i), "Block");
- intptr_t block_id;
- if (!ParseBlockId(CheckSymbol(Retrieve(block_sexp, 1)), &block_id)) {
- return false;
- }
- if (block_sexp_map.LookupValue(block_id) != nullptr) {
- StoreError(block_sexp->At(1), "multiple definitions of block found");
- return false;
- }
- block_sexp_map.Insert(block_id, block_sexp);
- auto const type_tag =
- CheckSymbol(block_sexp->ExtraLookupValue("block_type"));
- // Entry block headers are already parsed, but others aren't.
- if (block_map_.LookupValue(block_id) == nullptr) {
- if (ParseBlockHeader(block_sexp, block_id, type_tag) == nullptr) {
- return false;
- }
- }
- if (max_block_id_ < block_id) max_block_id_ = block_id;
- }
-
- // Now start parsing the contents of blocks from the worklist. We use an
- // IntMap to keep track of what blocks have already been fully parsed.
- IntMap<bool> fully_parsed_block_map(zone());
- while (!worklist->is_empty()) {
- auto const block_id = worklist->RemoveLast();
-
- // If we've already encountered this block, skip it.
- if (fully_parsed_block_map.LookupValue(block_id)) continue;
-
- auto const block_sexp = block_sexp_map.LookupValue(block_id);
- ASSERT(block_sexp != nullptr);
-
- current_block_ = block_map_.LookupValue(block_id);
- ASSERT(current_block_ != nullptr);
- ASSERT(current_block_->PredecessorCount() > 0);
-
- if (!ParseBlockContents(block_sexp, worklist)) return false;
-
- // Mark this block as done.
- fully_parsed_block_map.Insert(block_id, true);
- }
-
- // Double-check that all blocks were reached by the worklist algorithm.
- auto it = block_sexp_map.GetIterator();
- while (auto kv = it.Next()) {
- if (!fully_parsed_block_map.LookupValue(kv->key)) {
- StoreError(kv->value, "block unreachable in flow graph");
- return false;
- }
- }
-
- return true;
-}
-
-bool FlowGraphDeserializer::ParseInitialDefinitions(SExpList* list) {
- ASSERT(current_block_ != nullptr);
- ASSERT(current_block_->IsBlockEntryWithInitialDefs());
- auto const block = current_block_->AsBlockEntryWithInitialDefs();
- if (list == nullptr) return false;
- for (intptr_t i = 2; i < list->Length(); i++) {
- const auto def_sexp = CheckTaggedList(Retrieve(list, i), "def");
- const auto def = ParseDefinition(def_sexp);
- if (def == nullptr) return false;
- flow_graph_->AddToInitialDefinitions(block, def);
- }
- return true;
-}
-
-BlockEntryInstr* FlowGraphDeserializer::ParseBlockHeader(SExpList* list,
- intptr_t block_id,
- SExpSymbol* tag) {
- ASSERT(flow_graph_ != nullptr);
- // We should only parse block headers once.
- ASSERT(block_map_.LookupValue(block_id) == nullptr);
- if (list == nullptr) return nullptr;
-
-#if defined(DEBUG)
- intptr_t parsed_block_id;
- auto const id_sexp = CheckSymbol(Retrieve(list, 1));
- if (!ParseBlockId(id_sexp, &parsed_block_id)) return nullptr;
- ASSERT(block_id == parsed_block_id);
-#endif
-
- auto const kind = FlowGraphSerializer::BlockEntryTagToKind(tag);
-
- intptr_t deopt_id = DeoptId::kNone;
- if (auto const deopt_int = CheckInteger(list->ExtraLookupValue("deopt_id"))) {
- deopt_id = deopt_int->value();
- }
- intptr_t try_index = kInvalidTryIndex;
- if (auto const try_int = CheckInteger(list->ExtraLookupValue("try_index"))) {
- try_index = try_int->value();
- }
-
- BlockEntryInstr* block = nullptr;
- EntryInfo common_info = {block_id, try_index, deopt_id};
- switch (kind) {
- case FlowGraphSerializer::kTarget:
- block = DeserializeTargetEntry(list, common_info);
- break;
- case FlowGraphSerializer::kNormal:
- block = DeserializeFunctionEntry(list, common_info);
- if (block != nullptr) {
- auto const graph = flow_graph_->graph_entry();
- graph->set_normal_entry(block->AsFunctionEntry());
- }
- break;
- case FlowGraphSerializer::kUnchecked: {
- block = DeserializeFunctionEntry(list, common_info);
- if (block != nullptr) {
- auto const graph = flow_graph_->graph_entry();
- graph->set_unchecked_entry(block->AsFunctionEntry());
- }
- break;
- }
- case FlowGraphSerializer::kJoin:
- block = DeserializeJoinEntry(list, common_info);
- break;
- case FlowGraphSerializer::kInvalid:
- StoreError(tag, "invalid block entry tag");
- return nullptr;
- default:
- StoreError(tag, "unhandled block type");
- return nullptr;
- }
- if (block == nullptr) return nullptr;
-
- block_map_.Insert(block_id, block);
- return block;
-}
-
-bool FlowGraphDeserializer::ParsePhis(SExpList* list) {
- ASSERT(current_block_ != nullptr && current_block_->IsJoinEntry());
- auto const join = current_block_->AsJoinEntry();
- const intptr_t start_pos = 2;
- auto const end_pos = SkipPhis(list);
- if (end_pos < start_pos) return false;
-
- for (intptr_t i = start_pos; i < end_pos; i++) {
- auto const def_sexp = CheckTaggedList(Retrieve(list, i), "def");
- auto const phi_sexp = CheckTaggedList(Retrieve(def_sexp, 2), "Phi");
- // SkipPhis should already have checked which instructions, if any,
- // are Phi definitions.
- ASSERT(phi_sexp != nullptr);
-
- // This is a generalization of FlowGraph::AddPhi where we let ParseValue
- // create the values (as they may contain type information).
- auto const phi = new (zone()) PhiInstr(join, phi_sexp->Length() - 1);
- phi->mark_alive();
- for (intptr_t i = 0, n = phi_sexp->Length() - 1; i < n; i++) {
- auto const val = ParseValue(Retrieve(phi_sexp, i + 1));
- if (val == nullptr) return false;
- phi->SetInputAt(i, val);
- val->definition()->AddInputUse(val);
- }
- join->InsertPhi(phi);
-
- if (!ParseDefinitionWithParsedBody(def_sexp, phi)) return false;
- }
-
- return true;
-}
-
-intptr_t FlowGraphDeserializer::SkipPhis(SExpList* list) {
- // All blocks are S-exps of the form (Block B# inst...), so skip the first
- // two entries and then skip any Phi definitions.
- for (intptr_t i = 2, n = list->Length(); i < n; i++) {
- auto const def_sexp = CheckTaggedList(Retrieve(list, i), "def");
- if (def_sexp == nullptr) return i;
- auto const phi_sexp = CheckTaggedList(Retrieve(def_sexp, 2), "Phi");
- if (phi_sexp == nullptr) return i;
- }
-
- StoreError(list, "block is empty or contains only Phi definitions");
- return -1;
-}
-
-bool FlowGraphDeserializer::ParseBlockContents(SExpList* list,
- BlockWorklist* worklist) {
- ASSERT(current_block_ != nullptr);
-
- // Parse any Phi definitions now before parsing the block environment.
- if (current_block_->IsJoinEntry()) {
- if (!ParsePhis(list)) return false;
- }
-
- // For blocks with initial definitions or phi definitions, this needs to be
- // done after those are parsed. In addition, block environments can also use
- // definitions from dominating blocks, so we need the contents of dominating
- // blocks to first be parsed.
- //
- // However, we must parse the environment before parsing any instructions
- // in the body of the block to ensure we don't mistakenly allow local
- // definitions to appear in the environment.
- if (auto const env_sexp = CheckList(list->ExtraLookupValue("env"))) {
- auto const env = ParseEnvironment(env_sexp);
- if (env == nullptr) return false;
- env->DeepCopyTo(zone(), current_block_);
- }
-
- auto const pos = SkipPhis(list);
- if (pos < 2) return false;
- Instruction* last_inst = current_block_;
- for (intptr_t i = pos, n = list->Length(); i < n; i++) {
- auto const inst = ParseInstruction(CheckTaggedList(Retrieve(list, i)));
- if (inst == nullptr) return false;
- last_inst = last_inst->AppendInstruction(inst);
- }
-
- ASSERT(last_inst != nullptr && last_inst != current_block_);
- if (last_inst->SuccessorCount() > 0) {
- for (intptr_t i = last_inst->SuccessorCount() - 1; i >= 0; i--) {
- auto const succ_block = last_inst->SuccessorAt(i);
- succ_block->AddPredecessor(current_block_);
- worklist->Add(succ_block->block_id());
- }
- }
-
- return true;
-}
-
-bool FlowGraphDeserializer::ParseDefinitionWithParsedBody(SExpList* list,
- Definition* def) {
- if (auto const type_sexp =
- CheckTaggedList(list->ExtraLookupValue("type"), "CompileType")) {
- CompileType* typ = ParseCompileType(type_sexp);
- if (typ == nullptr) return false;
- def->UpdateType(*typ);
- }
-
- if (auto const range_sexp =
- CheckTaggedList(list->ExtraLookupValue("range"), "Range")) {
- Range range;
- if (!ParseRange(range_sexp, &range)) return false;
- def->set_range(range);
- }
-
- auto const name_sexp = CheckSymbol(Retrieve(list, 1));
- if (name_sexp == nullptr) return false;
-
- // If the name is "_", this is a subclass of Definition where there's no real
- // "result" that's being bound. We were just here to add Definition-specific
- // extra info.
- if (name_sexp->Equals("_")) return true;
-
- intptr_t index;
- if (ParseSSATemp(name_sexp, &index)) {
- if (definition_map_.HasKey(index)) {
- StoreError(list, "multiple definitions for the same SSA index");
- return false;
- }
- def->set_ssa_temp_index(index);
- if (index > max_ssa_index_) max_ssa_index_ = index;
- } else {
- // TODO(sstrickl): Add temp support for non-SSA computed graphs.
- StoreError(list, "unhandled name for definition");
- return false;
- }
-
- definition_map_.Insert(index, def);
- if (!FixPendingValues(index, def)) return false;
- return true;
-}
-
-Definition* FlowGraphDeserializer::ParseDefinition(SExpList* list) {
- if (list == nullptr) return nullptr;
- ASSERT(list->Tag() != nullptr && list->Tag()->Equals("def"));
- auto const inst_sexp = CheckTaggedList(Retrieve(list, 2));
- auto const inst = ParseInstruction(inst_sexp);
- if (inst == nullptr) return nullptr;
- if (auto const def = inst->AsDefinition()) {
- if (!ParseDefinitionWithParsedBody(list, def)) return nullptr;
- return def;
- } else {
- StoreError(list, "instruction cannot be body of definition");
- return nullptr;
- }
-}
-
-Instruction* FlowGraphDeserializer::ParseInstruction(SExpList* list) {
- if (list == nullptr) return nullptr;
- auto const tag = list->Tag();
- if (tag->Equals("def")) return ParseDefinition(list);
-
- intptr_t deopt_id = DeoptId::kNone;
- if (auto const deopt_int = CheckInteger(list->ExtraLookupValue("deopt_id"))) {
- deopt_id = deopt_int->value();
- }
- TokenPosition token_pos = TokenPosition::kNoSource;
- if (auto const token_int =
- CheckInteger(list->ExtraLookupValue("token_pos"))) {
- token_pos = TokenPosition::Deserialize(token_int->value());
- }
- intptr_t inlining_id = -1;
- if (auto const inlining_int =
- CheckInteger(list->ExtraLookupValue("inlining_id"))) {
- inlining_id = inlining_int->value();
- }
- InstrInfo common_info = {deopt_id, InstructionSource(token_pos, inlining_id)};
-
- // Parse the environment before handling the instruction, as we may have
- // references to PushArguments and parsing the instruction may pop
- // PushArguments off the stack.
- // TODO(alexmarkov): revise as it may not be needed anymore.
- Environment* env = nullptr;
- if (auto const env_sexp = CheckList(list->ExtraLookupValue("env"))) {
- env = ParseEnvironment(env_sexp);
- if (env == nullptr) return nullptr;
- }
-
- Instruction* inst = nullptr;
-
-#define HANDLE_CASE(name) \
- case kHandled##name: \
- inst = Deserialize##name(list, common_info); \
- break;
- switch (HandledInstructionForTag(tag)) {
- FOR_EACH_HANDLED_INSTRUCTION_IN_DESERIALIZER(HANDLE_CASE)
- case kHandledInvalid:
- StoreError(tag, "unhandled instruction");
- return nullptr;
- }
-#undef HANDLE_CASE
-
- if (inst == nullptr) return nullptr;
- if (env != nullptr) env->DeepCopyTo(zone(), inst);
- return inst;
-}
-
-FunctionEntryInstr* FlowGraphDeserializer::DeserializeFunctionEntry(
- SExpList* sexp,
- const EntryInfo& info) {
- ASSERT(flow_graph_ != nullptr);
- auto const graph = flow_graph_->graph_entry();
- auto const block = new (zone())
- FunctionEntryInstr(graph, info.block_id, info.try_index, info.deopt_id);
- current_block_ = block;
- if (!ParseInitialDefinitions(sexp)) return nullptr;
- return block;
-}
-
-GraphEntryInstr* FlowGraphDeserializer::DeserializeGraphEntry(
- SExpList* sexp,
- const EntryInfo& info) {
- auto const name_sexp = CheckSymbol(Retrieve(sexp, 1));
- // TODO(sstrickl): If the FlowGraphDeserializer was constructed with a
- // non-null ParsedFunction, we should check that the name matches here.
- // If not, then we should create an appropriate ParsedFunction here.
- if (name_sexp == nullptr) return nullptr;
-
- intptr_t osr_id = Compiler::kNoOSRDeoptId;
- if (auto const osr_id_sexp = CheckInteger(sexp->ExtraLookupValue("osr_id"))) {
- osr_id = osr_id_sexp->value();
- }
-
- ASSERT(parsed_function_ != nullptr);
- return new (zone()) GraphEntryInstr(*parsed_function_, osr_id, info.deopt_id);
-}
-
-JoinEntryInstr* FlowGraphDeserializer::DeserializeJoinEntry(
- SExpList* sexp,
- const EntryInfo& info) {
- return new (zone())
- JoinEntryInstr(info.block_id, info.try_index, info.deopt_id);
-}
-
-TargetEntryInstr* FlowGraphDeserializer::DeserializeTargetEntry(
- SExpList* sexp,
- const EntryInfo& info) {
- return new (zone())
- TargetEntryInstr(info.block_id, info.try_index, info.deopt_id);
-}
-
-AllocateObjectInstr* FlowGraphDeserializer::DeserializeAllocateObject(
- SExpList* sexp,
- const InstrInfo& info) {
- auto& cls = Class::ZoneHandle(zone());
- auto const cls_sexp = CheckTaggedList(Retrieve(sexp, 1), "Class");
- if (!ParseClass(cls_sexp, &cls)) return nullptr;
-
- Value* type_arguments = nullptr;
- if (cls.NumTypeArguments() > 0) {
- type_arguments = ParseValue(Retrieve(sexp, 2));
- if (type_arguments == nullptr) return nullptr;
- }
-
- auto const inst =
- new (zone()) AllocateObjectInstr(info.source, cls, type_arguments);
-
- if (auto const closure_sexp = CheckTaggedList(
- sexp->ExtraLookupValue("closure_function"), "Function")) {
- auto& closure_function = Function::Handle(zone());
- if (!ParseFunction(closure_sexp, &closure_function)) return nullptr;
- inst->set_closure_function(closure_function);
- }
-
- if (auto const ident_sexp = CheckSymbol(sexp->ExtraLookupValue("identity"))) {
- auto id = AliasIdentity::Unknown();
- if (!AliasIdentity::Parse(ident_sexp->value(), &id)) {
- return nullptr;
- }
- inst->SetIdentity(id);
- }
-
- return inst;
-}
-
-AssertAssignableInstr* FlowGraphDeserializer::DeserializeAssertAssignable(
- SExpList* sexp,
- const InstrInfo& info) {
- auto const val = ParseValue(Retrieve(sexp, 1));
- if (val == nullptr) return nullptr;
-
- auto const dst_type = ParseValue(Retrieve(sexp, 2));
- if (dst_type == nullptr) return nullptr;
-
- auto const inst_type_args = ParseValue(Retrieve(sexp, 3));
- if (inst_type_args == nullptr) return nullptr;
-
- auto const func_type_args = ParseValue(Retrieve(sexp, 4));
- if (func_type_args == nullptr) return nullptr;
-
- auto& dst_name = String::ZoneHandle(zone());
- auto const dst_name_sexp = Retrieve(sexp, "name");
- if (!ParseDartValue(dst_name_sexp, &dst_name)) return nullptr;
-
- auto kind = AssertAssignableInstr::Kind::kUnknown;
- if (auto const kind_sexp = CheckSymbol(sexp->ExtraLookupValue("kind"))) {
- if (!AssertAssignableInstr::ParseKind(kind_sexp->value(), &kind)) {
- StoreError(kind_sexp, "unknown AssertAssignable kind");
- return nullptr;
- }
- }
-
- return new (zone())
- AssertAssignableInstr(info.source, val, dst_type, inst_type_args,
- func_type_args, dst_name, info.deopt_id, kind);
-}
-
-AssertBooleanInstr* FlowGraphDeserializer::DeserializeAssertBoolean(
- SExpList* sexp,
- const InstrInfo& info) {
- auto const val = ParseValue(Retrieve(sexp, 1));
- if (val == nullptr) return nullptr;
-
- return new (zone()) AssertBooleanInstr(info.source, val, info.deopt_id);
-}
-
-BooleanNegateInstr* FlowGraphDeserializer::DeserializeBooleanNegate(
- SExpList* sexp,
- const InstrInfo& info) {
- auto const value = ParseValue(Retrieve(sexp, 1));
- if (value == nullptr) return nullptr;
-
- return new (zone()) BooleanNegateInstr(value);
-}
-
-BranchInstr* FlowGraphDeserializer::DeserializeBranch(SExpList* sexp,
- const InstrInfo& info) {
- auto const comp_sexp = CheckTaggedList(Retrieve(sexp, 1));
- auto const comp_inst = ParseInstruction(comp_sexp);
- if (comp_inst == nullptr) return nullptr;
- if (!comp_inst->IsComparison()) {
- StoreError(sexp->At(1), "expected comparison instruction");
- return nullptr;
- }
- auto const comparison = comp_inst->AsComparison();
-
- auto const true_block = FetchBlock(CheckSymbol(Retrieve(sexp, 2)));
- if (true_block == nullptr) return nullptr;
- if (!true_block->IsTargetEntry()) {
- StoreError(sexp->At(2), "true successor is not a target block");
- return nullptr;
- }
-
- auto const false_block = FetchBlock(CheckSymbol(Retrieve(sexp, 3)));
- if (false_block == nullptr) return nullptr;
- if (!false_block->IsTargetEntry()) {
- StoreError(sexp->At(3), "false successor is not a target block");
- return nullptr;
- }
-
- auto const branch = new (zone()) BranchInstr(comparison, info.deopt_id);
- *branch->true_successor_address() = true_block->AsTargetEntry();
- *branch->false_successor_address() = false_block->AsTargetEntry();
- return branch;
-}
-
-CheckNullInstr* FlowGraphDeserializer::DeserializeCheckNull(
- SExpList* sexp,
- const InstrInfo& info) {
- auto const val = ParseValue(Retrieve(sexp, 1));
- if (val == nullptr) return nullptr;
-
- auto& func_name = String::ZoneHandle(zone());
- if (auto const name_sexp =
- CheckString(sexp->ExtraLookupValue("function_name"))) {
- func_name = String::New(name_sexp->value(), Heap::kOld);
- }
-
- return new (zone())
- CheckNullInstr(val, func_name, info.deopt_id, info.source);
-}
-
-CheckStackOverflowInstr* FlowGraphDeserializer::DeserializeCheckStackOverflow(
- SExpList* sexp,
- const InstrInfo& info) {
- intptr_t stack_depth = 0;
- if (auto const stack_sexp =
- CheckInteger(sexp->ExtraLookupValue("stack_depth"))) {
- stack_depth = stack_sexp->value();
- }
-
- intptr_t loop_depth = 0;
- if (auto const loop_sexp =
- CheckInteger(sexp->ExtraLookupValue("loop_depth"))) {
- loop_depth = loop_sexp->value();
- }
-
- auto kind = CheckStackOverflowInstr::kOsrAndPreemption;
- if (auto const kind_sexp = CheckSymbol(sexp->ExtraLookupValue("kind"))) {
- ASSERT(kind_sexp->Equals("OsrOnly"));
- kind = CheckStackOverflowInstr::kOsrOnly;
- }
-
- return new (zone()) CheckStackOverflowInstr(info.source, stack_depth,
- loop_depth, info.deopt_id, kind);
-}
-
-ConstantInstr* FlowGraphDeserializer::DeserializeConstant(
- SExpList* sexp,
- const InstrInfo& info) {
- Object& obj = Object::ZoneHandle(zone());
- if (!ParseDartValue(Retrieve(sexp, 1), &obj)) return nullptr;
- return new (zone()) ConstantInstr(obj, info.source);
-}
-
-DebugStepCheckInstr* FlowGraphDeserializer::DeserializeDebugStepCheck(
- SExpList* sexp,
- const InstrInfo& info) {
- auto kind = UntaggedPcDescriptors::kAnyKind;
- if (auto const kind_sexp = CheckSymbol(Retrieve(sexp, "stub_kind"))) {
- if (!UntaggedPcDescriptors::ParseKind(kind_sexp->value(), &kind)) {
- StoreError(kind_sexp, "not a valid UntaggedPcDescriptors::Kind name");
- return nullptr;
- }
- }
- return new (zone()) DebugStepCheckInstr(info.source, kind, info.deopt_id);
-}
-
-GotoInstr* FlowGraphDeserializer::DeserializeGoto(SExpList* sexp,
- const InstrInfo& info) {
- auto const block = FetchBlock(CheckSymbol(Retrieve(sexp, 1)));
- if (block == nullptr) return nullptr;
- if (!block->IsJoinEntry()) {
- StoreError(sexp->At(1), "target of goto must be join entry");
- return nullptr;
- }
- return new (zone()) GotoInstr(block->AsJoinEntry(), info.deopt_id);
-}
-
-InstanceCallInstr* FlowGraphDeserializer::DeserializeInstanceCall(
- SExpList* sexp,
- const InstrInfo& info) {
- auto& interface_target = Function::ZoneHandle(zone());
- auto& tearoff_interface_target = Function::ZoneHandle(zone());
- if (!ParseDartValue(Retrieve(sexp, "interface_target"), &interface_target)) {
- return nullptr;
- }
- if (!ParseDartValue(Retrieve(sexp, "tearoff_interface_target"),
- &tearoff_interface_target)) {
- return nullptr;
- }
- auto& function_name = String::ZoneHandle(zone());
- // If we have an explicit function_name value, then use that value. Otherwise,
- // if we have an non-null interface_target, use its name.
- if (auto const name_sexp = sexp->ExtraLookupValue("function_name")) {
- if (!ParseDartValue(name_sexp, &function_name)) return nullptr;
- } else if (!interface_target.IsNull()) {
- function_name = interface_target.name();
- } else if (!tearoff_interface_target.IsNull()) {
- function_name = tearoff_interface_target.name();
- }
-
- auto token_kind = Token::Kind::kILLEGAL;
- if (auto const kind_sexp =
- CheckSymbol(sexp->ExtraLookupValue("token_kind"))) {
- if (!Token::FromStr(kind_sexp->value(), &token_kind)) {
- StoreError(kind_sexp, "unexpected token kind");
- return nullptr;
- }
- }
-
- CallInfo call_info(zone());
- if (!ParseCallInfo(sexp, &call_info)) return nullptr;
-
- intptr_t checked_arg_count = 0;
- if (auto const checked_sexp =
- CheckInteger(sexp->ExtraLookupValue("checked_arg_count"))) {
- checked_arg_count = checked_sexp->value();
- }
-
- auto const inst = new (zone()) InstanceCallInstr(
- info.source, function_name, token_kind, call_info.inputs,
- call_info.type_args_len, call_info.argument_names, checked_arg_count,
- info.deopt_id, interface_target, tearoff_interface_target);
-
- if (call_info.result_type != nullptr) {
- inst->SetResultType(zone(), *call_info.result_type);
- }
-
- inst->set_entry_kind(call_info.entry_kind);
-
- if (auto const ic_data_sexp =
- CheckTaggedList(Retrieve(sexp, "ic_data"), "ICData")) {
- if (!CreateICData(ic_data_sexp, inst)) return nullptr;
- }
-
- return inst;
-}
-
-LoadClassIdInstr* FlowGraphDeserializer::DeserializeLoadClassId(
- SExpList* sexp,
- const InstrInfo& info) {
- auto const val = ParseValue(Retrieve(sexp, 1));
- if (val == nullptr) return nullptr;
-
- return new (zone()) LoadClassIdInstr(val);
-}
-
-LoadFieldInstr* FlowGraphDeserializer::DeserializeLoadField(
- SExpList* sexp,
- const InstrInfo& info) {
- auto const instance = ParseValue(Retrieve(sexp, 1));
- if (instance == nullptr) return nullptr;
-
- const Slot* slot;
- if (!ParseSlot(CheckTaggedList(Retrieve(sexp, 2)), &slot)) return nullptr;
-
- bool calls_initializer = false;
- if (auto const calls_initializer_sexp =
- CheckBool(sexp->ExtraLookupValue("calls_initializer"))) {
- calls_initializer = calls_initializer_sexp->value();
- }
-
- return new (zone()) LoadFieldInstr(instance, *slot, info.source,
- calls_initializer, info.deopt_id);
-}
-
-NativeCallInstr* FlowGraphDeserializer::DeserializeNativeCall(
- SExpList* sexp,
- const InstrInfo& info) {
- auto& function = Function::ZoneHandle(zone());
- if (!ParseDartValue(Retrieve(sexp, "function"), &function)) return nullptr;
- if (!function.IsFunction()) {
- StoreError(sexp->At(1), "expected a Function value");
- return nullptr;
- }
-
- auto const name_sexp = CheckString(Retrieve(sexp, "name"));
- if (name_sexp == nullptr) return nullptr;
- const auto& name =
- String::ZoneHandle(zone(), String::New(name_sexp->value()));
-
- bool link_lazily = false;
- if (auto const link_sexp = CheckBool(sexp->ExtraLookupValue("link_lazily"))) {
- link_lazily = link_sexp->value();
- }
-
- CallInfo call_info(zone());
- if (!ParseCallInfo(sexp, &call_info)) return nullptr;
-
- return new (zone()) NativeCallInstr(&name, &function, link_lazily,
- info.source, call_info.inputs);
-}
-
-ParameterInstr* FlowGraphDeserializer::DeserializeParameter(
- SExpList* sexp,
- const InstrInfo& info) {
- ASSERT(current_block_ != nullptr);
- if (auto const index_sexp = CheckInteger(Retrieve(sexp, 1))) {
- const auto param_offset_sexp =
- CheckInteger(sexp->ExtraLookupValue("param_offset"));
- ASSERT(param_offset_sexp != nullptr);
- const auto representation_sexp =
- CheckSymbol(sexp->ExtraLookupValue("representation"));
- Representation representation;
- if (!Location::ParseRepresentation(representation_sexp->value(),
- &representation)) {
- StoreError(representation_sexp, "unknown parameter representation");
- }
- return new (zone())
- ParameterInstr(index_sexp->value(), param_offset_sexp->value(),
- current_block_, representation);
- }
- return nullptr;
-}
-
-ReturnInstr* FlowGraphDeserializer::DeserializeReturn(SExpList* list,
- const InstrInfo& info) {
- Value* val = ParseValue(Retrieve(list, 1));
- if (val == nullptr) return nullptr;
- return new (zone()) ReturnInstr(info.source, val, info.deopt_id);
-}
-
-SpecialParameterInstr* FlowGraphDeserializer::DeserializeSpecialParameter(
- SExpList* sexp,
- const InstrInfo& info) {
- ASSERT(current_block_ != nullptr);
- auto const kind_sexp = CheckSymbol(Retrieve(sexp, 1));
- if (kind_sexp == nullptr) return nullptr;
- SpecialParameterInstr::SpecialParameterKind kind;
- if (!SpecialParameterInstr::ParseKind(kind_sexp->value(), &kind)) {
- StoreError(kind_sexp, "unknown special parameter kind");
- return nullptr;
- }
- return new (zone())
- SpecialParameterInstr(kind, info.deopt_id, current_block_);
-}
-
-StaticCallInstr* FlowGraphDeserializer::DeserializeStaticCall(
- SExpList* sexp,
- const InstrInfo& info) {
- auto& function = Function::ZoneHandle(zone());
- auto const function_sexp =
- CheckTaggedList(Retrieve(sexp, "function"), "Function");
- if (!ParseFunction(function_sexp, &function)) return nullptr;
-
- CallInfo call_info(zone());
- if (!ParseCallInfo(sexp, &call_info)) return nullptr;
-
- intptr_t call_count = 0;
- if (auto const call_count_sexp =
- CheckInteger(sexp->ExtraLookupValue("call_count"))) {
- call_count = call_count_sexp->value();
- }
-
- auto rebind_rule = ICData::kStatic;
- if (auto const rebind_sexp =
- CheckSymbol(sexp->ExtraLookupValue("rebind_rule"))) {
- if (!ICData::ParseRebindRule(rebind_sexp->value(), &rebind_rule)) {
- StoreError(rebind_sexp, "unknown rebind rule value");
- return nullptr;
- }
- }
-
- auto const inst = new (zone()) StaticCallInstr(
- info.source, function, call_info.type_args_len, call_info.argument_names,
- call_info.inputs, info.deopt_id, call_count, rebind_rule);
-
- if (call_info.result_type != nullptr) {
- inst->SetResultType(zone(), *call_info.result_type);
- }
-
- inst->set_entry_kind(call_info.entry_kind);
-
- if (auto const ic_data_sexp =
- CheckTaggedList(sexp->ExtraLookupValue("ic_data"), "ICData")) {
- if (!CreateICData(ic_data_sexp, inst)) return nullptr;
- }
-
- return inst;
-}
-
-StoreInstanceFieldInstr* FlowGraphDeserializer::DeserializeStoreInstanceField(
- SExpList* sexp,
- const InstrInfo& info) {
- auto const instance = ParseValue(Retrieve(sexp, 1));
- if (instance == nullptr) return nullptr;
-
- const Slot* slot = nullptr;
- if (!ParseSlot(CheckTaggedList(Retrieve(sexp, 2), "Slot"), &slot)) {
- return nullptr;
- }
-
- auto const value = ParseValue(Retrieve(sexp, 3));
- if (value == nullptr) return nullptr;
-
- auto barrier_type = kNoStoreBarrier;
- if (auto const bar_sexp = CheckBool(sexp->ExtraLookupValue("emit_barrier"))) {
- if (bar_sexp->value()) barrier_type = kEmitStoreBarrier;
- }
-
- auto kind = StoreInstanceFieldInstr::Kind::kOther;
- if (auto const init_sexp = CheckBool(sexp->ExtraLookupValue("is_init"))) {
- if (init_sexp->value()) kind = StoreInstanceFieldInstr::Kind::kInitializing;
- }
-
- return new (zone()) StoreInstanceFieldInstr(*slot, instance, value,
- barrier_type, info.source, kind);
-}
-
-StrictCompareInstr* FlowGraphDeserializer::DeserializeStrictCompare(
- SExpList* sexp,
- const InstrInfo& info) {
- auto const token_sexp = CheckSymbol(Retrieve(sexp, 1));
- if (token_sexp == nullptr) return nullptr;
- Token::Kind kind;
- if (!Token::FromStr(token_sexp->value(), &kind)) return nullptr;
-
- auto const left = ParseValue(Retrieve(sexp, 2));
- if (left == nullptr) return nullptr;
-
- auto const right = ParseValue(Retrieve(sexp, 3));
- if (right == nullptr) return nullptr;
-
- bool needs_check = false;
- if (auto const check_sexp = CheckBool(Retrieve(sexp, "needs_check"))) {
- needs_check = check_sexp->value();
- }
-
- return new (zone()) StrictCompareInstr(info.source, kind, left, right,
- needs_check, info.deopt_id);
-}
-
-ThrowInstr* FlowGraphDeserializer::DeserializeThrow(SExpList* sexp,
- const InstrInfo& info) {
- Value* exception = ParseValue(Retrieve(sexp, 1));
- if (exception == nullptr) return nullptr;
- return new (zone()) ThrowInstr(info.source, info.deopt_id, exception);
-}
-
-bool FlowGraphDeserializer::ParseCallInfo(SExpList* call,
- CallInfo* out,
- intptr_t num_extra_inputs) {
- ASSERT(out != nullptr);
-
- if (auto const len_sexp =
- CheckInteger(call->ExtraLookupValue("type_args_len"))) {
- out->type_args_len = len_sexp->value();
- }
-
- if (auto const arg_names_sexp =
- CheckList(call->ExtraLookupValue("arg_names"))) {
- out->argument_names = Array::New(arg_names_sexp->Length(), Heap::kOld);
- for (intptr_t i = 0, n = arg_names_sexp->Length(); i < n; i++) {
- auto name_sexp = CheckString(Retrieve(arg_names_sexp, i));
- if (name_sexp == nullptr) return false;
- tmp_string_ = String::New(name_sexp->value(), Heap::kOld);
- out->argument_names.SetAt(i, tmp_string_);
- }
- }
-
- if (auto const args_len_sexp =
- CheckInteger(call->ExtraLookupValue("args_len"))) {
- out->args_len = args_len_sexp->value();
- }
-
- if (auto const result_sexp = CheckTaggedList(
- call->ExtraLookupValue("result_type"), "CompileType")) {
- out->result_type = ParseCompileType(result_sexp);
- }
-
- if (auto const kind_sexp =
- CheckSymbol(call->ExtraLookupValue("entry_kind"))) {
- if (!Code::ParseEntryKind(kind_sexp->value(), &out->entry_kind))
- return false;
- }
-
- // Type arguments are wrapped in a TypeArguments array, so no matter how
- // many there are, they are contained in a single pushed argument.
- auto const all_args_len = (out->type_args_len > 0 ? 1 : 0) + out->args_len;
-
- const intptr_t num_inputs = all_args_len + num_extra_inputs;
- out->inputs = new (zone()) InputsArray(zone(), num_inputs);
- for (intptr_t i = 0; i < num_inputs; ++i) {
- auto const input = ParseValue(Retrieve(call, 1 + i));
- if (input == nullptr) return false;
- out->inputs->Add(input);
- }
-
- return true;
-}
-
-Value* FlowGraphDeserializer::ParseValue(SExpression* sexp,
- bool allow_pending) {
- CompileType* type = nullptr;
- bool inherit_type = false;
- auto name = sexp->AsSymbol();
- if (name == nullptr) {
- auto const list = CheckTaggedList(sexp, "value");
- name = CheckSymbol(Retrieve(list, 1));
- if (auto const type_sexp =
- CheckTaggedList(list->ExtraLookupValue("type"), "CompileType")) {
- type = ParseCompileType(type_sexp);
- if (type == nullptr) return nullptr;
- } else if (auto const inherit_sexp =
- CheckBool(list->ExtraLookupValue("inherit_type"))) {
- inherit_type = inherit_sexp->value();
- } else {
- // We assume that the type should be inherited from the definition for
- // for (value ...) forms without an explicit type.
- inherit_type = true;
- }
- }
- intptr_t index;
- if (!ParseUse(name, &index)) return nullptr;
- auto const def = definition_map_.LookupValue(index);
- Value* val;
- if (def == nullptr) {
- if (!allow_pending) {
- StoreError(sexp, "found use prior to definition");
- return nullptr;
- }
- val = AddNewPendingValue(sexp, index, inherit_type);
- } else {
- val = new (zone()) Value(def);
- if (inherit_type) {
- if (def->HasType()) {
- val->reaching_type_ = def->Type();
- } else {
- StoreError(sexp, "value inherits type, but no type found");
- return nullptr;
- }
- }
- }
- if (type != nullptr) val->SetReachingType(type);
- return val;
-}
-
-CompileType* FlowGraphDeserializer::ParseCompileType(SExpList* sexp) {
- // TODO(sstrickl): Currently we only print out nullable if it's false
- // (or during verbose printing). Switch this when NNBD is the standard.
- bool nullable = CompileType::kNullable;
- if (auto const nullable_sexp =
- CheckBool(sexp->ExtraLookupValue("nullable"))) {
- nullable = nullable_sexp->value() ? CompileType::kNullable
- : CompileType::kNonNullable;
- }
-
- intptr_t cid = kIllegalCid;
- if (auto const cid_sexp = CheckInteger(sexp->ExtraLookupValue("cid"))) {
- // TODO(sstrickl): Check that the cid is a valid concrete cid, or a cid
- // otherwise found in CompileTypes like kIllegalCid or kDynamicCid.
- cid = cid_sexp->value();
- }
-
- AbstractType* type = nullptr;
- if (auto const type_sexp = sexp->ExtraLookupValue("type")) {
- auto& type_handle = AbstractType::ZoneHandle(zone());
- if (!ParseAbstractType(type_sexp, &type_handle)) return nullptr;
- type = &type_handle;
- }
- return new (zone()) CompileType(nullable, cid, type);
-}
-
-Environment* FlowGraphDeserializer::ParseEnvironment(SExpList* list) {
- if (list == nullptr) return nullptr;
- intptr_t fixed_param_count = 0;
- if (auto const fpc_sexp =
- CheckInteger(list->ExtraLookupValue("fixed_param_count"))) {
- fixed_param_count = fpc_sexp->value();
- }
- Environment* outer_env = nullptr;
- if (auto const outer_sexp = CheckList(list->ExtraLookupValue("outer"))) {
- outer_env = ParseEnvironment(outer_sexp);
- if (outer_env == nullptr) return nullptr;
- if (auto const deopt_sexp =
- CheckInteger(outer_sexp->ExtraLookupValue("deopt_id"))) {
- outer_env->deopt_id_ = deopt_sexp->value();
- }
- }
-
- ASSERT(parsed_function_ != nullptr);
- auto const env = new (zone()) Environment(list->Length(), fixed_param_count,
- *parsed_function_, outer_env);
-
- for (intptr_t i = 0; i < list->Length(); i++) {
- auto const elem_sexp = Retrieve(list, i);
- if (elem_sexp == nullptr) return nullptr;
- auto val = ParseValue(elem_sexp, /*allow_pending=*/false);
- if (val == nullptr) return nullptr;
- env->PushValue(val);
- }
-
- return env;
-}
-
-bool FlowGraphDeserializer::ParseDartValue(SExpression* sexp, Object* out) {
- ASSERT(out != nullptr);
- if (sexp == nullptr) return false;
- *out = Object::null();
-
- if (auto const sym = sexp->AsSymbol()) {
- // We'll use the null value in *out as a marker later, so go ahead and exit
- // early if we parse one.
- if (sym->Equals("null")) return true;
- if (sym->Equals("sentinel")) {
- *out = Object::sentinel().ptr();
- return true;
- }
-
- // The only other symbols that should appear in Dart value position are
- // names of constant definitions.
- auto const val = ParseValue(sym, /*allow_pending=*/false);
- if (val == nullptr) return false;
- if (!val->BindsToConstant()) {
- StoreError(sym, "not a reference to a constant definition");
- return false;
- }
- *out = val->BoundConstant().ptr();
- // Values used in constant definitions have already been canonicalized,
- // so just exit.
- return true;
- }
-
- // Other instance values may need to be canonicalized, so do that before
- // returning.
- if (auto const b = sexp->AsBool()) {
- *out = Bool::Get(b->value()).ptr();
- } else if (auto const str = sexp->AsString()) {
- *out = String::New(str->value(), Heap::kOld);
- } else if (auto const i = sexp->AsInteger()) {
- *out = Integer::New(i->value(), Heap::kOld);
- } else if (auto const d = sexp->AsDouble()) {
- *out = Double::New(d->value(), Heap::kOld);
- } else if (auto const list = CheckTaggedList(sexp)) {
- auto const tag = list->Tag();
- if (tag->Equals("Class")) {
- return ParseClass(list, out);
- } else if (tag->Equals("Type")) {
- return ParseType(list, out);
- } else if (tag->Equals("TypeArguments")) {
- return ParseTypeArguments(list, out);
- } else if (tag->Equals("Field")) {
- return ParseField(list, out);
- } else if (tag->Equals("Function")) {
- return ParseFunction(list, out);
- } else if (tag->Equals("FunctionType")) {
- return ParseFunctionType(list, out);
- } else if (tag->Equals("TypeParameter")) {
- return ParseTypeParameter(list, out);
- } else if (tag->Equals("Array")) {
- return ParseArray(list, out);
- } else if (tag->Equals("ImmutableList")) {
- return ParseImmutableList(list, out);
- } else if (tag->Equals("Instance")) {
- return ParseInstance(list, out);
- } else if (tag->Equals("Closure")) {
- return ParseClosure(list, out);
- } else if (tag->Equals("TypeRef")) {
- return ParseTypeRef(list, out);
- }
- }
-
- // If we're here and still haven't gotten a non-null value, then something
- // went wrong. (Likely an unrecognized value.)
- if (out->IsNull()) {
- StoreError(sexp, "unhandled Dart value");
- return false;
- }
-
- if (!out->IsInstance()) return true;
- return CanonicalizeInstance(sexp, out);
-}
-
-bool FlowGraphDeserializer::CanonicalizeInstance(SExpression* sexp,
- Object* out) {
- ASSERT(out != nullptr);
- if (!out->IsInstance()) return true;
- // Instance::Canonicalize uses the current zone for the passed in thread,
- // not an explicitly provided zone. This means we cannot be run in a context
- // where [thread()->zone()] does not match [zone()] (e.g., due to StackZone)
- // until this is addressed.
- *out = Instance::Cast(*out).Canonicalize(thread());
- return true;
-}
-
-bool FlowGraphDeserializer::ParseAbstractType(SExpression* sexp, Object* out) {
- ASSERT(out != nullptr);
- if (sexp == nullptr) return false;
-
- // If it's a symbol, it should be a reference to a constant definition, which
- // is handled in ParseType.
- if (auto const sym = sexp->AsSymbol()) {
- return ParseType(sexp, out);
- } else if (auto const list = CheckTaggedList(sexp)) {
- auto const tag = list->Tag();
- if (tag->Equals("Type")) {
- return ParseType(list, out);
- } else if (tag->Equals("TypeParameter")) {
- return ParseTypeParameter(list, out);
- } else if (tag->Equals("TypeRef")) {
- return ParseTypeRef(list, out);
- }
- }
-
- StoreError(sexp, "not an AbstractType");
- return false;
-}
-
-bool FlowGraphDeserializer::ParseClass(SExpList* list, Object* out) {
- ASSERT(out != nullptr);
- if (list == nullptr) return false;
-
- auto const ref_sexp = Retrieve(list, 1);
- if (ref_sexp == nullptr) return false;
- if (auto const cid_sexp = ref_sexp->AsInteger()) {
- ClassTable* table = thread()->isolate_group()->class_table();
- if (!table->HasValidClassAt(cid_sexp->value())) {
- StoreError(cid_sexp, "no valid class found for cid");
- return false;
- }
- *out = table->At(cid_sexp->value());
- } else if (auto const name_sexp = ref_sexp->AsSymbol()) {
- if (!ParseCanonicalName(name_sexp, out)) return false;
- if (!out->IsClass()) {
- StoreError(name_sexp, "expected the name of a class");
- return false;
- }
- }
- return true;
-}
-
-bool FlowGraphDeserializer::ParseClosure(SExpList* list, Object* out) {
- ASSERT(out != nullptr);
- if (list == nullptr) return false;
-
- auto& function = Function::ZoneHandle(zone());
- auto const function_sexp = CheckTaggedList(Retrieve(list, 1), "Function");
- if (!ParseFunction(function_sexp, &function)) return false;
-
- auto& context = Context::ZoneHandle(zone());
- if (list->ExtraLookupValue("context") != nullptr) {
- StoreError(list, "closures with contexts currently unhandled");
- return false;
- }
-
- auto& inst_type_args = TypeArguments::ZoneHandle(zone());
- if (auto const type_args_sexp = Retrieve(list, "inst_type_args")) {
- if (!ParseTypeArguments(type_args_sexp, &inst_type_args)) return false;
- }
-
- auto& func_type_args = TypeArguments::ZoneHandle(zone());
- if (auto const type_args_sexp = Retrieve(list, "func_type_args")) {
- if (!ParseTypeArguments(type_args_sexp, &func_type_args)) return false;
- }
-
- auto& delayed_type_args = TypeArguments::ZoneHandle(zone());
- if (auto const type_args_sexp = Retrieve(list, "delayed_type_args")) {
- if (!ParseTypeArguments(type_args_sexp, &delayed_type_args)) {
- return false;
- }
- }
-
- *out = Closure::New(inst_type_args, func_type_args, delayed_type_args,
- function, context, Heap::kOld);
- return CanonicalizeInstance(list, out);
-}
-
-bool FlowGraphDeserializer::ParseField(SExpList* list, Object* out) {
- auto const name_sexp = CheckSymbol(Retrieve(list, 1));
- if (!ParseCanonicalName(name_sexp, out)) return false;
- if (!out->IsField()) {
- StoreError(list, "expected a Field name");
- return false;
- }
- return true;
-}
-
-bool FlowGraphDeserializer::ParseFunction(SExpList* list, Object* out) {
- ASSERT(out != nullptr);
- if (list == nullptr) return false;
-
- auto const name_sexp = CheckSymbol(Retrieve(list, 1));
- if (!ParseCanonicalName(name_sexp, out)) return false;
- if (!out->IsFunction()) {
- StoreError(list, "expected a Function name");
- return false;
- }
- auto& function = Function::Cast(*out);
- // Check the kind expected by the S-expression if one was specified.
- if (auto const kind_sexp = CheckSymbol(list->ExtraLookupValue("kind"))) {
- UntaggedFunction::Kind kind;
- if (!UntaggedFunction::ParseKind(kind_sexp->value(), &kind)) {
- StoreError(kind_sexp, "unexpected function kind");
- return false;
- }
- if (function.kind() != kind) {
- auto const kind_str = UntaggedFunction::KindToCString(function.kind());
- StoreError(list, "retrieved function has kind %s", kind_str);
- return false;
- }
- }
- return true;
-}
-
-bool FlowGraphDeserializer::ParseFunctionType(SExpList* list, Object* out) {
- ASSERT(out != nullptr);
- if (list == nullptr) return false;
- auto& type_params = TypeArguments::ZoneHandle(zone());
- if (auto const type_params_sexp = Retrieve(list, "type_params")) {
- if (!ParseTypeArguments(type_params_sexp, &type_params)) return false;
- }
- auto& result_type = AbstractType::ZoneHandle(zone());
- if (auto const result_type_sexp = Retrieve(list, "result_type")) {
- if (!ParseAbstractType(result_type_sexp, &result_type)) return false;
- }
- auto& parameter_types = Array::ZoneHandle(zone());
- if (auto const parameter_types_sexp = Retrieve(list, "parameter_types")) {
- if (!ParseDartValue(parameter_types_sexp, ¶meter_types)) return false;
- }
- auto& parameter_names = Array::ZoneHandle(zone());
- if (auto const parameter_names_sexp = Retrieve(list, "parameter_names")) {
- if (!ParseDartValue(parameter_names_sexp, ¶meter_names)) return false;
- }
- intptr_t packed_fields;
- if (auto const packed_fields_sexp =
- CheckInteger(list->ExtraLookupValue("packed_fields"))) {
- packed_fields = packed_fields_sexp->value();
- } else {
- return false;
- }
- auto& sig = FunctionType::ZoneHandle(zone(), FunctionType::New());
- sig.set_type_parameters(type_params);
- sig.set_result_type(result_type);
- sig.set_parameter_types(parameter_types);
- sig.set_parameter_names(parameter_names);
- sig.set_packed_fields(packed_fields);
- *out = sig.ptr();
- return true;
-}
-
-bool FlowGraphDeserializer::ParseArray(SExpList* list, Object* out) {
- ASSERT(out != nullptr);
- if (list == nullptr) return false;
-
- *out = Array::New(list->Length() - 1, Heap::kOld);
- auto& arr = Array::Cast(*out);
- // Arrays may contain other arrays, so we'll need a new handle in which to
- // store elements.
- auto& elem = Object::Handle(zone());
- for (intptr_t i = 1; i < list->Length(); i++) {
- if (!ParseDartValue(Retrieve(list, i), &elem)) return false;
- arr.SetAt(i - 1, elem);
- }
- if (auto type_args_sexp = list->ExtraLookupValue("type_args")) {
- if (!ParseTypeArguments(type_args_sexp, &array_type_args_)) return false;
- arr.SetTypeArguments(array_type_args_);
- }
- return true;
-}
-
-bool FlowGraphDeserializer::ParseImmutableList(SExpList* list, Object* out) {
- if (!ParseArray(list, out)) return false;
-
- Array::Cast(*out).MakeImmutable();
- return CanonicalizeInstance(list, out);
-}
-
-bool FlowGraphDeserializer::ParseInstance(SExpList* list, Object* out) {
- ASSERT(out != nullptr);
- if (list == nullptr) return false;
- auto const cid_sexp = CheckInteger(Retrieve(list, 1));
- if (cid_sexp == nullptr) return false;
-
- auto const table = thread()->isolate_group()->class_table();
- if (!table->HasValidClassAt(cid_sexp->value())) {
- StoreError(cid_sexp, "cid is not valid");
- return false;
- }
-
- ASSERT(cid_sexp->value() != kNullCid); // Must use canonical instances.
- ASSERT(cid_sexp->value() != kBoolCid); // Must use canonical instances.
- instance_class_ = table->At(cid_sexp->value());
- *out = Instance::New(instance_class_, Heap::kOld);
- auto& instance = Instance::Cast(*out);
-
- if (auto const type_args = list->ExtraLookupValue("type_args")) {
- instance_type_args_ = TypeArguments::null();
- if (!ParseTypeArguments(type_args, &instance_type_args_)) return false;
- if (!instance_class_.IsGeneric()) {
- StoreError(list,
- "type arguments provided for an instance of a "
- "non-generic class");
- return false;
- }
- instance.SetTypeArguments(instance_type_args_);
- }
-
- // Pick out and store the final instance fields of the class, as values must
- // be provided for them. Error if there are any non-final instance fields.
- instance_fields_array_ = instance_class_.fields();
- auto const field_count = instance_fields_array_.Length();
- GrowableArray<const Field*> final_fields(zone(), field_count);
- for (intptr_t i = 0, n = field_count; i < n; i++) {
- instance_field_ = Field::RawCast(instance_fields_array_.At(i));
- if (!instance_field_.is_instance()) continue;
- if (!instance_field_.is_final()) {
- StoreError(list, "class for instance has non-final instance fields");
- return false;
- }
- auto& fresh_handle = Field::Handle(zone(), instance_field_.ptr());
- final_fields.Add(&fresh_handle);
- }
-
- // If there is no (Fields...) sub-expression or it has no extra info, then
- // ensure there are no final fields before returning the canonicalized form.
- SExpList* fields_sexp = nullptr;
- bool fields_provided = list->Length() > 2;
- if (fields_provided) {
- fields_sexp = CheckTaggedList(Retrieve(list, 2), "Fields");
- if (fields_sexp == nullptr) return false;
- fields_provided = fields_sexp->ExtraLength() != 0;
- }
- if (!fields_provided) {
- if (!final_fields.is_empty()) {
- StoreError(list, "values not provided for final fields of instance");
- return false;
- }
- return CanonicalizeInstance(list, out);
- }
-
- // At this point, we have final instance field values to set on the new
- // instance before canonicalization. When setting instance fields, we may
- // cause field guards to be invalidated. Because of this, we must either be
- // running on the mutator thread or be at a safepoint when calling `SetField`.
- //
- // For IR round-trips, the constants we create have already existed before in
- // the VM heap, which means field invalidation cannot occur. Thus, we create a
- // closure that sets the fields of the instance and then conditionally run
- // that closure at a safepoint if not in the mutator thread.
- //
- // TODO(dartbug.com/36882): When deserializing IR that was not generated
- // during the RoundTripSerialization pass, we are no longer guaranteed that
- // deserialization of instances will not invalidate field guards. Thus, we may
- // need to support invalidating field guards on non-mutator threads or fall
- // back onto forcing the deserialization to happen on the mutator thread.
- auto set_instance_fields = [&]() {
- auto& inst = Instance::Cast(*out);
- // We'll need to allocate a handle for the parsed value as we may have
- // instances as field values and so this function may be re-entered.
- auto& value = Object::Handle(zone());
- for (auto field : final_fields) {
- tmp_string_ = field->UserVisibleName();
- auto const name = tmp_string_.ToCString();
- auto const value_sexp = Retrieve(fields_sexp, name);
- if (value_sexp == nullptr) {
- StoreError(list, "no value provided for final instance field %s", name);
- return false;
- }
- if (!ParseDartValue(value_sexp, &value)) return false;
- inst.SetField(*field, value);
- }
- return true;
- };
-
- auto const t = Thread::Current();
- if (!t->IsMutatorThread()) {
- SafepointOperationScope safepoint_scope(t);
- if (!set_instance_fields()) return false;
- } else {
- if (!set_instance_fields()) return false;
- }
-
- return CanonicalizeInstance(list, out);
-}
-
-bool FlowGraphDeserializer::ParseType(SExpression* sexp, Object* out) {
- ASSERT(out != nullptr);
- if (sexp == nullptr) return false;
-
- if (auto const sym = sexp->AsSymbol()) {
- auto const val = ParseValue(sexp, /*allow_pending=*/false);
- if (val == nullptr) {
- StoreError(sexp, "expected type or reference to constant definition");
- return false;
- }
- if (!val->BindsToConstant()) {
- StoreError(sexp, "reference to non-constant definition");
- return false;
- }
- *out = val->BoundConstant().ptr();
- if (!out->IsType()) {
- StoreError(sexp, "expected Type constant");
- return false;
- }
- return true;
- }
- auto const list = CheckTaggedList(sexp, "Type");
- if (list == nullptr) return false;
-
- const auto hash_sexp = CheckInteger(list->ExtraLookupValue("hash"));
- const auto is_recursive = hash_sexp != nullptr;
- // This isn't necessary the hash value we will have in the new FlowGraph, but
- // it will be how this type is referred to by TypeRefs in the serialized one.
- auto const old_hash = is_recursive ? hash_sexp->value() : 0;
- ZoneGrowableArray<TypeRef*>* pending_typerefs = nullptr;
- if (is_recursive) {
- if (pending_typeref_map_.LookupValue(old_hash) != nullptr) {
- StoreError(sexp, "already parsing a type with hash %" Pd64 "",
- hash_sexp->value());
- return false;
- }
- pending_typerefs = new (zone()) ZoneGrowableArray<TypeRef*>(zone(), 2);
- pending_typeref_map_.Insert(old_hash, pending_typerefs);
- }
-
- const auto cls_sexp = CheckTaggedList(Retrieve(list, 1), "Class");
- if (cls_sexp == nullptr) {
- // TODO(sstrickl): Handle types not derived from classes.
- StoreError(list, "non-class types not currently handled");
- return false;
- }
- TokenPosition token_pos = TokenPosition::kNoSource;
- if (const auto pos_sexp = CheckInteger(list->ExtraLookupValue("token_pos"))) {
- token_pos = TokenPosition::Deserialize(pos_sexp->value());
- }
- auto type_args_ptr = &Object::null_type_arguments();
- if (const auto ta_sexp = list->ExtraLookupValue("type_args")) {
- // ParseTypeArguments may re-enter ParseType after setting the contents of
- // the passed in handle, so we need to allocate a new handle here.
- auto& type_args = TypeArguments::Handle(zone());
- if (!ParseTypeArguments(ta_sexp, &type_args)) return false;
- type_args_ptr = &type_args;
- }
- // Guaranteed not to re-enter ParseType.
- if (!ParseClass(cls_sexp, &type_class_)) return false;
- const Nullability nullability =
- type_class_.IsNullClass() ? Nullability::kNullable : Nullability::kLegacy;
- *out = Type::New(type_class_, *type_args_ptr, nullability);
- auto& type = Type::Cast(*out);
- if (is_recursive) {
- while (!pending_typerefs->is_empty()) {
- auto const ref = pending_typerefs->RemoveLast();
- ASSERT(ref != nullptr);
- ref->set_type(type);
- }
- pending_typeref_map_.Remove(old_hash);
-
- // If there are still pending typerefs, we can't canonicalize yet until
- // an enclosing type where we have resolved them. This is a conservative
- // check, as we do not ensure that any of the still-pending typerefs are
- // found within this type.
- //
- // This is within the is_recursive check because if this type was
- // non-recursive, then even if there are pending type refs, we are
- // guaranteed that none of them are in this type.
- if (ArePendingTypeRefs()) return true;
- }
-
- // Need to set this for canonicalization. We ensure in the serializer
- // that only finalized types are successfully serialized.
- type.SetIsFinalized();
- return CanonicalizeInstance(list, out);
-}
-
-bool FlowGraphDeserializer::ParseTypeArguments(SExpression* sexp, Object* out) {
- ASSERT(out != nullptr);
- if (sexp == nullptr) return false;
-
- if (auto const sym = sexp->AsSymbol()) {
- auto const val = ParseValue(sexp, /*allow_pending=*/false);
- if (val == nullptr) {
- StoreError(sexp,
- "expected type arguments or reference to constant definition");
- return false;
- }
- if (!val->BindsToConstant()) {
- StoreError(sexp, "reference to non-constant definition");
- return false;
- }
- *out = val->BoundConstant().ptr();
- if (!out->IsTypeArguments()) {
- StoreError(sexp, "expected TypeArguments constant");
- return false;
- }
- return true;
- }
- auto const list = CheckTaggedList(sexp, "TypeArguments");
- if (list == nullptr) return false;
-
- *out = TypeArguments::New(list->Length() - 1, Heap::kOld);
- auto& type_args = TypeArguments::Cast(*out);
- // We may reenter ParseTypeArguments while parsing one of the elements, so we
- // need a fresh handle here.
- auto& elem = AbstractType::Handle(zone());
- for (intptr_t i = 1, n = list->Length(); i < n; i++) {
- if (!ParseAbstractType(Retrieve(list, i), &elem)) return false;
- type_args.SetTypeAt(i - 1, elem);
- }
-
- // If there are still pending typerefs, we can't canonicalize yet.
- if (ArePendingTypeRefs()) return true;
-
- return CanonicalizeInstance(list, out);
-}
-
-bool FlowGraphDeserializer::ParseTypeParameter(SExpList* list, Object* out) {
- ASSERT(out != nullptr);
- if (list == nullptr) return false;
-
- Class& cls = Class::Handle();
- if (auto const cid_sexp = CheckInteger(list->ExtraLookupValue("cid"))) {
- const intptr_t cid = cid_sexp->value();
- ClassTable* table = thread()->isolate_group()->class_table();
- if (!table->HasValidClassAt(cid)) {
- StoreError(cid_sexp, "no valid class found for cid");
- return false;
- }
- cls = table->At(cid);
- } else {
- return false;
- }
- auto const base_sexp = CheckInteger(list->ExtraLookupValue("base"));
- if (base_sexp == nullptr) return false;
- intptr_t base = base_sexp->value();
- auto const index_sexp = CheckInteger(list->ExtraLookupValue("index"));
- if (index_sexp == nullptr) return false;
- intptr_t index = index_sexp->value();
- auto const name_sexp = CheckSymbol(Retrieve(list, 1));
- if (name_sexp == nullptr) return false;
- tmp_string_ = String::New(name_sexp->value());
-
- *out =
- TypeParameter::New(cls, base, index, tmp_string_, Object::dynamic_type(),
- false, Nullability::kLegacy);
- TypeParameter::Cast(*out).SetIsFinalized();
- return CanonicalizeInstance(list, out);
-}
-
-bool FlowGraphDeserializer::ParseTypeRef(SExpList* list, Object* out) {
- ASSERT(out != nullptr);
- if (list == nullptr) return false;
-
- const bool contains_type = list->Length() > 1;
- if (contains_type) {
- auto& type = Type::Handle(zone());
- if (!ParseAbstractType(Retrieve(list, 1), &type)) return false;
- *out = TypeRef::New(type);
- // If the TypeRef appears outside the referrent, then the referrent
- // should be already canonicalized. This serves as a double-check that
- // is the case.
- return CanonicalizeInstance(list, out);
- }
- // If there is no type in the body, then this must be a referrent to
- // a Type containing this TypeRef. That means we must have a hash value.
- auto const hash_sexp = CheckInteger(Retrieve(list, "hash"));
- if (hash_sexp == nullptr) return false;
- auto const old_hash = hash_sexp->value();
- auto const pending = pending_typeref_map_.LookupValue(old_hash);
- if (pending == nullptr) {
- StoreError(list, "reference to recursive type found outside type");
- return false;
- }
- *out = TypeRef::New(Object::null_abstract_type());
- pending->Add(static_cast<TypeRef*>(out));
-
- // We can only canonicalize TypeRefs appearing within their referrent
- // when its containing value is canonicalized.
- return true;
-}
-
-bool FlowGraphDeserializer::ParseCanonicalName(SExpSymbol* sym, Object* obj) {
- ASSERT(obj != nullptr);
- if (sym == nullptr) return false;
- auto const name = sym->value();
- // TODO(sstrickl): No library URL, handle this better.
- if (*name == ':') {
- StoreError(sym, "expected non-empty library");
- return false;
- }
- const char* lib_end = nullptr;
- if (auto const first = strchr(name, ':')) {
- lib_end = strchr(first + 1, ':');
- if (lib_end == nullptr) lib_end = strchr(first + 1, '\0');
- } else {
- StoreError(sym, "malformed library");
- return false;
- }
- tmp_string_ =
- String::FromUTF8(reinterpret_cast<const uint8_t*>(name), lib_end - name);
- name_library_ = Library::LookupLibrary(thread(), tmp_string_);
- if (*lib_end == '\0') {
- *obj = name_library_.ptr();
- return true;
- }
- const char* const class_start = lib_end + 1;
- if (*class_start == '\0') {
- StoreError(sym, "no class found after colon");
- return false;
- }
- // If classes are followed by another part, it's either a function
- // (separated by ':') or a field (separated by '.').
- const char* class_end = strchr(class_start, ':');
- if (class_end == nullptr) class_end = strchr(class_start, '.');
- if (class_end == nullptr) class_end = strchr(class_start, '\0');
- const bool empty_name = class_end == class_start;
- name_class_ = Class::null();
- if (empty_name) {
- name_class_ = name_library_.toplevel_class();
- } else {
- tmp_string_ = String::FromUTF8(
- reinterpret_cast<const uint8_t*>(class_start), class_end - class_start);
- name_class_ = name_library_.LookupClassAllowPrivate(tmp_string_);
- }
- if (name_class_.IsNull()) {
- StoreError(sym, "failure looking up class %s in library %s",
- empty_name ? "at top level" : tmp_string_.ToCString(),
- name_library_.ToCString());
- return false;
- }
- if (*class_end == '\0') {
- *obj = name_class_.ptr();
- return true;
- }
- if (*class_end == '.') {
- if (class_end[1] == '\0') {
- StoreError(sym, "no field name found after period");
- return false;
- }
- const char* const field_start = class_end + 1;
- const char* field_end = strchr(field_start, '\0');
- tmp_string_ = String::FromUTF8(
- reinterpret_cast<const uint8_t*>(field_start), field_end - field_start);
- name_field_ = name_class_.LookupFieldAllowPrivate(tmp_string_);
- if (name_field_.IsNull()) {
- StoreError(sym, "failure looking up field %s in class %s",
- tmp_string_.ToCString(),
- empty_name ? "at top level" : name_class_.ToCString());
- return false;
- }
- *obj = name_field_.ptr();
- return true;
- }
- if (class_end[1] == '\0') {
- StoreError(sym, "no function name found after final colon");
- return false;
- }
- const char* func_start = class_end + 1;
- name_function_ = Function::null();
- while (true) {
- const char* func_end = strchr(func_start, ':');
- intptr_t name_len = func_end - func_start;
- bool is_forwarder = false;
- if (func_end != nullptr && name_len == 3) {
- // Special case for getters/setters, where they are prefixed with "get:"
- // or "set:", as those colons should not be used as separators.
- if (strncmp(func_start, "get", 3) == 0 ||
- strncmp(func_start, "set", 3) == 0) {
- func_end = strchr(func_end + 1, ':');
- } else if (strncmp(func_start, "dyn", 3) == 0) {
- // Dynamic invocation forwarders start with "dyn:" and we'll need to
- // look up the base function and then retrieve the forwarder from it.
- is_forwarder = true;
- func_start = func_end + 1;
- func_end = strchr(func_end + 1, ':');
- }
- }
- if (func_end == nullptr) func_end = strchr(func_start, '\0');
- name_len = func_end - func_start;
-
- // Check for tearoff names before we overwrite the contents of tmp_string_.
- if (!name_function_.IsNull()) {
- ASSERT(!tmp_string_.IsNull());
- auto const parent_name = tmp_string_.ToCString();
- // ImplicitClosureFunctions (tearoffs) have the same name as the Function
- // to which they are attached. We currently don't handle any other kinds
- // of local functions.
- if (name_function_.HasImplicitClosureFunction() && *func_end == '\0' &&
- strncmp(parent_name, func_start, name_len) == 0) {
- *obj = name_function_.ImplicitClosureFunction();
- return true;
- }
- StoreError(sym, "no handling for local functions");
- return false;
- }
-
- // Check for the prefix "<anonymous ..." in the name and fail if found,
- // since we can't resolve these.
- static auto const anon_prefix = "<anonymous ";
- static const intptr_t prefix_len = strlen(anon_prefix);
- if ((name_len > prefix_len) &&
- strncmp(anon_prefix, func_start, prefix_len) == 0) {
- StoreError(sym, "cannot resolve anonymous values");
- return false;
- }
-
- tmp_string_ = String::FromUTF8(reinterpret_cast<const uint8_t*>(func_start),
- name_len);
- name_function_ = name_class_.LookupFunctionAllowPrivate(tmp_string_);
- if (name_function_.IsNull()) {
- StoreError(sym, "failure looking up function %s in class %s",
- tmp_string_.ToCString(), name_class_.ToCString());
- return false;
- }
- if (is_forwarder) {
- tmp_string_ = name_function_.name();
- tmp_string_ = Function::CreateDynamicInvocationForwarderName(tmp_string_);
- name_function_ =
- name_function_.GetDynamicInvocationForwarder(tmp_string_);
- }
- if (func_end[0] == '\0') break;
- if (func_end[1] == '\0') {
- StoreError(sym, "no function name found after final colon");
- return false;
- }
- func_start = func_end + 1;
- }
- *obj = name_function_.ptr();
- return true;
-}
-
-bool FlowGraphDeserializer::ParseSlot(SExpList* list, const Slot** out) {
- ASSERT(out != nullptr);
- const auto offset_sexp = CheckInteger(Retrieve(list, 1));
- if (offset_sexp == nullptr) return false;
- const auto offset = offset_sexp->value();
-
- const auto kind_sexp = CheckSymbol(Retrieve(list, "kind"));
- if (kind_sexp == nullptr) return false;
- Slot::Kind kind;
- if (!Slot::ParseKind(kind_sexp->value(), &kind)) {
- StoreError(kind_sexp, "unknown Slot kind");
- return false;
- }
-
- switch (kind) {
- case Slot::Kind::kDartField: {
- auto& field = Field::ZoneHandle(zone());
- const auto field_sexp = CheckTaggedList(Retrieve(list, "field"), "Field");
- if (!ParseDartValue(field_sexp, &field)) return false;
- ASSERT(parsed_function_ != nullptr);
- *out =
- &Slot::Get(kernel::BaseFlowGraphBuilder::MayCloneField(zone(), field),
- parsed_function_);
- break;
- }
- case Slot::Kind::kTypeArguments:
- *out = &Slot::GetTypeArgumentsSlotAt(thread(), offset);
- break;
- case Slot::Kind::kTypeArgumentsIndex:
- *out = &Slot::GetTypeArgumentsIndexSlot(thread(), offset);
- break;
- case Slot::Kind::kArrayElement:
- *out = &Slot::GetArrayElementSlot(thread(), offset);
- break;
- case Slot::Kind::kCapturedVariable:
- StoreError(kind_sexp, "unhandled Slot kind");
- return false;
- default:
- *out = &Slot::GetNativeSlot(kind);
- break;
- }
- return true;
-}
-
-bool FlowGraphDeserializer::ParseRange(SExpList* list, Range* out) {
- if (list == nullptr) return false;
- RangeBoundary min, max;
- if (!ParseRangeBoundary(Retrieve(list, 1), &min)) return false;
- if (list->Length() == 2) {
- max = min;
- } else {
- if (!ParseRangeBoundary(Retrieve(list, 2), &max)) return false;
- }
- out->min_ = min;
- out->max_ = max;
- return true;
-}
-
-bool FlowGraphDeserializer::ParseRangeBoundary(SExpression* sexp,
- RangeBoundary* out) {
- if (sexp == nullptr) return false;
- if (auto const int_sexp = sexp->AsInteger()) {
- out->kind_ = RangeBoundary::Kind::kConstant;
- out->value_ = int_sexp->value();
- } else if (auto const sym_sexp = sexp->AsSymbol()) {
- if (!RangeBoundary::ParseKind(sym_sexp->value(), &out->kind_)) return false;
- } else if (auto const list_sexp = sexp->AsList()) {
- intptr_t index;
- if (!ParseUse(CheckSymbol(Retrieve(list_sexp, 1)), &index)) return false;
- auto const def = definition_map_.LookupValue(index);
- if (def == nullptr) {
- StoreError(list_sexp, "no definition for symbolic range boundary");
- return false;
- }
- out->kind_ = RangeBoundary::Kind::kSymbol;
- out->value_ = reinterpret_cast<intptr_t>(def);
- if (auto const offset_sexp =
- CheckInteger(list_sexp->ExtraLookupValue("offset"))) {
- auto const offset = offset_sexp->value();
- if (!RangeBoundary::IsValidOffsetForSymbolicRangeBoundary(offset)) {
- StoreError(sexp, "invalid offset for symbolic range boundary");
- return false;
- }
- out->offset_ = offset;
- }
- } else {
- StoreError(sexp, "unexpected value for range boundary");
- return false;
- }
- return true;
-}
-
-bool FlowGraphDeserializer::ParseBlockId(SExpSymbol* sym, intptr_t* out) {
- return ParseSymbolAsPrefixedInt(sym, 'B', out);
-}
-
-bool FlowGraphDeserializer::ParseSSATemp(SExpSymbol* sym, intptr_t* out) {
- return ParseSymbolAsPrefixedInt(sym, 'v', out);
-}
-
-bool FlowGraphDeserializer::ParseUse(SExpSymbol* sym, intptr_t* out) {
- // TODO(sstrickl): Handle non-SSA temp uses.
- return ParseSSATemp(sym, out);
-}
-
-bool FlowGraphDeserializer::ParseSymbolAsPrefixedInt(SExpSymbol* sym,
- char prefix,
- intptr_t* out) {
- ASSERT(out != nullptr);
- if (sym == nullptr) return false;
- auto const name = sym->value();
- if (*name != prefix) {
- StoreError(sym, "expected symbol starting with '%c'", prefix);
- return false;
- }
- int64_t i;
- if (!OS::StringToInt64(name + 1, &i)) {
- StoreError(sym, "expected number following symbol prefix '%c'", prefix);
- return false;
- }
- *out = i;
- return true;
-}
-
-bool FlowGraphDeserializer::ArePendingTypeRefs() const {
- // We'll do a deep check, because while there may be recursive types still
- // being parsed, if there are no pending type refs to those recursive types,
- // we're still good to canonicalize.
- if (pending_typeref_map_.IsEmpty()) return false;
- auto it = pending_typeref_map_.GetIterator();
- while (auto kv = it.Next()) {
- if (!kv->value->is_empty()) return true;
- }
- return false;
-}
-
-bool FlowGraphDeserializer::CreateICData(SExpList* list, Instruction* inst) {
- ASSERT(inst != nullptr);
- if (list == nullptr) return false;
-
- const String* function_name = nullptr;
- Array& arguments_descriptor = Array::Handle(zone());
- intptr_t num_args_checked;
- ICData::RebindRule rebind_rule;
-
- if (auto const call = inst->AsInstanceCall()) {
- function_name = &call->function_name();
- arguments_descriptor = call->GetArgumentsDescriptor();
- num_args_checked = call->checked_argument_count();
- rebind_rule = ICData::RebindRule::kInstance;
- } else if (auto const call = inst->AsStaticCall()) {
- function_name = &String::Handle(zone(), call->function().name());
- arguments_descriptor = call->GetArgumentsDescriptor();
- num_args_checked =
- MethodRecognizer::NumArgsCheckedForStaticCall(call->function());
- rebind_rule = ICData::RebindRule::kStatic;
- } else {
- StoreError(list, "unexpected instruction type for ICData");
- return false;
- }
-
- auto type_ptr = &Object::null_abstract_type();
- if (auto const type_sexp = list->ExtraLookupValue("receivers_static_type")) {
- auto& type = AbstractType::ZoneHandle(zone());
- if (!ParseAbstractType(type_sexp, &type)) return false;
- type_ptr = &type;
- }
-
- ASSERT(parsed_function_ != nullptr);
- auto& ic_data = ICData::ZoneHandle(
- zone(), ICData::New(parsed_function_->function(), *function_name,
- arguments_descriptor, inst->deopt_id(),
- num_args_checked, rebind_rule, *type_ptr));
-
- if (auto const is_mega_sexp =
- CheckBool(list->ExtraLookupValue("is_megamorphic"))) {
- ic_data.set_is_megamorphic(is_mega_sexp->value());
- }
-
- auto const class_table = thread()->isolate_group()->class_table();
- GrowableArray<intptr_t> class_ids(zone(), 2);
- for (intptr_t i = 1, n = list->Length(); i < n; i++) {
- auto const entry = CheckList(Retrieve(list, i));
- if (entry == nullptr) return false;
- ASSERT(ic_data.NumArgsTested() == entry->Length());
-
- intptr_t count = 0;
- if (auto const count_sexp =
- CheckInteger(entry->ExtraLookupValue("count"))) {
- count = count_sexp->value();
- }
-
- auto& target = Function::ZoneHandle(zone());
- if (!ParseDartValue(Retrieve(entry, "target"), &target)) return false;
-
- // We can't use AddCheck for NumArgsTested < 2. We'll handle 0 here, and
- // 1 after the for loop.
- if (entry->Length() == 0) {
- if (count != 0) {
- StoreError(entry, "expected a zero count for no checked args");
- return false;
- }
- ic_data = ICData::NewForStaticCall(parsed_function_->function(), target,
- arguments_descriptor, inst->deopt_id(),
- num_args_checked, rebind_rule);
- continue;
- }
-
- class_ids.Clear();
- for (intptr_t j = 0, num_cids = entry->Length(); j < num_cids; j++) {
- auto const cid_sexp = CheckInteger(Retrieve(entry, j));
- if (cid_sexp == nullptr) return false;
- const intptr_t cid = cid_sexp->value();
- // kObjectCid is a special case used for AddTarget() entries with
- // a non-zero number of checked arguments.
- if (cid != kObjectCid && !class_table->HasValidClassAt(cid)) {
- StoreError(cid_sexp, "cid is not a valid class");
- return false;
- }
- class_ids.Add(cid);
- }
-
- if (entry->Length() == 1) {
- ic_data.AddReceiverCheck(class_ids.At(0), target, count);
- } else {
- ic_data.AddCheck(class_ids, target, count);
- }
- }
-
- if (auto const call = inst->AsInstanceCall()) {
- call->set_ic_data(const_cast<const ICData*>(&ic_data));
- } else if (auto const call = inst->AsStaticCall()) {
- call->set_ic_data(&ic_data);
- }
-
- return true;
-}
-
-Value* FlowGraphDeserializer::AddNewPendingValue(SExpression* sexp,
- intptr_t index,
- bool inherit_type) {
- ASSERT(flow_graph_ != nullptr);
- auto const value = new (zone()) Value(flow_graph_->constant_null());
- ASSERT(!definition_map_.HasKey(index));
- auto list = values_map_.LookupValue(index);
- if (list == nullptr) {
- list = new (zone()) ZoneGrowableArray<PendingValue>(zone(), 2);
- values_map_.Insert(index, list);
- }
- list->Add({sexp, value, inherit_type});
- return value;
-}
-
-bool FlowGraphDeserializer::FixPendingValues(intptr_t index, Definition* def) {
- if (auto value_list = values_map_.LookupValue(index)) {
- for (intptr_t i = 0; i < value_list->length(); i++) {
- const auto& value_info = value_list->At(i);
- auto const value = value_info.value;
- const bool inherit_type = value_info.inherit_type;
- value->BindTo(def);
- if (!inherit_type) continue;
- if (def->HasType()) {
- value->reaching_type_ = def->Type();
- } else {
- StoreError(value_info.sexp, "value inherits type, but no type found");
- return false;
- }
- }
- values_map_.Remove(index);
- }
- return true;
-}
-
-BlockEntryInstr* FlowGraphDeserializer::FetchBlock(SExpSymbol* sym) {
- if (sym == nullptr) return nullptr;
- intptr_t block_id;
- if (!ParseBlockId(sym, &block_id)) return nullptr;
- auto const entry = block_map_.LookupValue(block_id);
- if (entry == nullptr) {
- StoreError(sym, "reference to undefined block");
- return nullptr;
- }
- return entry;
-}
-
-#define BASE_CHECK_DEF(name, type) \
- SExp##name* FlowGraphDeserializer::Check##name(SExpression* sexp) { \
- if (sexp == nullptr) return nullptr; \
- if (!sexp->Is##name()) { \
- StoreError(sexp, "expected " #name); \
- return nullptr; \
- } \
- return sexp->As##name(); \
- }
-
-FOR_EACH_S_EXPRESSION(BASE_CHECK_DEF)
-
-#undef BASE_CHECK_DEF
-
-bool FlowGraphDeserializer::IsTag(SExpression* sexp, const char* label) {
- auto const sym = CheckSymbol(sexp);
- if (sym == nullptr) return false;
- if (label != nullptr && !sym->Equals(label)) {
- StoreError(sym, "expected symbol %s", label);
- return false;
- }
- return true;
-}
-
-SExpList* FlowGraphDeserializer::CheckTaggedList(SExpression* sexp,
- const char* label) {
- auto const list = CheckList(sexp);
- const intptr_t tag_pos = 0;
- if (!IsTag(Retrieve(list, tag_pos), label)) return nullptr;
- return list;
-}
-
-void FlowGraphDeserializer::StoreError(SExpression* sexp,
- const char* format,
- ...) {
- va_list args;
- va_start(args, format);
- const char* const message = OS::VSCreate(zone(), format, args);
- va_end(args);
- error_sexp_ = sexp;
- error_message_ = message;
-}
-
-void FlowGraphDeserializer::ReportError() const {
- ASSERT(error_sexp_ != nullptr);
- ASSERT(error_message_ != nullptr);
- OS::PrintErr("Unable to deserialize flow_graph: %s\n", error_message_);
- OS::PrintErr("Error at S-expression %s\n", error_sexp_->ToCString(zone()));
- OS::Abort();
-}
-
-} // namespace dart
diff --git a/runtime/vm/compiler/backend/il_deserializer.h b/runtime/vm/compiler/backend/il_deserializer.h
deleted file mode 100644
index 5049850..0000000
--- a/runtime/vm/compiler/backend/il_deserializer.h
+++ /dev/null
@@ -1,421 +0,0 @@
-// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#ifndef RUNTIME_VM_COMPILER_BACKEND_IL_DESERIALIZER_H_
-#define RUNTIME_VM_COMPILER_BACKEND_IL_DESERIALIZER_H_
-
-#if defined(DART_PRECOMPILED_RUNTIME)
-#error "AOT runtime should not use compiler sources (including header files)"
-#endif // defined(DART_PRECOMPILED_RUNTIME)
-
-#include "platform/assert.h"
-
-#include "vm/allocation.h"
-#include "vm/compiler/backend/flow_graph.h"
-#include "vm/compiler/backend/il.h"
-#include "vm/compiler/backend/sexpression.h"
-#include "vm/compiler/compiler_pass.h"
-#include "vm/object.h"
-#include "vm/parser.h"
-#include "vm/thread.h"
-#include "vm/zone.h"
-
-namespace dart {
-
-// Deserializes FlowGraphs from S-expressions.
-class FlowGraphDeserializer : ValueObject {
- public:
- // Adds to the given array all the instructions in the flow graph that are
- // guaranteed not to be handled by the current implementation of the
- // FlowGraphDeserializer. This way, we can filter out graphs that are
- // guaranteed not to be deserializable before going through the round-trip
- // serialization process.
- //
- // Note that there may be other reasons that the deserializer may fail on
- // a given flow graph, so no new members of the array is necessary, but not
- // sufficient, for a successful round-trip pass.
- static void AllUnhandledInstructions(const FlowGraph* graph,
- GrowableArray<Instruction*>* out);
-
- // Takes the FlowGraph from [state] and runs it through the serializer
- // and deserializer. If the deserializer successfully deserializes the
- // graph, then the FlowGraph in [state] is replaced with the new one.
- static void RoundTripSerialization(CompilerPassState* state);
-
- FlowGraphDeserializer(Thread* thread,
- Zone* zone,
- SExpression* root,
- const ParsedFunction* pf = nullptr)
- : thread_(ASSERT_NOTNULL(thread)),
- zone_(ASSERT_NOTNULL(zone)),
- root_sexp_(ASSERT_NOTNULL(root)),
- parsed_function_(pf),
- block_map_(zone),
- definition_map_(zone),
- values_map_(zone),
- recursive_types_map_(zone),
- pending_typeref_map_(zone),
- array_type_args_(TypeArguments::Handle(zone)),
- instance_class_(Class::Handle(zone)),
- instance_field_(Field::Handle(zone)),
- instance_fields_array_(Array::Handle(zone)),
- instance_type_args_(TypeArguments::Handle(zone)),
- name_class_(Class::Handle(zone)),
- name_field_(Field::Handle(zone)),
- name_function_(Function::Handle(zone)),
- name_library_(Library::Handle(zone)),
- type_class_(Class::Handle(zone)),
- type_param_class_(Class::Handle(zone)),
- tmp_string_(String::Handle(zone)) {
- // See canonicalization comment in ParseDartValue as to why this is
- // currently necessary.
- ASSERT(thread->zone() == zone);
- }
-
- // Walks [root_sexp_] and constructs a new FlowGraph.
- FlowGraph* ParseFlowGraph();
-
- const char* error_message() const { return error_message_; }
- SExpression* error_sexp() const { return error_sexp_; }
-
- // Prints the current error information to stderr and aborts.
- DART_NORETURN void ReportError() const;
-
- private:
-#define FOR_EACH_HANDLED_BLOCK_TYPE_IN_DESERIALIZER(M) \
- M(FunctionEntry) \
- M(GraphEntry) \
- M(JoinEntry) \
- M(TargetEntry)
-
-#define FOR_EACH_HANDLED_INSTRUCTION_IN_DESERIALIZER(M) \
- M(AllocateObject) \
- M(AssertAssignable) \
- M(AssertBoolean) \
- M(BooleanNegate) \
- M(Branch) \
- M(CheckNull) \
- M(CheckStackOverflow) \
- M(Constant) \
- M(DebugStepCheck) \
- M(Goto) \
- M(InstanceCall) \
- M(LoadClassId) \
- M(LoadField) \
- M(NativeCall) \
- M(Parameter) \
- M(Return) \
- M(SpecialParameter) \
- M(StaticCall) \
- M(StoreInstanceField) \
- M(StrictCompare) \
- M(Throw)
-
- // Helper methods for AllUnhandledInstructions.
- static bool IsHandledInstruction(Instruction* inst);
- static bool IsHandledConstant(const Object& obj);
-
- // **GENERAL DESIGN NOTES FOR PARSING METHODS**
- //
- // For functions that take an SExpression or a subclass, they should return
- // an error signal (false, nullptr, etc.) without changing the error state if
- // passed in nullptr. This way, methods can be chained without intermediate
- // checking.
- //
- // Also, for parsing methods for expressions that are known to be of a certain
- // form, they will take the appropriate subclass of SExpression and assume
- // that the form was already pre-checked by the caller. For forms that are
- // tagged lists, this includes the fact that there is at least one element
- // and the first element is a symbol. If the form can only have one possible
- // tag, they also assume the tag has already been checked.
-
- // Helper functions that do length/key exists checking and also check that
- // the retrieved element is not nullptr. Notably, do not use these if the
- // retrieved element is optional, to avoid changing the error state
- // unnecessarily.
- SExpression* Retrieve(SExpList* list, intptr_t index);
- SExpression* Retrieve(SExpList* list, const char* key);
-
- bool ParseConstantPool(SExpList* pool);
- bool ParseEntries(SExpList* list);
-
- using BlockWorklist = GrowableArray<intptr_t>;
-
- // Starts parsing the contents of [list], where the blocks begin at position
- // [pos] and [worklist] contains the blocks whose body instructions should
- // be parsed first.
- bool ParseBlocks(SExpList* list, intptr_t pos, BlockWorklist* worklist);
-
- // Block parsing is split into two passes. This pass adds function entries
- // to the flow graph and also parses initial definitions found in the Entries
- // list. The block is added to the [block_map_] before returning.
- BlockEntryInstr* ParseBlockHeader(SExpList* list,
- intptr_t block_id,
- SExpSymbol* tag);
-
- // Expects [current_block_] to be set before calling.
- bool ParseInitialDefinitions(SExpList* list);
-
- // Expects [current_block_] to be set before calling.
- // Takes the tagged list to parse and the index where parsing should start.
- // Attempts to parse Phi definitions until the first non-Phi instruction.
- bool ParsePhis(SExpList* list);
-
- // Expects [current_block_] to be set before calling.
- // Returns the position of the first non-Phi instruction in a block.
- intptr_t SkipPhis(SExpList* list);
-
- // Parses the deopt environment, Phi definitions for JoinEntrys, and the
- // instructions in the body of the block. Adds the IDs of the block successors
- // to the worklist, if any. [current_block_] and [pushed_stack_] must be set
- // before calling.
- bool ParseBlockContents(SExpList* list, BlockWorklist* worklist);
-
- // Helper function used by ParseConstantPool, ParsePhis, and ParseDefinition.
- // This handles all the extra information stored in (def ...) expressions,
- // and also ensures the index of the definition is appropriately adjusted to
- // match those found in the serialized form.
- bool ParseDefinitionWithParsedBody(SExpList* list, Definition* def);
-
- Definition* ParseDefinition(SExpList* list);
- Instruction* ParseInstruction(SExpList* list);
-
- struct EntryInfo {
- intptr_t block_id;
- intptr_t try_index;
- intptr_t deopt_id;
- };
-
-#define HANDLER_DECL(name) \
- name##Instr* Deserialize##name(SExpList* list, const EntryInfo& info);
-
- FOR_EACH_HANDLED_BLOCK_TYPE_IN_DESERIALIZER(HANDLER_DECL);
-
-#undef HANDLER_DECL
-
- struct InstrInfo {
- const intptr_t deopt_id;
- const InstructionSource source;
- };
-
- enum HandledInstruction {
-#define HANDLED_INST_DECL(name) kHandled##name,
- FOR_EACH_HANDLED_INSTRUCTION_IN_DESERIALIZER(HANDLED_INST_DECL)
-#undef HANDLED_INST_DECL
- // clang-format off
- kHandledInvalid = -1,
- // clang-format on
- };
-
-#define HANDLE_CASE(name) \
- if (strcmp(tag->value(), #name) == 0) return kHandled##name;
- HandledInstruction HandledInstructionForTag(SExpSymbol* tag) {
- ASSERT(tag != nullptr);
- FOR_EACH_HANDLED_INSTRUCTION_IN_DESERIALIZER(HANDLE_CASE)
- return kHandledInvalid;
- }
-#undef HANDLE_CASE
-
-#define HANDLER_DECL(name) \
- name##Instr* Deserialize##name(SExpList* list, const InstrInfo& info);
-
- FOR_EACH_HANDLED_INSTRUCTION_IN_DESERIALIZER(HANDLER_DECL);
-
-#undef HANDLER_DECL
-
- // Common information parsed from call instruction S-expressions.
- struct CallInfo : public ValueObject {
- explicit CallInfo(Zone* zone) : argument_names(Array::ZoneHandle(zone)) {}
-
- Array& argument_names;
- intptr_t type_args_len = 0;
- intptr_t args_len = 0;
- InputsArray* inputs = nullptr;
- CompileType* result_type = nullptr;
- Code::EntryKind entry_kind = Code::EntryKind::kNormal;
- };
-
- // Helper function for parsing call instructions that returns a structure
- // of information common to all calls.
- bool ParseCallInfo(SExpList* call,
- CallInfo* out,
- intptr_t num_extra_inputs = 0);
-
- // Parses [sexp] as a value form, that is, either the binding name for
- // a definition as a symbol or the form (value <name> { ... }).
- // If [allow_pending], then values for definitions not already in the
- // [definition_map_] will be added to the [values_map_], otherwise,
- // values for definitions not yet seen cause an error to be stored and
- // nullptr to be returned.
- Value* ParseValue(SExpression* sexp, bool allow_pending = true);
- CompileType* ParseCompileType(SExpList* list);
-
- // Parses [list] as an environment form: a list containing either binding
- // names for definitions or a# for pushed arguments (where # is the depth
- // of the argument from the top of the stack). Requires [pushed_stack_] to
- // be set if any references to pushed arguments are found.
- Environment* ParseEnvironment(SExpList* list);
-
- // Parsing functions for which there are no good distinguished error
- // values, so use out parameters and a boolean return instead.
-
- // Parses a Dart value and returns a canonicalized result.
- bool ParseDartValue(SExpression* sexp, Object* out);
-
- // Canonicalizes and replaces the original contents of the handle pointed to
- // by [inst] if [inst] is an Instance (if not, it trivially succeeds). The
- // replacement happens whether successful or not. [sexp] is the SExpression
- // to be used for error reporting.
- bool CanonicalizeInstance(SExpression* sexp, Object* inst);
-
- // Helper functions for ParseDartValue for parsing particular type of values.
- // If necessary, they canonicalize the returned value, and so may be used
- // directly by other code as well. Helpers that take SExpression* take either
- // serialized constants or references to constant definitions.
- //
- // Due to particulars of operator=() on non-Object values, for a given X,
- // ParseX takes Object* instead of X* for the out parameter.
- bool ParseAbstractType(SExpression* sexp, Object* out);
- bool ParseClass(SExpList* list, Object* out);
- bool ParseClosure(SExpList* list, Object* out);
- bool ParseField(SExpList* list, Object* out);
- bool ParseFunction(SExpList* list, Object* out);
- bool ParseSignature(SExpList* list, Object* out);
- bool ParseArray(SExpList* list, Object* out);
- bool ParseImmutableList(SExpList* list, Object* out);
- bool ParseInstance(SExpList* list, Object* out);
- bool ParseType(SExpression* sexp, Object* out);
- bool ParseFunctionType(SExpList* list, Object* out);
- bool ParseTypeParameter(SExpList* list, Object* out);
- bool ParseTypeArguments(SExpression* sexp, Object* out);
- bool ParseTypeRef(SExpList* list, Object* out);
-
- bool ParseCanonicalName(SExpSymbol* sym, Object* out);
-
- const Field& MayCloneField(const Field& field) const;
- bool ParseSlot(SExpList* list, const Slot** out);
- bool ParseRange(SExpList* list, Range* out);
- bool ParseRangeBoundary(SExpression* sexp, RangeBoundary* out);
-
- bool ParseBlockId(SExpSymbol* sym, intptr_t* out);
- bool ParseSSATemp(SExpSymbol* sym, intptr_t* out);
- bool ParseUse(SExpSymbol* sym, intptr_t* out);
- bool ParseSymbolAsPrefixedInt(SExpSymbol* sym, char prefix, intptr_t* out);
-
- bool ArePendingTypeRefs() const;
-
- // Allocates a new ICData structure. [list] is the ICData S-expression, while
- // [inst] is the Instruction generated from the instruction S-expression
- // containing [list].
- bool CreateICData(SExpList* list, Instruction* inst);
-
- // Helper function for creating a placeholder value when the definition
- // with index [i] has not yet been seen. If [inherit_type], then the type of
- // the definition should be used as the reaching type for the use. [s] is used
- // for any errors that occur when resolving the pending value.
- Value* AddNewPendingValue(SExpression* s, intptr_t i, bool inherit_type);
-
- // Helper function for rebinding values pending on this definition.
- bool FixPendingValues(intptr_t index, Definition* def);
-
- // Retrieves the block corresponding to the given block ID symbol from
- // [block_map_]. Assumes all blocks have had their header parsed.
- BlockEntryInstr* FetchBlock(SExpSymbol* sym);
-
- // Utility functions for checking the shape of an S-expression.
- // If these functions return nullptr for a non-null argument, they have the
- // side effect of setting the stored error message.
-#define BASE_CHECK_DECL(name, type) SExp##name* Check##name(SExpression* sexp);
- FOR_EACH_S_EXPRESSION(BASE_CHECK_DECL)
-#undef BASE_CHECK_DECL
-
- // Checks whether [sexp] is a symbol with the given label.
- bool IsTag(SExpression* sexp, const char* label);
-
- // A version of CheckList that also checks that the list has at least one
- // element and that the first element is a symbol. If [label] is non-null,
- // then the initial symbol element is checked against it.
- SExpList* CheckTaggedList(SExpression* sexp, const char* label = nullptr);
-
- // Stores appropriate error information using the SExpression as the location
- // and the rest of the arguments as an error message for the user.
- void StoreError(SExpression* s, const char* fmt, ...) PRINTF_ATTRIBUTE(3, 4);
-
- Thread* thread() const { return thread_; }
- Zone* zone() const { return zone_; }
-
- Thread* const thread_;
- Zone* const zone_;
- SExpression* const root_sexp_;
- const ParsedFunction* parsed_function_;
-
- FlowGraph* flow_graph_ = nullptr;
- BlockEntryInstr* current_block_ = nullptr;
- intptr_t max_block_id_ = -1;
- intptr_t max_ssa_index_ = -1;
-
- // Map from block IDs to blocks. Does not contain an entry for block 0
- // (the graph entry), since it is only used at known points and is already
- // available via [flow_graph_].
- IntMap<BlockEntryInstr*> block_map_;
-
- // Map from variable indexes to definitions.
- IntMap<Definition*> definition_map_;
-
- // Information needed to handle uses seen prior to their definitions.
- struct PendingValue {
- // SExpression used for error reporting.
- SExpression* sexp;
- // Value to be rebound once the right definition is found.
- Value* value;
- // Whether the type should inherit the type of the found definition.
- bool inherit_type;
- };
-
- // Map from variable indices to lists of values. The list of values are
- // values that were parsed prior to the corresponding definition being found.
- IntMap<ZoneGrowableArray<PendingValue>*> values_map_;
-
- // Map from hash values to SExpLists. This is used by ParseTypeRef to
- // determine whether or not the recursive type it refers to is being currently
- // built. The SExpList can be used to report hash collisions.
- IntMap<SExpList*> recursive_types_map_;
-
- // Map from hash values to arrays of TypeRefs. This is used by ParseType and
- // ParseTypeRef to store and later fill in TypeRefs pending on the type being
- // constructed. Since entries are added at the start of parsing recursive
- // Type S-exps and removed before the resulting Type is successfully returned,
- // this map should be empty outside of parsing recursive types.
- IntMap<ZoneGrowableArray<TypeRef*>*> pending_typeref_map_;
-
- // Temporary handles used by functions that are not re-entrant or where the
- // handle is not live after the re-entrant call. Comments show which handles
- // are expected to only be used within a single method.
- TypeArguments& array_type_args_; // ParseImmutableList
- Class& instance_class_; // ParseInstance
- Field& instance_field_; // ParseInstance
- Array& instance_fields_array_; // ParseInstance
- TypeArguments& instance_type_args_; // ParseInstance
- Class& name_class_; // ParseCanonicalName
- Field& name_field_; // ParseCanonicalName
- Function& name_function_; // ParseCanonicalName
- Library& name_library_; // ParseCanonicalName
- Class& type_class_; // ParseType
- Class& type_param_class_; // ParseTypeParameter
- // Uses of string handles tend to be immediate, so we only need one.
- String& tmp_string_;
-
- // Stores a message appropriate to surfacing to the user when an error
- // occurs.
- const char* error_message_ = nullptr;
- // Stores the location of the deserialization error by containing the
- // S-expression which caused the failure.
- SExpression* error_sexp_ = nullptr;
-
- DISALLOW_COPY_AND_ASSIGN(FlowGraphDeserializer);
-};
-
-} // namespace dart
-
-#endif // RUNTIME_VM_COMPILER_BACKEND_IL_DESERIALIZER_H_
diff --git a/runtime/vm/compiler/backend/il_serializer.cc b/runtime/vm/compiler/backend/il_serializer.cc
deleted file mode 100644
index 31fd469..0000000
--- a/runtime/vm/compiler/backend/il_serializer.cc
+++ /dev/null
@@ -1,1508 +0,0 @@
-// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#include "vm/compiler/backend/il_serializer.h"
-
-#include "vm/compiler/backend/flow_graph.h"
-#include "vm/compiler/backend/il.h"
-#include "vm/compiler/backend/range_analysis.h"
-#include "vm/compiler/method_recognizer.h"
-#include "vm/object_store.h"
-#include "vm/os.h"
-#include "vm/zone_text_buffer.h"
-
-namespace dart {
-
-DEFINE_FLAG(bool,
- serialize_flow_graph_types,
- true,
- "Serialize inferred type information in flow graphs");
-
-DEFINE_FLAG(bool,
- verbose_flow_graph_serialization,
- false,
- "Serialize extra information useful for debugging");
-
-DEFINE_FLAG(bool,
- pretty_print_serialization,
- false,
- "Format serialized output nicely");
-
-DECLARE_FLAG(bool, populate_llvm_constant_pool);
-
-const char* const FlowGraphSerializer::initial_indent = "";
-
-FlowGraphSerializer::FlowGraphSerializer(Zone* zone,
- const FlowGraph* flow_graph)
- : flow_graph_(ASSERT_NOTNULL(flow_graph)),
- zone_(zone),
- object_store_(flow_graph->thread()->isolate_group()->object_store()),
- open_recursive_types_(zone_),
- llvm_constants_(
- GrowableObjectArray::Handle(zone_,
- object_store_->llvm_constant_pool())),
- llvm_functions_(
- GrowableObjectArray::Handle(zone_,
- object_store_->llvm_function_pool())),
- llvm_constant_map_(zone_, object_store_->llvm_constant_hash_table()),
- llvm_index_(Smi::Handle(zone_)),
- tmp_string_(String::Handle(zone_)),
- array_type_args_((TypeArguments::Handle(zone_))),
- closure_context_(Context::Handle(zone_)),
- closure_function_(Function::Handle(zone_)),
- closure_type_args_(TypeArguments::Handle(zone_)),
- code_owner_(Object::Handle(zone_)),
- context_parent_(Context::Handle(zone_)),
- context_elem_(Object::Handle(zone_)),
- function_type_args_(TypeArguments::Handle(zone_)),
- ic_data_target_(Function::Handle(zone_)),
- ic_data_type_(AbstractType::Handle(zone_)),
- instance_field_(Field::Handle(zone_)),
- instance_type_args_(TypeArguments::Handle(zone_)),
- serialize_library_(Library::Handle(zone_)),
- serialize_owner_(Class::Handle(zone_)),
- serialize_parent_(Function::Handle(zone_)),
- type_arguments_elem_(AbstractType::Handle(zone_)),
- type_class_(Class::Handle(zone_)),
- type_signature_(FunctionType::Handle(zone_)),
- type_ref_type_(AbstractType::Handle(zone_)) {
- // Double-check that the zone in the flow graph is a parent of the
- // zone we'll be using for serialization.
- ASSERT(flow_graph->zone()->ContainsNestedZone(zone));
-}
-
-FlowGraphSerializer::~FlowGraphSerializer() {
- object_store_->set_llvm_constant_hash_table(llvm_constant_map_.Release());
-}
-
-void FlowGraphSerializer::SerializeToBuffer(Zone* zone,
- const FlowGraph* flow_graph,
- BaseTextBuffer* buffer) {
- ASSERT(buffer != nullptr);
- auto const sexp = SerializeToSExp(zone, flow_graph);
- if (FLAG_pretty_print_serialization) {
- sexp->SerializeTo(zone, buffer, initial_indent);
- } else {
- sexp->SerializeToLine(buffer);
- }
- buffer->AddString("\n\n");
-}
-
-SExpression* FlowGraphSerializer::SerializeToSExp(Zone* zone,
- const FlowGraph* flow_graph) {
- FlowGraphSerializer serializer(zone, flow_graph);
- return serializer.FlowGraphToSExp();
-}
-
-#define KIND_STR(name) #name,
-static const char* block_entry_kind_tags[FlowGraphSerializer::kNumEntryKinds] =
- {FOR_EACH_BLOCK_ENTRY_KIND(KIND_STR)};
-#undef KIND_STR
-
-FlowGraphSerializer::BlockEntryKind FlowGraphSerializer::BlockEntryTagToKind(
- SExpSymbol* tag) {
- if (tag == nullptr) return kTarget;
- auto const str = tag->value();
- for (intptr_t i = 0; i < kNumEntryKinds; i++) {
- auto const current = block_entry_kind_tags[i];
- if (strcmp(str, current) == 0) return static_cast<BlockEntryKind>(i);
- }
- return kInvalid;
-}
-
-void FlowGraphSerializer::AddBool(SExpList* sexp, bool b) {
- sexp->Add(new (zone()) SExpBool(b));
-}
-
-void FlowGraphSerializer::AddInteger(SExpList* sexp, intptr_t i) {
- sexp->Add(new (zone()) SExpInteger(i));
-}
-
-void FlowGraphSerializer::AddString(SExpList* sexp, const char* cstr) {
- sexp->Add(new (zone()) SExpString(cstr));
-}
-
-void FlowGraphSerializer::AddSymbol(SExpList* sexp, const char* cstr) {
- sexp->Add(new (zone()) SExpSymbol(cstr));
-}
-
-void FlowGraphSerializer::AddExtraBool(SExpList* sexp,
- const char* label,
- bool b) {
- sexp->AddExtra(label, new (zone()) SExpBool(b));
-}
-
-void FlowGraphSerializer::AddExtraInteger(SExpList* sexp,
- const char* label,
- intptr_t i) {
- sexp->AddExtra(label, new (zone()) SExpInteger(i));
-}
-
-void FlowGraphSerializer::AddExtraString(SExpList* sexp,
- const char* label,
- const char* cstr) {
- sexp->AddExtra(label, new (zone()) SExpString(cstr));
-}
-
-void FlowGraphSerializer::AddExtraSymbol(SExpList* sexp,
- const char* label,
- const char* cstr) {
- sexp->AddExtra(label, new (zone()) SExpSymbol(cstr));
-}
-
-SExpression* FlowGraphSerializer::BlockIdToSExp(intptr_t block_id) {
- return new (zone()) SExpSymbol(OS::SCreate(zone(), "B%" Pd "", block_id));
-}
-
-void FlowGraphSerializer::SerializeCanonicalName(BaseTextBuffer* b,
- const Object& obj) {
- ASSERT(!obj.IsNull());
- if (obj.IsFunction()) {
- const auto& function = Function::Cast(obj);
- tmp_string_ = function.name();
- // We only want private keys removed, no other changes.
- tmp_string_ = String::RemovePrivateKey(tmp_string_);
- const char* function_name = tmp_string_.ToCString();
- // If this function is an inner closure then the parent points to its
- // containing function, which will also be part of the canonical name.
- //
- // We retrieve the owner before retrieving the parent function, as the
- // inner closure chain may be arbitrarily deep and serialize_parent_ is
- // passed in on recursive calls. When it is, then changing serialize_parent_
- // to the parent function also changes the contents of obj and thus we'd
- // no longer be able to retrieve the child function or its owner.
- //
- // This does mean that serialize_owner_ gets overwritten for each recursive
- // call until we reach the end of the chain, but we only use its contents at
- // the end of the chain anyway.
- serialize_owner_ = function.Owner();
- serialize_parent_ = function.parent_function();
- if (!serialize_parent_.IsNull()) {
- SerializeCanonicalName(b, serialize_parent_);
- } else {
- ASSERT(!serialize_owner_.IsNull());
- SerializeCanonicalName(b, serialize_owner_);
- }
- b->Printf(":%s", function_name);
- } else if (obj.IsClass()) {
- const auto& cls = Class::Cast(obj);
- tmp_string_ = cls.ScrubbedName();
- const char* class_name = tmp_string_.ToCString();
- serialize_library_ = cls.library();
- if (!serialize_library_.IsNull()) {
- SerializeCanonicalName(b, serialize_library_);
- }
- b->Printf(":%s", class_name);
- } else if (obj.IsLibrary()) {
- const Library& lib = Library::Cast(obj);
- tmp_string_ = lib.url();
- const char* lib_name = tmp_string_.ToCString();
- if (lib_name[0] == '\0') return;
- b->AddString(lib_name);
- } else if (obj.IsField()) {
- const auto& field = Field::Cast(obj);
- tmp_string_ = field.UserVisibleName();
- const char* field_name = tmp_string_.ToCString();
- serialize_owner_ = field.Owner();
- ASSERT(!serialize_owner_.IsNull());
- SerializeCanonicalName(b, serialize_owner_);
- b->Printf(".%s", field_name);
- } else {
- UNREACHABLE();
- }
-}
-
-SExpression* FlowGraphSerializer::CanonicalNameToSExp(const Object& obj) {
- ASSERT(!obj.IsNull());
- ZoneTextBuffer b(zone_, 100);
- SerializeCanonicalName(&b, obj);
- return new (zone()) SExpSymbol(b.buffer());
-}
-
-SExpSymbol* FlowGraphSerializer::BlockEntryKindToTag(BlockEntryKind k) {
- ASSERT(k >= 0 && k < kNumEntryKinds);
- return new (zone()) SExpSymbol(block_entry_kind_tags[k]);
-}
-
-#define KIND_TAG(name) block_entry_kind_tags[k##name]
-SExpSymbol* FlowGraphSerializer::BlockEntryTag(const BlockEntryInstr* entry) {
- if (entry == nullptr) return nullptr;
- if (entry->IsGraphEntry()) {
- return BlockEntryKindToTag(kGraph);
- }
- if (entry->IsOsrEntry()) {
- return BlockEntryKindToTag(kOSR);
- }
- if (entry->IsCatchBlockEntry()) {
- return BlockEntryKindToTag(kCatch);
- }
- if (entry->IsIndirectEntry()) {
- return BlockEntryKindToTag(kIndirect);
- }
- if (entry->IsFunctionEntry()) {
- if (entry == flow_graph()->graph_entry()->normal_entry()) {
- return BlockEntryKindToTag(kNormal);
- }
- if (entry == flow_graph()->graph_entry()->unchecked_entry()) {
- return BlockEntryKindToTag(kUnchecked);
- }
- }
- if (entry->IsJoinEntry()) {
- return BlockEntryKindToTag(kJoin);
- }
- return nullptr;
-}
-#undef KIND_TAG
-
-SExpression* FlowGraphSerializer::FunctionEntryToSExp(
- const BlockEntryInstr* entry) {
- if (entry == nullptr) return nullptr;
- auto sexp = new (zone()) SExpList(zone());
- sexp->Add(BlockEntryTag(entry));
- sexp->Add(BlockIdToSExp(entry->block_id()));
- if (auto const with_defs = entry->AsBlockEntryWithInitialDefs()) {
- auto const initial_defs = with_defs->initial_definitions();
- for (intptr_t i = 0; i < initial_defs->length(); i++) {
- sexp->Add(initial_defs->At(i)->ToSExpression(this));
- }
- }
-
- // Also include the extra info here, to avoid having to find the
- // corresponding block to get it.
- entry->BlockEntryInstr::AddExtraInfoToSExpression(sexp, this);
-
- return sexp;
-}
-
-SExpression* FlowGraphSerializer::EntriesToSExp(const GraphEntryInstr* start) {
- auto sexp = new (zone()) SExpList(zone());
- AddSymbol(sexp, "Entries");
- if (auto const normal = FunctionEntryToSExp(start->normal_entry())) {
- sexp->Add(normal);
- }
- if (auto const unchecked = FunctionEntryToSExp(start->unchecked_entry())) {
- sexp->Add(unchecked);
- }
- if (auto const osr = FunctionEntryToSExp(start->osr_entry())) {
- sexp->Add(osr);
- }
- for (intptr_t i = 0; i < start->catch_entries().length(); i++) {
- sexp->Add(FunctionEntryToSExp(start->catch_entries().At(i)));
- }
- for (intptr_t i = 0; i < start->indirect_entries().length(); i++) {
- sexp->Add(FunctionEntryToSExp(start->indirect_entries().At(i)));
- }
- return sexp;
-}
-
-SExpression* FlowGraphSerializer::FlowGraphToSExp() {
- auto const start = flow_graph()->graph_entry();
- auto const sexp = new (zone()) SExpList(zone());
- AddSymbol(sexp, "FlowGraph");
- sexp->Add(CanonicalNameToSExp(flow_graph()->function()));
- AddExtraInteger(sexp, "deopt_id", start->deopt_id());
- if (start->env() != nullptr) {
- sexp->AddExtra("env", start->env()->ToSExpression(this));
- }
- if (start->IsCompiledForOsr()) {
- AddExtraInteger(sexp, "osr_id", start->osr_id());
- }
- if (auto const constants = ConstantPoolToSExp(start)) {
- sexp->Add(constants);
- }
- sexp->Add(EntriesToSExp(start));
- auto& block_order = flow_graph()->reverse_postorder();
- // Skip the first block, which will be the graph entry block (B0). We
- // output all its information as part of the function expression, so it'll
- // just show up as an empty block here.
- ASSERT(block_order[0]->IsGraphEntry());
- for (intptr_t i = 1; i < block_order.length(); ++i) {
- sexp->Add(block_order[i]->ToSExpression(this));
- }
- if (FLAG_populate_llvm_constant_pool) {
- auto const new_index = llvm_functions_.Length();
- llvm_functions_.Add(flow_graph_->function());
- AddExtraInteger(sexp, "llvm_index", new_index);
- }
- return sexp;
-}
-
-SExpression* FlowGraphSerializer::UseToSExp(const Definition* definition) {
- ASSERT(definition != nullptr);
- ASSERT(definition->HasSSATemp() || definition->HasTemp());
- if (definition->HasSSATemp()) {
- const intptr_t temp_index = definition->ssa_temp_index();
- const auto name_cstr = OS::SCreate(zone(), "v%" Pd "", temp_index);
- if (definition->HasPairRepresentation()) {
- auto sexp = new (zone()) SExpList(zone());
- AddSymbol(sexp, name_cstr);
- AddSymbol(sexp, OS::SCreate(zone(), "v%" Pd "", temp_index + 1));
- return sexp;
- } else {
- return new (zone()) SExpSymbol(name_cstr);
- }
- } else if (definition->HasTemp()) {
- const intptr_t temp_index = definition->temp_index();
- return new (zone()) SExpSymbol(OS::SCreate(zone(), "t%" Pd "", temp_index));
- }
- UNREACHABLE();
-}
-
-SExpression* FlowGraphSerializer::ClassToSExp(const Class& cls) {
- if (cls.IsNull()) return nullptr;
- auto sexp = new (zone()) SExpList(zone());
- AddSymbol(sexp, "Class");
- AddInteger(sexp, cls.id());
- if (FLAG_verbose_flow_graph_serialization) {
- sexp->AddExtra("name", CanonicalNameToSExp(cls));
- // Currently, AbstractTypeToSExp assumes that serializing a class cannot
- // re-enter it. If we make that possible by serializing parts of a class
- // that can contain AbstractTypes, especially types that are not type
- // parameters or type references, fix AbstractTypeToSExp appropriately.
- }
- return sexp;
-}
-
-static bool ShouldSerializeType(CompileType* type) {
- return (FLAG_verbose_flow_graph_serialization ||
- FLAG_serialize_flow_graph_types) &&
- type != nullptr;
-}
-
-SExpression* FlowGraphSerializer::FieldToSExp(const Field& field) {
- if (field.IsNull()) return nullptr;
- auto sexp = new (zone()) SExpList(zone());
- AddSymbol(sexp, "Field");
- sexp->Add(CanonicalNameToSExp(field));
- CompileType t(field.is_nullable(), field.guarded_cid(), nullptr);
- if (ShouldSerializeType(&t)) {
- sexp->AddExtra("type", t.ToSExpression(this));
- }
- return sexp;
-}
-
-SExpression* FlowGraphSerializer::AbstractTypeToSExp(const AbstractType& t) {
- if (t.IsNull()) return nullptr;
- ASSERT(t.IsFinalized());
- auto sexp = new (zone()) SExpList(zone());
- if (t.IsTypeParameter()) {
- const auto& param = TypeParameter::Cast(t);
- AddSymbol(sexp, "TypeParameter");
- AddExtraInteger(sexp, "cid", param.parameterized_class_id());
- AddExtraInteger(sexp, "base", param.base());
- AddExtraInteger(sexp, "index", param.index());
- tmp_string_ = param.name();
- AddSymbol(sexp, tmp_string_.ToCString());
- // TODO(regis): bound, default argument, flags, nullability, hash.
- return sexp;
- }
- if (t.IsTypeRef()) {
- const auto& ref = TypeRef::Cast(t);
- AddSymbol(sexp, "TypeRef");
- type_ref_type_ = ref.type();
- auto const hash = type_ref_type_.Hash();
- // Check to see if this is a TypeRef to a type we're currently serializing.
- // If it is not, then we need to serialize the underlying type, as it
- // otherwise won't be available when deserializing.
- auto const open_type = open_recursive_types_.LookupValue(hash);
- if (open_type == nullptr) {
- // Allocate a new handle as we may re-enter the TypeRef branch.
- auto& type = AbstractType::Handle(zone(), ref.type());
- sexp->Add(AbstractTypeToSExp(type));
- // If we serialized the referrent, then we don't need this information,
- // but it may be useful for debugging so add it in verbose mode.
- if (FLAG_verbose_flow_graph_serialization) {
- AddExtraInteger(sexp, "hash", hash);
- }
- } else {
- // Make sure we didn't have a hash collision.
- ASSERT(open_type->Equals(type_ref_type_));
- AddExtraInteger(sexp, "hash", hash);
- }
- if (FLAG_verbose_flow_graph_serialization) {
- AddExtraString(sexp, "type", type_ref_type_.ToCString());
- }
- return sexp;
- }
- // We want to check for the type being recursive before we may serialize
- // any sub-parts that include possible TypeRefs to this type.
- const bool is_recursive = t.IsRecursive();
- intptr_t hash = 0;
- if (is_recursive) {
- hash = t.Hash();
- AddExtraInteger(sexp, "hash", hash);
- open_recursive_types_.Insert(hash, &t);
- }
- if (t.IsFunctionType()) {
- const auto& sig = FunctionType::Handle(zone(), FunctionType::Cast(t).ptr());
- AddSymbol(sexp, "FunctionType");
- function_type_args_ = sig.type_parameters();
- if (auto const ta_sexp = NonEmptyTypeArgumentsToSExp(function_type_args_)) {
- sexp->AddExtra("type_params", ta_sexp);
- }
- auto& type = AbstractType::Handle(zone(), sig.result_type());
- sexp->AddExtra("result_type", AbstractTypeToSExp(type));
- auto& parameter_types = Array::Handle(zone(), sig.parameter_types());
- sexp->AddExtra("parameter_types", ArrayToSExp(parameter_types));
- auto& parameter_names = Array::Handle(zone(), sig.parameter_names());
- sexp->AddExtra("parameter_names", ArrayToSExp(parameter_names));
- AddExtraInteger(sexp, "packed_fields", sig.packed_fields());
- // If we were parsing a recursive type, we're now done building it, so
- // remove it from the open recursive types.
- if (is_recursive) open_recursive_types_.Remove(hash);
- return sexp;
- }
- ASSERT(t.IsType());
- AddSymbol(sexp, "Type");
- const auto& type = Type::Cast(t);
- if (type.HasTypeClass()) {
- type_class_ = type.type_class();
- // This avoids re-entry as long as serializing a class doesn't involve
- // serializing concrete (non-parameter, non-reference) types.
- sexp->Add(DartValueToSExp(type_class_));
- } else {
- // TODO(dartbug.com/36882): Actually structure non-class types instead of
- // just printing out this version.
- AddExtraString(sexp, "name", type.ToCString());
- }
- // Since type arguments may themselves be instantiations of generic
- // types, we may call back into this function in the middle of printing
- // the TypeArguments and so we must allocate a fresh handle here.
- const auto& args = TypeArguments::Handle(zone(), type.arguments());
- if (auto const args_sexp = NonEmptyTypeArgumentsToSExp(args)) {
- sexp->AddExtra("type_args", args_sexp);
- }
- // If we were parsing a recursive type, we're now done building it, so
- // remove it from the open recursive types.
- if (is_recursive) open_recursive_types_.Remove(hash);
- return sexp;
-}
-
-SExpression* FlowGraphSerializer::CodeToSExp(const Code& code) {
- if (code.IsNull()) return nullptr;
- auto sexp = new (zone()) SExpList(zone());
- AddSymbol(sexp, "Code");
- if (code.IsStubCode()) {
- AddSymbol(sexp, StubCode::NameOfStub(code.EntryPoint()));
- if (FLAG_verbose_flow_graph_serialization) {
- AddExtraSymbol(sexp, "kind", "stub");
- }
- return sexp;
- }
- code_owner_ = code.owner();
- if (!code_owner_.IsNull() && FLAG_verbose_flow_graph_serialization) {
- if (code_owner_.IsClass()) {
- AddExtraSymbol(sexp, "kind", "allocate");
- } else if (code_owner_.IsAbstractType()) {
- AddExtraSymbol(sexp, "kind", "type_test");
- } else {
- ASSERT(code_owner_.IsFunction());
- AddExtraSymbol(sexp, "kind", "function");
- }
- }
- sexp->Add(DartValueToSExp(code_owner_));
- return sexp;
-}
-
-SExpression* FlowGraphSerializer::TypeArgumentsToSExp(const TypeArguments& ta) {
- if (ta.IsNull()) return nullptr;
- auto sexp = new (zone()) SExpList(zone());
- AddSymbol(sexp, "TypeArguments");
- for (intptr_t i = 0; i < ta.Length(); i++) {
- type_arguments_elem_ = ta.TypeAt(i);
- sexp->Add(DartValueToSExp(type_arguments_elem_));
- }
- if (FLAG_verbose_flow_graph_serialization && ta.IsRecursive()) {
- AddExtraInteger(sexp, "hash", ta.Hash());
- }
- return sexp;
-}
-
-SExpression* FlowGraphSerializer::InstanceToSExp(const Instance& inst) {
- if (inst.IsNull()) return nullptr;
-
- // Since InstanceToSExp may use ObjectToSExp (via DartValueToSExp) for field
- // values that aren't entries in the constant pool, and ObjectToSExp may
- // re-enter InstanceToSExp, allocate fresh handles here for the argument to
- // DartValueToSExp and other handles that are live across the call.
- const auto& instance_class = Class::Handle(zone(), inst.clazz());
- const auto& instance_fields_array =
- Array::Handle(zone(), instance_class.fields());
- auto& instance_field_value = Object::Handle(zone());
-
- auto const sexp = new (zone()) SExpList(zone());
- AddSymbol(sexp, "Instance");
- AddInteger(sexp, instance_class.id());
- auto const fields = new (zone()) SExpList(zone());
- AddSymbol(fields, "Fields");
- for (intptr_t i = 0; i < instance_fields_array.Length(); i++) {
- instance_field_ = Field::RawCast(instance_fields_array.At(i));
- // We don't need to serialize static fields, since they're shared by
- // all instances.
- if (instance_field_.is_static()) continue;
- // We should only be getting const instances, which means that we
- // should only see final instance fields.
- ASSERT(instance_field_.is_final());
- tmp_string_ = instance_field_.UserVisibleName();
- auto const label = tmp_string_.ToCString();
- instance_field_value = inst.GetField(instance_field_);
- fields->AddExtra(label, DartValueToSExp(instance_field_value));
- }
- if (fields->ExtraLength() != 0 || FLAG_verbose_flow_graph_serialization) {
- sexp->Add(fields);
- }
- if (instance_class.IsGeneric()) {
- instance_type_args_ = inst.GetTypeArguments();
- if (auto const args = NonEmptyTypeArgumentsToSExp(instance_type_args_)) {
- sexp->AddExtra("type_args", args);
- }
- }
- if (FLAG_verbose_flow_graph_serialization) {
- AddExtraInteger(sexp, "size", inst.InstanceSize());
- // We know the following won't call back into InstanceToSExp because we're
- // providing it a class.
- if (auto const cls = DartValueToSExp(instance_class)) {
- sexp->AddExtra("class", cls);
- }
- }
- return sexp;
-}
-
-SExpression* FlowGraphSerializer::FunctionToSExp(const Function& func) {
- if (func.IsNull()) return nullptr;
- auto const sexp = new (zone()) SExpList(zone());
- AddSymbol(sexp, "Function");
- sexp->Add(CanonicalNameToSExp(func));
- if (func.IsRecognized()) {
- AddExtraSymbol(sexp, "recognized",
- MethodRecognizer::KindToCString(func.recognized_kind()));
- }
- if (func.is_native()) {
- tmp_string_ = func.native_name();
- if (!tmp_string_.IsNull()) {
- AddExtraSymbol(sexp, "native_name", tmp_string_.ToCString());
- }
- }
- if (func.kind() != UntaggedFunction::Kind::kRegularFunction ||
- FLAG_verbose_flow_graph_serialization) {
- AddExtraSymbol(sexp, "kind", UntaggedFunction::KindToCString(func.kind()));
- }
- function_type_args_ = func.type_parameters();
- if (auto const ta_sexp = NonEmptyTypeArgumentsToSExp(function_type_args_)) {
- sexp->AddExtra("type_args", ta_sexp);
- }
- return sexp;
-}
-
-SExpression* FlowGraphSerializer::ImmutableListToSExp(const Array& arr) {
- if (arr.IsNull()) return nullptr;
- // We should only be getting immutable lists when serializing Dart values
- // in flow graphs.
- ASSERT(arr.IsImmutable());
- auto sexp = new (zone()) SExpList(zone());
- AddSymbol(sexp, "ImmutableList");
- // We allocate a new Object handle to use for the calls to DartValueToSExp
- // in case any Array elements contain non-constant-pool, non-empty Arrays.
- auto& array_elem = Object::Handle(zone());
- for (intptr_t i = 0; i < arr.Length(); i++) {
- array_elem = arr.At(i);
- sexp->Add(DartValueToSExp(array_elem));
- }
- array_type_args_ = arr.GetTypeArguments();
- if (auto const type_args_sexp = TypeArgumentsToSExp(array_type_args_)) {
- sexp->AddExtra("type_args", type_args_sexp);
- }
- return sexp;
-}
-
-SExpression* FlowGraphSerializer::ArrayToSExp(const Array& arr) {
- if (arr.IsNull()) return nullptr;
- auto sexp = new (zone()) SExpList(zone());
- AddSymbol(sexp, "Array");
- auto& array_elem = Object::Handle(zone());
- for (intptr_t i = 0; i < arr.Length(); i++) {
- array_elem = arr.At(i);
- sexp->Add(DartValueToSExp(array_elem));
- }
- return sexp;
-}
-
-SExpression* FlowGraphSerializer::ClosureToSExp(const Closure& c) {
- if (c.IsNull()) return nullptr;
- auto sexp = new (zone()) SExpList(zone());
- AddSymbol(sexp, "Closure");
- closure_function_ = c.function();
- if (auto const func = FunctionToSExp(closure_function_)) {
- sexp->Add(func);
- }
- closure_context_ = c.context();
- if (auto const context = ContextToSExp(closure_context_)) {
- sexp->AddExtra("context", context);
- }
- closure_type_args_ = c.function_type_arguments();
- if (auto const type_args = NonEmptyTypeArgumentsToSExp(closure_type_args_)) {
- sexp->AddExtra("func_type_args", type_args);
- }
- closure_type_args_ = c.instantiator_type_arguments();
- if (auto const type_args = NonEmptyTypeArgumentsToSExp(closure_type_args_)) {
- sexp->AddExtra("inst_type_args", type_args);
- }
- closure_type_args_ = c.delayed_type_arguments();
- if (auto const type_args = NonEmptyTypeArgumentsToSExp(closure_type_args_)) {
- sexp->AddExtra("delayed_type_args", type_args);
- }
- return sexp;
-}
-
-SExpression* FlowGraphSerializer::ContextToSExp(const Context& c) {
- if (c.IsNull()) return nullptr;
- auto sexp = new (zone()) SExpList(zone());
- AddSymbol(sexp, "Context");
- for (intptr_t i = 0; i < c.num_variables(); i++) {
- context_elem_ = c.At(i);
- auto const elem_sexp = DartValueToSExp(context_elem_);
- if (elem_sexp == nullptr) return nullptr;
- sexp->Add(elem_sexp);
- }
- context_parent_ = c.parent();
- if (auto const parent_sexp = ContextToSExp(context_parent_)) {
- sexp->AddExtra("parent", parent_sexp);
- }
- return sexp;
-}
-
-SExpression* FlowGraphSerializer::ObjectToSExp(const Object& dartval) {
- if (dartval.IsNull()) {
- return new (zone()) SExpSymbol("null");
- }
- if (dartval.ptr() == Object::sentinel().ptr()) {
- return new (zone()) SExpSymbol("sentinel");
- }
- if (dartval.IsString()) {
- return new (zone()) SExpString(dartval.ToCString());
- }
- if (dartval.IsSmi()) {
- return new (zone()) SExpInteger(Smi::Cast(dartval).Value());
- }
- if (dartval.IsMint()) {
- return new (zone()) SExpInteger(Mint::Cast(dartval).value());
- }
- if (dartval.IsBool()) {
- return new (zone()) SExpBool(Bool::Cast(dartval).value());
- }
- if (dartval.IsDouble()) {
- return new (zone()) SExpDouble(Double::Cast(dartval).value());
- }
- if (dartval.IsField()) {
- return FieldToSExp(Field::Cast(dartval));
- }
- if (dartval.IsClass()) {
- return ClassToSExp(Class::Cast(dartval));
- }
- if (dartval.IsTypeArguments()) {
- return TypeArgumentsToSExp(TypeArguments::Cast(dartval));
- }
- if (dartval.IsCode()) {
- return CodeToSExp(Code::Cast(dartval));
- }
- if (dartval.IsArray()) {
- return ImmutableListToSExp(Array::Cast(dartval));
- }
- if (dartval.IsFunction()) {
- return FunctionToSExp(Function::Cast(dartval));
- }
- if (dartval.IsClosure()) {
- return ClosureToSExp(Closure::Cast(dartval));
- }
- if (dartval.IsAbstractType()) {
- return AbstractTypeToSExp(AbstractType::Cast(dartval));
- }
- ASSERT(dartval.IsInstance());
- return InstanceToSExp(Instance::Cast(dartval));
-}
-
-SExpression* FlowGraphSerializer::DartValueToSExp(const Object& obj) {
- if (auto const def = flow_graph()->GetExistingConstant(obj)) {
- ASSERT(def->IsDefinition());
- return UseToSExp(def->AsDefinition());
- }
- return ObjectToSExp(obj);
-}
-
-SExpression* FlowGraphSerializer::NonEmptyTypeArgumentsToSExp(
- const TypeArguments& ta) {
- if (ta.IsNull() || ta.Length() == 0) return nullptr;
- return DartValueToSExp(ta);
-}
-
-SExpression* FlowGraphSerializer::ConstantPoolToSExp(
- const GraphEntryInstr* start) {
- auto const initial_defs = start->initial_definitions();
- if (initial_defs == nullptr || initial_defs->is_empty()) return nullptr;
- auto constant_list = new (zone()) SExpList(zone());
- AddSymbol(constant_list, "Constants");
- for (intptr_t i = 0; i < initial_defs->length(); i++) {
- ASSERT(initial_defs->At(i)->IsConstant());
- auto const definition = initial_defs->At(i)->AsDefinition();
- auto elem = new (zone()) SExpList(zone());
- AddSymbol(elem, "def");
- elem->Add(UseToSExp(definition));
- // Use ObjectToSExp here, not DartValueToSExp!
- const auto& value = definition->AsConstant()->value();
- elem->Add(ObjectToSExp(value));
- AddDefinitionExtraInfoToSExp(definition, elem);
- // Only add constants to the LLVM constant pool that are actually used in
- // the flow graph.
- if (FLAG_populate_llvm_constant_pool && definition->HasUses()) {
- auto const pool_len = llvm_constants_.Length();
- llvm_index_ = Smi::New(pool_len);
- llvm_index_ ^= llvm_constant_map_.InsertOrGetValue(value, llvm_index_);
- if (llvm_index_.Value() == pool_len) {
- llvm_constants_.Add(value);
- }
- AddExtraInteger(elem, "llvm_index", llvm_index_.Value());
- }
- constant_list->Add(elem);
- }
- return constant_list;
-}
-
-SExpression* Instruction::ToSExpression(FlowGraphSerializer* s) const {
- auto sexp = new (s->zone()) SExpList(s->zone());
- s->AddSymbol(sexp, DebugName());
- AddOperandsToSExpression(sexp, s);
- AddExtraInfoToSExpression(sexp, s);
- return sexp;
-}
-
-SExpression* BlockEntryInstr::ToSExpression(FlowGraphSerializer* s) const {
- auto sexp = new (s->zone()) SExpList(s->zone());
- s->AddSymbol(sexp, "Block");
- sexp->Add(s->BlockIdToSExp(block_id()));
- AddOperandsToSExpression(sexp, s);
- AddExtraInfoToSExpression(sexp, s);
- return sexp;
-}
-
-void BlockEntryInstr::AddExtraInfoToSExpression(SExpList* sexp,
- FlowGraphSerializer* s) const {
- Instruction::AddExtraInfoToSExpression(sexp, s);
- if (try_index() != kInvalidTryIndex) {
- s->AddExtraInteger(sexp, "try_index", try_index());
- }
- if (auto const entry_tag = s->BlockEntryTag(this)) {
- sexp->AddExtra("block_type", entry_tag);
- }
- if (FLAG_verbose_flow_graph_serialization) {
- if (PredecessorCount() > 0) {
- auto const preds = new (s->zone()) SExpList(s->zone());
- for (intptr_t i = 0; i < PredecessorCount(); i++) {
- preds->Add(s->BlockIdToSExp(PredecessorAt(i)->block_id()));
- }
- sexp->AddExtra("predecessors", preds);
- }
- }
-}
-
-void BlockEntryInstr::AddOperandsToSExpression(SExpList* sexp,
- FlowGraphSerializer* s) const {
- for (const auto* inst = next_; inst != nullptr; inst = inst->next_) {
- sexp->Add(inst->ToSExpression(s));
- }
-}
-
-void JoinEntryInstr::AddOperandsToSExpression(SExpList* sexp,
- FlowGraphSerializer* s) const {
- if (auto phi_list = phis()) {
- for (intptr_t i = 0; i < phi_list->length(); i++) {
- sexp->Add(phi_list->At(i)->ToSExpression(s));
- }
- }
- BlockEntryInstr::AddOperandsToSExpression(sexp, s);
-}
-
-void Instruction::AddOperandsToSExpression(SExpList* sexp,
- FlowGraphSerializer* s) const {
- for (intptr_t i = 0; i < InputCount(); ++i) {
- if (InputAt(i) == nullptr) continue;
- sexp->Add(InputAt(i)->ToSExpression(s));
- }
-}
-
-void Instruction::AddExtraInfoToSExpression(SExpList* sexp,
- FlowGraphSerializer* s) const {
- if (GetDeoptId() != DeoptId::kNone) {
- s->AddExtraInteger(sexp, "deopt_id", GetDeoptId());
- }
- if (env() != nullptr) {
- sexp->AddExtra("env", env()->ToSExpression(s));
- }
- if (!token_pos().IsNoSource()) {
- s->AddExtraInteger(sexp, "token_pos", token_pos().Serialize());
- }
- if (has_inlining_id()) {
- s->AddExtraInteger(sexp, "inlining_id", inlining_id());
- }
-}
-
-SExpression* Range::ToSExpression(FlowGraphSerializer* s) {
- auto const sexp = new (s->zone()) SExpList(s->zone());
- s->AddSymbol(sexp, "Range");
- sexp->Add(min_.ToSExpression(s));
- if (!max_.Equals(min_)) sexp->Add(max_.ToSExpression(s));
- return sexp;
-}
-
-SExpression* RangeBoundary::ToSExpression(FlowGraphSerializer* s) {
- switch (kind_) {
- case kSymbol: {
- auto const sexp = new (s->zone()) SExpList(s->zone());
- sexp->Add(s->UseToSExp(symbol()));
- if (offset() != 0) {
- s->AddExtraInteger(sexp, "offset", offset());
- }
- return sexp;
- }
- case kConstant:
- return new (s->zone()) SExpInteger(value_);
- default:
- return new (s->zone()) SExpSymbol(RangeBoundary::KindToCString(kind_));
- }
-}
-
-bool FlowGraphSerializer::HasDefinitionExtraInfo(const Definition* def) {
- return ShouldSerializeType(def->type_) || def->range() != nullptr;
-}
-
-void FlowGraphSerializer::AddDefinitionExtraInfoToSExp(const Definition* def,
- SExpList* sexp) {
- // Type() isn't a const method as it can cause changes to the type_
- // field, so access type_ directly instead.
- if (ShouldSerializeType(def->type_)) {
- sexp->AddExtra("type", def->type_->ToSExpression(this));
- }
- if (def->range() != nullptr) {
- sexp->AddExtra("range", def->range()->ToSExpression(this));
- }
-}
-
-SExpression* Definition::ToSExpression(FlowGraphSerializer* s) const {
- // If we don't have a temp index, then this is a Definition that has no
- // usable result.
- const bool binds_name = HasSSATemp() || HasTemp();
- // Don't serialize non-binding definitions as definitions unless we either
- // have Definition-specific extra info or we're in verbose mode.
- if (!binds_name && !FLAG_verbose_flow_graph_serialization &&
- !s->HasDefinitionExtraInfo(this)) {
- return Instruction::ToSExpression(s);
- }
- auto sexp = new (s->zone()) SExpList(s->zone());
- s->AddSymbol(sexp, "def");
- if (binds_name) {
- sexp->Add(s->UseToSExp(this));
- } else {
- // Since there is Definition-specific extra info to serialize, we use "_"
- // as the bound name, which lets the deserializer know the result is unused.
- s->AddSymbol(sexp, "_");
- }
- // Add only Definition-specific extra info to this form. Any extra info
- // that is Instruction-specific or specific to the actual instruction type is
- // added to the nested instruction form.
- s->AddDefinitionExtraInfoToSExp(this, sexp);
- sexp->Add(Instruction::ToSExpression(s));
- return sexp;
-}
-
-void AssertAssignableInstr::AddExtraInfoToSExpression(
- SExpList* sexp,
- FlowGraphSerializer* s) const {
- Instruction::AddExtraInfoToSExpression(sexp, s);
- sexp->AddExtra("name", s->DartValueToSExp(dst_name()));
-}
-
-void ConstantInstr::AddOperandsToSExpression(SExpList* sexp,
- FlowGraphSerializer* s) const {
- sexp->Add(s->DartValueToSExp(value()));
-}
-
-void BranchInstr::AddOperandsToSExpression(SExpList* sexp,
- FlowGraphSerializer* s) const {
- sexp->Add(comparison()->ToSExpression(s));
- sexp->Add(s->BlockIdToSExp(true_successor()->block_id()));
- sexp->Add(s->BlockIdToSExp(false_successor()->block_id()));
-}
-
-void ParameterInstr::AddOperandsToSExpression(SExpList* sexp,
- FlowGraphSerializer* s) const {
- s->AddInteger(sexp, index());
- s->AddExtraInteger(sexp, "param_offset", param_offset());
- s->AddExtraSymbol(sexp, "representation",
- Location::RepresentationToCString(representation()));
-}
-
-void SpecialParameterInstr::AddOperandsToSExpression(
- SExpList* sexp,
- FlowGraphSerializer* s) const {
- ASSERT(kind() < SpecialParameterInstr::kNumKinds);
- s->AddSymbol(sexp, KindToCString(kind()));
-}
-
-SExpression* FlowGraphSerializer::LocalVariableToSExp(const LocalVariable& v) {
- auto const sexp = new (zone()) SExpList(zone());
- AddSymbol(sexp, "LocalVariable");
- if (!v.name().IsNull()) {
- AddSymbol(sexp, v.name().ToCString());
- }
- if (v.index().IsValid()) {
- AddExtraInteger(sexp, "index", v.index().value());
- }
- return sexp;
-}
-
-void LoadLocalInstr::AddOperandsToSExpression(SExpList* sexp,
- FlowGraphSerializer* s) const {
- sexp->Add(s->LocalVariableToSExp(local()));
-}
-
-void StoreLocalInstr::AddOperandsToSExpression(SExpList* sexp,
- FlowGraphSerializer* s) const {
- sexp->Add(s->LocalVariableToSExp(local()));
-}
-
-SExpression* FlowGraphSerializer::SlotToSExp(const Slot& slot) {
- auto sexp = new (zone()) SExpList(zone());
- AddSymbol(sexp, "Slot");
- AddInteger(sexp, slot.offset_in_bytes());
- AddExtraSymbol(sexp, "kind", Slot::KindToCString(slot.kind()));
- if (slot.IsDartField()) {
- sexp->AddExtra("field", DartValueToSExp(slot.field()));
- }
- return sexp;
-}
-
-void LoadFieldInstr::AddOperandsToSExpression(SExpList* sexp,
- FlowGraphSerializer* s) const {
- sexp->Add(instance()->ToSExpression(s));
- sexp->Add(s->SlotToSExp(slot()));
-}
-
-void LoadFieldInstr::AddExtraInfoToSExpression(SExpList* sexp,
- FlowGraphSerializer* s) const {
- Instruction::AddExtraInfoToSExpression(sexp, s);
- if (calls_initializer() || FLAG_verbose_flow_graph_serialization) {
- s->AddExtraBool(sexp, "calls_initializer", calls_initializer());
- }
-}
-
-void StoreInstanceFieldInstr::AddOperandsToSExpression(
- SExpList* sexp,
- FlowGraphSerializer* s) const {
- sexp->Add(instance()->ToSExpression(s));
- sexp->Add(s->SlotToSExp(slot()));
- sexp->Add(value()->ToSExpression(s));
-}
-
-void StoreInstanceFieldInstr::AddExtraInfoToSExpression(
- SExpList* sexp,
- FlowGraphSerializer* s) const {
- Instruction::AddExtraInfoToSExpression(sexp, s);
- if (is_initialization_ || FLAG_verbose_flow_graph_serialization) {
- s->AddExtraBool(sexp, "is_init", is_initialization_);
- }
- if (emit_store_barrier_ != kNoStoreBarrier ||
- FLAG_verbose_flow_graph_serialization) {
- // Make sure that we aren't seeing a new value added to the StoreBarrierType
- // enum that isn't handled by the serializer.
- ASSERT(emit_store_barrier_ == kNoStoreBarrier ||
- emit_store_barrier_ == kEmitStoreBarrier);
- s->AddExtraBool(sexp, "emit_barrier",
- emit_store_barrier_ != kNoStoreBarrier);
- }
-}
-
-void LoadIndexedUnsafeInstr::AddExtraInfoToSExpression(
- SExpList* sexp,
- FlowGraphSerializer* s) const {
- Instruction::AddExtraInfoToSExpression(sexp, s);
- if (offset() > 0 || FLAG_verbose_flow_graph_serialization) {
- s->AddExtraInteger(sexp, "offset", offset());
- }
-}
-
-void StoreIndexedUnsafeInstr::AddExtraInfoToSExpression(
- SExpList* sexp,
- FlowGraphSerializer* s) const {
- Instruction::AddExtraInfoToSExpression(sexp, s);
- if (offset() > 0 || FLAG_verbose_flow_graph_serialization) {
- s->AddExtraInteger(sexp, "offset", offset());
- }
-}
-
-void ComparisonInstr::AddOperandsToSExpression(SExpList* sexp,
- FlowGraphSerializer* s) const {
- s->AddSymbol(sexp, Token::Str(kind()));
- Instruction::AddOperandsToSExpression(sexp, s);
-}
-
-void StrictCompareInstr::AddExtraInfoToSExpression(
- SExpList* sexp,
- FlowGraphSerializer* s) const {
- Instruction::AddExtraInfoToSExpression(sexp, s);
- if (needs_number_check_ || FLAG_verbose_flow_graph_serialization) {
- s->AddExtraBool(sexp, "needs_check", needs_number_check_);
- }
-}
-
-void DoubleTestOpInstr::AddOperandsToSExpression(SExpList* sexp,
- FlowGraphSerializer* s) const {
- const bool negated = kind() != Token::kEQ;
- switch (op_kind()) {
- case MethodRecognizer::kDouble_getIsNaN:
- s->AddSymbol(sexp, negated ? "IsNotNaN" : "IsNaN");
- break;
- case MethodRecognizer::kDouble_getIsInfinite:
- s->AddSymbol(sexp, negated ? "IsNotInfinite" : "IsInfinite");
- break;
- default:
- UNREACHABLE();
- }
- sexp->Add(value()->ToSExpression(s));
-}
-
-void GotoInstr::AddOperandsToSExpression(SExpList* sexp,
- FlowGraphSerializer* s) const {
- sexp->Add(s->BlockIdToSExp(successor()->block_id()));
-}
-
-void DebugStepCheckInstr::AddExtraInfoToSExpression(
- SExpList* sexp,
- FlowGraphSerializer* s) const {
- Instruction::AddExtraInfoToSExpression(sexp, s);
- if (stub_kind_ != UntaggedPcDescriptors::kAnyKind ||
- FLAG_verbose_flow_graph_serialization) {
- auto const stub_kind_name =
- UntaggedPcDescriptors::KindToCString(stub_kind_);
- ASSERT(stub_kind_name != nullptr);
- s->AddExtraSymbol(sexp, "stub_kind", stub_kind_name);
- }
-}
-
-SExpression* FlowGraphSerializer::ICDataToSExp(const ICData* ic_data) {
- auto const sexp = new (zone()) SExpList(zone());
- AddSymbol(sexp, "ICData");
-
- if (ic_data->is_tracking_exactness()) {
- ic_data_type_ = ic_data->receivers_static_type();
- sexp->AddExtra("receivers_static_type", AbstractTypeToSExp(ic_data_type_));
- }
-
- if (ic_data->is_megamorphic() || FLAG_verbose_flow_graph_serialization) {
- AddExtraBool(sexp, "is_megamorphic", ic_data->is_megamorphic());
- }
-
- auto const num_checks = ic_data->NumberOfChecks();
- GrowableArray<intptr_t> class_ids(zone(), 2);
- for (intptr_t i = 0; i < num_checks; i++) {
- auto const entry = new (zone()) SExpList(zone());
-
- auto const count = ic_data->GetCountAt(i);
- if (count > 0 || FLAG_verbose_flow_graph_serialization) {
- AddExtraInteger(entry, "count", count);
- }
-
- class_ids.Clear();
- ic_data->GetCheckAt(i, &class_ids, &ic_data_target_);
- entry->AddExtra("target", DartValueToSExp(ic_data_target_));
- for (auto const cid : class_ids) {
- entry->Add(new (zone()) SExpInteger(cid));
- }
-
- sexp->Add(entry);
- }
-
- if (FLAG_verbose_flow_graph_serialization) {
- AddExtraSymbol(sexp, "rebind_rule",
- ICData::RebindRuleToCString(ic_data->rebind_rule()));
- tmp_string_ = ic_data->target_name();
- AddExtraString(sexp, "target_name", tmp_string_.ToCString());
- ic_data_target_ = ic_data->Owner();
- sexp->AddExtra("owner", DartValueToSExp(ic_data_target_));
- AddExtraInteger(sexp, "num_args_tested", ic_data->NumArgsTested());
- auto& args_desc = Array::Handle(zone(), ic_data->arguments_descriptor());
- sexp->AddExtra("arguments_descriptor", DartValueToSExp(args_desc));
- }
-
- return sexp;
-}
-
-void TailCallInstr::AddOperandsToSExpression(SExpList* sexp,
- FlowGraphSerializer* s) const {
- if (auto const code = s->DartValueToSExp(code_)) {
- sexp->Add(code);
- }
- Instruction::AddOperandsToSExpression(sexp, s);
-}
-
-void NativeCallInstr::AddOperandsToSExpression(SExpList* sexp,
- FlowGraphSerializer* s) const {
- Instruction::AddOperandsToSExpression(sexp, s);
-}
-
-void NativeCallInstr::AddExtraInfoToSExpression(SExpList* sexp,
- FlowGraphSerializer* s) const {
- TemplateDartCall<0>::AddExtraInfoToSExpression(sexp, s);
- if (auto const func = s->DartValueToSExp(function())) {
- sexp->AddExtra("function", func);
- }
- if (!native_name().IsNull()) {
- s->AddExtraString(sexp, "name", native_name().ToCString());
- }
- if (link_lazily() || FLAG_verbose_flow_graph_serialization) {
- s->AddExtraBool(sexp, "link_lazily", link_lazily());
- }
-}
-
-template <intptr_t kExtraInputs>
-void TemplateDartCall<kExtraInputs>::AddExtraInfoToSExpression(
- SExpList* sexp,
- FlowGraphSerializer* s) const {
- Instruction::AddExtraInfoToSExpression(sexp, s);
- if (type_args_len() > 0 || FLAG_verbose_flow_graph_serialization) {
- s->AddExtraInteger(sexp, "type_args_len", type_args_len());
- }
- s->AddExtraInteger(sexp, "args_len", ArgumentCountWithoutTypeArgs());
-
- const auto& arg_names = argument_names();
- if (!arg_names.IsNull()) {
- auto arg_names_sexp = new (s->zone()) SExpList(s->zone());
- auto& str = String::Handle(s->zone());
- for (intptr_t i = 0; i < arg_names.Length(); i++) {
- str = String::RawCast(arg_names.At(i));
- arg_names_sexp->Add(s->ObjectToSExp(str));
- }
- sexp->AddExtra("arg_names", arg_names_sexp);
- }
-
- ASSERT(!HasPushArguments());
-}
-
-void ClosureCallInstr::AddExtraInfoToSExpression(SExpList* sexp,
- FlowGraphSerializer* s) const {
- // For now, just here to ensure TemplateDartCall<1>::AddExtraInfoToSExpression
- // gets instantiated.
- TemplateDartCall<1>::AddExtraInfoToSExpression(sexp, s);
-}
-
-void StaticCallInstr::AddOperandsToSExpression(SExpList* sexp,
- FlowGraphSerializer* s) const {
- Instruction::AddOperandsToSExpression(sexp, s);
-}
-
-void StaticCallInstr::AddExtraInfoToSExpression(SExpList* sexp,
- FlowGraphSerializer* s) const {
- TemplateDartCall<0>::AddExtraInfoToSExpression(sexp, s);
-
- if (auto const func = s->DartValueToSExp(function())) {
- sexp->AddExtra("function", func);
- }
-
- if (HasICData()) {
- sexp->AddExtra("ic_data", s->ICDataToSExp(ic_data()));
- } else if (CallCount() > 0 || FLAG_verbose_flow_graph_serialization) {
- s->AddExtraInteger(sexp, "call_count", CallCount());
- }
-
- if (rebind_rule_ != ICData::kStatic ||
- FLAG_verbose_flow_graph_serialization) {
- auto const str = ICData::RebindRuleToCString(rebind_rule_);
- ASSERT(str != nullptr);
- s->AddExtraSymbol(sexp, "rebind_rule", str);
- }
-
- if (ShouldSerializeType(result_type())) {
- sexp->AddExtra("result_type", result_type()->ToSExpression(s));
- }
-
- if (entry_kind() != Code::EntryKind::kNormal ||
- FLAG_verbose_flow_graph_serialization) {
- auto const kind_str = Code::EntryKindToCString(entry_kind());
- s->AddExtraSymbol(sexp, "entry_kind", kind_str);
- }
-}
-
-void InstanceCallBaseInstr::AddOperandsToSExpression(
- SExpList* sexp,
- FlowGraphSerializer* s) const {
- Instruction::AddOperandsToSExpression(sexp, s);
-}
-
-void InstanceCallBaseInstr::AddExtraInfoToSExpression(
- SExpList* sexp,
- FlowGraphSerializer* s) const {
- TemplateDartCall<0>::AddExtraInfoToSExpression(sexp, s);
-
- if (auto const target = s->DartValueToSExp(interface_target())) {
- sexp->AddExtra("interface_target", target);
- }
-
- if (auto const target = s->DartValueToSExp(tearoff_interface_target())) {
- sexp->AddExtra("tearoff_interface_target", target);
- }
-
- if (HasICData()) {
- sexp->AddExtra("ic_data", s->ICDataToSExp(ic_data()));
- }
-
- if (function_name().IsNull()) {
- if (!interface_target().IsNull() || !tearoff_interface_target().IsNull()) {
- s->AddExtraSymbol(sexp, "function_name", "null");
- }
- } else {
- if (interface_target().IsNull() ||
- (function_name().ptr() != interface_target().name() &&
- function_name().ptr() != tearoff_interface_target().name())) {
- s->AddExtraString(sexp, "function_name", function_name().ToCString());
- }
- }
-
- if (token_kind() != Token::kILLEGAL) {
- s->AddExtraSymbol(sexp, "token_kind", Token::Str(token_kind()));
- }
-
- if (ShouldSerializeType(result_type())) {
- sexp->AddExtra("result_type", result_type()->ToSExpression(s));
- }
-
- if (entry_kind() != Code::EntryKind::kNormal ||
- FLAG_verbose_flow_graph_serialization) {
- auto const kind_str = Code::EntryKindToCString(entry_kind());
- s->AddExtraSymbol(sexp, "entry_kind", kind_str);
- }
-}
-
-void InstanceCallInstr::AddExtraInfoToSExpression(
- SExpList* sexp,
- FlowGraphSerializer* s) const {
- InstanceCallBaseInstr::AddExtraInfoToSExpression(sexp, s);
-
- if (checked_argument_count() > 0 || FLAG_verbose_flow_graph_serialization) {
- s->AddExtraInteger(sexp, "checked_arg_count", checked_argument_count());
- }
-}
-
-void PolymorphicInstanceCallInstr::AddExtraInfoToSExpression(
- SExpList* sexp,
- FlowGraphSerializer* s) const {
- InstanceCallBaseInstr::AddExtraInfoToSExpression(sexp, s);
-
- if (targets().length() > 0 || FLAG_verbose_flow_graph_serialization) {
- auto elem_list = new (s->zone()) SExpList(s->zone());
- for (intptr_t i = 0; i < targets().length(); i++) {
- auto elem = new (s->zone()) SExpList(s->zone());
- const TargetInfo* ti = targets().TargetAt(i);
- if (ti->cid_start == ti->cid_end) {
- s->AddInteger(elem, ti->cid_start);
- } else {
- auto range = new (s->zone()) SExpList(s->zone());
- s->AddInteger(range, ti->cid_start);
- s->AddInteger(range, ti->cid_end);
- elem->Add(range);
- }
- if (auto const target = s->DartValueToSExp(*ti->target)) {
- elem->Add(target);
- }
- elem_list->Add(elem);
- }
- sexp->AddExtra("targets", elem_list);
- }
-}
-
-void AllocateObjectInstr::AddOperandsToSExpression(
- SExpList* sexp,
- FlowGraphSerializer* s) const {
- if (auto const sexp_cls = s->DartValueToSExp(cls())) {
- sexp->Add(sexp_cls);
- }
- if (type_arguments() != nullptr) {
- sexp->Add(type_arguments()->ToSExpression(s));
- }
-}
-
-void AllocateObjectInstr::AddExtraInfoToSExpression(
- SExpList* sexp,
- FlowGraphSerializer* s) const {
- Instruction::AddExtraInfoToSExpression(sexp, s);
- s->AddExtraInteger(sexp, "size", cls().target_instance_size());
- if (auto const closure = s->DartValueToSExp(closure_function())) {
- sexp->AddExtra("closure_function", closure);
- }
- if (!Identity().IsUnknown() || FLAG_verbose_flow_graph_serialization) {
- s->AddExtraSymbol(sexp, "identity", Identity().ToCString());
- }
-}
-
-void BinaryIntegerOpInstr::AddOperandsToSExpression(
- SExpList* sexp,
- FlowGraphSerializer* s) const {
- s->AddSymbol(sexp, Token::Str(op_kind()));
- sexp->Add(left()->ToSExpression(s));
- sexp->Add(right()->ToSExpression(s));
-}
-
-void CheckedSmiOpInstr::AddOperandsToSExpression(SExpList* sexp,
- FlowGraphSerializer* s) const {
- s->AddSymbol(sexp, Token::Str(op_kind()));
- sexp->Add(left()->ToSExpression(s));
- sexp->Add(right()->ToSExpression(s));
-}
-
-// clang-format off
-static const char* simd_op_kind_string[] = {
-#define CASE(Arity, Mask, Name, ...) #Name,
- SIMD_OP_LIST(CASE, CASE)
-#undef CASE
- "IllegalSimdOp",
-};
-// clang-format on
-
-void SimdOpInstr::AddOperandsToSExpression(SExpList* sexp,
- FlowGraphSerializer* s) const {
- s->AddSymbol(sexp, simd_op_kind_string[kind()]);
- Instruction::AddOperandsToSExpression(sexp, s);
-}
-
-void SimdOpInstr::AddExtraInfoToSExpression(SExpList* sexp,
- FlowGraphSerializer* s) const {
- Instruction::AddExtraInfoToSExpression(sexp, s);
- if (HasMask()) {
- s->AddExtraInteger(sexp, "mask", mask());
- }
-}
-
-void LoadIndexedInstr::AddExtraInfoToSExpression(SExpList* sexp,
- FlowGraphSerializer* s) const {
- Instruction::AddExtraInfoToSExpression(sexp, s);
- if (aligned() || FLAG_verbose_flow_graph_serialization) {
- s->AddExtraBool(sexp, "aligned", aligned());
- }
- if (index_scale() > 1 || FLAG_verbose_flow_graph_serialization) {
- s->AddExtraInteger(sexp, "scale", index_scale());
- }
- if (class_id() != kDynamicCid || FLAG_verbose_flow_graph_serialization) {
- s->AddExtraInteger(sexp, "cid", class_id());
- }
-}
-
-void StoreIndexedInstr::AddExtraInfoToSExpression(
- SExpList* sexp,
- FlowGraphSerializer* s) const {
- Instruction::AddExtraInfoToSExpression(sexp, s);
- if (aligned() || FLAG_verbose_flow_graph_serialization) {
- s->AddExtraBool(sexp, "aligned", aligned());
- }
- if (index_scale() > 1 || FLAG_verbose_flow_graph_serialization) {
- s->AddExtraInteger(sexp, "scale", index_scale());
- }
- if (class_id() != kDynamicCid || FLAG_verbose_flow_graph_serialization) {
- s->AddExtraInteger(sexp, "cid", class_id());
- }
-}
-
-void CheckStackOverflowInstr::AddExtraInfoToSExpression(
- SExpList* sexp,
- FlowGraphSerializer* s) const {
- Instruction::AddExtraInfoToSExpression(sexp, s);
- if (stack_depth() > 0 || FLAG_verbose_flow_graph_serialization) {
- s->AddExtraInteger(sexp, "stack_depth", stack_depth());
- }
- if (in_loop() || FLAG_verbose_flow_graph_serialization) {
- s->AddExtraInteger(sexp, "loop_depth", loop_depth());
- }
- if (kind_ != kOsrAndPreemption) {
- ASSERT(kind_ == kOsrOnly);
- s->AddExtraSymbol(sexp, "kind", "OsrOnly");
- }
-}
-
-void CheckNullInstr::AddExtraInfoToSExpression(SExpList* sexp,
- FlowGraphSerializer* s) const {
- Instruction::AddExtraInfoToSExpression(sexp, s);
- if (!function_name_.IsNull()) {
- s->AddExtraString(sexp, "function_name", function_name_.ToCString());
- }
-}
-
-SExpression* Value::ToSExpression(FlowGraphSerializer* s) const {
- auto name = s->UseToSExp(definition());
- // If we're not serializing types or there is no reaching type for this use,
- // just serialize the use as the bound name.
- if (!ShouldSerializeType(reaching_type_)) return name;
-
- auto sexp = new (s->zone()) SExpList(s->zone());
- s->AddSymbol(sexp, "value");
- sexp->Add(name);
- // If there is no owner for the type, then serialize the type in full.
- // Otherwise the owner should be the definition, so we'll inherit the type
- // from it. (That is, (value v<X>) with no explicit type info means the
- // reaching type comes from the definition of v<X>.) We'll serialize an
- // "inherit_type" extra info field to make this explicit when in verbose mode.
- if (reaching_type_->owner() == nullptr) {
- sexp->AddExtra("type", reaching_type_->ToSExpression(s));
- } else {
- ASSERT(reaching_type_->owner() == definition());
- }
- if (FLAG_verbose_flow_graph_serialization) {
- s->AddExtraBool(sexp, "inherit_type",
- reaching_type_->owner() == definition());
- }
- return sexp;
-}
-
-SExpression* CompileType::ToSExpression(FlowGraphSerializer* s) const {
- ASSERT(FLAG_verbose_flow_graph_serialization ||
- FLAG_serialize_flow_graph_types);
-
- auto sexp = new (s->zone()) SExpList(s->zone());
- s->AddSymbol(sexp, "CompileType");
- AddExtraInfoToSExpression(sexp, s);
- return sexp;
-}
-
-void CompileType::AddExtraInfoToSExpression(SExpList* sexp,
- FlowGraphSerializer* s) const {
- if (cid_ != kIllegalCid || FLAG_verbose_flow_graph_serialization) {
- s->AddExtraInteger(sexp, "cid", cid_);
- }
- // TODO(sstrickl): Currently we only print out nullable if it's false
- // (or during verbose printing). Switch this when NNBD is the standard.
- if (!is_nullable() || FLAG_verbose_flow_graph_serialization) {
- s->AddExtraBool(sexp, "nullable", is_nullable());
- }
- if (type_ != nullptr) {
- sexp->AddExtra("type", s->DartValueToSExp(*type_));
- }
-}
-
-SExpression* Environment::ToSExpression(FlowGraphSerializer* s) const {
- auto sexp = new (s->zone()) SExpList(s->zone());
- for (intptr_t i = 0; i < values_.length(); ++i) {
- ASSERT(!values_[i]->definition()->IsPushArgument());
- sexp->Add(values_[i]->ToSExpression(s));
- // TODO(sstrickl): This currently assumes that there are no locations in the
- // environment (e.g. before register allocation). If we ever want to print
- // out environments on steps after AllocateRegisters, we'll need to handle
- // locations as well.
- ASSERT(locations_ == nullptr || locations_[i].IsInvalid());
- }
- if (outer_ != NULL) {
- auto outer_sexp = outer_->ToSExpression(s)->AsList();
- if (outer_->deopt_id_ != DeoptId::kNone) {
- s->AddExtraInteger(outer_sexp, "deopt_id", outer_->deopt_id_);
- }
- sexp->AddExtra("outer", outer_sexp);
- }
- return sexp;
-}
-
-} // namespace dart
diff --git a/runtime/vm/compiler/backend/il_serializer.h b/runtime/vm/compiler/backend/il_serializer.h
deleted file mode 100644
index fda5731..0000000
--- a/runtime/vm/compiler/backend/il_serializer.h
+++ /dev/null
@@ -1,198 +0,0 @@
-// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#ifndef RUNTIME_VM_COMPILER_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 "platform/assert.h"
-#include "platform/text_buffer.h"
-
-#include "vm/allocation.h"
-#include "vm/compiler/backend/flow_graph.h"
-#include "vm/compiler/backend/il.h"
-#include "vm/compiler/backend/sexpression.h"
-#include "vm/hash_table.h"
-#include "vm/object.h"
-#include "vm/zone.h"
-
-namespace dart {
-
-// Flow graph serialization.
-class FlowGraphSerializer : ValueObject {
- public:
-#define FOR_EACH_BLOCK_ENTRY_KIND(M) \
- M(Target) \
- M(Join) \
- M(Graph) \
- M(Normal) \
- M(Unchecked) \
- M(OSR) \
- M(Catch) \
- M(Indirect)
-
- enum BlockEntryKind {
-#define KIND_DECL(name) k##name,
- FOR_EACH_BLOCK_ENTRY_KIND(KIND_DECL)
-#undef KIND_DECL
- // clang-format off
- kNumEntryKinds,
- kInvalid = -1,
- // clang-format on
- };
-
- // Special case: returns kTarget for a nullptr input.
- static BlockEntryKind BlockEntryTagToKind(SExpSymbol* tag);
- SExpSymbol* BlockEntryKindToTag(BlockEntryKind k);
- static bool BlockEntryKindHasInitialDefs(BlockEntryKind kind);
-
- static void SerializeToBuffer(Zone* zone,
- const FlowGraph* flow_graph,
- BaseTextBuffer* buffer);
- static SExpression* SerializeToSExp(Zone* zone, const FlowGraph* flow_graph);
-
- const FlowGraph* flow_graph() const { return flow_graph_; }
- Zone* zone() const { return zone_; }
-
- SExpression* FlowGraphToSExp();
-
- SExpSymbol* BlockEntryTag(const BlockEntryInstr* entry);
- SExpression* BlockIdToSExp(intptr_t block_id);
- SExpression* CanonicalNameToSExp(const Object& obj);
- SExpression* UseToSExp(const Definition* definition);
-
- // Helper method for creating canonical names.
- void SerializeCanonicalName(BaseTextBuffer* b, const Object& obj);
-
- // Methods for serializing Dart values. If the argument
- // value is the null object, the null pointer is returned.
- SExpression* AbstractTypeToSExp(const AbstractType& typ);
- SExpression* ArrayToSExp(const Array& arr);
- SExpression* ImmutableListToSExp(const Array& arr);
- SExpression* ClassToSExp(const Class& cls);
- SExpression* ClosureToSExp(const Closure& c);
- SExpression* ContextToSExp(const Context& c);
- SExpression* CodeToSExp(const Code& c);
- SExpression* FieldToSExp(const Field& f);
- SExpression* FunctionToSExp(const Function& f);
- SExpression* InstanceToSExp(const Instance& obj);
- SExpression* TypeArgumentsToSExp(const TypeArguments& ta);
-
- // A method for serializing a Dart value of arbitrary type. Unlike the
- // type-specific methods, this returns the symbol "null" for the null object.
- SExpression* ObjectToSExp(const Object& obj);
-
- // A wrapper method for ObjectToSExp that first checks and sees if
- // the provided value is in the constant pool. If it is, then it
- // returns a reference to the constant definition via UseToSExp.
- SExpression* DartValueToSExp(const Object& obj);
-
- // A wrapper method for TypeArgumentsToSExp that also returns nullptr if the
- // type arguments are empty and checks against the constant pool.
- SExpression* NonEmptyTypeArgumentsToSExp(const TypeArguments& ta);
-
- // Methods for serializing IL-specific values.
- SExpression* LocalVariableToSExp(const LocalVariable& v);
- SExpression* SlotToSExp(const Slot& s);
- SExpression* ICDataToSExp(const ICData* ic_data);
-
- // Helper methods for adding Definition-specific extra info.
- bool HasDefinitionExtraInfo(const Definition* def);
- void AddDefinitionExtraInfoToSExp(const Definition* def, SExpList* sexp);
-
- // Helper methods for adding atoms to S-expression lists
- void AddBool(SExpList* sexp, bool b);
- void AddInteger(SExpList* sexp, intptr_t i);
- void AddString(SExpList* sexp, const char* cstr);
- void AddSymbol(SExpList* sexp, const char* cstr);
- void AddExtraBool(SExpList* sexp, const char* label, bool b);
- void AddExtraInteger(SExpList* sexp, const char* label, intptr_t i);
- void AddExtraString(SExpList* sexp, const char* label, const char* cstr);
- void AddExtraSymbol(SExpList* sexp, const char* label, const char* cstr);
-
- private:
- friend class Precompiler; // For LLVMConstantsMap.
-
- FlowGraphSerializer(Zone* zone, const FlowGraph* flow_graph);
- ~FlowGraphSerializer();
-
- static const char* const initial_indent;
-
- // Helper methods for the function level that are not used by any
- // instruction serialization methods.
- SExpression* FunctionEntryToSExp(const BlockEntryInstr* entry);
- SExpression* EntriesToSExp(const GraphEntryInstr* start);
- SExpression* ConstantPoolToSExp(const GraphEntryInstr* start);
-
- const FlowGraph* const flow_graph_;
- Zone* const zone_;
- ObjectStore* const object_store_;
-
- // A map of currently open (being serialized) recursive types. We use this
- // to determine whether to serialize the referred types in TypeRefs.
- IntMap<const AbstractType*> open_recursive_types_;
-
- // Used for --populate-llvm-constant-pool in ConstantPoolToSExp.
- class LLVMPoolMapKeyEqualsTraits : public AllStatic {
- public:
- static const char* Name() { return "LLVMPoolMapKeyEqualsTraits"; }
- static bool ReportStats() { return false; }
-
- static bool IsMatch(const Object& a, const Object& b) {
- return a.ptr() == b.ptr();
- }
- static uword Hash(const Object& obj) {
- if (obj.IsSmi()) return static_cast<uword>(obj.ptr());
- if (obj.IsInstance()) return Instance::Cast(obj).CanonicalizeHash();
- return obj.GetClassId();
- }
- };
- typedef UnorderedHashMap<LLVMPoolMapKeyEqualsTraits> LLVMPoolMap;
-
- GrowableObjectArray& llvm_constants_;
- GrowableObjectArray& llvm_functions_;
- LLVMPoolMap llvm_constant_map_;
- Smi& llvm_index_;
-
- // Handles used across functions, where the contained value is used
- // immediately and does not need to live across calls to other serializer
- // functions.
- String& tmp_string_;
-
- // Handles for use within a single function in the following cases:
- //
- // * The function is guaranteed to not be re-entered during execution.
- // * The contained value is not live across any possible re-entry.
- //
- // Generally, the most likely source of possible re-entry is calling
- // DartValueToSExp with a sub-element of type Object, but any call to a
- // FlowGraphSerializer method that may eventually enter one of the methods
- // listed below should be examined with care.
- TypeArguments& array_type_args_; // ArrayToSExp
- Context& closure_context_; // ClosureToSExp
- Function& closure_function_; // ClosureToSExp
- TypeArguments& closure_type_args_; // ClosureToSExp
- Object& code_owner_; // CodeToSExp
- Context& context_parent_; // ContextToSExp
- Object& context_elem_; // ContextToSExp
- TypeArguments& function_type_args_; // FunctionToSExp
- Function& ic_data_target_; // ICDataToSExp
- AbstractType& ic_data_type_; // ICDataToSExp
- Field& instance_field_; // InstanceToSExp
- TypeArguments& instance_type_args_; // InstanceToSExp
- Library& serialize_library_; // SerializeCanonicalName
- Class& serialize_owner_; // SerializeCanonicalName
- Function& serialize_parent_; // SerializeCanonicalName
- AbstractType& type_arguments_elem_; // TypeArgumentsToSExp
- Class& type_class_; // AbstractTypeToSExp
- FunctionType& type_signature_; // AbstractTypeToSExp
- AbstractType& type_ref_type_; // AbstractTypeToSExp
-};
-
-} // namespace dart
-
-#endif // RUNTIME_VM_COMPILER_BACKEND_IL_SERIALIZER_H_
diff --git a/runtime/vm/compiler/backend/range_analysis.h b/runtime/vm/compiler/backend/range_analysis.h
index 7491def..ab21d74 100644
--- a/runtime/vm/compiler/backend/range_analysis.h
+++ b/runtime/vm/compiler/backend/range_analysis.h
@@ -14,9 +14,6 @@
namespace dart {
-class SExpression;
-class FlowGraphSerializer;
-
class RangeBoundary : public ValueObject {
public:
#define FOR_EACH_RANGE_BOUNDARY_KIND(V) \
@@ -246,7 +243,6 @@
void PrintTo(BaseTextBuffer* f) const;
const char* ToCString() const;
- SExpression* ToSExpression(FlowGraphSerializer* s);
static RangeBoundary Add(const RangeBoundary& a,
const RangeBoundary& b,
@@ -347,7 +343,6 @@
void PrintTo(BaseTextBuffer* f) const;
static const char* ToCString(const Range* range);
- SExpression* ToSExpression(FlowGraphSerializer* s);
bool Equals(const Range* other) {
ASSERT(min_.IsUnknown() == max_.IsUnknown());
diff --git a/runtime/vm/compiler/backend/sexpression.cc b/runtime/vm/compiler/backend/sexpression.cc
deleted file mode 100644
index 7307ef3..0000000
--- a/runtime/vm/compiler/backend/sexpression.cc
+++ /dev/null
@@ -1,686 +0,0 @@
-// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#include "vm/compiler/backend/sexpression.h"
-
-#include <ctype.h>
-#include "platform/utils.h"
-#include "vm/double_conversion.h"
-#include "vm/zone_text_buffer.h"
-
-namespace dart {
-
-SExpression* SExpression::FromCString(Zone* zone, const char* str) {
- SExpParser parser(zone, str);
- auto sexp = parser.Parse();
- if (sexp == nullptr) parser.ReportError();
- return sexp;
-}
-
-const char* SExpression::ToCString(Zone* zone) const {
- ZoneTextBuffer buf(zone, 1 * KB);
- SerializeToLine(&buf);
- return buf.buffer();
-}
-
-bool SExpBool::Equals(SExpression* sexp) const {
- if (auto const b = sexp->AsBool()) return b->Equals(value());
- return false;
-}
-
-bool SExpBool::Equals(bool val) const {
- return value() == val;
-}
-
-void SExpBool::SerializeToLine(BaseTextBuffer* buffer) const {
- buffer->AddString(value() ? SExpParser::kBoolTrueSymbol
- : SExpParser::kBoolFalseSymbol);
-}
-
-bool SExpDouble::Equals(SExpression* sexp) const {
- if (auto const d = sexp->AsDouble()) return d->Equals(value());
- return false;
-}
-
-bool SExpDouble::Equals(double val) const {
- return value() == val;
-}
-
-void SExpDouble::SerializeToLine(BaseTextBuffer* buffer) const {
- // Use existing Dart serialization for Doubles.
- const intptr_t kBufSize = 128;
- char strbuf[kBufSize];
- DoubleToCString(value(), strbuf, kBufSize);
- buffer->Printf("%s", strbuf);
-}
-
-bool SExpInteger::Equals(SExpression* sexp) const {
- if (auto const i = sexp->AsInteger()) return i->Equals(value());
- return false;
-}
-
-bool SExpInteger::Equals(int64_t val) const {
- return value() == val;
-}
-
-void SExpInteger::SerializeToLine(BaseTextBuffer* buffer) const {
- buffer->Printf("%" Pd64 "", value());
-}
-
-bool SExpString::Equals(SExpression* sexp) const {
- if (auto const s = sexp->AsString()) return s->Equals(value());
- return false;
-}
-
-bool SExpString::Equals(const char* str) const {
- return strcmp(value(), str) == 0;
-}
-
-void SExpString::SerializeToLine(BaseTextBuffer* buffer) const {
- TextBuffer buf(80);
- buf.AddChar('"');
- buf.AddEscapedString(value());
- buf.AddChar('"');
- buffer->AddString(buf.buffer());
-}
-
-bool SExpSymbol::Equals(SExpression* sexp) const {
- if (auto const s = sexp->AsSymbol()) return s->Equals(value());
- return false;
-}
-
-bool SExpSymbol::Equals(const char* str) const {
- return strcmp(value(), str) == 0;
-}
-
-void SExpSymbol::SerializeToLine(BaseTextBuffer* buffer) const {
- buffer->AddString(value());
-}
-
-void SExpList::Add(SExpression* sexp) {
- contents_.Add(sexp);
-}
-
-void SExpList::AddExtra(const char* label, SExpression* value) {
- ASSERT(!extra_info_.HasKey(label));
- extra_info_.Insert({label, value});
-}
-
-bool SExpList::Equals(SExpression* sexp) const {
- if (!sexp->IsList()) return false;
- auto list = sexp->AsList();
- if (Length() != list->Length()) return false;
- if (ExtraLength() != list->ExtraLength()) return false;
- for (intptr_t i = 0; i < Length(); i++) {
- if (!At(i)->Equals(list->At(i))) return false;
- }
- auto this_it = ExtraIterator();
- while (auto kv = this_it.Next()) {
- if (!list->ExtraHasKey(kv->key)) return false;
- if (!kv->value->Equals(list->ExtraLookupValue(kv->key))) return false;
- }
- return true;
-}
-
-const char* const SExpList::kElemIndent = " ";
-const char* const SExpList::kExtraIndent = " ";
-
-static intptr_t HandleLineBreaking(Zone* zone,
- BaseTextBuffer* buffer,
- SExpression* element,
- BaseTextBuffer* line_buffer,
- const char* sub_indent,
- intptr_t width,
- bool leading_space,
- intptr_t remaining) {
- element->SerializeToLine(line_buffer);
- const intptr_t single_line_width = line_buffer->length();
- const intptr_t leading_length = leading_space ? 1 : 0;
-
- if ((leading_length + single_line_width) < remaining) {
- if (leading_space) buffer->AddChar(' ');
- buffer->AddString(line_buffer->buffer());
- line_buffer->Clear();
- return remaining - (leading_length + single_line_width);
- }
- const intptr_t old_length = buffer->length();
- buffer->Printf("\n%s", sub_indent);
- const intptr_t line_used = buffer->length() - old_length + 1;
- remaining = width - line_used;
- if ((single_line_width < remaining) || element->IsAtom()) {
- buffer->AddString(line_buffer->buffer());
- line_buffer->Clear();
- return remaining - single_line_width;
- }
- line_buffer->Clear();
- element->SerializeTo(zone, buffer, sub_indent, width);
- return 0;
-}
-
-// Assumes that we are starting on a line after [indent] amount of space.
-void SExpList::SerializeTo(Zone* zone,
- BaseTextBuffer* buffer,
- const char* indent,
- intptr_t width) const {
- TextBuffer single_line(width);
- const char* sub_indent = OS::SCreate(zone, "%s%s", indent, kElemIndent);
-
- buffer->AddChar('(');
- intptr_t remaining = width - strlen(indent) - 1;
- for (intptr_t i = 0; i < contents_.length(); i++) {
- remaining = HandleLineBreaking(zone, buffer, contents_.At(i), &single_line,
- sub_indent, width, i != 0, remaining);
- }
-
- if (!extra_info_.IsEmpty()) {
- SerializeExtraInfoToLine(&single_line);
- if (single_line.length() < remaining - 1) {
- buffer->Printf(" %s", single_line.buffer());
- } else {
- const intptr_t old_length = buffer->length();
- buffer->Printf("\n%s", sub_indent);
- const intptr_t line_used = buffer->length() - old_length + 1;
- remaining = width - line_used;
- if (single_line.length() < remaining) {
- buffer->AddString(single_line.buffer());
- } else {
- SerializeExtraInfoTo(zone, buffer, sub_indent, width);
- }
- }
- }
- buffer->AddChar(')');
-}
-
-void SExpList::SerializeToLine(BaseTextBuffer* buffer) const {
- buffer->AddChar('(');
- for (intptr_t i = 0; i < contents_.length(); i++) {
- if (i != 0) buffer->AddChar(' ');
- contents_.At(i)->SerializeToLine(buffer);
- }
- if (!extra_info_.IsEmpty()) {
- buffer->AddChar(' ');
- SerializeExtraInfoToLine(buffer);
- }
- buffer->AddChar(')');
-}
-
-void SExpList::SerializeExtraInfoTo(Zone* zone,
- BaseTextBuffer* buffer,
- const char* indent,
- int width) const {
- const char* sub_indent = OS::SCreate(zone, "%s%s", indent, kExtraIndent);
- TextBuffer single_line(width);
-
- buffer->AddChar('{');
- auto it = ExtraIterator();
- while (auto kv = it.Next()) {
- const intptr_t old_length = buffer->length();
- buffer->Printf("\n%s%s", sub_indent, kv->key);
- const intptr_t remaining = width - (buffer->length() - old_length + 1);
- HandleLineBreaking(zone, buffer, kv->value, &single_line, sub_indent, width,
- /*leading_space=*/true, remaining);
- buffer->AddChar(',');
- }
- buffer->Printf("\n%s}", indent);
-}
-
-void SExpList::SerializeExtraInfoToLine(BaseTextBuffer* buffer) const {
- buffer->AddString("{");
- auto it = ExtraIterator();
- while (auto kv = it.Next()) {
- buffer->Printf(" %s ", kv->key);
- kv->value->SerializeToLine(buffer);
- buffer->AddChar(',');
- }
- buffer->AddString(" }");
-}
-
-const char* const SExpParser::kBoolTrueSymbol = "true";
-const char* const SExpParser::kBoolFalseSymbol = "false";
-char const SExpParser::kDoubleExponentChar =
- DoubleToStringConstants::kExponentChar;
-const char* const SExpParser::kDoubleInfinitySymbol =
- DoubleToStringConstants::kInfinitySymbol;
-const char* const SExpParser::kDoubleNaNSymbol =
- DoubleToStringConstants::kNaNSymbol;
-
-const char* const SExpParser::ErrorStrings::kOpenString =
- "unterminated quoted string starting at position %" Pd "";
-const char* const SExpParser::ErrorStrings::kBadUnicodeEscape =
- "malformed Unicode escape";
-const char* const SExpParser::ErrorStrings::kOpenSExpList =
- "unterminated S-expression list starting at position %" Pd "";
-const char* const SExpParser::ErrorStrings::kOpenMap =
- "unterminated extra info map starting at position %" Pd "";
-const char* const SExpParser::ErrorStrings::kNestedMap =
- "extra info map start when already within extra info map";
-const char* const SExpParser::ErrorStrings::kMapOutsideList =
- "extra info map start not within S-expression list";
-const char* const SExpParser::ErrorStrings::kNonSymbolLabel =
- "non-symbol in label position for extra info map";
-const char* const SExpParser::ErrorStrings::kNoMapLabel =
- "no extra info map label provided";
-const char* const SExpParser::ErrorStrings::kRepeatedMapLabel =
- "extra info map label %s provided more than once";
-const char* const SExpParser::ErrorStrings::kNoMapValue =
- "no value provided for extra info map label %s";
-const char* const SExpParser::ErrorStrings::kExtraMapValue =
- "extra value following label %s in extra info map";
-const char* const SExpParser::ErrorStrings::kUnexpectedComma =
- "comma found outside extra info map";
-const char* const SExpParser::ErrorStrings::kUnexpectedRightParen =
- "unexpected closing parenthesis";
-const char* const SExpParser::ErrorStrings::kUnexpectedRightCurly =
- "unexpected closing curly brace";
-
-#define PARSE_ERROR(x, ...) \
- StoreError(x, __VA_ARGS__); \
- return nullptr
-
-SExpression* SExpParser::Parse() {
- Reset();
- while (auto token = GetNextToken()) {
- const intptr_t start_pos = token->cstr() - buffer_;
- switch (token->type()) {
- case kLeftParen: {
- if (in_extra_) {
- if (cur_label_ == nullptr) {
- PARSE_ERROR(start_pos, ErrorStrings::kNonSymbolLabel);
- } else if (cur_value_ != nullptr) {
- PARSE_ERROR(start_pos, ErrorStrings::kExtraMapValue, cur_label_);
- }
- }
- auto sexp = new (zone_) SExpList(zone_, start_pos);
- list_stack_.Add(sexp);
- in_extra_stack_.Add(in_extra_);
- extra_start_stack_.Add(extra_start_);
- cur_label_stack_.Add(cur_label_);
- in_extra_ = false;
- extra_start_ = -1;
- cur_label_ = nullptr;
- break;
- }
- case kRightParen: {
- if (list_stack_.is_empty()) {
- PARSE_ERROR(start_pos, ErrorStrings::kUnexpectedRightParen);
- }
- if (in_extra_) {
- PARSE_ERROR(start_pos, ErrorStrings::kOpenMap, extra_start_);
- }
- auto sexp = list_stack_.RemoveLast();
- in_extra_ = in_extra_stack_.RemoveLast();
- extra_start_ = extra_start_stack_.RemoveLast();
- cur_label_ = cur_label_stack_.RemoveLast();
- if (list_stack_.is_empty()) return sexp;
- if (in_extra_) {
- if (cur_label_ == nullptr) {
- PARSE_ERROR(start_pos, ErrorStrings::kOpenMap, extra_start_);
- }
- cur_value_ = sexp;
- } else {
- list_stack_.Last()->Add(sexp);
- }
- break;
- }
- case kLeftCurly:
- if (in_extra_) {
- PARSE_ERROR(start_pos, ErrorStrings::kNestedMap);
- }
- if (list_stack_.is_empty()) {
- PARSE_ERROR(start_pos, ErrorStrings::kMapOutsideList);
- }
- extra_start_ = start_pos;
- in_extra_ = true;
- break;
- case kRightCurly:
- if (!in_extra_ || list_stack_.is_empty()) {
- PARSE_ERROR(start_pos, ErrorStrings::kUnexpectedRightCurly);
- }
- if (cur_label_ != nullptr) {
- if (cur_value_ == nullptr) {
- PARSE_ERROR(start_pos, ErrorStrings::kNoMapValue, cur_label_);
- }
- list_stack_.Last()->AddExtra(cur_label_, cur_value_);
- cur_label_ = nullptr;
- cur_value_ = nullptr;
- }
- in_extra_ = false;
- extra_start_ = -1;
- break;
- case kComma: {
- if (!in_extra_ || list_stack_.is_empty()) {
- PARSE_ERROR(start_pos, ErrorStrings::kUnexpectedComma);
- }
- if (cur_label_ == nullptr) {
- PARSE_ERROR(start_pos, ErrorStrings::kNoMapLabel);
- } else if (cur_value_ == nullptr) {
- PARSE_ERROR(start_pos, ErrorStrings::kNoMapValue, cur_label_);
- }
- list_stack_.Last()->AddExtra(cur_label_, cur_value_);
- cur_label_ = nullptr;
- cur_value_ = nullptr;
- break;
- }
- case kSymbol: {
- auto sexp = TokenToSExpression(token);
- ASSERT(sexp->IsSymbol());
- if (in_extra_) {
- if (cur_value_ != nullptr) {
- PARSE_ERROR(start_pos, ErrorStrings::kExtraMapValue, cur_label_);
- }
- if (cur_label_ == nullptr) {
- const char* const label = sexp->AsSymbol()->value();
- if (list_stack_.Last()->ExtraHasKey(label)) {
- PARSE_ERROR(start_pos, ErrorStrings::kRepeatedMapLabel, label);
- }
- cur_label_ = sexp->AsSymbol()->value();
- } else {
- cur_value_ = sexp;
- }
- } else if (!list_stack_.is_empty()) {
- list_stack_.Last()->Add(sexp);
- } else {
- return sexp;
- }
- break;
- }
- case kBoolean:
- case kInteger:
- case kDouble:
- case kQuotedString: {
- auto sexp = TokenToSExpression(token);
- // TokenToSExpression has already set the error info, so just return.
- if (sexp == nullptr) return nullptr;
- if (in_extra_) {
- if (cur_label_ == nullptr) {
- PARSE_ERROR(start_pos, ErrorStrings::kNonSymbolLabel);
- } else if (cur_value_ != nullptr) {
- PARSE_ERROR(start_pos, ErrorStrings::kExtraMapValue, cur_label_);
- }
- cur_value_ = sexp;
- } else if (!list_stack_.is_empty()) {
- list_stack_.Last()->Add(sexp);
- } else {
- return sexp;
- }
- break;
- }
- default:
- UNREACHABLE();
- }
- }
- if (in_extra_) {
- PARSE_ERROR(buffer_size_, ErrorStrings::kOpenMap, extra_start_);
- } else if (!list_stack_.is_empty()) {
- const intptr_t list_start = list_stack_.Last()->start();
- PARSE_ERROR(buffer_size_, ErrorStrings::kOpenSExpList, list_start);
- }
- UNREACHABLE();
-}
-
-SExpression* SExpParser::TokenToSExpression(Token* token) {
- const intptr_t start_pos = token->cstr() - buffer_;
- switch (token->type()) {
- case kSymbol:
- return new (zone_) SExpSymbol(token->ToCString(zone_), start_pos);
- case kInteger: {
- const char* cstr = token->ToCString(zone_);
- int64_t val;
- if (!OS::StringToInt64(cstr, &val)) return nullptr;
- return new (zone_) SExpInteger(val, start_pos);
- }
- case kBoolean: {
- const bool is_true =
- strncmp(token->cstr(), kBoolTrueSymbol, token->length()) == 0;
- ASSERT(is_true ||
- strncmp(token->cstr(), kBoolFalseSymbol, token->length()) == 0);
- return new (zone_) SExpBool(is_true, start_pos);
- }
- case kDouble: {
- double val;
- if (!CStringToDouble(token->cstr(), token->length(), &val)) {
- return nullptr;
- }
- return new (zone_) SExpDouble(val, start_pos);
- }
- case kQuotedString: {
- const char* const cstr = token->cstr();
- char* const buf = zone_->Alloc<char>(token->length());
- // Skip the initial quote
- ASSERT(cstr[0] == '"');
- intptr_t old_pos = 1;
- intptr_t new_pos = 0;
- // The string _should_ end in a quote.
- while (old_pos < token->length() - 1) {
- if (cstr[old_pos] == '"') break;
- if (cstr[old_pos] != '\\') {
- buf[new_pos++] = cstr[old_pos++];
- continue;
- }
- old_pos++;
- if (old_pos >= token->length()) {
- PARSE_ERROR(start_pos + old_pos, ErrorStrings::kOpenString,
- start_pos);
- }
- const intptr_t escape_pos = start_pos + old_pos - 1;
- switch (cstr[old_pos]) {
- case 'b':
- buf[new_pos] = '\b';
- break;
- case 'f':
- buf[new_pos] = '\f';
- break;
- case 'n':
- buf[new_pos] = '\n';
- break;
- case 'r':
- buf[new_pos] = '\r';
- break;
- case 't':
- buf[new_pos] = '\t';
- break;
- case 'u': {
- const intptr_t first = old_pos + 1;
- const intptr_t last = old_pos + 4;
- if (last >= token->length()) {
- PARSE_ERROR(escape_pos, ErrorStrings::kBadUnicodeEscape);
- }
- intptr_t val = 0;
- for (const char *cursor = cstr + first, *end = cstr + last + 1;
- cursor < end; cursor++) {
- val *= 16;
- if (!Utils::IsHexDigit(*cursor)) {
- PARSE_ERROR(escape_pos, ErrorStrings::kBadUnicodeEscape);
- }
- val += Utils::HexDigitToInt(*cursor);
- }
- // Currently, just handle encoded ASCII instead of doing
- // handling Unicode characters.
- // (TextBuffer::AddEscapedString uses this for characters < 0x20.)
- ASSERT(val <= 0x7F);
- old_pos = last;
- buf[new_pos] = val;
- break;
- }
- default:
- // Identity escapes.
- buf[new_pos] = cstr[old_pos];
- break;
- }
- old_pos++;
- new_pos++;
- }
- if (cstr[old_pos] != '"') {
- PARSE_ERROR(start_pos + token->length(), ErrorStrings::kOpenString,
- start_pos);
- }
- buf[new_pos] = '\0';
- return new (zone_) SExpString(buf, start_pos);
- }
- default:
- UNREACHABLE();
- }
-}
-
-#undef PARSE_ERROR
-
-SExpParser::Token* SExpParser::GetNextToken() {
- intptr_t start_pos = cur_pos_;
- while (start_pos < buffer_size_) {
- if (isspace(buffer_[start_pos]) == 0) break;
- start_pos++;
- }
- if (start_pos >= buffer_size_) return nullptr;
- const char* start = buffer_ + start_pos;
- switch (*start) {
- case '(':
- cur_pos_ = start_pos + 1;
- return new (zone_) Token(kLeftParen, start, 1);
- case ')':
- cur_pos_ = start_pos + 1;
- return new (zone_) Token(kRightParen, start, 1);
- case ',':
- cur_pos_ = start_pos + 1;
- return new (zone_) Token(kComma, start, 1);
- case '{':
- cur_pos_ = start_pos + 1;
- return new (zone_) Token(kLeftCurly, start, 1);
- case '}':
- cur_pos_ = start_pos + 1;
- return new (zone_) Token(kRightCurly, start, 1);
- case '"': {
- intptr_t len = 1;
- while (start_pos + len < buffer_size_) {
- char curr = start[len];
- len++; // Length should include the quote, if any.
- if (curr == '\\') {
- // Skip past next character (if any), since it cannot
- // end the quoted string due to being escaped.
- if (start_pos + len >= buffer_size_) break;
- len++;
- continue;
- }
- if (curr == '"') break;
- }
- cur_pos_ = start_pos + len;
- return new (zone_) Token(kQuotedString, start, len);
- }
- default:
- break;
- }
- intptr_t len = 0;
- // Start number detection after possible negation sign.
- if (start[len] == '-') {
- len++;
- if ((start_pos + len) >= buffer_size_) {
- cur_pos_ = start_pos + len;
- return new (zone_) Token(kSymbol, start, len);
- }
- }
- // Keep the currently detected token type. Start off by assuming we have
- // an integer, then fall back to doubles if we see parts appropriate for
- // those but not integers, and fall back to symbols otherwise.
- TokenType type = kInteger;
- bool saw_exponent = false;
- while ((start_pos + len) < buffer_size_) {
- // Both numbers and symbols cannot contain these values, so we are at the
- // end of whichever one we're in.
- if (!IsSymbolContinue(start[len])) break;
- if (type == kInteger && start[len] == '.') {
- type = kDouble;
- len++;
- continue;
- }
- if (type != kSymbol && !saw_exponent && start[len] == kDoubleExponentChar) {
- saw_exponent = true;
- type = kDouble;
- len++;
- // Skip past negation in exponent if any.
- if ((start_pos + len) < buffer_size_ && start[len] == '-') len++;
- continue;
- }
- // If we find a character that can't appear in a number, then fall back
- // to symbol-ness.
- if (isdigit(start[len]) == 0) type = kSymbol;
- len++;
- }
- cur_pos_ = start_pos + len;
- // Skip special symbol detection if we don't have a symbol.
- if (type != kSymbol) return new (zone_) Token(type, start, len);
- // Check for special symbols used for booleans and certain Double values.
- switch (len) {
- case 3:
- if (strncmp(start, kDoubleNaNSymbol, len) == 0) type = kDouble;
- break;
- case 4:
- if (strncmp(start, kBoolTrueSymbol, len) == 0) type = kBoolean;
- break;
- case 5:
- if (strncmp(start, kBoolFalseSymbol, len) == 0) type = kBoolean;
- break;
- case 8:
- if (strncmp(start, kDoubleInfinitySymbol, len) == 0) type = kDouble;
- break;
- case 9:
- if (start[0] == '-' &&
- strncmp(start + 1, kDoubleInfinitySymbol, len - 1) == 0) {
- type = kDouble;
- }
- break;
- default:
- break;
- }
- return new (zone_) Token(type, start, len);
-}
-
-bool SExpParser::IsSymbolContinue(char c) {
- return (isspace(c) == 0) && c != '(' && c != ')' && c != ',' && c != '{' &&
- c != '}' && c != '"';
-}
-
-const char* const SExpParser::Token::TokenNames[kMaxTokens] = {
-#define S_EXP_TOKEN_NAME_STRING(name) #name,
- S_EXP_TOKEN_LIST(S_EXP_TOKEN_NAME_STRING)
-#undef S_EXP_TOKEN_NAME_STRING
-};
-
-const char* SExpParser::Token::ToCString(Zone* zone) {
- char* const buffer = zone->Alloc<char>(len_ + 1);
- strncpy(buffer, cstr_, len_);
- buffer[len_] = '\0';
- return buffer;
-}
-
-void SExpParser::Reset() {
- cur_pos_ = 0;
- in_extra_ = false;
- extra_start_ = -1;
- cur_label_ = nullptr;
- cur_value_ = nullptr;
- list_stack_.Clear();
- in_extra_stack_.Clear();
- extra_start_stack_.Clear();
- cur_label_stack_.Clear();
- error_pos_ = -1;
- error_message_ = nullptr;
-}
-
-void SExpParser::StoreError(intptr_t pos, const char* format, ...) {
- va_list args;
- va_start(args, format);
- const char* const message = OS::VSCreate(zone_, format, args);
- va_end(args);
- error_pos_ = pos;
- error_message_ = message;
-}
-
-void SExpParser::ReportError() const {
- ASSERT(error_message_ != nullptr);
- ASSERT(error_pos_ >= 0);
- OS::PrintErr("Unable to parse s-expression: %s\n", buffer_);
- OS::PrintErr("Error at character %" Pd ": %s\n", error_pos_, error_message_);
- OS::Abort();
-}
-
-} // namespace dart
diff --git a/runtime/vm/compiler/backend/sexpression.h b/runtime/vm/compiler/backend/sexpression.h
deleted file mode 100644
index 6bdc36e..0000000
--- a/runtime/vm/compiler/backend/sexpression.h
+++ /dev/null
@@ -1,305 +0,0 @@
-// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#ifndef RUNTIME_VM_COMPILER_BACKEND_SEXPRESSION_H_
-#define RUNTIME_VM_COMPILER_BACKEND_SEXPRESSION_H_
-
-#if defined(DART_PRECOMPILED_RUNTIME)
-#error "AOT runtime should not use compiler sources (including header files)"
-#endif // defined(DART_PRECOMPILED_RUNTIME)
-
-#include "platform/text_buffer.h"
-
-#include "vm/allocation.h"
-#include "vm/growable_array.h"
-#include "vm/hash_map.h"
-#include "vm/zone.h"
-
-namespace dart {
-
-#define FOR_EACH_S_EXPRESSION_ATOM(M) \
- M(Bool, bool) \
- M(Double, double) \
- M(Integer, int64_t) \
- M(String, const char*) \
- M(Symbol, const char*)
-
-#define FOR_EACH_S_EXPRESSION(M) \
- FOR_EACH_S_EXPRESSION_ATOM(M) \
- M(List, _)
-
-#define FOR_EACH_ABSTRACT_S_EXPRESSION(M) M(Atom, _)
-
-#define FORWARD_DECLARATION(name, value_type) class SExp##name;
-FOR_EACH_S_EXPRESSION(FORWARD_DECLARATION)
-FOR_EACH_ABSTRACT_S_EXPRESSION(FORWARD_DECLARATION)
-#undef FORWARD_DECLARATION
-
-// Abstract base class for S-expressions used as an intermediate form for the
-// IL serializer. These aren't true (LISP-like) S-expressions, as the atoms
-// are more restricted and the lists have extra information. Here is an
-// illustrative BNF-style grammar of the current serialized form of
-// S-expressions that includes non-whitespace literal tokens:
-//
-// <s-exp> ::= <atom> | <list>
-// <atom> ::= <bool> | <integer> | <string> | <symbol>
-// <list> ::= '(' <s-exp>* <extra-info>? ')'
-// <extra-info> ::= '{' <extra-elem>* '}'
-// <extra-elem> ::= <symbol> <s-exp> ','
-//
-// Here, <string>s are double-quoted strings with backslash escaping and
-// <symbol>s are sequences of consecutive non-whitespace characters that do not
-// include commas (,), parentheses (()), curly braces ({}), or the double-quote
-// character (").
-//
-// In addition, the <extra-info> is considered a map from symbol labels to
-// S-expression values, and as such each symbol used as a key in an <extra-info>
-// block should only appear once as a key within that block.
-class SExpression : public ZoneAllocated {
- public:
- explicit SExpression(intptr_t start = kInvalidPos) : start_(start) {}
- virtual ~SExpression() {}
-
- static intptr_t const kInvalidPos = -1;
-
- static SExpression* FromCString(Zone* zone, const char* cstr);
- const char* ToCString(Zone* zone) const;
- intptr_t start() const { return start_; }
-
-#define S_EXPRESSION_TYPE_CHECK(name, value_type) \
- bool Is##name() const { return (As##name() != nullptr); } \
- SExp##name* As##name() { \
- auto const const_this = const_cast<const SExpression*>(this); \
- return const_cast<SExp##name*>(const_this->As##name()); \
- } \
- virtual const SExp##name* As##name() const { return nullptr; }
-
- FOR_EACH_S_EXPRESSION(S_EXPRESSION_TYPE_CHECK)
- FOR_EACH_ABSTRACT_S_EXPRESSION(S_EXPRESSION_TYPE_CHECK)
-
- virtual const char* DebugName() const = 0;
- virtual bool Equals(SExpression* sexp) const = 0;
- virtual void SerializeTo(Zone* zone,
- BaseTextBuffer* buffer,
- const char* indent,
- intptr_t width = 80) const = 0;
- virtual void SerializeToLine(BaseTextBuffer* buffer) const = 0;
-
- private:
- // Starting character position of the s-expression in the original
- // serialization, if it was deserialized.
- intptr_t const start_;
- DISALLOW_COPY_AND_ASSIGN(SExpression);
-};
-
-class SExpAtom : public SExpression {
- public:
- explicit SExpAtom(intptr_t start = kInvalidPos) : SExpression(start) {}
-
- virtual const SExpAtom* AsAtom() const { return this; }
- // No atoms have sub-elements, so they always print to a single line.
- virtual void SerializeTo(Zone* zone,
- BaseTextBuffer* buffer,
- const char* indent,
- intptr_t width = 80) const {
- SerializeToLine(buffer);
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(SExpAtom);
-};
-
-#define DEFINE_S_EXPRESSION_TYPE_CHECK(name) \
- virtual const SExp##name* As##name() const { return this; } \
- virtual const char* DebugName() const { return #name; }
-
-// The various concrete S-expression atom classes are thin wrappers around
-// their contained value that includes serialization and type check methods.
-#define DEFINE_S_EXPRESSION_ATOM_CLASS(name, value_type) \
- class SExp##name : public SExpAtom { \
- public: \
- explicit SExp##name(value_type val, intptr_t start = kInvalidPos) \
- : SExpAtom(start), val_(val) {} \
- value_type value() const { return val_; } \
- virtual bool Equals(SExpression* sexp) const; \
- bool Equals(value_type val) const; \
- virtual void SerializeToLine(BaseTextBuffer* buffer) const; \
- DEFINE_S_EXPRESSION_TYPE_CHECK(name) \
- private: \
- value_type const val_; \
- DISALLOW_COPY_AND_ASSIGN(SExp##name); \
- };
-
-FOR_EACH_S_EXPRESSION_ATOM(DEFINE_S_EXPRESSION_ATOM_CLASS)
-
-// A list of S-expressions. Unlike normal S-expressions, an S-expression list
-// also contains a hash map kept separate from the elements, which we use for
-// extra non-argument information for IL instructions.
-class SExpList : public SExpression {
- public:
- explicit SExpList(Zone* zone, intptr_t start = kInvalidPos)
- : SExpression(start), contents_(zone, 2), extra_info_(zone) {}
-
- using ExtraInfoHashMap = CStringMap<SExpression*>;
-
- void Add(SExpression* sexp);
- void AddExtra(const char* label, SExpression* value);
-
- SExpression* At(intptr_t i) const { return contents_.At(i); }
- intptr_t Length() const { return contents_.length(); }
-
- intptr_t ExtraLength() const { return extra_info_.Length(); }
- ExtraInfoHashMap::Iterator ExtraIterator() const {
- return extra_info_.GetIterator();
- }
- bool ExtraHasKey(const char* cstr) const { return extra_info_.HasKey(cstr); }
- SExpression* ExtraLookupValue(const char* cstr) const {
- return extra_info_.LookupValue(cstr);
- }
-
- // Shortcut for retrieving the tag from a tagged list (list that contains an
- // initial symbol). Returns nullptr if the list is not a tagged list.
- SExpSymbol* Tag() const {
- if (Length() == 0 || !At(0)->IsSymbol()) return nullptr;
- return At(0)->AsSymbol();
- }
-
- DEFINE_S_EXPRESSION_TYPE_CHECK(List)
- virtual bool Equals(SExpression* sexp) const;
- virtual void SerializeTo(Zone* zone,
- BaseTextBuffer* buffer,
- const char* indent,
- intptr_t width = 80) const;
- virtual void SerializeToLine(BaseTextBuffer* buffer) const;
-
- private:
- static const char* const kElemIndent;
- static const char* const kExtraIndent;
-
- void SerializeExtraInfoTo(Zone* zone,
- BaseTextBuffer* buffer,
- const char* indent,
- int width) const;
- void SerializeExtraInfoToLine(BaseTextBuffer* buffer) const;
-
- ZoneGrowableArray<SExpression*> contents_;
- ExtraInfoHashMap extra_info_;
-
- DISALLOW_COPY_AND_ASSIGN(SExpList);
-};
-
-class SExpParser : public ValueObject {
- public:
- SExpParser(Zone* zone, const char* cstr)
- : SExpParser(zone, cstr, strlen(cstr)) {}
- SExpParser(Zone* zone, const char* cstr, intptr_t len)
- : zone_(zone),
- buffer_(ASSERT_NOTNULL(cstr)),
- buffer_size_(strnlen(cstr, len)),
- cur_label_(nullptr),
- cur_value_(nullptr),
- list_stack_(zone, 2),
- in_extra_stack_(zone, 2),
- extra_start_stack_(zone, 2),
- cur_label_stack_(zone, 2),
- error_message_(nullptr) {}
-
- // Constants used in serializing and deserializing S-expressions.
- static const char* const kBoolTrueSymbol;
- static const char* const kBoolFalseSymbol;
- static char const kDoubleExponentChar;
- static const char* const kDoubleInfinitySymbol;
- static const char* const kDoubleNaNSymbol;
-
- struct ErrorStrings : AllStatic {
- static const char* const kOpenString;
- static const char* const kBadUnicodeEscape;
- static const char* const kOpenSExpList;
- static const char* const kOpenMap;
- static const char* const kNestedMap;
- static const char* const kMapOutsideList;
- static const char* const kNonSymbolLabel;
- static const char* const kNoMapLabel;
- static const char* const kRepeatedMapLabel;
- static const char* const kNoMapValue;
- static const char* const kExtraMapValue;
- static const char* const kUnexpectedComma;
- static const char* const kUnexpectedRightParen;
- static const char* const kUnexpectedRightCurly;
- };
-
- intptr_t error_pos() const { return error_pos_; }
- const char* error_message() const { return error_message_; }
-
- const char* Input() const { return buffer_; }
- SExpression* Parse();
- DART_NORETURN void ReportError() const;
-
- private:
-#define S_EXP_TOKEN_LIST(M) \
- M(LeftParen) \
- M(RightParen) \
- M(Comma) \
- M(LeftCurly) \
- M(RightCurly) \
- M(QuotedString) \
- M(Integer) \
- M(Double) \
- M(Boolean) \
- M(Symbol)
-
- // clang-format off
-#define DEFINE_S_EXP_TOKEN_ENUM_LINE(name) k##name,
- enum TokenType {
- S_EXP_TOKEN_LIST(DEFINE_S_EXP_TOKEN_ENUM_LINE)
- kMaxTokens,
- };
-#undef DEFINE_S_EXP_TOKEN_ENUM
- // clang-format on
-
- class Token : public ZoneAllocated {
- public:
- Token(TokenType type, const char* cstr, intptr_t len)
- : type_(type), cstr_(cstr), len_(len) {}
-
- TokenType type() const { return type_; }
- intptr_t length() const { return len_; }
- const char* cstr() const { return cstr_; }
- const char* DebugName() const { return TokenNames[type()]; }
- const char* ToCString(Zone* zone);
-
- private:
- static const char* const TokenNames[kMaxTokens];
-
- TokenType const type_;
- const char* const cstr_;
- intptr_t const len_;
- };
-
- SExpression* TokenToSExpression(Token* token);
- Token* GetNextToken();
- void Reset();
- void StoreError(intptr_t pos, const char* format, ...) PRINTF_ATTRIBUTE(3, 4);
-
- static bool IsSymbolContinue(char c);
-
- Zone* const zone_;
- const char* const buffer_;
- intptr_t const buffer_size_;
- intptr_t cur_pos_ = 0;
- bool in_extra_ = false;
- intptr_t extra_start_ = -1;
- const char* cur_label_;
- SExpression* cur_value_;
- ZoneGrowableArray<SExpList*> list_stack_;
- ZoneGrowableArray<bool> in_extra_stack_;
- ZoneGrowableArray<intptr_t> extra_start_stack_;
- ZoneGrowableArray<const char*> cur_label_stack_;
- intptr_t error_pos_ = -1;
- const char* error_message_;
-};
-
-} // namespace dart
-
-#endif // RUNTIME_VM_COMPILER_BACKEND_SEXPRESSION_H_
diff --git a/runtime/vm/compiler/backend/sexpression_test.cc b/runtime/vm/compiler/backend/sexpression_test.cc
deleted file mode 100644
index 8c0edac..0000000
--- a/runtime/vm/compiler/backend/sexpression_test.cc
+++ /dev/null
@@ -1,355 +0,0 @@
-// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#include "vm/compiler/backend/sexpression.h"
-
-#include <cmath>
-#include "platform/assert.h"
-#include "vm/unit_test.h"
-
-namespace dart {
-
-#define EXPECT_SEXP_PARSE_ERROR(sexp, parser, pos, message) \
- do { \
- if (sexp != nullptr) { \
- dart::Expect(__FILE__, __LINE__) \
- .Fail("parse unexpectedly succeeded for \"%s\"", parser.Input()); \
- } \
- EXPECT_EQ(pos, parser.error_pos()); \
- EXPECT_STREQ(message, parser.error_message()); \
- } while (false);
-
-#define EXPECT_SEXP_PARSE_SUCCESS(sexp, parser) \
- do { \
- if (sexp == nullptr) { \
- EXPECT_NOTNULL(parser.error_message()); \
- dart::Expect(__FILE__, __LINE__) \
- .Fail("parse unexpectedly failed at \"%s\": %" Pd ": %s", \
- parser.Input() + parser.error_pos(), parser.error_pos(), \
- parser.error_message()); \
- } \
- } while (false);
-
-static const char* const shared_sexp_cstr =
- "(def v0 (Constant 3) { type (CompileType 147 { nullable false, name "
- "\"T{Smi}\"}), })";
-
-static void CheckDeserializedSExpParts(SExpression* sexp) {
- EXPECT_NOTNULL(sexp);
- EXPECT(sexp->IsList());
- SExpList* list = sexp->AsList();
- EXPECT_EQ(3, list->Length());
- EXPECT_NOTNULL(list->At(0));
- EXPECT(list->At(0)->IsSymbol());
- EXPECT_STREQ("def", list->At(0)->AsSymbol()->value());
- EXPECT_NOTNULL(list->At(1));
- EXPECT(list->At(1)->IsSymbol());
- EXPECT_STREQ("v0", list->At(1)->AsSymbol()->value());
- EXPECT_NOTNULL(list->At(2));
- EXPECT(list->At(2)->IsList());
-
- SExpList* sublist = list->At(2)->AsList();
- EXPECT_EQ(2, sublist->Length());
- EXPECT_NOTNULL(sublist->At(0));
- EXPECT(sublist->At(0)->IsSymbol());
- EXPECT_STREQ("Constant", sublist->At(0)->AsSymbol()->value());
- EXPECT_NOTNULL(sublist->At(1));
- EXPECT(sublist->At(1)->IsInteger());
- EXPECT_EQ(3, sublist->At(1)->AsInteger()->value());
- EXPECT_EQ(0, sublist->ExtraLength());
-
- EXPECT_EQ(1, list->ExtraLength());
- EXPECT(list->ExtraHasKey("type"));
- EXPECT(list->ExtraLookupValue("type")->IsList());
-
- SExpList* ctype = list->ExtraLookupValue("type")->AsList();
- EXPECT_EQ(2, ctype->Length());
- EXPECT_NOTNULL(ctype->At(0));
- EXPECT(ctype->At(0)->IsSymbol());
- EXPECT_STREQ("CompileType", ctype->At(0)->AsSymbol()->value());
- EXPECT_NOTNULL(ctype->At(1));
- EXPECT(ctype->At(1)->IsInteger());
- EXPECT_EQ(147, ctype->At(1)->AsInteger()->value());
-
- EXPECT_EQ(2, ctype->ExtraLength());
- EXPECT(ctype->ExtraHasKey("nullable"));
- EXPECT(ctype->ExtraLookupValue("nullable")->IsBool());
- EXPECT(!ctype->ExtraLookupValue("nullable")->AsBool()->value());
- EXPECT(ctype->ExtraHasKey("name"));
- EXPECT(ctype->ExtraLookupValue("name")->IsString());
- EXPECT_STREQ(ctype->ExtraLookupValue("name")->AsString()->value(), "T{Smi}");
-}
-
-ISOLATE_UNIT_TEST_CASE(DeserializeSExp) {
- Zone* const zone = Thread::Current()->zone();
- SExpression* sexp = SExpression::FromCString(zone, shared_sexp_cstr);
- CheckDeserializedSExpParts(sexp);
-
- // Treating escaped backslash appropriately so string is terminated.
- {
- const char* const cstr = "(def v0 (Constant 3) { foo \"123\\\\\" })";
- SExpParser parser(zone, cstr, strlen(cstr));
- SExpression* const sexp = parser.Parse();
- EXPECT_SEXP_PARSE_SUCCESS(sexp, parser);
- EXPECT(sexp->IsList());
- EXPECT_EQ(1, sexp->AsList()->ExtraLength());
- EXPECT(sexp->AsList()->ExtraHasKey("foo"));
- auto val = sexp->AsList()->ExtraLookupValue("foo");
- EXPECT(val->IsString());
- EXPECT_STREQ("123\\", val->AsString()->value());
- }
- // Valid unicode escapes are properly handled.
- {
- const char* const cstr =
- "(def v0 (Constant 3) { foo \"\\u0001\\u0020\\u0054\" })";
- SExpParser parser(zone, cstr, strlen(cstr));
- SExpression* const sexp = parser.Parse();
- EXPECT_SEXP_PARSE_SUCCESS(sexp, parser);
- EXPECT(sexp->IsList());
- EXPECT_EQ(1, sexp->AsList()->ExtraLength());
- EXPECT(sexp->AsList()->ExtraHasKey("foo"));
- auto val = sexp->AsList()->ExtraLookupValue("foo");
- EXPECT(val->IsString());
- EXPECT_STREQ("\x01 T", val->AsString()->value());
- }
-}
-
-ISOLATE_UNIT_TEST_CASE(DeserializeSExpNumbers) {
- Zone* const zone = Thread::Current()->zone();
-
- // Negative integers are handled.
- {
- const char* const cstr = "(-4 -50 -1414243)";
- SExpParser parser(zone, cstr, strlen(cstr));
- SExpression* const sexp = parser.Parse();
- EXPECT_SEXP_PARSE_SUCCESS(sexp, parser);
- EXPECT(sexp->IsList());
- auto list = sexp->AsList();
- EXPECT_EQ(3, list->Length());
- EXPECT_EQ(0, list->ExtraLength());
- for (intptr_t i = 0; i < list->Length(); i++) {
- EXPECT(list->At(i)->IsInteger());
- EXPECT(list->At(i)->AsInteger()->value() < 0);
- }
- }
-
- // Various decimal/exponent Doubles are appropriately handled.
- {
- const char* const cstr = "(1.05 0.05 .03 1e100 1e-100)";
- SExpParser parser(zone, cstr, strlen(cstr));
- SExpression* const sexp = parser.Parse();
- EXPECT_SEXP_PARSE_SUCCESS(sexp, parser);
- EXPECT(sexp->IsList());
- auto list = sexp->AsList();
- EXPECT_EQ(5, list->Length());
- EXPECT_EQ(0, list->ExtraLength());
- EXPECT(list->At(0)->IsDouble());
- double val = list->At(0)->AsDouble()->value();
- EXPECT(val > 1.04 && val < 1.06);
- EXPECT(list->At(1)->IsDouble());
- val = list->At(1)->AsDouble()->value();
- EXPECT(val > 0.04 && val < 0.06);
- EXPECT(list->At(2)->IsDouble());
- val = list->At(2)->AsDouble()->value();
- EXPECT(val > 0.02 && val < 0.04);
- EXPECT(list->At(3)->IsDouble());
- val = list->At(3)->AsDouble()->value();
- EXPECT(val > 0.9e100 && val < 1.1e100);
- EXPECT(list->At(4)->IsDouble());
- val = list->At(4)->AsDouble()->value();
- EXPECT(val > 0.9e-100 && val < 1.1e-100);
- }
-
- // Special Double symbols are appropriately handled.
- {
- const char* const cstr = "(NaN Infinity -Infinity)";
- SExpParser parser(zone, cstr, strlen(cstr));
- SExpression* const sexp = parser.Parse();
- EXPECT_SEXP_PARSE_SUCCESS(sexp, parser);
- EXPECT(sexp->IsList());
- auto list = sexp->AsList();
- EXPECT_EQ(3, list->Length());
- EXPECT_EQ(0, list->ExtraLength());
- EXPECT(list->At(0)->IsDouble());
- double val = list->At(0)->AsDouble()->value();
- EXPECT(isnan(val));
- EXPECT(list->At(1)->IsDouble());
- val = list->At(1)->AsDouble()->value();
- EXPECT(val > 0.0);
- EXPECT(isinf(val));
- EXPECT(list->At(2)->IsDouble());
- val = list->At(2)->AsDouble()->value();
- EXPECT(val < 0.0);
- EXPECT(isinf(val));
- }
-}
-
-ISOLATE_UNIT_TEST_CASE(DeserializeSExpRoundTrip) {
- Zone* const zone = Thread::Current()->zone();
- SExpression* sexp = SExpression::FromCString(zone, shared_sexp_cstr);
-
- TextBuffer buf(100);
- sexp->SerializeTo(zone, &buf, "", 9999);
- SExpression* round_trip = SExpression::FromCString(zone, buf.buffer());
- CheckDeserializedSExpParts(round_trip);
- EXPECT(sexp->Equals(round_trip));
-
- char* const old_serialization = buf.Steal();
- round_trip->SerializeTo(zone, &buf, "", 9999);
- char* const new_serialization = buf.buffer();
- EXPECT_STREQ(old_serialization, new_serialization);
- free(old_serialization);
-}
-
-ISOLATE_UNIT_TEST_CASE(DeserializeSExpMapsJoined) {
- Zone* const zone = Thread::Current()->zone();
- // Same as shared_sexp_cstr except we split the map on the CompileType into
- // two parts.
- const char* const cstr =
- "(def v0 (Constant 3) { type (CompileType { nullable false } 147 { name "
- "\"T{Smi}\"}), })";
- SExpression* sexp = SExpression::FromCString(zone, cstr);
- CheckDeserializedSExpParts(sexp);
-}
-
-ISOLATE_UNIT_TEST_CASE(DeserializeSExpFailures) {
- Zone* const zone = Thread::Current()->zone();
- // Unterminated s-exp list
- {
- const char* const before_start = "(def v0 ";
- const char* const after_start = "(Constant 3";
- const char* const cstr =
- OS::SCreate(zone, "%s%s", before_start, after_start);
- const intptr_t start_pos = strlen(before_start);
- const intptr_t error_pos = strlen(cstr);
- SExpParser parser(zone, cstr, strlen(cstr));
- SExpression* const sexp = parser.Parse();
- const char* const expected_message =
- OS::SCreate(zone, SExpParser::ErrorStrings::kOpenSExpList, start_pos);
- EXPECT_SEXP_PARSE_ERROR(sexp, parser, error_pos, expected_message);
- }
- // Non-symbol label in map pair
- {
- const char* const before_error = "(def v0 (Constant 3) { ";
- const intptr_t error_pos = strlen(before_error);
- const char* const error = "3 4 })";
- const char* const cstr = OS::SCreate(zone, "%s%s", before_error, error);
- SExpParser parser(zone, cstr, strlen(cstr));
- SExpression* const sexp = parser.Parse();
- const char* const expected_message =
- SExpParser::ErrorStrings::kNonSymbolLabel;
- EXPECT_SEXP_PARSE_ERROR(sexp, parser, error_pos, expected_message);
- }
- // No values in a map pair
- {
- const char* const label = "foo";
- const char* const before_error =
- OS::SCreate(zone, "(def v0 (Constant 3) { %s ", label);
- const intptr_t error_pos = strlen(before_error);
- const char* const error = "})";
- const char* const cstr = OS::SCreate(zone, "%s%s", before_error, error);
- SExpParser parser(zone, cstr, strlen(cstr));
- SExpression* const sexp = parser.Parse();
- const char* const expected_message =
- OS::SCreate(zone, SExpParser::ErrorStrings::kNoMapValue, label);
- EXPECT_SEXP_PARSE_ERROR(sexp, parser, error_pos, expected_message);
- }
- // Multiple values in a map pair
- {
- const char* const label = "foo";
- const char* const before_error =
- OS::SCreate(zone, "(def v0 (Constant 3) { %s 4 ", label);
- const intptr_t error_pos = strlen(before_error);
- const char* const error = "5, })";
- const char* const cstr = OS::SCreate(zone, "%s%s", before_error, error);
- SExpParser parser(zone, cstr, strlen(cstr));
- SExpression* const sexp = parser.Parse();
- const char* const expected_message =
- OS::SCreate(zone, SExpParser::ErrorStrings::kExtraMapValue, label);
- EXPECT_SEXP_PARSE_ERROR(sexp, parser, error_pos, expected_message);
- }
- // Unterminated quoted string
- {
- const char* const before_string =
- OS::SCreate(zone, "(def v0 (Constant 3) { foo ");
- const intptr_t string_pos = strlen(before_string);
- const char* const error = "\"abc })";
- const char* const cstr = OS::SCreate(zone, "%s%s", before_string, error);
- const intptr_t error_pos = strlen(cstr);
- SExpParser parser(zone, cstr, strlen(cstr));
- SExpression* const sexp = parser.Parse();
- const char* const expected_message =
- OS::SCreate(zone, SExpParser::ErrorStrings::kOpenString, string_pos);
- EXPECT_SEXP_PARSE_ERROR(sexp, parser, error_pos, expected_message);
- }
- // Unterminated extra info map
- {
- const char* const before_map = "(def v0 (Constant 3) ";
- const intptr_t map_pos = strlen(before_map);
- const char* const map_start = "{ foo 3, ";
- const char* const before_error =
- OS::SCreate(zone, "%s%s", before_map, map_start);
- const intptr_t error_pos = strlen(before_error);
- const char* const error = ")";
- const char* const cstr = OS::SCreate(zone, "%s%s", before_error, error);
- SExpParser parser(zone, cstr, strlen(cstr));
- SExpression* const sexp = parser.Parse();
- const char* const expected_message =
- OS::SCreate(zone, SExpParser::ErrorStrings::kOpenMap, map_pos);
- EXPECT_SEXP_PARSE_ERROR(sexp, parser, error_pos, expected_message);
- }
- // Repeated extra info map label
- {
- const char* const label = "foo";
- const char* const before_error =
- OS::SCreate(zone, "(def v0 (Constant 3) { %s 3, ", label);
- const intptr_t error_pos = strlen(before_error);
- const char* const error = OS::SCreate(zone, "%s 4, })", label);
- const char* const cstr = OS::SCreate(zone, "%s%s", before_error, error);
- SExpParser parser(zone, cstr, strlen(cstr));
- SExpression* const sexp = parser.Parse();
- const char* const expected_message =
- OS::SCreate(zone, SExpParser::ErrorStrings::kRepeatedMapLabel, label);
- EXPECT_SEXP_PARSE_ERROR(sexp, parser, error_pos, expected_message);
- }
- // Unicode escape with non-hex digits.
- {
- const char* const before_error = "(def v0 (Constant 3) { foo \"123";
- const intptr_t error_pos = strlen(before_error);
- const char* const error = "\\u12FG\" })";
- const char* const cstr = OS::SCreate(zone, "%s%s", before_error, error);
- SExpParser parser(zone, cstr, strlen(cstr));
- SExpression* const sexp = parser.Parse();
- const char* const expected_message =
- SExpParser::ErrorStrings::kBadUnicodeEscape;
- EXPECT_SEXP_PARSE_ERROR(sexp, parser, error_pos, expected_message);
- }
- // Unicode escape with less than four hex digits.
- {
- const char* const before_error = "(def v0 (Constant 3) { foo \"123";
- const intptr_t error_pos = strlen(before_error);
- const char* const error = "\\u12\" })";
- const char* const cstr = OS::SCreate(zone, "%s%s", before_error, error);
- SExpParser parser(zone, cstr, strlen(cstr));
- SExpression* const sexp = parser.Parse();
- const char* const expected_message =
- SExpParser::ErrorStrings::kBadUnicodeEscape;
- EXPECT_SEXP_PARSE_ERROR(sexp, parser, error_pos, expected_message);
- }
- // Treating backslashed quote appropriately to detect unterminated string
- {
- const char* const before_string = "(def v0 (Constant 3) { foo ";
- const intptr_t string_pos = strlen(before_string);
- const char* const error = "\"123\\\" })";
- const char* const cstr = OS::SCreate(zone, "%s%s", before_string, error);
- const intptr_t error_pos = strlen(cstr);
- SExpParser parser(zone, cstr, strlen(cstr));
- SExpression* const sexp = parser.Parse();
- const char* const expected_message =
- OS::SCreate(zone, SExpParser::ErrorStrings::kOpenString, string_pos);
- EXPECT_SEXP_PARSE_ERROR(sexp, parser, error_pos, expected_message);
- }
-}
-
-} // namespace dart
diff --git a/runtime/vm/compiler/compiler_pass.cc b/runtime/vm/compiler/compiler_pass.cc
index 2a6f91f..1dfcdce 100644
--- a/runtime/vm/compiler/compiler_pass.cc
+++ b/runtime/vm/compiler/compiler_pass.cc
@@ -8,9 +8,7 @@
#include "vm/compiler/backend/branch_optimizer.h"
#include "vm/compiler/backend/constant_propagator.h"
#include "vm/compiler/backend/flow_graph_checker.h"
-#include "vm/compiler/backend/il_deserializer.h"
#include "vm/compiler/backend/il_printer.h"
-#include "vm/compiler/backend/il_serializer.h"
#include "vm/compiler/backend/inliner.h"
#include "vm/compiler/backend/linearscan.h"
#include "vm/compiler/backend/range_analysis.h"
@@ -80,14 +78,6 @@
"List of comma separated compilation passes flags. "
"Use -Name to disable a pass, Name to print IL after it. "
"Do --compiler-passes=help for more information.");
-DEFINE_FLAG(bool,
- early_round_trip_serialization,
- false,
- "Perform early round trip serialization compiler pass.");
-DEFINE_FLAG(bool,
- late_round_trip_serialization,
- false,
- "Perform late round trip serialization compiler pass.");
DECLARE_FLAG(bool, print_flow_graph);
DECLARE_FLAG(bool, print_flow_graph_optimized);
@@ -286,9 +276,6 @@
PipelineMode mode,
CompilerPassState* pass_state) {
INVOKE_PASS(ComputeSSA);
- if (FLAG_early_round_trip_serialization) {
- INVOKE_PASS(RoundTripSerialization);
- }
INVOKE_PASS(SetOuterInliningId);
INVOKE_PASS(TypePropagation);
INVOKE_PASS(Canonicalize);
@@ -309,10 +296,6 @@
INVOKE_PASS_AOT(DelayAllocations);
INVOKE_PASS(EliminateWriteBarriers);
INVOKE_PASS(FinalizeGraph);
- INVOKE_PASS_AOT(SerializeGraph);
- if (FLAG_late_round_trip_serialization) {
- INVOKE_PASS(RoundTripSerialization);
- }
INVOKE_PASS(AllocateRegisters);
INVOKE_PASS(ReorderBlocks);
return pass_state->flow_graph();
@@ -321,9 +304,6 @@
FlowGraph* CompilerPass::RunPipeline(PipelineMode mode,
CompilerPassState* pass_state) {
INVOKE_PASS(ComputeSSA);
- if (FLAG_early_round_trip_serialization) {
- INVOKE_PASS(RoundTripSerialization);
- }
INVOKE_PASS_AOT(ApplyClassIds);
INVOKE_PASS_AOT(TypePropagation);
INVOKE_PASS(ApplyICData);
@@ -382,12 +362,6 @@
INVOKE_PASS(AllocationSinking_DetachMaterializations);
INVOKE_PASS(EliminateWriteBarriers);
INVOKE_PASS(FinalizeGraph);
- // If we are serializing the flow graph, do it now before we start
- // doing register allocation.
- INVOKE_PASS_AOT(SerializeGraph);
- if (FLAG_late_round_trip_serialization) {
- INVOKE_PASS(RoundTripSerialization);
- }
INVOKE_PASS(AllocateRegisters);
INVOKE_PASS(ReorderBlocks);
return pass_state->flow_graph();
@@ -576,27 +550,4 @@
flow_graph->RemoveRedefinitions();
});
-#if defined(DART_PRECOMPILER)
-COMPILER_PASS(SerializeGraph, {
- if (state->precompiler == nullptr) return false;
- if (auto stream = state->precompiler->il_serialization_stream()) {
- auto file_write = Dart::file_write_callback();
- ASSERT(file_write != nullptr);
-
- const intptr_t kInitialBufferSize = 1 * MB;
- TextBuffer buffer(kInitialBufferSize);
- StackZone stack_zone(Thread::Current());
- FlowGraphSerializer::SerializeToBuffer(stack_zone.GetZone(), flow_graph,
- &buffer);
-
- file_write(buffer.buffer(), buffer.length(), stream);
- }
-});
-#endif
-
-COMPILER_PASS(RoundTripSerialization, {
- FlowGraphDeserializer::RoundTripSerialization(state);
- ASSERT(state->flow_graph() != nullptr);
-})
-
} // namespace dart
diff --git a/runtime/vm/compiler/compiler_pass.h b/runtime/vm/compiler/compiler_pass.h
index 1904561..39dc9bd 100644
--- a/runtime/vm/compiler/compiler_pass.h
+++ b/runtime/vm/compiler/compiler_pass.h
@@ -44,9 +44,7 @@
V(OptimizeTypedDataAccesses) \
V(RangeAnalysis) \
V(ReorderBlocks) \
- V(RoundTripSerialization) \
V(SelectRepresentations) \
- V(SerializeGraph) \
V(SetOuterInliningId) \
V(TryCatchOptimization) \
V(TryOptimizePatterns) \
diff --git a/runtime/vm/compiler/compiler_sources.gni b/runtime/vm/compiler/compiler_sources.gni
index edfa863..8cc4b39 100644
--- a/runtime/vm/compiler/compiler_sources.gni
+++ b/runtime/vm/compiler/compiler_sources.gni
@@ -57,13 +57,9 @@
"backend/il.h",
"backend/il_arm.cc",
"backend/il_arm64.cc",
- "backend/il_deserializer.cc",
- "backend/il_deserializer.h",
"backend/il_ia32.cc",
"backend/il_printer.cc",
"backend/il_printer.h",
- "backend/il_serializer.cc",
- "backend/il_serializer.h",
"backend/il_x64.cc",
"backend/inliner.cc",
"backend/inliner.h",
@@ -79,8 +75,6 @@
"backend/range_analysis.h",
"backend/redundancy_elimination.cc",
"backend/redundancy_elimination.h",
- "backend/sexpression.cc",
- "backend/sexpression.h",
"backend/slot.cc",
"backend/slot.h",
"backend/type_propagator.cc",
@@ -175,7 +169,6 @@
"backend/range_analysis_test.cc",
"backend/reachability_fence_test.cc",
"backend/redundancy_elimination_test.cc",
- "backend/sexpression_test.cc",
"backend/slot_test.cc",
"backend/type_propagator_test.cc",
"backend/typed_data_aot_test.cc",
diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc
index 65332f5..3835109 100644
--- a/runtime/vm/dart.cc
+++ b/runtime/vm/dart.cc
@@ -53,10 +53,6 @@
DEFINE_FLAG(bool, trace_shutdown, false, "Trace VM shutdown on stderr");
DECLARE_FLAG(bool, strong);
-#if defined(DART_PRECOMPILED_RUNTIME)
-DEFINE_FLAG(bool, print_llvm_constant_pool, false, "Print LLVM constant pool");
-#endif
-
Isolate* Dart::vm_isolate_ = NULL;
int64_t Dart::start_time_micros_ = 0;
ThreadPool* Dart::thread_pool_ = NULL;
@@ -811,52 +807,6 @@
#endif // !defined(DART_PRECOMPILED_RUNTIME)
}
-#if defined(DART_PRECOMPILED_RUNTIME)
-static void PrintLLVMConstantPool(Thread* T, Isolate* I) {
- StackZone printing_zone(T);
- HandleScope printing_scope(T);
- TextBuffer b(1000);
- const auto& constants = GrowableObjectArray::Handle(
- I->group()->object_store()->llvm_constant_pool());
- if (constants.IsNull()) {
- b.AddString("No constant pool information in snapshot.\n\n");
- } else {
- auto const len = constants.Length();
- b.Printf("Constant pool contents (length %" Pd "):\n", len);
- auto& obj = Object::Handle();
- for (intptr_t i = 0; i < len; i++) {
- obj = constants.At(i);
- b.Printf(" %5" Pd ": ", i);
- if (obj.IsString()) {
- b.AddChar('"');
- b.AddEscapedString(obj.ToCString());
- b.AddChar('"');
- } else {
- b.AddString(obj.ToCString());
- }
- b.AddChar('\n');
- }
- b.AddString("End of constant pool.\n\n");
- }
- const auto& functions = GrowableObjectArray::Handle(
- I->group()->object_store()->llvm_function_pool());
- if (functions.IsNull()) {
- b.AddString("No function pool information in snapshot.\n\n");
- } else {
- auto const len = functions.Length();
- b.Printf("Function pool contents (length %" Pd "):\n", len);
- auto& obj = Function::Handle();
- for (intptr_t i = 0; i < len; i++) {
- obj ^= functions.At(i);
- ASSERT(!obj.IsNull());
- b.Printf(" %5" Pd ": %s\n", i, obj.ToFullyQualifiedCString());
- }
- b.AddString("End of function pool.\n\n");
- }
- THR_Print("%s", b.buffer());
-}
-#endif
-
ErrorPtr Dart::InitializeIsolate(const uint8_t* snapshot_data,
const uint8_t* snapshot_instructions,
const uint8_t* kernel_buffer,
@@ -913,11 +863,6 @@
#if !defined(TARGET_ARCH_IA32)
ASSERT(IG->object_store()->build_method_extractor_code() != Code::null());
#endif
-#if defined(DART_PRECOMPILED_RUNTIME)
- if (FLAG_print_llvm_constant_pool) {
- PrintLLVMConstantPool(T, I);
- }
-#endif // defined(DART_PRECOMPILED_RUNTIME)
} else {
#if !defined(TARGET_ARCH_IA32)
if (I != Dart::vm_isolate()) {
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 19f8743..cdda785 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -2256,8 +2256,6 @@
}
private:
- friend class FlowGraphSerializer; // For is_megamorphic()
-
static ICDataPtr New();
// Grows the array and also sets the argument to the index that should be used
diff --git a/runtime/vm/object_store.h b/runtime/vm/object_store.h
index 7554f4d..55f8b6d 100644
--- a/runtime/vm/object_store.h
+++ b/runtime/vm/object_store.h
@@ -169,9 +169,6 @@
RW(Function, complete_on_async_return) \
RW(Function, complete_on_async_error) \
RW(Class, async_star_stream_controller) \
- RW(GrowableObjectArray, llvm_constant_pool) \
- RW(GrowableObjectArray, llvm_function_pool) \
- RW(Array, llvm_constant_hash_table) \
RW(CompressedStackMaps, canonicalized_stack_map_entries) \
RW(ObjectPool, global_object_pool) \
RW(Array, unique_dynamic_targets) \
diff --git a/tools/VERSION b/tools/VERSION
index 8f43000..cf2e335 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 13
PATCH 0
-PRERELEASE 123
+PRERELEASE 124
PRERELEASE_PATCH 0
\ No newline at end of file