1// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#include "vm/compiler/backend/il_deserializer.h"
6
7#include "vm/compiler/backend/il_serializer.h"
8#include "vm/compiler/backend/range_analysis.h"
9#include "vm/compiler/call_specializer.h"
10#include "vm/compiler/jit/compiler.h"
11#include "vm/flags.h"
12#include "vm/json_writer.h"
13#include "vm/os.h"
14
15namespace dart {
16
17DEFINE_FLAG(bool,
18 trace_round_trip_serialization,
19 false,
20 "Print out tracing information during round trip serialization.");
21DEFINE_FLAG(bool,
22 print_json_round_trip_results,
23 false,
24 "Print out results of each round trip serialization in JSON form.");
25
26// Contains the contents of a single round-trip result.
27struct RoundTripResults : public ValueObject {
28 explicit RoundTripResults(Zone* zone, const Function& func)
29 : function(func), unhandled(zone, 2) {}
30
31 // The function for which a flow graph was being parsed.
32 const Function& function;
33 // Whether the round trip succeeded.
34 bool success = false;
35 // An array of unhandled instructions found in the flow graph.
36 GrowableArray<Instruction*> unhandled;
37 // The serialized form of the flow graph, if computed.
38 SExpression* serialized = nullptr;
39 // The error information from the deserializer, if an error occurred.
40 const char* error_message = nullptr;
41 SExpression* error_sexp = nullptr;
42};
43
44// Return a textual description of how to find the sub-expression [to_find]
45// inside a [root] S-Expression.
46static const char* GetSExpressionPosition(Zone* zone,
47 SExpression* root,
48 SExpression* to_find) {
49 // The S-expression to find _is_ the root, so no description is needed.
50 if (root == to_find) return "";
51 // The S-expression to find cannot be a sub-expression of the given root,
52 // so return nullptr to signal this.
53 if (!root->IsList()) return nullptr;
54 auto const list = root->AsList();
55 for (intptr_t i = 0, n = list->Length(); i < n; i++) {
56 if (auto const str = GetSExpressionPosition(zone, list->At(i), to_find)) {
57 return OS::SCreate(zone, "element %" Pd "%s%s", i,
58 *str == '\0' ? "" : " -> ", str);
59 }
60 }
61 auto it = list->ExtraIterator();
62 while (auto kv = it.Next()) {
63 if (auto const str = GetSExpressionPosition(zone, kv->value, to_find)) {
64 return OS::SCreate(zone, "label %s%s%s", kv->key,
65 *str == '\0' ? "" : " -> ", str);
66 }
67 }
68 return nullptr;
69}
70
71static void PrintRoundTripResults(Zone* zone, const RoundTripResults& results) {
72 // A few checks to make sure we'll print out enough info. First, if there are
73 // no unhandled instructions, then we should have serialized the flow graph.
74 ASSERT(!results.unhandled.is_empty() || results.serialized != nullptr);
75 // If we failed, then either there are unhandled instructions or we have
76 // an appropriate error message and sexp from the FlowGraphDeserializer.
77 ASSERT(results.success || !results.unhandled.is_empty() ||
78 (results.error_message != nullptr && results.error_sexp != nullptr));
79
80 JSONWriter js;
81
82 js.OpenObject();
83 js.PrintProperty("function", results.function.ToFullyQualifiedCString());
84 js.PrintPropertyBool("success", results.success);
85
86 if (!results.unhandled.is_empty()) {
87 CStringMap<intptr_t> count_map(zone);
88 for (auto inst : results.unhandled) {
89 auto const name = inst->DebugName();
90 auto const old_count = count_map.LookupValue(name);
91 count_map.Update({name, old_count + 1});
92 }
93
94 auto count_it = count_map.GetIterator();
95 js.OpenObject("unhandled");
96 while (auto kv = count_it.Next()) {
97 js.PrintProperty64(kv->key, kv->value);
98 }
99 js.CloseObject();
100 }
101
102 if (results.serialized != nullptr) {
103 TextBuffer buf(1000);
104 results.serialized->SerializeTo(zone, &buf, "");
105 js.PrintProperty("serialized", buf.buffer());
106 }
107
108 if (results.error_message != nullptr) {
109 js.OpenObject("error");
110 js.PrintProperty("message", results.error_message);
111
112 ASSERT(results.error_sexp != nullptr);
113 TextBuffer buf(1000);
114 results.error_sexp->SerializeTo(zone, &buf, "");
115 js.PrintProperty("expression", buf.buffer());
116
117 auto const sexp_position =
118 GetSExpressionPosition(zone, results.serialized, results.error_sexp);
119 js.PrintProperty("path", sexp_position);
120 js.CloseObject();
121 }
122
123 js.CloseObject();
124 THR_Print("Results of round trip serialization: %s\n", js.buffer()->buffer());
125}
126
127void FlowGraphDeserializer::RoundTripSerialization(CompilerPassState* state) {
128 auto const flow_graph = state->flow_graph();
129
130 // The deserialized flow graph must be in the same zone as the original flow
131 // graph, to ensure it has the right lifetime. Thus, we leave an explicit
132 // use of [flow_graph->zone()] in the deserializer construction.
133 //
134 // Otherwise, it would be nice to use a StackZone to limit the lifetime of the
135 // serialized form (and other values created with this [zone] variable), since
136 // it only needs to live for the dynamic extent of this method.
137 //
138 // However, creating a StackZone for it also changes the zone associated with
139 // the thread. Also, some parts of the VM used in later updates to the
140 // deserializer implicitly pick up the zone to use either from a passed-in
141 // thread or the current thread instead of taking an explicit zone.
142 //
143 // For now, just serialize into the same zone as the original flow graph, and
144 // we can revisit this if this causes a performance issue or if we can ensure
145 // that those VM parts mentioned can be passed an explicit zone.
146 Zone* const zone = flow_graph->zone();
147
148 // Final flow graph, if we successfully serialize and deserialize.
149 FlowGraph* new_graph = nullptr;
150
151 // Stored information for printing results if requested.
152 RoundTripResults results(zone, flow_graph->function());
153
154 FlowGraphDeserializer::AllUnhandledInstructions(flow_graph,
155 &results.unhandled);
156 if (results.unhandled.is_empty()) {
157 results.serialized = FlowGraphSerializer::SerializeToSExp(zone, flow_graph);
158
159 if (FLAG_trace_round_trip_serialization && results.serialized != nullptr) {
160 TextBuffer buf(1000);
161 results.serialized->SerializeTo(zone, &buf, "");
162 THR_Print("Serialized flow graph:\n%s\n", buf.buffer());
163 }
164
165 // For the deserializer, use the thread from the compiler pass and zone
166 // associated with the existing flow graph to make sure the new flow graph
167 // has the right lifetime.
168 FlowGraphDeserializer d(state->thread, flow_graph->zone(),
169 results.serialized, &flow_graph->parsed_function());
170 new_graph = d.ParseFlowGraph();
171 if (new_graph == nullptr) {
172 ASSERT(d.error_message() != nullptr && d.error_sexp() != nullptr);
173 if (FLAG_trace_round_trip_serialization) {
174 THR_Print("Failure during deserialization: %s\n", d.error_message());
175 THR_Print("At S-expression %s\n", d.error_sexp()->ToCString(zone));
176 if (auto const pos = GetSExpressionPosition(zone, results.serialized,
177 d.error_sexp())) {
178 THR_Print("Path from root: %s\n", pos);
179 }
180 }
181 results.error_message = d.error_message();
182 results.error_sexp = d.error_sexp();
183 } else {
184 if (FLAG_trace_round_trip_serialization) {
185 THR_Print("Successfully deserialized graph for %s\n",
186 results.serialized->AsList()->At(1)->AsSymbol()->value());
187 }
188 results.success = true;
189 }
190 } else if (FLAG_trace_round_trip_serialization) {
191 THR_Print("Cannot serialize graph due to instruction: %s\n",
192 results.unhandled.At(0)->DebugName());
193 }
194
195 if (FLAG_print_json_round_trip_results) PrintRoundTripResults(zone, results);
196
197 if (new_graph != nullptr) {
198 state->set_flow_graph(new_graph);
199 }
200}
201
202#define HANDLED_CASE(name) \
203 if (inst->Is##name()) return true;
204bool FlowGraphDeserializer::IsHandledInstruction(Instruction* inst) {
205 if (auto const const_inst = inst->AsConstant()) {
206 return IsHandledConstant(const_inst->value());
207 }
208 FOR_EACH_HANDLED_BLOCK_TYPE_IN_DESERIALIZER(HANDLED_CASE)
209 FOR_EACH_HANDLED_INSTRUCTION_IN_DESERIALIZER(HANDLED_CASE)
210 return false;
211}
212#undef HANDLED_CASE
213
214void FlowGraphDeserializer::AllUnhandledInstructions(
215 const FlowGraph* graph,
216 GrowableArray<Instruction*>* unhandled) {
217 ASSERT(graph != nullptr);
218 ASSERT(unhandled != nullptr);
219 for (auto block_it = graph->reverse_postorder_iterator(); !block_it.Done();
220 block_it.Advance()) {
221 auto const entry = block_it.Current();
222 if (!IsHandledInstruction(entry)) unhandled->Add(entry);
223 // Check that the Phi instructions in JoinEntrys do not have pair
224 // representation.
225 if (auto const join_block = entry->AsJoinEntry()) {
226 auto const phis = join_block->phis();
227 auto const length = ((phis == nullptr) ? 0 : phis->length());
228 for (intptr_t i = 0; i < length; i++) {
229 auto const current = phis->At(i);
230 for (intptr_t j = 0; j < current->InputCount(); j++) {
231 if (current->InputAt(j)->definition()->HasPairRepresentation()) {
232 unhandled->Add(current);
233 }
234 }
235 }
236 }
237 if (auto const def_block = entry->AsBlockEntryWithInitialDefs()) {
238 auto const defs = def_block->initial_definitions();
239 for (intptr_t i = 0; i < defs->length(); i++) {
240 auto const current = defs->At(i);
241 if (!IsHandledInstruction(current)) unhandled->Add(current);
242 }
243 }
244 for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) {
245 auto current = it.Current();
246 // We handle branches, so we need to check the comparison instruction.
247 if (current->IsBranch()) current = current->AsBranch()->comparison();
248 if (!IsHandledInstruction(current)) unhandled->Add(current);
249 }
250 }
251}
252
253// Keep in sync with work in ParseDartValue. Right now, this is just a shallow
254// check, not a deep one.
255bool FlowGraphDeserializer::IsHandledConstant(const Object& obj) {
256 if (obj.IsArray()) return Array::Cast(obj).IsImmutable();
257 return obj.IsNull() || obj.IsClass() || obj.IsFunction() || obj.IsField() ||
258 obj.IsInstance();
259}
260
261SExpression* FlowGraphDeserializer::Retrieve(SExpList* list, intptr_t index) {
262 if (list == nullptr) return nullptr;
263 if (list->Length() <= index) {
264 StoreError(list, "expected at least %" Pd " element(s) in list", index + 1);
265 return nullptr;
266 }
267 auto const elem = list->At(index);
268 if (elem == nullptr) {
269 StoreError(list, "null value at index %" Pd "", index);
270 }
271 return elem;
272}
273
274SExpression* FlowGraphDeserializer::Retrieve(SExpList* list, const char* key) {
275 if (list == nullptr) return nullptr;
276 if (!list->ExtraHasKey(key)) {
277 StoreError(list, "expected an extra info entry for key %s", key);
278 return nullptr;
279 }
280 auto const elem = list->ExtraLookupValue(key);
281 if (elem == nullptr) {
282 StoreError(list, "null value for key %s", key);
283 }
284 return elem;
285}
286
287FlowGraph* FlowGraphDeserializer::ParseFlowGraph() {
288 auto const root = CheckTaggedList(root_sexp_, "FlowGraph");
289 if (root == nullptr) return nullptr;
290
291 intptr_t deopt_id = DeoptId::kNone;
292 if (auto const deopt_id_sexp =
293 CheckInteger(root->ExtraLookupValue("deopt_id"))) {
294 deopt_id = deopt_id_sexp->value();
295 }
296 EntryInfo common_info = {0, kInvalidTryIndex, deopt_id};
297
298 auto const graph = DeserializeGraphEntry(root, common_info);
299
300 PrologueInfo pi(-1, -1);
301 flow_graph_ = new (zone()) FlowGraph(*parsed_function_, graph, 0, pi);
302 flow_graph_->CreateCommonConstants();
303
304 intptr_t pos = 2;
305 if (auto const pool = CheckTaggedList(Retrieve(root, pos), "Constants")) {
306 if (!ParseConstantPool(pool)) return nullptr;
307 pos++;
308 }
309
310 // The deopt environment for the graph entry may use entries from the
311 // constant pool, so that must be parsed first.
312 if (auto const env_sexp = CheckList(root->ExtraLookupValue("env"))) {
313 current_block_ = graph;
314 auto const env = ParseEnvironment(env_sexp);
315 if (env == nullptr) return nullptr;
316 env->DeepCopyTo(zone(), graph);
317 }
318
319 auto const entries_sexp = CheckTaggedList(Retrieve(root, pos), "Entries");
320 if (!ParseEntries(entries_sexp)) return nullptr;
321 pos++;
322
323 // Now prime the block worklist with entries. We keep the block worklist
324 // in reverse order so that we can just pop the next block for content
325 // parsing off the end.
326 BlockWorklist block_worklist(zone(), entries_sexp->Length() - 1);
327
328 const auto& indirect_entries = graph->indirect_entries();
329 for (auto indirect_entry : indirect_entries) {
330 block_worklist.Add(indirect_entry->block_id());
331 }
332
333 const auto& catch_entries = graph->catch_entries();
334 for (auto catch_entry : catch_entries) {
335 block_worklist.Add(catch_entry->block_id());
336 }
337
338 if (auto const osr_entry = graph->osr_entry()) {
339 block_worklist.Add(osr_entry->block_id());
340 }
341 if (auto const unchecked_entry = graph->unchecked_entry()) {
342 block_worklist.Add(unchecked_entry->block_id());
343 }
344 if (auto const normal_entry = graph->normal_entry()) {
345 block_worklist.Add(normal_entry->block_id());
346 }
347
348 if (!ParseBlocks(root, pos, &block_worklist)) return nullptr;
349
350 // Before we return the new graph, make sure all definitions were found for
351 // all pending values.
352 if (values_map_.Length() > 0) {
353 auto it = values_map_.GetIterator();
354 auto const kv = it.Next();
355 ASSERT(kv->value->length() > 0);
356 const auto& value_info = kv->value->At(0);
357 StoreError(value_info.sexp, "no definition found for use in flow graph");
358 return nullptr;
359 }
360
361 flow_graph_->set_max_block_id(max_block_id_);
362 // The highest numbered SSA temp might need two slots (e.g. for unboxed
363 // integers on 32-bit platforms), so we add 2 to the highest seen SSA temp
364 // index to get to the new current SSA temp index. In cases where the highest
365 // numbered SSA temp originally had only one slot assigned, this can result
366 // in different SSA temp numbering in later passes between the original and
367 // deserialized graphs.
368 flow_graph_->set_current_ssa_temp_index(max_ssa_index_ + 2);
369 // Now that the deserializer has finished re-creating all the blocks in the
370 // flow graph, the blocks must be rediscovered. In addition, if ComputeSSA
371 // has already been run, dominators must be recomputed as well.
372 flow_graph_->DiscoverBlocks();
373 // Currently we only handle SSA graphs, so always do this.
374 GrowableArray<BitVector*> dominance_frontier;
375 flow_graph_->ComputeDominators(&dominance_frontier);
376
377 return flow_graph_;
378}
379
380bool FlowGraphDeserializer::ParseConstantPool(SExpList* pool) {
381 ASSERT(flow_graph_ != nullptr);
382 if (pool == nullptr) return false;
383 // Definitions in the constant pool may refer to later definitions. However,
384 // there should be no cycles possible between constant objects, so using a
385 // worklist algorithm we should always be able to make progress.
386 // Since we will not be adding new definitions, we make the initial size of
387 // the worklist the number of definitions in the constant pool.
388 GrowableArray<SExpList*> worklist(zone(), pool->Length() - 1);
389 // In order to ensure that the definition order is the same in the original
390 // flow graph, we can't just simply call GetConstant() whenever we
391 // successfully parse a constant. Instead, we'll create a stand-in
392 // ConstantInstr that we can temporarily stick in the definition_map_, and
393 // then once finished we'll go back through, add the constants via
394 // GetConstant() and parse any extra information.
395 DirectChainedHashMap<RawPointerKeyValueTrait<SExpList, ConstantInstr*>>
396 parsed_constants(zone());
397 // We keep old_worklist in reverse order so that we can just RemoveLast
398 // to get elements in their original order.
399 for (intptr_t i = pool->Length() - 1; i > 0; i--) {
400 const auto def_sexp = CheckTaggedList(pool->At(i), "def");
401 if (def_sexp == nullptr) return false;
402 worklist.Add(def_sexp);
403 }
404 while (true) {
405 const intptr_t worklist_len = worklist.length();
406 GrowableArray<SExpList*> parse_failures(zone(), worklist_len);
407 while (!worklist.is_empty()) {
408 const auto def_sexp = worklist.RemoveLast();
409 auto& obj = Object::ZoneHandle(zone());
410 if (!ParseDartValue(Retrieve(def_sexp, 2), &obj)) {
411 parse_failures.Add(def_sexp);
412 continue;
413 }
414 ConstantInstr* def = new (zone()) ConstantInstr(obj);
415 // Instead of parsing the whole definition, just get the SSA index so
416 // we can insert it into the definition_map_.
417 intptr_t index;
418 auto const name_sexp = CheckSymbol(Retrieve(def_sexp, 1));
419 if (!ParseSSATemp(name_sexp, &index)) return false;
420 def->set_ssa_temp_index(index);
421 ASSERT(!definition_map_.HasKey(index));
422 definition_map_.Insert(index, def);
423 parsed_constants.Insert({def_sexp, def});
424 }
425 if (parse_failures.is_empty()) break;
426 // We've gone through the whole worklist without success, so return
427 // the last error we encountered.
428 if (parse_failures.length() == worklist_len) return false;
429 // worklist was added to in order, so we need to reverse its contents
430 // when we add them to old_worklist.
431 while (!parse_failures.is_empty()) {
432 worklist.Add(parse_failures.RemoveLast());
433 }
434 }
435 // Now loop back through the constant pool definition S-expressions and
436 // get the real ConstantInstrs the flow graph will be using and finish
437 // parsing.
438 for (intptr_t i = 1; i < pool->Length(); i++) {
439 auto const def_sexp = CheckTaggedList(pool->At(i));
440 auto const temp_def = parsed_constants.LookupValue(def_sexp);
441 ASSERT(temp_def != nullptr);
442 // Remove the temporary definition from definition_map_ so this doesn't get
443 // flagged as a redefinition.
444 definition_map_.Remove(temp_def->ssa_temp_index());
445 ConstantInstr* real_def = flow_graph_->GetConstant(temp_def->value());
446 if (!ParseDefinitionWithParsedBody(def_sexp, real_def)) return false;
447 ASSERT(temp_def->ssa_temp_index() == real_def->ssa_temp_index());
448 }
449 return true;
450}
451
452bool FlowGraphDeserializer::ParseEntries(SExpList* list) {
453 ASSERT(flow_graph_ != nullptr);
454 if (list == nullptr) return false;
455 for (intptr_t i = 1; i < list->Length(); i++) {
456 const auto entry = CheckTaggedList(Retrieve(list, i));
457 if (entry == nullptr) return false;
458 intptr_t block_id;
459 if (!ParseBlockId(CheckSymbol(Retrieve(entry, 1)), &block_id)) {
460 return false;
461 }
462 if (block_map_.LookupValue(block_id) != nullptr) {
463 StoreError(entry->At(1), "multiple entries for block found");
464 return false;
465 }
466 const auto tag = entry->Tag();
467 if (ParseBlockHeader(entry, block_id, tag) == nullptr) return false;
468 }
469 return true;
470}
471
472bool FlowGraphDeserializer::ParseBlocks(SExpList* list,
473 intptr_t pos,
474 BlockWorklist* worklist) {
475 // First, ensure that all the block headers have been parsed. Set up a
476 // map from block IDs to S-expressions and the max_block_id while we're at it.
477 IntMap<SExpList*> block_sexp_map(zone());
478 for (intptr_t i = pos, n = list->Length(); i < n; i++) {
479 auto const block_sexp = CheckTaggedList(Retrieve(list, i), "Block");
480 intptr_t block_id;
481 if (!ParseBlockId(CheckSymbol(Retrieve(block_sexp, 1)), &block_id)) {
482 return false;
483 }
484 if (block_sexp_map.LookupValue(block_id) != nullptr) {
485 StoreError(block_sexp->At(1), "multiple definitions of block found");
486 return false;
487 }
488 block_sexp_map.Insert(block_id, block_sexp);
489 auto const type_tag =
490 CheckSymbol(block_sexp->ExtraLookupValue("block_type"));
491 // Entry block headers are already parsed, but others aren't.
492 if (block_map_.LookupValue(block_id) == nullptr) {
493 if (ParseBlockHeader(block_sexp, block_id, type_tag) == nullptr) {
494 return false;
495 }
496 }
497 if (max_block_id_ < block_id) max_block_id_ = block_id;
498 }
499
500 // Now start parsing the contents of blocks from the worklist. We use an
501 // IntMap to keep track of what blocks have already been fully parsed.
502 IntMap<bool> fully_parsed_block_map(zone());
503 while (!worklist->is_empty()) {
504 auto const block_id = worklist->RemoveLast();
505
506 // If we've already encountered this block, skip it.
507 if (fully_parsed_block_map.LookupValue(block_id)) continue;
508
509 auto const block_sexp = block_sexp_map.LookupValue(block_id);
510 ASSERT(block_sexp != nullptr);
511
512 current_block_ = block_map_.LookupValue(block_id);
513 ASSERT(current_block_ != nullptr);
514 ASSERT(current_block_->PredecessorCount() > 0);
515
516 if (!ParseBlockContents(block_sexp, worklist)) return false;
517
518 // Mark this block as done.
519 fully_parsed_block_map.Insert(block_id, true);
520 }
521
522 // Double-check that all blocks were reached by the worklist algorithm.
523 auto it = block_sexp_map.GetIterator();
524 while (auto kv = it.Next()) {
525 if (!fully_parsed_block_map.LookupValue(kv->key)) {
526 StoreError(kv->value, "block unreachable in flow graph");
527 return false;
528 }
529 }
530
531 return true;
532}
533
534bool FlowGraphDeserializer::ParseInitialDefinitions(SExpList* list) {
535 ASSERT(current_block_ != nullptr);
536 ASSERT(current_block_->IsBlockEntryWithInitialDefs());
537 auto const block = current_block_->AsBlockEntryWithInitialDefs();
538 if (list == nullptr) return false;
539 for (intptr_t i = 2; i < list->Length(); i++) {
540 const auto def_sexp = CheckTaggedList(Retrieve(list, i), "def");
541 const auto def = ParseDefinition(def_sexp);
542 if (def == nullptr) return false;
543 flow_graph_->AddToInitialDefinitions(block, def);
544 }
545 return true;
546}
547
548BlockEntryInstr* FlowGraphDeserializer::ParseBlockHeader(SExpList* list,
549 intptr_t block_id,
550 SExpSymbol* tag) {
551 ASSERT(flow_graph_ != nullptr);
552 // We should only parse block headers once.
553 ASSERT(block_map_.LookupValue(block_id) == nullptr);
554 if (list == nullptr) return nullptr;
555
556#if defined(DEBUG)
557 intptr_t parsed_block_id;
558 auto const id_sexp = CheckSymbol(Retrieve(list, 1));
559 if (!ParseBlockId(id_sexp, &parsed_block_id)) return nullptr;
560 ASSERT(block_id == parsed_block_id);
561#endif
562
563 auto const kind = FlowGraphSerializer::BlockEntryTagToKind(tag);
564
565 intptr_t deopt_id = DeoptId::kNone;
566 if (auto const deopt_int = CheckInteger(list->ExtraLookupValue("deopt_id"))) {
567 deopt_id = deopt_int->value();
568 }
569 intptr_t try_index = kInvalidTryIndex;
570 if (auto const try_int = CheckInteger(list->ExtraLookupValue("try_index"))) {
571 try_index = try_int->value();
572 }
573
574 BlockEntryInstr* block = nullptr;
575 EntryInfo common_info = {block_id, try_index, deopt_id};
576 switch (kind) {
577 case FlowGraphSerializer::kTarget:
578 block = DeserializeTargetEntry(list, common_info);
579 break;
580 case FlowGraphSerializer::kNormal:
581 block = DeserializeFunctionEntry(list, common_info);
582 if (block != nullptr) {
583 auto const graph = flow_graph_->graph_entry();
584 graph->set_normal_entry(block->AsFunctionEntry());
585 }
586 break;
587 case FlowGraphSerializer::kUnchecked: {
588 block = DeserializeFunctionEntry(list, common_info);
589 if (block != nullptr) {
590 auto const graph = flow_graph_->graph_entry();
591 graph->set_unchecked_entry(block->AsFunctionEntry());
592 }
593 break;
594 }
595 case FlowGraphSerializer::kJoin:
596 block = DeserializeJoinEntry(list, common_info);
597 break;
598 case FlowGraphSerializer::kInvalid:
599 StoreError(tag, "invalid block entry tag");
600 return nullptr;
601 default:
602 StoreError(tag, "unhandled block type");
603 return nullptr;
604 }
605 if (block == nullptr) return nullptr;
606
607 block_map_.Insert(block_id, block);
608 return block;
609}
610
611bool FlowGraphDeserializer::ParsePhis(SExpList* list) {
612 ASSERT(current_block_ != nullptr && current_block_->IsJoinEntry());
613 auto const join = current_block_->AsJoinEntry();
614 const intptr_t start_pos = 2;
615 auto const end_pos = SkipPhis(list);
616 if (end_pos < start_pos) return false;
617
618 for (intptr_t i = start_pos; i < end_pos; i++) {
619 auto const def_sexp = CheckTaggedList(Retrieve(list, i), "def");
620 auto const phi_sexp = CheckTaggedList(Retrieve(def_sexp, 2), "Phi");
621 // SkipPhis should already have checked which instructions, if any,
622 // are Phi definitions.
623 ASSERT(phi_sexp != nullptr);
624
625 // This is a generalization of FlowGraph::AddPhi where we let ParseValue
626 // create the values (as they may contain type information).
627 auto const phi = new (zone()) PhiInstr(join, phi_sexp->Length() - 1);
628 phi->mark_alive();
629 for (intptr_t i = 0, n = phi_sexp->Length() - 1; i < n; i++) {
630 auto const val = ParseValue(Retrieve(phi_sexp, i + 1));
631 if (val == nullptr) return false;
632 phi->SetInputAt(i, val);
633 val->definition()->AddInputUse(val);
634 }
635 join->InsertPhi(phi);
636
637 if (!ParseDefinitionWithParsedBody(def_sexp, phi)) return false;
638 }
639
640 return true;
641}
642
643intptr_t FlowGraphDeserializer::SkipPhis(SExpList* list) {
644 // All blocks are S-exps of the form (Block B# inst...), so skip the first
645 // two entries and then skip any Phi definitions.
646 for (intptr_t i = 2, n = list->Length(); i < n; i++) {
647 auto const def_sexp = CheckTaggedList(Retrieve(list, i), "def");
648 if (def_sexp == nullptr) return i;
649 auto const phi_sexp = CheckTaggedList(Retrieve(def_sexp, 2), "Phi");
650 if (phi_sexp == nullptr) return i;
651 }
652
653 StoreError(list, "block is empty or contains only Phi definitions");
654 return -1;
655}
656
657bool FlowGraphDeserializer::ParseBlockContents(SExpList* list,
658 BlockWorklist* worklist) {
659 ASSERT(current_block_ != nullptr);
660
661 // Parse any Phi definitions now before parsing the block environment.
662 if (current_block_->IsJoinEntry()) {
663 if (!ParsePhis(list)) return false;
664 }
665
666 // For blocks with initial definitions or phi definitions, this needs to be
667 // done after those are parsed. In addition, block environments can also use
668 // definitions from dominating blocks, so we need the contents of dominating
669 // blocks to first be parsed.
670 //
671 // However, we must parse the environment before parsing any instructions
672 // in the body of the block to ensure we don't mistakenly allow local
673 // definitions to appear in the environment.
674 if (auto const env_sexp = CheckList(list->ExtraLookupValue("env"))) {
675 auto const env = ParseEnvironment(env_sexp);
676 if (env == nullptr) return false;
677 env->DeepCopyTo(zone(), current_block_);
678 }
679
680 auto const pos = SkipPhis(list);
681 if (pos < 2) return false;
682 Instruction* last_inst = current_block_;
683 for (intptr_t i = pos, n = list->Length(); i < n; i++) {
684 auto const inst = ParseInstruction(CheckTaggedList(Retrieve(list, i)));
685 if (inst == nullptr) return false;
686 last_inst = last_inst->AppendInstruction(inst);
687 }
688
689 ASSERT(last_inst != nullptr && last_inst != current_block_);
690 if (last_inst->SuccessorCount() > 0) {
691 for (intptr_t i = last_inst->SuccessorCount() - 1; i >= 0; i--) {
692 auto const succ_block = last_inst->SuccessorAt(i);
693 succ_block->AddPredecessor(current_block_);
694 worklist->Add(succ_block->block_id());
695 }
696 }
697
698 return true;
699}
700
701bool FlowGraphDeserializer::ParseDefinitionWithParsedBody(SExpList* list,
702 Definition* def) {
703 if (auto const type_sexp =
704 CheckTaggedList(list->ExtraLookupValue("type"), "CompileType")) {
705 CompileType* typ = ParseCompileType(type_sexp);
706 if (typ == nullptr) return false;
707 def->UpdateType(*typ);
708 }
709
710 if (auto const range_sexp =
711 CheckTaggedList(list->ExtraLookupValue("range"), "Range")) {
712 Range range;
713 if (!ParseRange(range_sexp, &range)) return false;
714 def->set_range(range);
715 }
716
717 auto const name_sexp = CheckSymbol(Retrieve(list, 1));
718 if (name_sexp == nullptr) return false;
719
720 // If the name is "_", this is a subclass of Definition where there's no real
721 // "result" that's being bound. We were just here to add Definition-specific
722 // extra info.
723 if (name_sexp->Equals("_")) return true;
724
725 intptr_t index;
726 if (ParseSSATemp(name_sexp, &index)) {
727 if (definition_map_.HasKey(index)) {
728 StoreError(list, "multiple definitions for the same SSA index");
729 return false;
730 }
731 def->set_ssa_temp_index(index);
732 if (index > max_ssa_index_) max_ssa_index_ = index;
733 } else {
734 // TODO(sstrickl): Add temp support for non-SSA computed graphs.
735 StoreError(list, "unhandled name for definition");
736 return false;
737 }
738
739 definition_map_.Insert(index, def);
740 if (!FixPendingValues(index, def)) return false;
741 return true;
742}
743
744Definition* FlowGraphDeserializer::ParseDefinition(SExpList* list) {
745 if (list == nullptr) return nullptr;
746 ASSERT(list->Tag() != nullptr && list->Tag()->Equals("def"));
747 auto const inst_sexp = CheckTaggedList(Retrieve(list, 2));
748 auto const inst = ParseInstruction(inst_sexp);
749 if (inst == nullptr) return nullptr;
750 if (auto const def = inst->AsDefinition()) {
751 if (!ParseDefinitionWithParsedBody(list, def)) return nullptr;
752 return def;
753 } else {
754 StoreError(list, "instruction cannot be body of definition");
755 return nullptr;
756 }
757}
758
759Instruction* FlowGraphDeserializer::ParseInstruction(SExpList* list) {
760 if (list == nullptr) return nullptr;
761 auto const tag = list->Tag();
762 if (tag->Equals("def")) return ParseDefinition(list);
763
764 intptr_t deopt_id = DeoptId::kNone;
765 if (auto const deopt_int = CheckInteger(list->ExtraLookupValue("deopt_id"))) {
766 deopt_id = deopt_int->value();
767 }
768 TokenPosition token_pos = TokenPosition::kNoSource;
769 if (auto const token_int =
770 CheckInteger(list->ExtraLookupValue("token_pos"))) {
771 token_pos = TokenPosition(token_int->value());
772 }
773 InstrInfo common_info = {deopt_id, token_pos};
774
775 // Parse the environment before handling the instruction, as we may have
776 // references to PushArguments and parsing the instruction may pop
777 // PushArguments off the stack.
778 // TODO(alexmarkov): revise as it may not be needed anymore.
779 Environment* env = nullptr;
780 if (auto const env_sexp = CheckList(list->ExtraLookupValue("env"))) {
781 env = ParseEnvironment(env_sexp);
782 if (env == nullptr) return nullptr;
783 }
784
785 Instruction* inst = nullptr;
786
787#define HANDLE_CASE(name) \
788 case kHandled##name: \
789 inst = Deserialize##name(list, common_info); \
790 break;
791 switch (HandledInstructionForTag(tag)) {
792 FOR_EACH_HANDLED_INSTRUCTION_IN_DESERIALIZER(HANDLE_CASE)
793 case kHandledInvalid:
794 StoreError(tag, "unhandled instruction");
795 return nullptr;
796 }
797#undef HANDLE_CASE
798
799 if (inst == nullptr) return nullptr;
800 if (env != nullptr) env->DeepCopyTo(zone(), inst);
801 return inst;
802}
803
804FunctionEntryInstr* FlowGraphDeserializer::DeserializeFunctionEntry(
805 SExpList* sexp,
806 const EntryInfo& info) {
807 ASSERT(flow_graph_ != nullptr);
808 auto const graph = flow_graph_->graph_entry();
809 auto const block = new (zone())
810 FunctionEntryInstr(graph, info.block_id, info.try_index, info.deopt_id);
811 current_block_ = block;
812 if (!ParseInitialDefinitions(sexp)) return nullptr;
813 return block;
814}
815
816GraphEntryInstr* FlowGraphDeserializer::DeserializeGraphEntry(
817 SExpList* sexp,
818 const EntryInfo& info) {
819 auto const name_sexp = CheckSymbol(Retrieve(sexp, 1));
820 // TODO(sstrickl): If the FlowGraphDeserializer was constructed with a
821 // non-null ParsedFunction, we should check that the name matches here.
822 // If not, then we should create an appropriate ParsedFunction here.
823 if (name_sexp == nullptr) return nullptr;
824
825 intptr_t osr_id = Compiler::kNoOSRDeoptId;
826 if (auto const osr_id_sexp = CheckInteger(sexp->ExtraLookupValue("osr_id"))) {
827 osr_id = osr_id_sexp->value();
828 }
829
830 ASSERT(parsed_function_ != nullptr);
831 return new (zone()) GraphEntryInstr(*parsed_function_, osr_id, info.deopt_id);
832}
833
834JoinEntryInstr* FlowGraphDeserializer::DeserializeJoinEntry(
835 SExpList* sexp,
836 const EntryInfo& info) {
837 return new (zone())
838 JoinEntryInstr(info.block_id, info.try_index, info.deopt_id);
839}
840
841TargetEntryInstr* FlowGraphDeserializer::DeserializeTargetEntry(
842 SExpList* sexp,
843 const EntryInfo& info) {
844 return new (zone())
845 TargetEntryInstr(info.block_id, info.try_index, info.deopt_id);
846}
847
848AllocateObjectInstr* FlowGraphDeserializer::DeserializeAllocateObject(
849 SExpList* sexp,
850 const InstrInfo& info) {
851 auto& cls = Class::ZoneHandle(zone());
852 auto const cls_sexp = CheckTaggedList(Retrieve(sexp, 1), "Class");
853 if (!ParseClass(cls_sexp, &cls)) return nullptr;
854
855 Value* type_arguments = nullptr;
856 if (cls.NumTypeArguments() > 0) {
857 type_arguments = ParseValue(Retrieve(sexp, 2));
858 if (type_arguments == nullptr) return nullptr;
859 }
860
861 auto const inst =
862 new (zone()) AllocateObjectInstr(info.token_pos, cls, type_arguments);
863
864 if (auto const closure_sexp = CheckTaggedList(
865 sexp->ExtraLookupValue("closure_function"), "Function")) {
866 auto& closure_function = Function::Handle(zone());
867 if (!ParseFunction(closure_sexp, &closure_function)) return nullptr;
868 inst->set_closure_function(closure_function);
869 }
870
871 if (auto const ident_sexp = CheckSymbol(sexp->ExtraLookupValue("identity"))) {
872 auto id = AliasIdentity::Unknown();
873 if (!AliasIdentity::Parse(ident_sexp->value(), &id)) {
874 return nullptr;
875 }
876 inst->SetIdentity(id);
877 }
878
879 return inst;
880}
881
882AssertAssignableInstr* FlowGraphDeserializer::DeserializeAssertAssignable(
883 SExpList* sexp,
884 const InstrInfo& info) {
885 auto const val = ParseValue(Retrieve(sexp, 1));
886 if (val == nullptr) return nullptr;
887
888 auto const dst_type = ParseValue(Retrieve(sexp, 2));
889 if (dst_type == nullptr) return nullptr;
890
891 auto const inst_type_args = ParseValue(Retrieve(sexp, 3));
892 if (inst_type_args == nullptr) return nullptr;
893
894 auto const func_type_args = ParseValue(Retrieve(sexp, 4));
895 if (func_type_args == nullptr) return nullptr;
896
897 auto& dst_name = String::ZoneHandle(zone());
898 auto const dst_name_sexp = Retrieve(sexp, "name");
899 if (!ParseDartValue(dst_name_sexp, &dst_name)) return nullptr;
900
901 auto kind = AssertAssignableInstr::Kind::kUnknown;
902 if (auto const kind_sexp = CheckSymbol(sexp->ExtraLookupValue("kind"))) {
903 if (!AssertAssignableInstr::ParseKind(kind_sexp->value(), &kind)) {
904 StoreError(kind_sexp, "unknown AssertAssignable kind");
905 return nullptr;
906 }
907 }
908
909 return new (zone())
910 AssertAssignableInstr(info.token_pos, val, dst_type, inst_type_args,
911 func_type_args, dst_name, info.deopt_id, kind);
912}
913
914AssertBooleanInstr* FlowGraphDeserializer::DeserializeAssertBoolean(
915 SExpList* sexp,
916 const InstrInfo& info) {
917 auto const val = ParseValue(Retrieve(sexp, 1));
918 if (val == nullptr) return nullptr;
919
920 return new (zone()) AssertBooleanInstr(info.token_pos, val, info.deopt_id);
921}
922
923BooleanNegateInstr* FlowGraphDeserializer::DeserializeBooleanNegate(
924 SExpList* sexp,
925 const InstrInfo& info) {
926 auto const value = ParseValue(Retrieve(sexp, 1));
927 if (value == nullptr) return nullptr;
928
929 return new (zone()) BooleanNegateInstr(value);
930}
931
932BranchInstr* FlowGraphDeserializer::DeserializeBranch(SExpList* sexp,
933 const InstrInfo& info) {
934 auto const comp_sexp = CheckTaggedList(Retrieve(sexp, 1));
935 auto const comp_inst = ParseInstruction(comp_sexp);
936 if (comp_inst == nullptr) return nullptr;
937 if (!comp_inst->IsComparison()) {
938 StoreError(sexp->At(1), "expected comparison instruction");
939 return nullptr;
940 }
941 auto const comparison = comp_inst->AsComparison();
942
943 auto const true_block = FetchBlock(CheckSymbol(Retrieve(sexp, 2)));
944 if (true_block == nullptr) return nullptr;
945 if (!true_block->IsTargetEntry()) {
946 StoreError(sexp->At(2), "true successor is not a target block");
947 return nullptr;
948 }
949
950 auto const false_block = FetchBlock(CheckSymbol(Retrieve(sexp, 3)));
951 if (false_block == nullptr) return nullptr;
952 if (!false_block->IsTargetEntry()) {
953 StoreError(sexp->At(3), "false successor is not a target block");
954 return nullptr;
955 }
956
957 auto const branch = new (zone()) BranchInstr(comparison, info.deopt_id);
958 *branch->true_successor_address() = true_block->AsTargetEntry();
959 *branch->false_successor_address() = false_block->AsTargetEntry();
960 return branch;
961}
962
963CheckNullInstr* FlowGraphDeserializer::DeserializeCheckNull(
964 SExpList* sexp,
965 const InstrInfo& info) {
966 auto const val = ParseValue(Retrieve(sexp, 1));
967 if (val == nullptr) return nullptr;
968
969 auto& func_name = String::ZoneHandle(zone());
970 if (auto const name_sexp =
971 CheckString(sexp->ExtraLookupValue("function_name"))) {
972 func_name = String::New(name_sexp->value(), Heap::kOld);
973 }
974
975 return new (zone())
976 CheckNullInstr(val, func_name, info.deopt_id, info.token_pos);
977}
978
979CheckStackOverflowInstr* FlowGraphDeserializer::DeserializeCheckStackOverflow(
980 SExpList* sexp,
981 const InstrInfo& info) {
982 intptr_t stack_depth = 0;
983 if (auto const stack_sexp =
984 CheckInteger(sexp->ExtraLookupValue("stack_depth"))) {
985 stack_depth = stack_sexp->value();
986 }
987
988 intptr_t loop_depth = 0;
989 if (auto const loop_sexp =
990 CheckInteger(sexp->ExtraLookupValue("loop_depth"))) {
991 loop_depth = loop_sexp->value();
992 }
993
994 auto kind = CheckStackOverflowInstr::kOsrAndPreemption;
995 if (auto const kind_sexp = CheckSymbol(sexp->ExtraLookupValue("kind"))) {
996 ASSERT(kind_sexp->Equals("OsrOnly"));
997 kind = CheckStackOverflowInstr::kOsrOnly;
998 }
999
1000 return new (zone()) CheckStackOverflowInstr(info.token_pos, stack_depth,
1001 loop_depth, info.deopt_id, kind);
1002}
1003
1004ConstantInstr* FlowGraphDeserializer::DeserializeConstant(
1005 SExpList* sexp,
1006 const InstrInfo& info) {
1007 Object& obj = Object::ZoneHandle(zone());
1008 if (!ParseDartValue(Retrieve(sexp, 1), &obj)) return nullptr;
1009 return new (zone()) ConstantInstr(obj, info.token_pos);
1010}
1011
1012DebugStepCheckInstr* FlowGraphDeserializer::DeserializeDebugStepCheck(
1013 SExpList* sexp,
1014 const InstrInfo& info) {
1015 auto kind = PcDescriptorsLayout::kAnyKind;
1016 if (auto const kind_sexp = CheckSymbol(Retrieve(sexp, "stub_kind"))) {
1017 if (!PcDescriptorsLayout::ParseKind(kind_sexp->value(), &kind)) {
1018 StoreError(kind_sexp, "not a valid PcDescriptorsLayout::Kind name");
1019 return nullptr;
1020 }
1021 }
1022 return new (zone()) DebugStepCheckInstr(info.token_pos, kind, info.deopt_id);
1023}
1024
1025GotoInstr* FlowGraphDeserializer::DeserializeGoto(SExpList* sexp,
1026 const InstrInfo& info) {
1027 auto const block = FetchBlock(CheckSymbol(Retrieve(sexp, 1)));
1028 if (block == nullptr) return nullptr;
1029 if (!block->IsJoinEntry()) {
1030 StoreError(sexp->At(1), "target of goto must be join entry");
1031 return nullptr;
1032 }
1033 return new (zone()) GotoInstr(block->AsJoinEntry(), info.deopt_id);
1034}
1035
1036InstanceCallInstr* FlowGraphDeserializer::DeserializeInstanceCall(
1037 SExpList* sexp,
1038 const InstrInfo& info) {
1039 auto& interface_target = Function::ZoneHandle(zone());
1040 auto& tearoff_interface_target = Function::ZoneHandle(zone());
1041 if (!ParseDartValue(Retrieve(sexp, "interface_target"), &interface_target)) {
1042 return nullptr;
1043 }
1044 if (!ParseDartValue(Retrieve(sexp, "tearoff_interface_target"),
1045 &tearoff_interface_target)) {
1046 return nullptr;
1047 }
1048 auto& function_name = String::ZoneHandle(zone());
1049 // If we have an explicit function_name value, then use that value. Otherwise,
1050 // if we have an non-null interface_target, use its name.
1051 if (auto const name_sexp = sexp->ExtraLookupValue("function_name")) {
1052 if (!ParseDartValue(name_sexp, &function_name)) return nullptr;
1053 } else if (!interface_target.IsNull()) {
1054 function_name = interface_target.name();
1055 } else if (!tearoff_interface_target.IsNull()) {
1056 function_name = tearoff_interface_target.name();
1057 }
1058
1059 auto token_kind = Token::Kind::kILLEGAL;
1060 if (auto const kind_sexp =
1061 CheckSymbol(sexp->ExtraLookupValue("token_kind"))) {
1062 if (!Token::FromStr(kind_sexp->value(), &token_kind)) {
1063 StoreError(kind_sexp, "unexpected token kind");
1064 return nullptr;
1065 }
1066 }
1067
1068 CallInfo call_info(zone());
1069 if (!ParseCallInfo(sexp, &call_info)) return nullptr;
1070
1071 intptr_t checked_arg_count = 0;
1072 if (auto const checked_sexp =
1073 CheckInteger(sexp->ExtraLookupValue("checked_arg_count"))) {
1074 checked_arg_count = checked_sexp->value();
1075 }
1076
1077 auto const inst = new (zone()) InstanceCallInstr(
1078 info.token_pos, function_name, token_kind, call_info.inputs,
1079 call_info.type_args_len, call_info.argument_names, checked_arg_count,
1080 info.deopt_id, interface_target, tearoff_interface_target);
1081
1082 if (call_info.result_type != nullptr) {
1083 inst->SetResultType(zone(), *call_info.result_type);
1084 }
1085
1086 inst->set_entry_kind(call_info.entry_kind);
1087
1088 if (auto const ic_data_sexp =
1089 CheckTaggedList(Retrieve(sexp, "ic_data"), "ICData")) {
1090 if (!CreateICData(ic_data_sexp, inst)) return nullptr;
1091 }
1092
1093 return inst;
1094}
1095
1096LoadClassIdInstr* FlowGraphDeserializer::DeserializeLoadClassId(
1097 SExpList* sexp,
1098 const InstrInfo& info) {
1099 auto const val = ParseValue(Retrieve(sexp, 1));
1100 if (val == nullptr) return nullptr;
1101
1102 return new (zone()) LoadClassIdInstr(val);
1103}
1104
1105LoadFieldInstr* FlowGraphDeserializer::DeserializeLoadField(
1106 SExpList* sexp,
1107 const InstrInfo& info) {
1108 auto const instance = ParseValue(Retrieve(sexp, 1));
1109 if (instance == nullptr) return nullptr;
1110
1111 const Slot* slot;
1112 if (!ParseSlot(CheckTaggedList(Retrieve(sexp, 2)), &slot)) return nullptr;
1113
1114 bool calls_initializer = false;
1115 if (auto const calls_initializer_sexp =
1116 CheckBool(sexp->ExtraLookupValue("calls_initializer"))) {
1117 calls_initializer = calls_initializer_sexp->value();
1118 }
1119
1120 return new (zone()) LoadFieldInstr(instance, *slot, info.token_pos,
1121 calls_initializer, info.deopt_id);
1122}
1123
1124NativeCallInstr* FlowGraphDeserializer::DeserializeNativeCall(
1125 SExpList* sexp,
1126 const InstrInfo& info) {
1127 auto& function = Function::ZoneHandle(zone());
1128 if (!ParseDartValue(Retrieve(sexp, "function"), &function)) return nullptr;
1129 if (!function.IsFunction()) {
1130 StoreError(sexp->At(1), "expected a Function value");
1131 return nullptr;
1132 }
1133
1134 auto const name_sexp = CheckString(Retrieve(sexp, "name"));
1135 if (name_sexp == nullptr) return nullptr;
1136 const auto& name =
1137 String::ZoneHandle(zone(), String::New(name_sexp->value()));
1138
1139 bool link_lazily = false;
1140 if (auto const link_sexp = CheckBool(sexp->ExtraLookupValue("link_lazily"))) {
1141 link_lazily = link_sexp->value();
1142 }
1143
1144 CallInfo call_info(zone());
1145 if (!ParseCallInfo(sexp, &call_info)) return nullptr;
1146
1147 return new (zone()) NativeCallInstr(&name, &function, link_lazily,
1148 info.token_pos, call_info.inputs);
1149}
1150
1151ParameterInstr* FlowGraphDeserializer::DeserializeParameter(
1152 SExpList* sexp,
1153 const InstrInfo& info) {
1154 ASSERT(current_block_ != nullptr);
1155 if (auto const index_sexp = CheckInteger(Retrieve(sexp, 1))) {
1156 const auto param_offset_sexp =
1157 CheckInteger(sexp->ExtraLookupValue("param_offset"));
1158 ASSERT(param_offset_sexp != nullptr);
1159 const auto representation_sexp =
1160 CheckSymbol(sexp->ExtraLookupValue("representation"));
1161 Representation representation;
1162 if (!Location::ParseRepresentation(representation_sexp->value(),
1163 &representation)) {
1164 StoreError(representation_sexp, "unknown parameter representation");
1165 }
1166 return new (zone())
1167 ParameterInstr(index_sexp->value(), param_offset_sexp->value(),
1168 current_block_, representation);
1169 }
1170 return nullptr;
1171}
1172
1173ReturnInstr* FlowGraphDeserializer::DeserializeReturn(SExpList* list,
1174 const InstrInfo& info) {
1175 Value* val = ParseValue(Retrieve(list, 1));
1176 if (val == nullptr) return nullptr;
1177 return new (zone()) ReturnInstr(info.token_pos, val, info.deopt_id);
1178}
1179
1180SpecialParameterInstr* FlowGraphDeserializer::DeserializeSpecialParameter(
1181 SExpList* sexp,
1182 const InstrInfo& info) {
1183 ASSERT(current_block_ != nullptr);
1184 auto const kind_sexp = CheckSymbol(Retrieve(sexp, 1));
1185 if (kind_sexp == nullptr) return nullptr;
1186 SpecialParameterInstr::SpecialParameterKind kind;
1187 if (!SpecialParameterInstr::ParseKind(kind_sexp->value(), &kind)) {
1188 StoreError(kind_sexp, "unknown special parameter kind");
1189 return nullptr;
1190 }
1191 return new (zone())
1192 SpecialParameterInstr(kind, info.deopt_id, current_block_);
1193}
1194
1195StaticCallInstr* FlowGraphDeserializer::DeserializeStaticCall(
1196 SExpList* sexp,
1197 const InstrInfo& info) {
1198 auto& function = Function::ZoneHandle(zone());
1199 auto const function_sexp =
1200 CheckTaggedList(Retrieve(sexp, "function"), "Function");
1201 if (!ParseFunction(function_sexp, &function)) return nullptr;
1202
1203 CallInfo call_info(zone());
1204 if (!ParseCallInfo(sexp, &call_info)) return nullptr;
1205
1206 intptr_t call_count = 0;
1207 if (auto const call_count_sexp =
1208 CheckInteger(sexp->ExtraLookupValue("call_count"))) {
1209 call_count = call_count_sexp->value();
1210 }
1211
1212 auto rebind_rule = ICData::kStatic;
1213 if (auto const rebind_sexp =
1214 CheckSymbol(sexp->ExtraLookupValue("rebind_rule"))) {
1215 if (!ICData::ParseRebindRule(rebind_sexp->value(), &rebind_rule)) {
1216 StoreError(rebind_sexp, "unknown rebind rule value");
1217 return nullptr;
1218 }
1219 }
1220
1221 auto const inst = new (zone())
1222 StaticCallInstr(info.token_pos, function, call_info.type_args_len,
1223 call_info.argument_names, call_info.inputs, info.deopt_id,
1224 call_count, rebind_rule);
1225
1226 if (call_info.result_type != nullptr) {
1227 inst->SetResultType(zone(), *call_info.result_type);
1228 }
1229
1230 inst->set_entry_kind(call_info.entry_kind);
1231
1232 if (auto const ic_data_sexp =
1233 CheckTaggedList(sexp->ExtraLookupValue("ic_data"), "ICData")) {
1234 if (!CreateICData(ic_data_sexp, inst)) return nullptr;
1235 }
1236
1237 return inst;
1238}
1239
1240StoreInstanceFieldInstr* FlowGraphDeserializer::DeserializeStoreInstanceField(
1241 SExpList* sexp,
1242 const InstrInfo& info) {
1243 auto const instance = ParseValue(Retrieve(sexp, 1));
1244 if (instance == nullptr) return nullptr;
1245
1246 const Slot* slot = nullptr;
1247 if (!ParseSlot(CheckTaggedList(Retrieve(sexp, 2), "Slot"), &slot)) {
1248 return nullptr;
1249 }
1250
1251 auto const value = ParseValue(Retrieve(sexp, 3));
1252 if (value == nullptr) return nullptr;
1253
1254 auto barrier_type = kNoStoreBarrier;
1255 if (auto const bar_sexp = CheckBool(sexp->ExtraLookupValue("emit_barrier"))) {
1256 if (bar_sexp->value()) barrier_type = kEmitStoreBarrier;
1257 }
1258
1259 auto kind = StoreInstanceFieldInstr::Kind::kOther;
1260 if (auto const init_sexp = CheckBool(sexp->ExtraLookupValue("is_init"))) {
1261 if (init_sexp->value()) kind = StoreInstanceFieldInstr::Kind::kInitializing;
1262 }
1263
1264 return new (zone()) StoreInstanceFieldInstr(
1265 *slot, instance, value, barrier_type, info.token_pos, kind);
1266}
1267
1268StrictCompareInstr* FlowGraphDeserializer::DeserializeStrictCompare(
1269 SExpList* sexp,
1270 const InstrInfo& info) {
1271 auto const token_sexp = CheckSymbol(Retrieve(sexp, 1));
1272 if (token_sexp == nullptr) return nullptr;
1273 Token::Kind kind;
1274 if (!Token::FromStr(token_sexp->value(), &kind)) return nullptr;
1275
1276 auto const left = ParseValue(Retrieve(sexp, 2));
1277 if (left == nullptr) return nullptr;
1278
1279 auto const right = ParseValue(Retrieve(sexp, 3));
1280 if (right == nullptr) return nullptr;
1281
1282 bool needs_check = false;
1283 if (auto const check_sexp = CheckBool(Retrieve(sexp, "needs_check"))) {
1284 needs_check = check_sexp->value();
1285 }
1286
1287 return new (zone()) StrictCompareInstr(info.token_pos, kind, left, right,
1288 needs_check, info.deopt_id);
1289}
1290
1291ThrowInstr* FlowGraphDeserializer::DeserializeThrow(SExpList* sexp,
1292 const InstrInfo& info) {
1293 Value* exception = ParseValue(Retrieve(sexp, 1));
1294 if (exception == nullptr) return nullptr;
1295 return new (zone()) ThrowInstr(info.token_pos, info.deopt_id, exception);
1296}
1297
1298bool FlowGraphDeserializer::ParseCallInfo(SExpList* call,
1299 CallInfo* out,
1300 intptr_t num_extra_inputs) {
1301 ASSERT(out != nullptr);
1302
1303 if (auto const len_sexp =
1304 CheckInteger(call->ExtraLookupValue("type_args_len"))) {
1305 out->type_args_len = len_sexp->value();
1306 }
1307
1308 if (auto const arg_names_sexp =
1309 CheckList(call->ExtraLookupValue("arg_names"))) {
1310 out->argument_names = Array::New(arg_names_sexp->Length(), Heap::kOld);
1311 for (intptr_t i = 0, n = arg_names_sexp->Length(); i < n; i++) {
1312 auto name_sexp = CheckString(Retrieve(arg_names_sexp, i));
1313 if (name_sexp == nullptr) return false;
1314 tmp_string_ = String::New(name_sexp->value(), Heap::kOld);
1315 out->argument_names.SetAt(i, tmp_string_);
1316 }
1317 }
1318
1319 if (auto const args_len_sexp =
1320 CheckInteger(call->ExtraLookupValue("args_len"))) {
1321 out->args_len = args_len_sexp->value();
1322 }
1323
1324 if (auto const result_sexp = CheckTaggedList(
1325 call->ExtraLookupValue("result_type"), "CompileType")) {
1326 out->result_type = ParseCompileType(result_sexp);
1327 }
1328
1329 if (auto const kind_sexp =
1330 CheckSymbol(call->ExtraLookupValue("entry_kind"))) {
1331 if (!Code::ParseEntryKind(kind_sexp->value(), &out->entry_kind))
1332 return false;
1333 }
1334
1335 // Type arguments are wrapped in a TypeArguments array, so no matter how
1336 // many there are, they are contained in a single pushed argument.
1337 auto const all_args_len = (out->type_args_len > 0 ? 1 : 0) + out->args_len;
1338
1339 const intptr_t num_inputs = all_args_len + num_extra_inputs;
1340 out->inputs = new (zone()) InputsArray(zone(), num_inputs);
1341 for (intptr_t i = 0; i < num_inputs; ++i) {
1342 auto const input = ParseValue(Retrieve(call, 1 + i));
1343 if (input == nullptr) return false;
1344 out->inputs->Add(input);
1345 }
1346
1347 return true;
1348}
1349
1350Value* FlowGraphDeserializer::ParseValue(SExpression* sexp,
1351 bool allow_pending) {
1352 CompileType* type = nullptr;
1353 bool inherit_type = false;
1354 auto name = sexp->AsSymbol();
1355 if (name == nullptr) {
1356 auto const list = CheckTaggedList(sexp, "value");
1357 name = CheckSymbol(Retrieve(list, 1));
1358 if (auto const type_sexp =
1359 CheckTaggedList(list->ExtraLookupValue("type"), "CompileType")) {
1360 type = ParseCompileType(type_sexp);
1361 if (type == nullptr) return nullptr;
1362 } else if (auto const inherit_sexp =
1363 CheckBool(list->ExtraLookupValue("inherit_type"))) {
1364 inherit_type = inherit_sexp->value();
1365 } else {
1366 // We assume that the type should be inherited from the definition for
1367 // for (value ...) forms without an explicit type.
1368 inherit_type = true;
1369 }
1370 }
1371 intptr_t index;
1372 if (!ParseUse(name, &index)) return nullptr;
1373 auto const def = definition_map_.LookupValue(index);
1374 Value* val;
1375 if (def == nullptr) {
1376 if (!allow_pending) {
1377 StoreError(sexp, "found use prior to definition");
1378 return nullptr;
1379 }
1380 val = AddNewPendingValue(sexp, index, inherit_type);
1381 } else {
1382 val = new (zone()) Value(def);
1383 if (inherit_type) {
1384 if (def->HasType()) {
1385 val->reaching_type_ = def->Type();
1386 } else {
1387 StoreError(sexp, "value inherits type, but no type found");
1388 return nullptr;
1389 }
1390 }
1391 }
1392 if (type != nullptr) val->SetReachingType(type);
1393 return val;
1394}
1395
1396CompileType* FlowGraphDeserializer::ParseCompileType(SExpList* sexp) {
1397 // TODO(sstrickl): Currently we only print out nullable if it's false
1398 // (or during verbose printing). Switch this when NNBD is the standard.
1399 bool nullable = CompileType::kNullable;
1400 if (auto const nullable_sexp =
1401 CheckBool(sexp->ExtraLookupValue("nullable"))) {
1402 nullable = nullable_sexp->value() ? CompileType::kNullable
1403 : CompileType::kNonNullable;
1404 }
1405
1406 intptr_t cid = kIllegalCid;
1407 if (auto const cid_sexp = CheckInteger(sexp->ExtraLookupValue("cid"))) {
1408 // TODO(sstrickl): Check that the cid is a valid concrete cid, or a cid
1409 // otherwise found in CompileTypes like kIllegalCid or kDynamicCid.
1410 cid = cid_sexp->value();
1411 }
1412
1413 AbstractType* type = nullptr;
1414 if (auto const type_sexp = sexp->ExtraLookupValue("type")) {
1415 auto& type_handle = AbstractType::ZoneHandle(zone());
1416 if (!ParseAbstractType(type_sexp, &type_handle)) return nullptr;
1417 type = &type_handle;
1418 }
1419 return new (zone()) CompileType(nullable, cid, type);
1420}
1421
1422Environment* FlowGraphDeserializer::ParseEnvironment(SExpList* list) {
1423 if (list == nullptr) return nullptr;
1424 intptr_t fixed_param_count = 0;
1425 if (auto const fpc_sexp =
1426 CheckInteger(list->ExtraLookupValue("fixed_param_count"))) {
1427 fixed_param_count = fpc_sexp->value();
1428 }
1429 Environment* outer_env = nullptr;
1430 if (auto const outer_sexp = CheckList(list->ExtraLookupValue("outer"))) {
1431 outer_env = ParseEnvironment(outer_sexp);
1432 if (outer_env == nullptr) return nullptr;
1433 if (auto const deopt_sexp =
1434 CheckInteger(outer_sexp->ExtraLookupValue("deopt_id"))) {
1435 outer_env->deopt_id_ = deopt_sexp->value();
1436 }
1437 }
1438
1439 ASSERT(parsed_function_ != nullptr);
1440 auto const env = new (zone()) Environment(list->Length(), fixed_param_count,
1441 *parsed_function_, outer_env);
1442
1443 for (intptr_t i = 0; i < list->Length(); i++) {
1444 auto const elem_sexp = Retrieve(list, i);
1445 if (elem_sexp == nullptr) return nullptr;
1446 auto val = ParseValue(elem_sexp, /*allow_pending=*/false);
1447 if (val == nullptr) return nullptr;
1448 env->PushValue(val);
1449 }
1450
1451 return env;
1452}
1453
1454bool FlowGraphDeserializer::ParseDartValue(SExpression* sexp, Object* out) {
1455 ASSERT(out != nullptr);
1456 if (sexp == nullptr) return false;
1457 *out = Object::null();
1458
1459 if (auto const sym = sexp->AsSymbol()) {
1460 // We'll use the null value in *out as a marker later, so go ahead and exit
1461 // early if we parse one.
1462 if (sym->Equals("null")) return true;
1463 if (sym->Equals("sentinel")) {
1464 *out = Object::sentinel().raw();
1465 return true;
1466 }
1467
1468 // The only other symbols that should appear in Dart value position are
1469 // names of constant definitions.
1470 auto const val = ParseValue(sym, /*allow_pending=*/false);
1471 if (val == nullptr) return false;
1472 if (!val->BindsToConstant()) {
1473 StoreError(sym, "not a reference to a constant definition");
1474 return false;
1475 }
1476 *out = val->BoundConstant().raw();
1477 // Values used in constant definitions have already been canonicalized,
1478 // so just exit.
1479 return true;
1480 }
1481
1482 // Other instance values may need to be canonicalized, so do that before
1483 // returning.
1484 if (auto const b = sexp->AsBool()) {
1485 *out = Bool::Get(b->value()).raw();
1486 } else if (auto const str = sexp->AsString()) {
1487 *out = String::New(str->value(), Heap::kOld);
1488 } else if (auto const i = sexp->AsInteger()) {
1489 *out = Integer::New(i->value(), Heap::kOld);
1490 } else if (auto const d = sexp->AsDouble()) {
1491 *out = Double::New(d->value(), Heap::kOld);
1492 } else if (auto const list = CheckTaggedList(sexp)) {
1493 auto const tag = list->Tag();
1494 if (tag->Equals("Class")) {
1495 return ParseClass(list, out);
1496 } else if (tag->Equals("Type")) {
1497 return ParseType(list, out);
1498 } else if (tag->Equals("TypeArguments")) {
1499 return ParseTypeArguments(list, out);
1500 } else if (tag->Equals("Field")) {
1501 return ParseField(list, out);
1502 } else if (tag->Equals("Function")) {
1503 return ParseFunction(list, out);
1504 } else if (tag->Equals("TypeParameter")) {
1505 return ParseTypeParameter(list, out);
1506 } else if (tag->Equals("ImmutableList")) {
1507 return ParseImmutableList(list, out);
1508 } else if (tag->Equals("Instance")) {
1509 return ParseInstance(list, out);
1510 } else if (tag->Equals("Closure")) {
1511 return ParseClosure(list, out);
1512 } else if (tag->Equals("TypeRef")) {
1513 return ParseTypeRef(list, out);
1514 }
1515 }
1516
1517 // If we're here and still haven't gotten a non-null value, then something
1518 // went wrong. (Likely an unrecognized value.)
1519 if (out->IsNull()) {
1520 StoreError(sexp, "unhandled Dart value");
1521 return false;
1522 }
1523
1524 if (!out->IsInstance()) return true;
1525 return CanonicalizeInstance(sexp, out);
1526}
1527
1528bool FlowGraphDeserializer::CanonicalizeInstance(SExpression* sexp,
1529 Object* out) {
1530 ASSERT(out != nullptr);
1531 if (!out->IsInstance()) return true;
1532 const char* error_str = nullptr;
1533 // CheckAndCanonicalize uses the current zone for the passed in thread,
1534 // not an explicitly provided zone. This means we cannot be run in a context
1535 // where [thread()->zone()] does not match [zone()] (e.g., due to StackZone)
1536 // until this is addressed.
1537 *out = Instance::Cast(*out).CheckAndCanonicalize(thread(), &error_str);
1538 if (error_str != nullptr) {
1539 StoreError(sexp, "error during canonicalization: %s", error_str);
1540 return false;
1541 }
1542 return true;
1543}
1544
1545bool FlowGraphDeserializer::ParseAbstractType(SExpression* sexp, Object* out) {
1546 ASSERT(out != nullptr);
1547 if (sexp == nullptr) return false;
1548
1549 // If it's a symbol, it should be a reference to a constant definition, which
1550 // is handled in ParseType.
1551 if (auto const sym = sexp->AsSymbol()) {
1552 return ParseType(sexp, out);
1553 } else if (auto const list = CheckTaggedList(sexp)) {
1554 auto const tag = list->Tag();
1555 if (tag->Equals("Type")) {
1556 return ParseType(list, out);
1557 } else if (tag->Equals("TypeParameter")) {
1558 return ParseTypeParameter(list, out);
1559 } else if (tag->Equals("TypeRef")) {
1560 return ParseTypeRef(list, out);
1561 }
1562 }
1563
1564 StoreError(sexp, "not an AbstractType");
1565 return false;
1566}
1567
1568bool FlowGraphDeserializer::ParseClass(SExpList* list, Object* out) {
1569 ASSERT(out != nullptr);
1570 if (list == nullptr) return false;
1571
1572 auto const ref_sexp = Retrieve(list, 1);
1573 if (ref_sexp == nullptr) return false;
1574 if (auto const cid_sexp = ref_sexp->AsInteger()) {
1575 ClassTable* table = thread()->isolate()->class_table();
1576 if (!table->HasValidClassAt(cid_sexp->value())) {
1577 StoreError(cid_sexp, "no valid class found for cid");
1578 return false;
1579 }
1580 *out = table->At(cid_sexp->value());
1581 } else if (auto const name_sexp = ref_sexp->AsSymbol()) {
1582 if (!ParseCanonicalName(name_sexp, out)) return false;
1583 if (!out->IsClass()) {
1584 StoreError(name_sexp, "expected the name of a class");
1585 return false;
1586 }
1587 }
1588 return true;
1589}
1590
1591bool FlowGraphDeserializer::ParseClosure(SExpList* list, Object* out) {
1592 ASSERT(out != nullptr);
1593 if (list == nullptr) return false;
1594
1595 auto& function = Function::ZoneHandle(zone());
1596 auto const function_sexp = CheckTaggedList(Retrieve(list, 1), "Function");
1597 if (!ParseFunction(function_sexp, &function)) return false;
1598
1599 auto& context = Context::ZoneHandle(zone());
1600 if (list->ExtraLookupValue("context") != nullptr) {
1601 StoreError(list, "closures with contexts currently unhandled");
1602 return false;
1603 }
1604
1605 auto& inst_type_args = TypeArguments::ZoneHandle(zone());
1606 if (auto const type_args_sexp = Retrieve(list, "inst_type_args")) {
1607 if (!ParseTypeArguments(type_args_sexp, &inst_type_args)) return false;
1608 }
1609
1610 auto& func_type_args = TypeArguments::ZoneHandle(zone());
1611 if (auto const type_args_sexp = Retrieve(list, "func_type_args")) {
1612 if (!ParseTypeArguments(type_args_sexp, &func_type_args)) return false;
1613 }
1614
1615 auto& delayed_type_args = TypeArguments::ZoneHandle(zone());
1616 if (auto const type_args_sexp = Retrieve(list, "delayed_type_args")) {
1617 if (!ParseTypeArguments(type_args_sexp, &delayed_type_args)) {
1618 return false;
1619 }
1620 }
1621
1622 *out = Closure::New(inst_type_args, func_type_args, delayed_type_args,
1623 function, context, Heap::kOld);
1624 return CanonicalizeInstance(list, out);
1625}
1626
1627bool FlowGraphDeserializer::ParseField(SExpList* list, Object* out) {
1628 auto const name_sexp = CheckSymbol(Retrieve(list, 1));
1629 if (!ParseCanonicalName(name_sexp, out)) return false;
1630 if (!out->IsField()) {
1631 StoreError(list, "expected a Field name");
1632 return false;
1633 }
1634 return true;
1635}
1636
1637bool FlowGraphDeserializer::ParseFunction(SExpList* list, Object* out) {
1638 ASSERT(out != nullptr);
1639 if (list == nullptr) return false;
1640
1641 auto const name_sexp = CheckSymbol(Retrieve(list, 1));
1642 if (!ParseCanonicalName(name_sexp, out)) return false;
1643 if (!out->IsFunction()) {
1644 StoreError(list, "expected a Function name");
1645 return false;
1646 }
1647 auto& function = Function::Cast(*out);
1648 // Check the kind expected by the S-expression if one was specified.
1649 if (auto const kind_sexp = CheckSymbol(list->ExtraLookupValue("kind"))) {
1650 FunctionLayout::Kind kind;
1651 if (!FunctionLayout::ParseKind(kind_sexp->value(), &kind)) {
1652 StoreError(kind_sexp, "unexpected function kind");
1653 return false;
1654 }
1655 if (function.kind() != kind) {
1656 auto const kind_str = FunctionLayout::KindToCString(function.kind());
1657 StoreError(list, "retrieved function has kind %s", kind_str);
1658 return false;
1659 }
1660 }
1661 return true;
1662}
1663
1664bool FlowGraphDeserializer::ParseImmutableList(SExpList* list, Object* out) {
1665 ASSERT(out != nullptr);
1666 if (list == nullptr) return false;
1667
1668 *out = Array::New(list->Length() - 1, Heap::kOld);
1669 auto& arr = Array::Cast(*out);
1670 // Arrays may contain other arrays, so we'll need a new handle in which to
1671 // store elements.
1672 auto& elem = Object::Handle(zone());
1673 for (intptr_t i = 1; i < list->Length(); i++) {
1674 if (!ParseDartValue(Retrieve(list, i), &elem)) return false;
1675 arr.SetAt(i - 1, elem);
1676 }
1677 if (auto type_args_sexp = list->ExtraLookupValue("type_args")) {
1678 if (!ParseTypeArguments(type_args_sexp, &array_type_args_)) return false;
1679 arr.SetTypeArguments(array_type_args_);
1680 }
1681 arr.MakeImmutable();
1682 return CanonicalizeInstance(list, out);
1683}
1684
1685bool FlowGraphDeserializer::ParseInstance(SExpList* list, Object* out) {
1686 ASSERT(out != nullptr);
1687 if (list == nullptr) return false;
1688 auto const cid_sexp = CheckInteger(Retrieve(list, 1));
1689 if (cid_sexp == nullptr) return false;
1690
1691 auto const table = thread()->isolate()->class_table();
1692 if (!table->HasValidClassAt(cid_sexp->value())) {
1693 StoreError(cid_sexp, "cid is not valid");
1694 return false;
1695 }
1696
1697 ASSERT(cid_sexp->value() != kNullCid); // Must use canonical instances.
1698 ASSERT(cid_sexp->value() != kBoolCid); // Must use canonical instances.
1699 instance_class_ = table->At(cid_sexp->value());
1700 *out = Instance::New(instance_class_, Heap::kOld);
1701 auto& instance = Instance::Cast(*out);
1702
1703 if (auto const type_args = list->ExtraLookupValue("type_args")) {
1704 instance_type_args_ = TypeArguments::null();
1705 if (!ParseTypeArguments(type_args, &instance_type_args_)) return false;
1706 if (!instance_class_.IsGeneric()) {
1707 StoreError(list,
1708 "type arguments provided for an instance of a "
1709 "non-generic class");
1710 return false;
1711 }
1712 instance.SetTypeArguments(instance_type_args_);
1713 }
1714
1715 // Pick out and store the final instance fields of the class, as values must
1716 // be provided for them. Error if there are any non-final instance fields.
1717 instance_fields_array_ = instance_class_.fields();
1718 auto const field_count = instance_fields_array_.Length();
1719 GrowableArray<const Field*> final_fields(zone(), field_count);
1720 for (intptr_t i = 0, n = field_count; i < n; i++) {
1721 instance_field_ = Field::RawCast(instance_fields_array_.At(i));
1722 if (!instance_field_.is_instance()) continue;
1723 if (!instance_field_.is_final()) {
1724 StoreError(list, "class for instance has non-final instance fields");
1725 return false;
1726 }
1727 auto& fresh_handle = Field::Handle(zone(), instance_field_.raw());
1728 final_fields.Add(&fresh_handle);
1729 }
1730
1731 // If there is no (Fields...) sub-expression or it has no extra info, then
1732 // ensure there are no final fields before returning the canonicalized form.
1733 SExpList* fields_sexp = nullptr;
1734 bool fields_provided = list->Length() > 2;
1735 if (fields_provided) {
1736 fields_sexp = CheckTaggedList(Retrieve(list, 2), "Fields");
1737 if (fields_sexp == nullptr) return false;
1738 fields_provided = fields_sexp->ExtraLength() != 0;
1739 }
1740 if (!fields_provided) {
1741 if (!final_fields.is_empty()) {
1742 StoreError(list, "values not provided for final fields of instance");
1743 return false;
1744 }
1745 return CanonicalizeInstance(list, out);
1746 }
1747
1748 // At this point, we have final instance field values to set on the new
1749 // instance before canonicalization. When setting instance fields, we may
1750 // cause field guards to be invalidated. Because of this, we must either be
1751 // running on the mutator thread or be at a safepoint when calling `SetField`.
1752 //
1753 // For IR round-trips, the constants we create have already existed before in
1754 // the VM heap, which means field invalidation cannot occur. Thus, we create a
1755 // closure that sets the fields of the instance and then conditionally run
1756 // that closure at a safepoint if not in the mutator thread.
1757 //
1758 // TODO(dartbug.com/36882): When deserializing IR that was not generated
1759 // during the RoundTripSerialization pass, we are no longer guaranteed that
1760 // deserialization of instances will not invalidate field guards. Thus, we may
1761 // need to support invalidating field guards on non-mutator threads or fall
1762 // back onto forcing the deserialization to happen on the mutator thread.
1763 auto set_instance_fields = [&]() {
1764 auto& inst = Instance::Cast(*out);
1765 // We'll need to allocate a handle for the parsed value as we may have
1766 // instances as field values and so this function may be re-entered.
1767 auto& value = Object::Handle(zone());
1768 for (auto field : final_fields) {
1769 tmp_string_ = field->UserVisibleName();
1770 auto const name = tmp_string_.ToCString();
1771 auto const value_sexp = Retrieve(fields_sexp, name);
1772 if (value_sexp == nullptr) {
1773 StoreError(list, "no value provided for final instance field %s", name);
1774 return false;
1775 }
1776 if (!ParseDartValue(value_sexp, &value)) return false;
1777 inst.SetField(*field, value);
1778 }
1779 return true;
1780 };
1781
1782 auto const t = Thread::Current();
1783 if (!t->IsMutatorThread()) {
1784 SafepointOperationScope safepoint_scope(t);
1785 if (!set_instance_fields()) return false;
1786 } else {
1787 if (!set_instance_fields()) return false;
1788 }
1789
1790 return CanonicalizeInstance(list, out);
1791}
1792
1793bool FlowGraphDeserializer::ParseType(SExpression* sexp, Object* out) {
1794 ASSERT(out != nullptr);
1795 if (sexp == nullptr) return false;
1796
1797 if (auto const sym = sexp->AsSymbol()) {
1798 auto const val = ParseValue(sexp, /*allow_pending=*/false);
1799 if (val == nullptr) {
1800 StoreError(sexp, "expected type or reference to constant definition");
1801 return false;
1802 }
1803 if (!val->BindsToConstant()) {
1804 StoreError(sexp, "reference to non-constant definition");
1805 return false;
1806 }
1807 *out = val->BoundConstant().raw();
1808 if (!out->IsType()) {
1809 StoreError(sexp, "expected Type constant");
1810 return false;
1811 }
1812 return true;
1813 }
1814 auto const list = CheckTaggedList(sexp, "Type");
1815 if (list == nullptr) return false;
1816
1817 const auto hash_sexp = CheckInteger(list->ExtraLookupValue("hash"));
1818 const auto is_recursive = hash_sexp != nullptr;
1819 // This isn't necessary the hash value we will have in the new FlowGraph, but
1820 // it will be how this type is referred to by TypeRefs in the serialized one.
1821 auto const old_hash = is_recursive ? hash_sexp->value() : 0;
1822 ZoneGrowableArray<TypeRef*>* pending_typerefs = nullptr;
1823 if (is_recursive) {
1824 if (pending_typeref_map_.LookupValue(old_hash) != nullptr) {
1825 StoreError(sexp, "already parsing a type with hash %" Pd64 "",
1826 hash_sexp->value());
1827 return false;
1828 }
1829 pending_typerefs = new (zone()) ZoneGrowableArray<TypeRef*>(zone(), 2);
1830 pending_typeref_map_.Insert(old_hash, pending_typerefs);
1831 }
1832
1833 const auto cls_sexp = CheckTaggedList(Retrieve(list, 1), "Class");
1834 if (cls_sexp == nullptr) {
1835 // TODO(sstrickl): Handle types not derived from classes.
1836 StoreError(list, "non-class types not currently handled");
1837 return false;
1838 }
1839 TokenPosition token_pos = TokenPosition::kNoSource;
1840 if (const auto pos_sexp = CheckInteger(list->ExtraLookupValue("token_pos"))) {
1841 token_pos = TokenPosition(pos_sexp->value());
1842 }
1843 auto type_args_ptr = &Object::null_type_arguments();
1844 if (const auto ta_sexp = list->ExtraLookupValue("type_args")) {
1845 // ParseTypeArguments may re-enter ParseType after setting the contents of
1846 // the passed in handle, so we need to allocate a new handle here.
1847 auto& type_args = TypeArguments::Handle(zone());
1848 if (!ParseTypeArguments(ta_sexp, &type_args)) return false;
1849 type_args_ptr = &type_args;
1850 }
1851 // Guaranteed not to re-enter ParseType.
1852 if (!ParseClass(cls_sexp, &type_class_)) return false;
1853 const Nullability nullability =
1854 type_class_.IsNullClass() ? Nullability::kNullable : Nullability::kLegacy;
1855 *out = Type::New(type_class_, *type_args_ptr, token_pos, nullability);
1856 auto& type = Type::Cast(*out);
1857 if (auto const sig_sexp = list->ExtraLookupValue("signature")) {
1858 auto& function = Function::Handle(zone());
1859 if (!ParseDartValue(sig_sexp, &function)) return false;
1860 type.set_signature(function);
1861 }
1862 if (is_recursive) {
1863 while (!pending_typerefs->is_empty()) {
1864 auto const ref = pending_typerefs->RemoveLast();
1865 ASSERT(ref != nullptr);
1866 ref->set_type(type);
1867 }
1868 pending_typeref_map_.Remove(old_hash);
1869
1870 // If there are still pending typerefs, we can't canonicalize yet until
1871 // an enclosing type where we have resolved them. This is a conservative
1872 // check, as we do not ensure that any of the still-pending typerefs are
1873 // found within this type.
1874 //
1875 // This is within the is_recursive check because if this type was
1876 // non-recursive, then even if there are pending type refs, we are
1877 // guaranteed that none of them are in this type.
1878 if (ArePendingTypeRefs()) return true;
1879 }
1880
1881 // Need to set this for canonicalization. We ensure in the serializer
1882 // that only finalized types are successfully serialized.
1883 type.SetIsFinalized();
1884 return CanonicalizeInstance(list, out);
1885}
1886
1887bool FlowGraphDeserializer::ParseTypeArguments(SExpression* sexp, Object* out) {
1888 ASSERT(out != nullptr);
1889 if (sexp == nullptr) return false;
1890
1891 if (auto const sym = sexp->AsSymbol()) {
1892 auto const val = ParseValue(sexp, /*allow_pending=*/false);
1893 if (val == nullptr) {
1894 StoreError(sexp,
1895 "expected type arguments or reference to constant definition");
1896 return false;
1897 }
1898 if (!val->BindsToConstant()) {
1899 StoreError(sexp, "reference to non-constant definition");
1900 return false;
1901 }
1902 *out = val->BoundConstant().raw();
1903 if (!out->IsTypeArguments()) {
1904 StoreError(sexp, "expected TypeArguments constant");
1905 return false;
1906 }
1907 return true;
1908 }
1909 auto const list = CheckTaggedList(sexp, "TypeArguments");
1910 if (list == nullptr) return false;
1911
1912 *out = TypeArguments::New(list->Length() - 1, Heap::kOld);
1913 auto& type_args = TypeArguments::Cast(*out);
1914 // We may reenter ParseTypeArguments while parsing one of the elements, so we
1915 // need a fresh handle here.
1916 auto& elem = AbstractType::Handle(zone());
1917 for (intptr_t i = 1, n = list->Length(); i < n; i++) {
1918 if (!ParseAbstractType(Retrieve(list, i), &elem)) return false;
1919 type_args.SetTypeAt(i - 1, elem);
1920 }
1921
1922 // If there are still pending typerefs, we can't canonicalize yet.
1923 if (ArePendingTypeRefs()) return true;
1924
1925 return CanonicalizeInstance(list, out);
1926}
1927
1928bool FlowGraphDeserializer::ParseTypeParameter(SExpList* list, Object* out) {
1929 ASSERT(out != nullptr);
1930 if (list == nullptr) return false;
1931
1932 const Function* function = nullptr;
1933 const Class* cls = nullptr;
1934 if (auto const func_sexp = CheckSymbol(list->ExtraLookupValue("function"))) {
1935 if (!ParseCanonicalName(func_sexp, &type_param_function_)) return false;
1936 if (!type_param_function_.IsFunction() || type_param_function_.IsNull()) {
1937 StoreError(func_sexp, "not a function name");
1938 return false;
1939 }
1940 function = &type_param_function_;
1941 } else if (auto const class_sexp =
1942 CheckInteger(list->ExtraLookupValue("class"))) {
1943 const intptr_t cid = class_sexp->value();
1944 auto const table = thread()->isolate()->class_table();
1945 if (!table->HasValidClassAt(cid)) {
1946 StoreError(class_sexp, "not a valid class id");
1947 return false;
1948 }
1949 type_param_class_ = table->At(cid);
1950 cls = &type_param_class_;
1951 } else {
1952 // If we weren't given an explicit source, check in the function for this
1953 // flow graph.
1954 ASSERT(parsed_function_ != nullptr);
1955 function = &parsed_function_->function();
1956 }
1957
1958 auto const name_sexp = CheckSymbol(Retrieve(list, 1));
1959 if (name_sexp == nullptr) return false;
1960 tmp_string_ = String::New(name_sexp->value());
1961
1962 *out = TypeParameter::null();
1963 if (function != nullptr) {
1964 *out = function->LookupTypeParameter(tmp_string_, nullptr);
1965 } else if (cls != nullptr) {
1966 *out = cls->LookupTypeParameter(tmp_string_);
1967 }
1968 if (out->IsNull()) {
1969 StoreError(name_sexp, "no type parameter found for name");
1970 return false;
1971 }
1972 return CanonicalizeInstance(list, out);
1973}
1974
1975bool FlowGraphDeserializer::ParseTypeRef(SExpList* list, Object* out) {
1976 ASSERT(out != nullptr);
1977 if (list == nullptr) return false;
1978
1979 const bool contains_type = list->Length() > 1;
1980 if (contains_type) {
1981 auto& type = Type::Handle(zone());
1982 if (!ParseAbstractType(Retrieve(list, 1), &type)) return false;
1983 *out = TypeRef::New(type);
1984 // If the TypeRef appears outside the referrent, then the referrent
1985 // should be already canonicalized. This serves as a double-check that
1986 // is the case.
1987 return CanonicalizeInstance(list, out);
1988 }
1989 // If there is no type in the body, then this must be a referrent to
1990 // a Type containing this TypeRef. That means we must have a hash value.
1991 auto const hash_sexp = CheckInteger(Retrieve(list, "hash"));
1992 if (hash_sexp == nullptr) return false;
1993 auto const old_hash = hash_sexp->value();
1994 auto const pending = pending_typeref_map_.LookupValue(old_hash);
1995 if (pending == nullptr) {
1996 StoreError(list, "reference to recursive type found outside type");
1997 return false;
1998 }
1999 *out = TypeRef::New(Object::null_abstract_type());
2000 pending->Add(static_cast<TypeRef*>(out));
2001
2002 // We can only canonicalize TypeRefs appearing within their referrent
2003 // when its containing value is canonicalized.
2004 return true;
2005}
2006
2007bool FlowGraphDeserializer::ParseCanonicalName(SExpSymbol* sym, Object* obj) {
2008 ASSERT(obj != nullptr);
2009 if (sym == nullptr) return false;
2010 auto const name = sym->value();
2011 // TODO(sstrickl): No library URL, handle this better.
2012 if (*name == ':') {
2013 StoreError(sym, "expected non-empty library");
2014 return false;
2015 }
2016 const char* lib_end = nullptr;
2017 if (auto const first = strchr(name, ':')) {
2018 lib_end = strchr(first + 1, ':');
2019 if (lib_end == nullptr) lib_end = strchr(first + 1, '\0');
2020 } else {
2021 StoreError(sym, "malformed library");
2022 return false;
2023 }
2024 tmp_string_ =
2025 String::FromUTF8(reinterpret_cast<const uint8_t*>(name), lib_end - name);
2026 name_library_ = Library::LookupLibrary(thread(), tmp_string_);
2027 if (*lib_end == '\0') {
2028 *obj = name_library_.raw();
2029 return true;
2030 }
2031 const char* const class_start = lib_end + 1;
2032 if (*class_start == '\0') {
2033 StoreError(sym, "no class found after colon");
2034 return false;
2035 }
2036 // If classes are followed by another part, it's either a function
2037 // (separated by ':') or a field (separated by '.').
2038 const char* class_end = strchr(class_start, ':');
2039 if (class_end == nullptr) class_end = strchr(class_start, '.');
2040 if (class_end == nullptr) class_end = strchr(class_start, '\0');
2041 const bool empty_name = class_end == class_start;
2042 name_class_ = Class::null();
2043 if (empty_name) {
2044 name_class_ = name_library_.toplevel_class();
2045 } else {
2046 tmp_string_ = String::FromUTF8(
2047 reinterpret_cast<const uint8_t*>(class_start), class_end - class_start);
2048 name_class_ = name_library_.LookupClassAllowPrivate(tmp_string_);
2049 }
2050 if (name_class_.IsNull()) {
2051 StoreError(sym, "failure looking up class %s in library %s",
2052 empty_name ? "at top level" : tmp_string_.ToCString(),
2053 name_library_.ToCString());
2054 return false;
2055 }
2056 if (*class_end == '\0') {
2057 *obj = name_class_.raw();
2058 return true;
2059 }
2060 if (*class_end == '.') {
2061 if (class_end[1] == '\0') {
2062 StoreError(sym, "no field name found after period");
2063 return false;
2064 }
2065 const char* const field_start = class_end + 1;
2066 const char* field_end = strchr(field_start, '\0');
2067 tmp_string_ = String::FromUTF8(
2068 reinterpret_cast<const uint8_t*>(field_start), field_end - field_start);
2069 name_field_ = name_class_.LookupFieldAllowPrivate(tmp_string_);
2070 if (name_field_.IsNull()) {
2071 StoreError(sym, "failure looking up field %s in class %s",
2072 tmp_string_.ToCString(),
2073 empty_name ? "at top level" : name_class_.ToCString());
2074 return false;
2075 }
2076 *obj = name_field_.raw();
2077 return true;
2078 }
2079 if (class_end[1] == '\0') {
2080 StoreError(sym, "no function name found after final colon");
2081 return false;
2082 }
2083 const char* func_start = class_end + 1;
2084 name_function_ = Function::null();
2085 while (true) {
2086 const char* func_end = strchr(func_start, ':');
2087 intptr_t name_len = func_end - func_start;
2088 bool is_forwarder = false;
2089 if (func_end != nullptr && name_len == 3) {
2090 // Special case for getters/setters, where they are prefixed with "get:"
2091 // or "set:", as those colons should not be used as separators.
2092 if (strncmp(func_start, "get", 3) == 0 ||
2093 strncmp(func_start, "set", 3) == 0) {
2094 func_end = strchr(func_end + 1, ':');
2095 } else if (strncmp(func_start, "dyn", 3) == 0) {
2096 // Dynamic invocation forwarders start with "dyn:" and we'll need to
2097 // look up the base function and then retrieve the forwarder from it.
2098 is_forwarder = true;
2099 func_start = func_end + 1;
2100 func_end = strchr(func_end + 1, ':');
2101 }
2102 }
2103 if (func_end == nullptr) func_end = strchr(func_start, '\0');
2104 name_len = func_end - func_start;
2105
2106 // Check for tearoff names before we overwrite the contents of tmp_string_.
2107 if (!name_function_.IsNull()) {
2108 ASSERT(!tmp_string_.IsNull());
2109 auto const parent_name = tmp_string_.ToCString();
2110 // ImplicitClosureFunctions (tearoffs) have the same name as the Function
2111 // to which they are attached. We currently don't handle any other kinds
2112 // of local functions.
2113 if (name_function_.HasImplicitClosureFunction() && *func_end == '\0' &&
2114 strncmp(parent_name, func_start, name_len) == 0) {
2115 *obj = name_function_.ImplicitClosureFunction();
2116 return true;
2117 }
2118 StoreError(sym, "no handling for local functions");
2119 return false;
2120 }
2121
2122 // Check for the prefix "<anonymous ..." in the name and fail if found,
2123 // since we can't resolve these.
2124 static auto const anon_prefix = "<anonymous ";
2125 static const intptr_t prefix_len = strlen(anon_prefix);
2126 if ((name_len > prefix_len) &&
2127 strncmp(anon_prefix, func_start, prefix_len) == 0) {
2128 StoreError(sym, "cannot resolve anonymous values");
2129 return false;
2130 }
2131
2132 tmp_string_ = String::FromUTF8(reinterpret_cast<const uint8_t*>(func_start),
2133 name_len);
2134 name_function_ = name_class_.LookupFunctionAllowPrivate(tmp_string_);
2135 if (name_function_.IsNull()) {
2136 StoreError(sym, "failure looking up function %s in class %s",
2137 tmp_string_.ToCString(), name_class_.ToCString());
2138 return false;
2139 }
2140 if (is_forwarder) {
2141 tmp_string_ = name_function_.name();
2142 tmp_string_ = Function::CreateDynamicInvocationForwarderName(tmp_string_);
2143 name_function_ =
2144 name_function_.GetDynamicInvocationForwarder(tmp_string_);
2145 }
2146 if (func_end[0] == '\0') break;
2147 if (func_end[1] == '\0') {
2148 StoreError(sym, "no function name found after final colon");
2149 return false;
2150 }
2151 func_start = func_end + 1;
2152 }
2153 *obj = name_function_.raw();
2154 return true;
2155}
2156
2157// Following the lead of BaseFlowGraphBuilder::MayCloneField here.
2158const Field& FlowGraphDeserializer::MayCloneField(const Field& field) const {
2159 if ((Compiler::IsBackgroundCompilation() ||
2160 FLAG_force_clone_compiler_objects) &&
2161 field.IsOriginal()) {
2162 return Field::ZoneHandle(zone(), field.CloneFromOriginal());
2163 }
2164 ASSERT(field.IsZoneHandle());
2165 return field;
2166}
2167
2168bool FlowGraphDeserializer::ParseSlot(SExpList* list, const Slot** out) {
2169 ASSERT(out != nullptr);
2170 const auto offset_sexp = CheckInteger(Retrieve(list, 1));
2171 if (offset_sexp == nullptr) return false;
2172 const auto offset = offset_sexp->value();
2173
2174 const auto kind_sexp = CheckSymbol(Retrieve(list, "kind"));
2175 if (kind_sexp == nullptr) return false;
2176 Slot::Kind kind;
2177 if (!Slot::ParseKind(kind_sexp->value(), &kind)) {
2178 StoreError(kind_sexp, "unknown Slot kind");
2179 return false;
2180 }
2181
2182 switch (kind) {
2183 case Slot::Kind::kDartField: {
2184 auto& field = Field::ZoneHandle(zone());
2185 const auto field_sexp = CheckTaggedList(Retrieve(list, "field"), "Field");
2186 if (!ParseDartValue(field_sexp, &field)) return false;
2187 ASSERT(parsed_function_ != nullptr);
2188 *out = &Slot::Get(MayCloneField(field), parsed_function_);
2189 break;
2190 }
2191 case Slot::Kind::kTypeArguments:
2192 *out = &Slot::GetTypeArgumentsSlotAt(thread(), offset);
2193 break;
2194 case Slot::Kind::kTypeArgumentsIndex:
2195 *out = &Slot::GetTypeArgumentsIndexSlot(thread(), offset);
2196 break;
2197 case Slot::Kind::kCapturedVariable:
2198 StoreError(kind_sexp, "unhandled Slot kind");
2199 return false;
2200 default:
2201 *out = &Slot::GetNativeSlot(kind);
2202 break;
2203 }
2204 return true;
2205}
2206
2207bool FlowGraphDeserializer::ParseRange(SExpList* list, Range* out) {
2208 if (list == nullptr) return false;
2209 RangeBoundary min, max;
2210 if (!ParseRangeBoundary(Retrieve(list, 1), &min)) return false;
2211 if (list->Length() == 2) {
2212 max = min;
2213 } else {
2214 if (!ParseRangeBoundary(Retrieve(list, 2), &max)) return false;
2215 }
2216 out->min_ = min;
2217 out->max_ = max;
2218 return true;
2219}
2220
2221bool FlowGraphDeserializer::ParseRangeBoundary(SExpression* sexp,
2222 RangeBoundary* out) {
2223 if (sexp == nullptr) return false;
2224 if (auto const int_sexp = sexp->AsInteger()) {
2225 out->kind_ = RangeBoundary::Kind::kConstant;
2226 out->value_ = int_sexp->value();
2227 } else if (auto const sym_sexp = sexp->AsSymbol()) {
2228 if (!RangeBoundary::ParseKind(sym_sexp->value(), &out->kind_)) return false;
2229 } else if (auto const list_sexp = sexp->AsList()) {
2230 intptr_t index;
2231 if (!ParseUse(CheckSymbol(Retrieve(list_sexp, 1)), &index)) return false;
2232 auto const def = definition_map_.LookupValue(index);
2233 if (def == nullptr) {
2234 StoreError(list_sexp, "no definition for symbolic range boundary");
2235 return false;
2236 }
2237 out->kind_ = RangeBoundary::Kind::kSymbol;
2238 out->value_ = reinterpret_cast<intptr_t>(def);
2239 if (auto const offset_sexp =
2240 CheckInteger(list_sexp->ExtraLookupValue("offset"))) {
2241 auto const offset = offset_sexp->value();
2242 if (!RangeBoundary::IsValidOffsetForSymbolicRangeBoundary(offset)) {
2243 StoreError(sexp, "invalid offset for symbolic range boundary");
2244 return false;
2245 }
2246 out->offset_ = offset;
2247 }
2248 } else {
2249 StoreError(sexp, "unexpected value for range boundary");
2250 return false;
2251 }
2252 return true;
2253}
2254
2255bool FlowGraphDeserializer::ParseBlockId(SExpSymbol* sym, intptr_t* out) {
2256 return ParseSymbolAsPrefixedInt(sym, 'B', out);
2257}
2258
2259bool FlowGraphDeserializer::ParseSSATemp(SExpSymbol* sym, intptr_t* out) {
2260 return ParseSymbolAsPrefixedInt(sym, 'v', out);
2261}
2262
2263bool FlowGraphDeserializer::ParseUse(SExpSymbol* sym, intptr_t* out) {
2264 // TODO(sstrickl): Handle non-SSA temp uses.
2265 return ParseSSATemp(sym, out);
2266}
2267
2268bool FlowGraphDeserializer::ParseSymbolAsPrefixedInt(SExpSymbol* sym,
2269 char prefix,
2270 intptr_t* out) {
2271 ASSERT(out != nullptr);
2272 if (sym == nullptr) return false;
2273 auto const name = sym->value();
2274 if (*name != prefix) {
2275 StoreError(sym, "expected symbol starting with '%c'", prefix);
2276 return false;
2277 }
2278 int64_t i;
2279 if (!OS::StringToInt64(name + 1, &i)) {
2280 StoreError(sym, "expected number following symbol prefix '%c'", prefix);
2281 return false;
2282 }
2283 *out = i;
2284 return true;
2285}
2286
2287bool FlowGraphDeserializer::ArePendingTypeRefs() const {
2288 // We'll do a deep check, because while there may be recursive types still
2289 // being parsed, if there are no pending type refs to those recursive types,
2290 // we're still good to canonicalize.
2291 if (pending_typeref_map_.IsEmpty()) return false;
2292 auto it = pending_typeref_map_.GetIterator();
2293 while (auto kv = it.Next()) {
2294 if (!kv->value->is_empty()) return true;
2295 }
2296 return false;
2297}
2298
2299bool FlowGraphDeserializer::CreateICData(SExpList* list, Instruction* inst) {
2300 ASSERT(inst != nullptr);
2301 if (list == nullptr) return false;
2302
2303 const String* function_name = nullptr;
2304 Array& arguments_descriptor = Array::Handle(zone());
2305 intptr_t num_args_checked;
2306 ICData::RebindRule rebind_rule;
2307
2308 if (auto const call = inst->AsInstanceCall()) {
2309 function_name = &call->function_name();
2310 arguments_descriptor = call->GetArgumentsDescriptor();
2311 num_args_checked = call->checked_argument_count();
2312 rebind_rule = ICData::RebindRule::kInstance;
2313 } else if (auto const call = inst->AsStaticCall()) {
2314 function_name = &String::Handle(zone(), call->function().name());
2315 arguments_descriptor = call->GetArgumentsDescriptor();
2316 num_args_checked =
2317 MethodRecognizer::NumArgsCheckedForStaticCall(call->function());
2318 rebind_rule = ICData::RebindRule::kStatic;
2319 } else {
2320 StoreError(list, "unexpected instruction type for ICData");
2321 return false;
2322 }
2323
2324 auto type_ptr = &Object::null_abstract_type();
2325 if (auto const type_sexp = list->ExtraLookupValue("receivers_static_type")) {
2326 auto& type = AbstractType::ZoneHandle(zone());
2327 if (!ParseAbstractType(type_sexp, &type)) return false;
2328 type_ptr = &type;
2329 }
2330
2331 ASSERT(parsed_function_ != nullptr);
2332 const auto& ic_data = ICData::ZoneHandle(
2333 zone(), ICData::New(parsed_function_->function(), *function_name,
2334 arguments_descriptor, inst->deopt_id(),
2335 num_args_checked, rebind_rule, *type_ptr));
2336
2337 if (auto const is_mega_sexp =
2338 CheckBool(list->ExtraLookupValue("is_megamorphic"))) {
2339 ic_data.set_is_megamorphic(is_mega_sexp->value());
2340 }
2341
2342 auto const class_table = thread()->isolate()->class_table();
2343 GrowableArray<intptr_t> class_ids(zone(), 2);
2344 for (intptr_t i = 1, n = list->Length(); i < n; i++) {
2345 auto const entry = CheckList(Retrieve(list, i));
2346 if (entry == nullptr) return false;
2347 ASSERT(ic_data.NumArgsTested() == entry->Length());
2348
2349 intptr_t count = 0;
2350 if (auto const count_sexp =
2351 CheckInteger(entry->ExtraLookupValue("count"))) {
2352 count = count_sexp->value();
2353 }
2354
2355 auto& target = Function::ZoneHandle(zone());
2356 if (!ParseDartValue(Retrieve(entry, "target"), &target)) return false;
2357
2358 // We can't use AddCheck for NumArgsTested < 2. We'll handle 0 here, and
2359 // 1 after the for loop.
2360 if (entry->Length() == 0) {
2361 if (count != 0) {
2362 StoreError(entry, "expected a zero count for no checked args");
2363 return false;
2364 }
2365 ic_data.AddTarget(target);
2366 continue;
2367 }
2368
2369 class_ids.Clear();
2370 for (intptr_t j = 0, num_cids = entry->Length(); j < num_cids; j++) {
2371 auto const cid_sexp = CheckInteger(Retrieve(entry, j));
2372 if (cid_sexp == nullptr) return false;
2373 const intptr_t cid = cid_sexp->value();
2374 // kObjectCid is a special case used for AddTarget() entries with
2375 // a non-zero number of checked arguments.
2376 if (cid != kObjectCid && !class_table->HasValidClassAt(cid)) {
2377 StoreError(cid_sexp, "cid is not a valid class");
2378 return false;
2379 }
2380 class_ids.Add(cid);
2381 }
2382
2383 if (entry->Length() == 1) {
2384 ic_data.AddReceiverCheck(class_ids.At(0), target, count);
2385 } else {
2386 ic_data.AddCheck(class_ids, target, count);
2387 }
2388 }
2389
2390 if (auto const call = inst->AsInstanceCall()) {
2391 call->set_ic_data(&ic_data);
2392 } else if (auto const call = inst->AsStaticCall()) {
2393 call->set_ic_data(&ic_data);
2394 }
2395
2396 return true;
2397}
2398
2399Value* FlowGraphDeserializer::AddNewPendingValue(SExpression* sexp,
2400 intptr_t index,
2401 bool inherit_type) {
2402 ASSERT(flow_graph_ != nullptr);
2403 auto const value = new (zone()) Value(flow_graph_->constant_null());
2404 ASSERT(!definition_map_.HasKey(index));
2405 auto list = values_map_.LookupValue(index);
2406 if (list == nullptr) {
2407 list = new (zone()) ZoneGrowableArray<PendingValue>(zone(), 2);
2408 values_map_.Insert(index, list);
2409 }
2410 list->Add({sexp, value, inherit_type});
2411 return value;
2412}
2413
2414bool FlowGraphDeserializer::FixPendingValues(intptr_t index, Definition* def) {
2415 if (auto value_list = values_map_.LookupValue(index)) {
2416 for (intptr_t i = 0; i < value_list->length(); i++) {
2417 const auto& value_info = value_list->At(i);
2418 auto const value = value_info.value;
2419 const bool inherit_type = value_info.inherit_type;
2420 value->BindTo(def);
2421 if (!inherit_type) continue;
2422 if (def->HasType()) {
2423 value->reaching_type_ = def->Type();
2424 } else {
2425 StoreError(value_info.sexp, "value inherits type, but no type found");
2426 return false;
2427 }
2428 }
2429 values_map_.Remove(index);
2430 }
2431 return true;
2432}
2433
2434BlockEntryInstr* FlowGraphDeserializer::FetchBlock(SExpSymbol* sym) {
2435 if (sym == nullptr) return nullptr;
2436 intptr_t block_id;
2437 if (!ParseBlockId(sym, &block_id)) return nullptr;
2438 auto const entry = block_map_.LookupValue(block_id);
2439 if (entry == nullptr) {
2440 StoreError(sym, "reference to undefined block");
2441 return nullptr;
2442 }
2443 return entry;
2444}
2445
2446#define BASE_CHECK_DEF(name, type) \
2447 SExp##name* FlowGraphDeserializer::Check##name(SExpression* sexp) { \
2448 if (sexp == nullptr) return nullptr; \
2449 if (!sexp->Is##name()) { \
2450 StoreError(sexp, "expected " #name); \
2451 return nullptr; \
2452 } \
2453 return sexp->As##name(); \
2454 }
2455
2456FOR_EACH_S_EXPRESSION(BASE_CHECK_DEF)
2457
2458#undef BASE_CHECK_DEF
2459
2460bool FlowGraphDeserializer::IsTag(SExpression* sexp, const char* label) {
2461 auto const sym = CheckSymbol(sexp);
2462 if (sym == nullptr) return false;
2463 if (label != nullptr && !sym->Equals(label)) {
2464 StoreError(sym, "expected symbol %s", label);
2465 return false;
2466 }
2467 return true;
2468}
2469
2470SExpList* FlowGraphDeserializer::CheckTaggedList(SExpression* sexp,
2471 const char* label) {
2472 auto const list = CheckList(sexp);
2473 const intptr_t tag_pos = 0;
2474 if (!IsTag(Retrieve(list, tag_pos), label)) return nullptr;
2475 return list;
2476}
2477
2478void FlowGraphDeserializer::StoreError(SExpression* sexp,
2479 const char* format,
2480 ...) {
2481 va_list args;
2482 va_start(args, format);
2483 const char* const message = OS::VSCreate(zone(), format, args);
2484 va_end(args);
2485 error_sexp_ = sexp;
2486 error_message_ = message;
2487}
2488
2489void FlowGraphDeserializer::ReportError() const {
2490 ASSERT(error_sexp_ != nullptr);
2491 ASSERT(error_message_ != nullptr);
2492 OS::PrintErr("Unable to deserialize flow_graph: %s\n", error_message_);
2493 OS::PrintErr("Error at S-expression %s\n", error_sexp_->ToCString(zone()));
2494 OS::Abort();
2495}
2496
2497} // namespace dart
2498