LCOV - code coverage report
Current view: top level - src/torque - csa-generator.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 468 503 93.0 %
Date: 2019-02-19 Functions: 30 32 93.8 %

          Line data    Source code
       1             : // Copyright 2018 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #include "src/torque/csa-generator.h"
       6             : 
       7             : #include "src/torque/type-oracle.h"
       8             : #include "src/torque/utils.h"
       9             : 
      10             : namespace v8 {
      11             : namespace internal {
      12             : namespace torque {
      13             : 
      14         724 : base::Optional<Stack<std::string>> CSAGenerator::EmitGraph(
      15             :     Stack<std::string> parameters) {
      16       13232 :   for (Block* block : cfg_.blocks()) {
      17        5530 :     out_ << "  compiler::CodeAssemblerParameterizedLabel<";
      18        5530 :     PrintCommaSeparatedList(out_, block->InputTypes(), [](const Type* t) {
      19       41189 :       return t->GetGeneratedTNodeTypeName();
      20       46719 :     });
      21       16590 :     out_ << "> " << BlockName(block) << "(&ca_, compiler::CodeAssemblerLabel::"
      22       11060 :          << (block->IsDeferred() ? "kDeferred" : "kNonDeferred") << ");\n";
      23             :   }
      24             : 
      25        2172 :   EmitInstruction(GotoInstruction{cfg_.start()}, &parameters);
      26        6978 :   for (Block* block : cfg_.blocks()) {
      27       15318 :     if (cfg_.end() && *cfg_.end() == block) continue;
      28       14883 :     out_ << "\n  if (" << BlockName(block) << ".is_used()) {\n";
      29        9922 :     EmitBlock(block);
      30        4961 :     out_ << "  }\n";
      31             :   }
      32        1448 :   if (cfg_.end()) {
      33         569 :     out_ << "\n";
      34        1707 :     return EmitBlock(*cfg_.end());
      35             :   }
      36             :   return base::nullopt;
      37             : }
      38             : 
      39        5530 : Stack<std::string> CSAGenerator::EmitBlock(const Block* block) {
      40             :   Stack<std::string> stack;
      41       46719 :   for (const Type* t : block->InputTypes()) {
      42       82378 :     stack.Push(FreshNodeName());
      43      123567 :     out_ << "    compiler::TNode<" << t->GetGeneratedTNodeTypeName() << "> "
      44       82378 :          << stack.Top() << ";\n";
      45             :   }
      46       11060 :   out_ << "    ca_.Bind(&" << BlockName(block);
      47       46719 :   for (const std::string& name : stack) {
      48       41189 :     out_ << ", &" << name;
      49             :   }
      50        5530 :   out_ << ");\n";
      51       45202 :   for (const Instruction& instruction : block->instructions()) {
      52       34142 :     EmitInstruction(instruction, &stack);
      53             :   }
      54        5530 :   return stack;
      55             : }
      56             : 
      57       34142 : void CSAGenerator::EmitSourcePosition(SourcePosition pos, bool always_emit) {
      58             :   const std::string& file = SourceFileMap::GetSource(pos.source);
      59       68284 :   if (always_emit || !previous_position_.CompareStartIgnoreColumn(pos)) {
      60             :     // Lines in Torque SourcePositions are zero-based, while the
      61             :     // CodeStubAssembler and downwind systems are one-based.
      62       10744 :     out_ << "    ca_.SetSourcePosition(\"" << file << "\", "
      63       10744 :          << (pos.start.line + 1) << ");\n";
      64        5372 :     previous_position_ = pos;
      65             :   }
      66       34142 : }
      67             : 
      68       68284 : void CSAGenerator::EmitInstruction(const Instruction& instruction,
      69             :                                    Stack<std::string>* stack) {
      70       34142 :   EmitSourcePosition(instruction->pos);
      71       34142 :   switch (instruction.kind()) {
      72             : #define ENUM_ITEM(T)          \
      73             :   case InstructionKind::k##T: \
      74             :     return EmitInstruction(instruction.Cast<T>(), stack);
      75       26372 :     TORQUE_INSTRUCTION_LIST(ENUM_ITEM)
      76             : #undef ENUM_ITEM
      77             :   }
      78             : }
      79             : 
      80       15258 : void CSAGenerator::EmitInstruction(const PeekInstruction& instruction,
      81             :                                    Stack<std::string>* stack) {
      82       30516 :   stack->Push(stack->Peek(instruction.slot));
      83       15258 : }
      84             : 
      85         856 : void CSAGenerator::EmitInstruction(const PokeInstruction& instruction,
      86             :                                    Stack<std::string>* stack) {
      87        1712 :   stack->Poke(instruction.slot, stack->Top());
      88        1712 :   stack->Pop();
      89         856 : }
      90             : 
      91           0 : void CSAGenerator::EmitInstruction(const DeleteRangeInstruction& instruction,
      92             :                                    Stack<std::string>* stack) {
      93        7770 :   stack->DeleteRange(instruction.range);
      94           0 : }
      95             : 
      96         195 : void CSAGenerator::EmitInstruction(
      97             :     const PushUninitializedInstruction& instruction,
      98             :     Stack<std::string>* stack) {
      99             :   // TODO(tebbi): This can trigger an error in CSA if it is used. Instead, we
     100             :   // should prevent usage of uninitialized in the type system. This
     101             :   // requires "if constexpr" being evaluated at Torque time.
     102         585 :   stack->Push("ca_.Uninitialized<" +
     103         390 :               instruction.type->GetGeneratedTNodeTypeName() + ">()");
     104         195 : }
     105             : 
     106          95 : void CSAGenerator::EmitInstruction(
     107             :     const PushBuiltinPointerInstruction& instruction,
     108             :     Stack<std::string>* stack) {
     109         190 :   stack->Push("ca_.UncheckedCast<BuiltinPtr>(ca_.SmiConstant(Builtins::k" +
     110          95 :               instruction.external_name + "))");
     111          95 : }
     112             : 
     113         311 : void CSAGenerator::EmitInstruction(
     114             :     const NamespaceConstantInstruction& instruction,
     115             :     Stack<std::string>* stack) {
     116         311 :   const Type* type = instruction.constant->type();
     117             :   std::vector<std::string> results;
     118        1244 :   for (const Type* lowered : LowerType(type)) {
     119         622 :     results.push_back(FreshNodeName());
     120         622 :     stack->Push(results.back());
     121         622 :     out_ << "    compiler::TNode<" << lowered->GetGeneratedTNodeTypeName()
     122         933 :          << "> " << stack->Top() << ";\n";
     123         622 :     out_ << "    USE(" << stack->Top() << ");\n";
     124             :   }
     125         311 :   out_ << "    ";
     126         311 :   if (type->IsStructType()) {
     127           0 :     out_ << "std::tie(";
     128           0 :     PrintCommaSeparatedList(out_, results);
     129           0 :     out_ << ") = ";
     130         622 :   } else if (results.size() == 1) {
     131         622 :     out_ << results[0] << " = ";
     132             :   }
     133         933 :   out_ << instruction.constant->ExternalAssemblerName() << "(state_)."
     134         622 :        << instruction.constant->constant_name() << "()";
     135         311 :   if (type->IsStructType()) {
     136           0 :     out_ << ".Flatten();\n";
     137             :   } else {
     138         311 :     out_ << ";\n";
     139         311 :   }
     140         311 : }
     141             : 
     142        4788 : void CSAGenerator::ProcessArgumentsCommon(
     143             :     const TypeVector& parameter_types, std::vector<std::string>* args,
     144             :     std::vector<std::string>* constexpr_arguments, Stack<std::string>* stack) {
     145       12837 :   for (auto it = parameter_types.rbegin(); it != parameter_types.rend(); ++it) {
     146        8049 :     const Type* type = *it;
     147             :     VisitResult arg;
     148        8049 :     if (type->IsConstexpr()) {
     149        1789 :       args->push_back(std::move(constexpr_arguments->back()));
     150             :       constexpr_arguments->pop_back();
     151             :     } else {
     152        6260 :       std::stringstream s;
     153        6260 :       size_t slot_count = LoweredSlotCount(type);
     154             :       VisitResult arg = VisitResult(type, stack->TopRange(slot_count));
     155       12520 :       EmitCSAValue(arg, *stack, s);
     156        6260 :       args->push_back(s.str());
     157       12520 :       stack->PopMany(slot_count);
     158             :     }
     159             :   }
     160             :   std::reverse(args->begin(), args->end());
     161        4788 : }
     162             : 
     163          98 : void CSAGenerator::EmitInstruction(const CallIntrinsicInstruction& instruction,
     164             :                                    Stack<std::string>* stack) {
     165             :   std::vector<std::string> constexpr_arguments =
     166          98 :       instruction.constexpr_arguments;
     167          98 :   std::vector<std::string> args;
     168             :   TypeVector parameter_types =
     169          98 :       instruction.intrinsic->signature().parameter_types.types;
     170          98 :   ProcessArgumentsCommon(parameter_types, &args, &constexpr_arguments, stack);
     171             : 
     172             :   Stack<std::string> pre_call_stack = *stack;
     173          98 :   const Type* return_type = instruction.intrinsic->signature().return_type;
     174          98 :   std::vector<std::string> results;
     175         392 :   for (const Type* type : LowerType(return_type)) {
     176         196 :     results.push_back(FreshNodeName());
     177         196 :     stack->Push(results.back());
     178         294 :     out_ << "    compiler::TNode<" << type->GetGeneratedTNodeTypeName() << "> "
     179         196 :          << stack->Top() << ";\n";
     180         196 :     out_ << "    USE(" << stack->Top() << ");\n";
     181             :   }
     182          98 :   out_ << "    ";
     183             : 
     184          98 :   if (return_type->IsStructType()) {
     185           0 :     out_ << "std::tie(";
     186           0 :     PrintCommaSeparatedList(out_, results);
     187           0 :     out_ << ") = ";
     188             :   } else {
     189         196 :     if (results.size() == 1) {
     190         196 :       out_ << results[0] << " = ";
     191             :     }
     192             :   }
     193             : 
     194         196 :   if (instruction.intrinsic->ExternalName() == "%RawDownCast") {
     195         124 :     if (parameter_types.size() != 1) {
     196           0 :       ReportError("%RawDownCast must take a single parameter");
     197             :     }
     198          62 :     if (!return_type->IsSubtypeOf(parameter_types[0])) {
     199             :       ReportError("%RawDownCast error: ", *return_type, " is not a subtype of ",
     200           0 :                   *parameter_types[0]);
     201             :     }
     202          62 :     if (return_type->IsSubtypeOf(TypeOracle::GetTaggedType())) {
     203         236 :       if (return_type->GetGeneratedTNodeTypeName() !=
     204         118 :           parameter_types[0]->GetGeneratedTNodeTypeName()) {
     205          40 :         out_ << "TORQUE_CAST";
     206             :       }
     207             :     }
     208          72 :   } else if (instruction.intrinsic->ExternalName() == "%FromConstexpr") {
     209          30 :     if (parameter_types.size() != 1 || !parameter_types[0]->IsConstexpr()) {
     210             :       ReportError(
     211             :           "%FromConstexpr must take a single parameter with constexpr "
     212           0 :           "type");
     213             :     }
     214          15 :     if (return_type->IsConstexpr()) {
     215           0 :       ReportError("%FromConstexpr must return a non-constexpr type");
     216             :     }
     217          15 :     if (return_type->IsSubtypeOf(TypeOracle::GetSmiType())) {
     218           3 :       out_ << "ca_.SmiConstant";
     219          12 :     } else if (return_type->IsSubtypeOf(TypeOracle::GetNumberType())) {
     220           4 :       out_ << "ca_.NumberConstant";
     221           8 :     } else if (return_type->IsSubtypeOf(TypeOracle::GetStringType())) {
     222           1 :       out_ << "ca_.StringConstant";
     223           7 :     } else if (return_type->IsSubtypeOf(TypeOracle::GetObjectType())) {
     224             :       ReportError(
     225             :           "%FromConstexpr cannot cast to subclass of HeapObject unless it's a "
     226           0 :           "String or Number");
     227           7 :     } else if (return_type->IsSubtypeOf(TypeOracle::GetIntPtrType())) {
     228           3 :       out_ << "ca_.IntPtrConstant";
     229           4 :     } else if (return_type->IsSubtypeOf(TypeOracle::GetUIntPtrType())) {
     230           1 :       out_ << "ca_.UintPtrConstant";
     231           3 :     } else if (return_type->IsSubtypeOf(TypeOracle::GetInt32Type())) {
     232           3 :       out_ << "ca_.Int32Constant";
     233             :     } else {
     234           0 :       std::stringstream s;
     235           0 :       s << "%FromConstexpr does not support return type " << *return_type;
     236           0 :       ReportError(s.str());
     237             :     }
     238          42 :   } else if (instruction.intrinsic->ExternalName() ==
     239             :              "%GetAllocationBaseSize") {
     240          18 :     if (instruction.specialization_types.size() != 1) {
     241             :       ReportError(
     242             :           "incorrect number of specialization classes for "
     243           0 :           "%GetAllocationBaseSize (should be one)");
     244             :     }
     245           7 :     const ClassType* class_type =
     246           9 :         ClassType::cast(instruction.specialization_types[0]);
     247             :     // Special case classes that may not always have a fixed size (e.g.
     248             :     // JSObjects). Their size must be fetched from the map.
     249           9 :     if (class_type != TypeOracle::GetJSObjectType()) {
     250           7 :       out_ << "CodeStubAssembler(state_).IntPtrConstant((";
     251          14 :       args[0] = std::to_string(class_type->size());
     252             :     } else {
     253             :       out_ << "CodeStubAssembler(state_).TimesTaggedSize(CodeStubAssembler("
     254           2 :               "state_).LoadMapInstanceSizeInWords(";
     255             :     }
     256          24 :   } else if (instruction.intrinsic->ExternalName() == "%Allocate") {
     257          18 :     out_ << "ca_.UncheckedCast<" << return_type->GetGeneratedTNodeTypeName()
     258           9 :          << ">(CodeStubAssembler(state_).Allocate";
     259           6 :   } else if (instruction.intrinsic->ExternalName() ==
     260             :              "%AllocateInternalClass") {
     261           3 :     out_ << "CodeStubAssembler(state_).AllocateUninitializedFixedArray";
     262             :   } else {
     263           0 :     ReportError("no built in intrinsic with name " +
     264           0 :                 instruction.intrinsic->ExternalName());
     265             :   }
     266             : 
     267          98 :   out_ << "(";
     268          98 :   PrintCommaSeparatedList(out_, args);
     269         196 :   if (instruction.intrinsic->ExternalName() == "%Allocate") out_ << ")";
     270         196 :   if (instruction.intrinsic->ExternalName() == "%GetAllocationBaseSize")
     271           9 :     out_ << "))";
     272          98 :   if (return_type->IsStructType()) {
     273           0 :     out_ << ").Flatten();\n";
     274             :   } else {
     275          98 :     out_ << ");\n";
     276             :   }
     277         196 :   if (instruction.intrinsic->ExternalName() == "%Allocate") {
     278           9 :     out_ << "    CodeStubAssembler(state_).InitializeFieldsWithRoot("
     279          18 :          << results[0] << ", ";
     280           9 :     out_ << "CodeStubAssembler(state_).IntPtrConstant("
     281          27 :          << std::to_string(ClassType::cast(return_type)->size()) << "), ";
     282           9 :     PrintCommaSeparatedList(out_, args);
     283           9 :     out_ << ", RootIndex::kUndefinedValue);\n";
     284          98 :   }
     285          98 : }
     286             : 
     287        4237 : void CSAGenerator::EmitInstruction(const CallCsaMacroInstruction& instruction,
     288             :                                    Stack<std::string>* stack) {
     289             :   std::vector<std::string> constexpr_arguments =
     290        4237 :       instruction.constexpr_arguments;
     291        4237 :   std::vector<std::string> args;
     292             :   TypeVector parameter_types =
     293        4237 :       instruction.macro->signature().parameter_types.types;
     294        4237 :   ProcessArgumentsCommon(parameter_types, &args, &constexpr_arguments, stack);
     295             : 
     296             :   Stack<std::string> pre_call_stack = *stack;
     297        4237 :   const Type* return_type = instruction.macro->signature().return_type;
     298        4237 :   std::vector<std::string> results;
     299       16731 :   for (const Type* type : LowerType(return_type)) {
     300        8040 :     results.push_back(FreshNodeName());
     301        8040 :     stack->Push(results.back());
     302       12060 :     out_ << "    compiler::TNode<" << type->GetGeneratedTNodeTypeName() << "> "
     303        8040 :          << stack->Top() << ";\n";
     304        8040 :     out_ << "    USE(" << stack->Top() << ");\n";
     305             :   }
     306             :   std::string catch_name =
     307        4237 :       PreCallableExceptionPreparation(instruction.catch_block);
     308        4237 :   out_ << "    ";
     309        4237 :   if (return_type->IsStructType()) {
     310          10 :     out_ << "std::tie(";
     311          10 :     PrintCommaSeparatedList(out_, results);
     312          10 :     out_ << ") = ";
     313             :   } else {
     314        8454 :     if (results.size() == 1) {
     315        7986 :       out_ << results[0] << " = ca_.UncheckedCast<"
     316       11979 :            << return_type->GetGeneratedTNodeTypeName() << ">(";
     317             :     }
     318             :   }
     319        8474 :   out_ << instruction.macro->external_assembler_name() << "(state_)."
     320        8474 :        << instruction.macro->ExternalName() << "(";
     321        4237 :   PrintCommaSeparatedList(out_, args);
     322        4237 :   if (return_type->IsStructType()) {
     323          10 :     out_ << ").Flatten();\n";
     324             :   } else {
     325        8454 :     if (results.size() == 1) out_ << ")";
     326        4227 :     out_ << ");\n";
     327             :   }
     328             :   PostCallableExceptionPreparation(catch_name, return_type,
     329        8474 :                                    instruction.catch_block, &pre_call_stack);
     330        4237 : }
     331             : 
     332         453 : void CSAGenerator::EmitInstruction(
     333             :     const CallCsaMacroAndBranchInstruction& instruction,
     334             :     Stack<std::string>* stack) {
     335             :   std::vector<std::string> constexpr_arguments =
     336         453 :       instruction.constexpr_arguments;
     337         453 :   std::vector<std::string> args;
     338             :   TypeVector parameter_types =
     339         453 :       instruction.macro->signature().parameter_types.types;
     340         453 :   ProcessArgumentsCommon(parameter_types, &args, &constexpr_arguments, stack);
     341             : 
     342             :   Stack<std::string> pre_call_stack = *stack;
     343         453 :   std::vector<std::string> results;
     344         453 :   const Type* return_type = instruction.macro->signature().return_type;
     345         453 :   if (return_type != TypeOracle::GetNeverType()) {
     346         948 :     for (const Type* type :
     347         622 :          LowerType(instruction.macro->signature().return_type)) {
     348         592 :       results.push_back(FreshNodeName());
     349         592 :       out_ << "    compiler::TNode<" << type->GetGeneratedTNodeTypeName()
     350         592 :            << "> " << results.back() << ";\n";
     351         592 :       out_ << "    USE(" << results.back() << ");\n";
     352             :     }
     353             :   }
     354             : 
     355         453 :   std::vector<std::string> label_names;
     356         453 :   std::vector<std::vector<std::string>> var_names;
     357        1388 :   const LabelDeclarationVector& labels = instruction.macro->signature().labels;
     358             :   DCHECK_EQ(labels.size(), instruction.label_blocks.size());
     359        1870 :   for (size_t i = 0; i < labels.size(); ++i) {
     360         482 :     TypeVector label_parameters = labels[i].types;
     361         964 :     label_names.push_back("label" + std::to_string(i));
     362         482 :     var_names.push_back({});
     363        1026 :     for (size_t j = 0; j < label_parameters.size(); ++j) {
     364         186 :       var_names[i].push_back("result_" + std::to_string(i) + "_" +
     365             :                              std::to_string(j));
     366          31 :       out_ << "    compiler::TypedCodeAssemblerVariable<"
     367         124 :            << label_parameters[j]->GetGeneratedTNodeTypeName() << "> "
     368          93 :            << var_names[i][j] << "(&ca_);\n";
     369             :     }
     370         964 :     out_ << "    compiler::CodeAssemblerLabel " << label_names[i]
     371         482 :          << "(&ca_);\n";
     372             :   }
     373             : 
     374             :   std::string catch_name =
     375         453 :       PreCallableExceptionPreparation(instruction.catch_block);
     376         453 :   out_ << "    ";
     377         906 :   if (results.size() == 1) {
     378         584 :     out_ << results[0] << " = ";
     379         161 :   } else if (results.size() > 1) {
     380           2 :     out_ << "std::tie(";
     381           2 :     PrintCommaSeparatedList(out_, results);
     382           2 :     out_ << ") = ";
     383             :   }
     384         906 :   out_ << instruction.macro->external_assembler_name() << "(state_)."
     385         906 :        << instruction.macro->ExternalName() << "(";
     386         453 :   PrintCommaSeparatedList(out_, args);
     387             :   bool first = args.empty();
     388        1870 :   for (size_t i = 0; i < label_names.size(); ++i) {
     389         482 :     if (!first) out_ << ", ";
     390         964 :     out_ << "&" << label_names[i];
     391             :     first = false;
     392        1539 :     for (size_t j = 0; j < var_names[i].size(); ++j) {
     393          31 :       out_ << ", &" << var_names[i][j];
     394             :     }
     395             :   }
     396         453 :   if (return_type->IsStructType()) {
     397           2 :     out_ << ").Flatten();\n";
     398             :   } else {
     399         451 :     out_ << ");\n";
     400             :   }
     401             : 
     402             :   PostCallableExceptionPreparation(catch_name, return_type,
     403         453 :                                    instruction.catch_block, &pre_call_stack);
     404             : 
     405         453 :   if (instruction.return_continuation) {
     406         652 :     out_ << "    ca_.Goto(&" << BlockName(*instruction.return_continuation);
     407        3523 :     for (const std::string& value : *stack) {
     408        3197 :       out_ << ", " << value;
     409             :     }
     410         948 :     for (const std::string& result : results) {
     411         296 :       out_ << ", " << result;
     412             :     }
     413         326 :     out_ << ");\n";
     414             :   }
     415        1417 :   for (size_t i = 0; i < label_names.size(); ++i) {
     416         964 :     out_ << "    if (" << label_names[i] << ".is_used()) {\n";
     417        1446 :     out_ << "      ca_.Bind(&" << label_names[i] << ");\n";
     418        1446 :     out_ << "      ca_.Goto(&" << BlockName(instruction.label_blocks[i]);
     419        5112 :     for (const std::string& value : *stack) {
     420        4630 :       out_ << ", " << value;
     421             :     }
     422        1477 :     for (const std::string& var : var_names[i]) {
     423          62 :       out_ << ", " << var << ".value()";
     424             :     }
     425         482 :     out_ << ");\n";
     426             : 
     427         482 :     out_ << "    }\n";
     428         453 :   }
     429         453 : }
     430             : 
     431          98 : void CSAGenerator::EmitInstruction(const CallBuiltinInstruction& instruction,
     432             :                                    Stack<std::string>* stack) {
     433          98 :   std::vector<std::string> arguments = stack->PopMany(instruction.argc);
     434             :   std::vector<const Type*> result_types =
     435          98 :       LowerType(instruction.builtin->signature().return_type);
     436          98 :   if (instruction.is_tailcall) {
     437           1 :     out_ << "   CodeStubAssembler(state_).TailCallBuiltin(Builtins::k"
     438           2 :          << instruction.builtin->ExternalName() << ", ";
     439           1 :     PrintCommaSeparatedList(out_, arguments);
     440           1 :     out_ << ");\n";
     441             :   } else {
     442          97 :     std::string result_name = FreshNodeName();
     443         194 :     if (result_types.size() == 1) {
     444          75 :       out_ << "    compiler::TNode<"
     445         225 :            << result_types[0]->GetGeneratedTNodeTypeName() << "> "
     446          75 :            << result_name << ";\n";
     447             :     }
     448             :     std::string catch_name =
     449          97 :         PreCallableExceptionPreparation(instruction.catch_block);
     450             :     Stack<std::string> pre_call_stack = *stack;
     451         194 :     if (result_types.size() == 1) {
     452          75 :       std::string generated_type = result_types[0]->GetGeneratedTNodeTypeName();
     453         150 :       stack->Push(result_name);
     454         150 :       out_ << "    " << result_name << " = ";
     455          75 :       if (generated_type != "Object") out_ << "TORQUE_CAST(";
     456          75 :       out_ << "CodeStubAssembler(state_).CallBuiltin(Builtins::k"
     457         150 :            << instruction.builtin->ExternalName() << ", ";
     458          75 :       PrintCommaSeparatedList(out_, arguments);
     459          75 :       if (generated_type != "Object") out_ << ")";
     460          75 :       out_ << ");\n";
     461         150 :       out_ << "    USE(" << result_name << ");\n";
     462             :     } else {
     463             :       DCHECK_EQ(0, result_types.size());
     464             :       // TODO(tebbi): Actually, builtins have to return a value, so we should
     465             :       // not have to handle this case.
     466          22 :       out_ << "    CodeStubAssembler(state_).CallBuiltin(Builtins::k"
     467          44 :            << instruction.builtin->ExternalName() << ", ";
     468          22 :       PrintCommaSeparatedList(out_, arguments);
     469          22 :       out_ << ");\n";
     470             :     }
     471             :     PostCallableExceptionPreparation(
     472             :         catch_name,
     473          97 :         result_types.size() == 0 ? TypeOracle::GetVoidType() : result_types[0],
     474          97 :         instruction.catch_block, &pre_call_stack);
     475          98 :   }
     476          98 : }
     477             : 
     478          14 : void CSAGenerator::EmitInstruction(
     479             :     const CallBuiltinPointerInstruction& instruction,
     480             :     Stack<std::string>* stack) {
     481             :   std::vector<std::string> function_and_arguments =
     482          14 :       stack->PopMany(1 + instruction.argc);
     483             :   std::vector<const Type*> result_types =
     484          28 :       LowerType(instruction.type->return_type());
     485          28 :   if (result_types.size() != 1) {
     486           0 :     ReportError("builtins must have exactly one result");
     487             :   }
     488          14 :   if (instruction.is_tailcall) {
     489           0 :     ReportError("tail-calls to builtin pointers are not supported");
     490             :   }
     491             : 
     492          28 :   stack->Push(FreshNodeName());
     493          14 :   std::string generated_type = result_types[0]->GetGeneratedTNodeTypeName();
     494          28 :   out_ << "    compiler::TNode<" << generated_type << "> " << stack->Top()
     495          14 :        << " = ";
     496          14 :   if (generated_type != "Object") out_ << "TORQUE_CAST(";
     497             :   out_ << "CodeStubAssembler(state_).CallBuiltinPointer(Builtins::"
     498             :           "CallableFor(ca_."
     499             :           "isolate(),"
     500          14 :           "ExampleBuiltinForTorqueFunctionPointerType("
     501          28 :        << instruction.type->function_pointer_type_id() << ")).descriptor(), ";
     502          14 :   PrintCommaSeparatedList(out_, function_and_arguments);
     503          14 :   out_ << ")";
     504          14 :   if (generated_type != "Object") out_ << ")";
     505          14 :   out_ << "; \n";
     506          42 :   out_ << "    USE(" << stack->Top() << ");\n";
     507          14 : }
     508             : 
     509        4818 : std::string CSAGenerator::PreCallableExceptionPreparation(
     510        4818 :     base::Optional<Block*> catch_block) {
     511             :   std::string catch_name;
     512        4818 :   if (catch_block) {
     513          26 :     catch_name = FreshCatchName();
     514          13 :     out_ << "    compiler::CodeAssemblerExceptionHandlerLabel " << catch_name
     515          13 :          << "_label(&ca_, compiler::CodeAssemblerLabel::kDeferred);\n";
     516          13 :     out_ << "    { compiler::CodeAssemblerScopedExceptionHandler s(&ca_, &"
     517          13 :          << catch_name << "_label);\n";
     518             :   }
     519        4818 :   return catch_name;
     520             : }
     521             : 
     522        4818 : void CSAGenerator::PostCallableExceptionPreparation(
     523             :     const std::string& catch_name, const Type* return_type,
     524        4818 :     base::Optional<Block*> catch_block, Stack<std::string>* stack) {
     525        4818 :   if (catch_block) {
     526          13 :     std::string block_name = BlockName(*catch_block);
     527          13 :     out_ << "    }\n";
     528          26 :     out_ << "    if (" << catch_name << "_label.is_used()) {\n";
     529          13 :     out_ << "      compiler::CodeAssemblerLabel " << catch_name
     530          13 :          << "_skip(&ca_);\n";
     531          13 :     if (!return_type->IsNever()) {
     532          20 :       out_ << "      ca_.Goto(&" << catch_name << "_skip);\n";
     533             :     }
     534          13 :     out_ << "      compiler::TNode<Object> " << catch_name
     535          13 :          << "_exception_object;\n";
     536          26 :     out_ << "      ca_.Bind(&" << catch_name << "_label, &" << catch_name
     537          13 :          << "_exception_object);\n";
     538          13 :     out_ << "      ca_.Goto(&" << block_name;
     539         230 :     for (size_t i = 0; i < stack->Size(); ++i) {
     540         102 :       out_ << ", " << stack->begin()[i];
     541             :     }
     542          26 :     out_ << ", " << catch_name << "_exception_object);\n";
     543          13 :     if (!return_type->IsNever()) {
     544          20 :       out_ << "      ca_.Bind(&" << catch_name << "_skip);\n";
     545             :     }
     546          13 :     out_ << "    }\n";
     547             :   }
     548        4818 : }
     549             : 
     550          31 : void CSAGenerator::EmitInstruction(const CallRuntimeInstruction& instruction,
     551             :                                    Stack<std::string>* stack) {
     552          31 :   std::vector<std::string> arguments = stack->PopMany(instruction.argc);
     553             :   const Type* return_type =
     554          31 :       instruction.runtime_function->signature().return_type;
     555             :   std::vector<const Type*> result_types;
     556          31 :   if (return_type != TypeOracle::GetNeverType()) {
     557          40 :     result_types = LowerType(return_type);
     558             :   }
     559          62 :   if (result_types.size() > 1) {
     560           0 :     ReportError("runtime function must have at most one result");
     561             :   }
     562          31 :   if (instruction.is_tailcall) {
     563           0 :     out_ << "    CodeStubAssembler(state_).TailCallRuntime(Runtime::k"
     564           0 :          << instruction.runtime_function->ExternalName() << ", ";
     565           0 :     PrintCommaSeparatedList(out_, arguments);
     566           0 :     out_ << ");\n";
     567             :   } else {
     568          31 :     std::string result_name = FreshNodeName();
     569          62 :     if (result_types.size() == 1) {
     570           7 :       out_ << "    compiler::TNode<"
     571          21 :            << result_types[0]->GetGeneratedTNodeTypeName() << "> "
     572           7 :            << result_name << ";\n";
     573             :     }
     574             :     std::string catch_name =
     575          31 :         PreCallableExceptionPreparation(instruction.catch_block);
     576             :     Stack<std::string> pre_call_stack = *stack;
     577          62 :     if (result_types.size() == 1) {
     578          14 :       stack->Push(result_name);
     579           7 :       out_ << "    " << result_name
     580           7 :            << " = TORQUE_CAST(CodeStubAssembler(state_).CallRuntime(Runtime::k"
     581          14 :            << instruction.runtime_function->ExternalName() << ", ";
     582           7 :       PrintCommaSeparatedList(out_, arguments);
     583           7 :       out_ << "));\n";
     584          14 :       out_ << "    USE(" << result_name << ");\n";
     585             :     } else {
     586             :       DCHECK_EQ(0, result_types.size());
     587          24 :       out_ << "    CodeStubAssembler(state_).CallRuntime(Runtime::k"
     588          48 :            << instruction.runtime_function->ExternalName() << ", ";
     589          24 :       PrintCommaSeparatedList(out_, arguments);
     590          24 :       out_ << ");\n";
     591          24 :       if (return_type == TypeOracle::GetNeverType()) {
     592          11 :         out_ << "    CodeStubAssembler(state_).Unreachable();\n";
     593             :       } else {
     594             :         DCHECK(return_type == TypeOracle::GetVoidType());
     595             :       }
     596             :     }
     597             :     PostCallableExceptionPreparation(catch_name, return_type,
     598          31 :                                      instruction.catch_block, &pre_call_stack);
     599          31 :   }
     600          31 : }
     601             : 
     602         731 : void CSAGenerator::EmitInstruction(const BranchInstruction& instruction,
     603             :                                    Stack<std::string>* stack) {
     604        2193 :   out_ << "    ca_.Branch(" << stack->Pop() << ", &"
     605        2193 :        << BlockName(instruction.if_true) << ", &"
     606        1462 :        << BlockName(instruction.if_false);
     607        7159 :   for (const std::string& value : *stack) {
     608        6428 :     out_ << ", " << value;
     609             :   }
     610         731 :   out_ << ");\n";
     611         731 : }
     612             : 
     613          54 : void CSAGenerator::EmitInstruction(
     614             :     const ConstexprBranchInstruction& instruction, Stack<std::string>* stack) {
     615         108 :   out_ << "    if ((" << instruction.condition << ")) {\n";
     616         108 :   out_ << "      ca_.Goto(&" << BlockName(instruction.if_true);
     617         487 :   for (const std::string& value : *stack) {
     618         433 :     out_ << ", " << value;
     619             :   }
     620          54 :   out_ << ");\n";
     621          54 :   out_ << "    } else {\n";
     622         108 :   out_ << "      ca_.Goto(&" << BlockName(instruction.if_false);
     623         487 :   for (const std::string& value : *stack) {
     624         433 :     out_ << ", " << value;
     625             :   }
     626          54 :   out_ << ");\n";
     627             : 
     628          54 :   out_ << "    }\n";
     629          54 : }
     630             : 
     631        3932 : void CSAGenerator::EmitInstruction(const GotoInstruction& instruction,
     632             :                                    Stack<std::string>* stack) {
     633        7864 :   out_ << "    ca_.Goto(&" << BlockName(instruction.destination);
     634       30458 :   for (const std::string& value : *stack) {
     635       26526 :     out_ << ", " << value;
     636             :   }
     637        3932 :   out_ << ");\n";
     638        3932 : }
     639             : 
     640         134 : void CSAGenerator::EmitInstruction(const GotoExternalInstruction& instruction,
     641             :                                    Stack<std::string>* stack) {
     642         176 :   for (auto it = instruction.variable_names.rbegin();
     643             :        it != instruction.variable_names.rend(); ++it) {
     644         168 :     out_ << "    *" << *it << " = " << stack->Pop() << ";\n";
     645             :   }
     646         268 :   out_ << "    ca_.Goto(" << instruction.destination << ");\n";
     647         134 : }
     648             : 
     649         183 : void CSAGenerator::EmitInstruction(const ReturnInstruction& instruction,
     650             :                                    Stack<std::string>* stack) {
     651         183 :   if (*linkage_ == Builtin::kVarArgsJavaScript) {
     652          72 :     out_ << "    " << ARGUMENTS_VARIABLE_STRING << "->PopAndReturn(";
     653             :   } else {
     654         111 :     out_ << "    CodeStubAssembler(state_).Return(";
     655             :   }
     656         549 :   out_ << stack->Pop() << ");\n";
     657         183 : }
     658             : 
     659           0 : void CSAGenerator::EmitInstruction(
     660             :     const PrintConstantStringInstruction& instruction,
     661             :     Stack<std::string>* stack) {
     662           0 :   out_ << "    CodeStubAssembler(state_).Print("
     663           0 :        << StringLiteralQuote(instruction.message) << ");\n";
     664           0 : }
     665             : 
     666         186 : void CSAGenerator::EmitInstruction(const AbortInstruction& instruction,
     667             :                                    Stack<std::string>* stack) {
     668         186 :   switch (instruction.kind) {
     669             :     case AbortInstruction::Kind::kUnreachable:
     670             :       DCHECK(instruction.message.empty());
     671          77 :       out_ << "    CodeStubAssembler(state_).Unreachable();\n";
     672          77 :       break;
     673             :     case AbortInstruction::Kind::kDebugBreak:
     674             :       DCHECK(instruction.message.empty());
     675           0 :       out_ << "    CodeStubAssembler(state_).DebugBreak();\n";
     676           0 :       break;
     677             :     case AbortInstruction::Kind::kAssertionFailure: {
     678             :       std::string file =
     679         109 :           StringLiteralQuote(SourceFileMap::GetSource(instruction.pos.source));
     680         109 :       out_ << "    CodeStubAssembler(state_).FailAssert("
     681         436 :            << StringLiteralQuote(instruction.message) << ", " << file << ", "
     682         218 :            << instruction.pos.start.line + 1 << ");\n";
     683             :       break;
     684             :     }
     685             :   }
     686         186 : }
     687             : 
     688          48 : void CSAGenerator::EmitInstruction(const UnsafeCastInstruction& instruction,
     689             :                                    Stack<std::string>* stack) {
     690             :   stack->Poke(stack->AboveTop() - 1,
     691         144 :               "ca_.UncheckedCast<" +
     692          96 :                   instruction.destination_type->GetGeneratedTNodeTypeName() +
     693         192 :                   ">(" + stack->Top() + ")");
     694          48 : }
     695             : 
     696          58 : void CSAGenerator::EmitInstruction(
     697             :     const LoadObjectFieldInstruction& instruction, Stack<std::string>* stack) {
     698             :   const Field& field =
     699         116 :       instruction.class_type->LookupField(instruction.field_name);
     700          58 :   std::string result_name = FreshNodeName();
     701             : 
     702             :   size_t field_size;
     703             :   std::string size_string;
     704             :   std::string machine_type;
     705         174 :   std::tie(field_size, size_string, machine_type) =
     706             :       field.GetFieldSizeInformation();
     707             : 
     708         116 :   if (instruction.class_type->IsExtern()) {
     709         123 :     out_ << field.name_and_type.type->GetGeneratedTypeName() << " "
     710          41 :          << result_name << " = ca_.UncheckedCast<"
     711          82 :          << field.name_and_type.type->GetGeneratedTNodeTypeName()
     712          82 :          << ">(CodeStubAssembler(state_).LoadObjectField(" << stack->Top()
     713         164 :          << ", " << field.aggregate->GetGeneratedTNodeTypeName() << "::k"
     714         123 :          << CamelifyString(field.name_and_type.name) << "Offset, "
     715          41 :          << machine_type + "));\n";
     716             :   } else {
     717          51 :     out_ << field.name_and_type.type->GetGeneratedTypeName() << " "
     718          17 :          << result_name << " = ca_.UncheckedCast<"
     719          34 :          << field.name_and_type.type->GetGeneratedTNodeTypeName()
     720          17 :          << ">(CodeStubAssembler(state_).UnsafeLoadFixedArrayElement("
     721          51 :          << stack->Top() << ", " << (field.offset / kTaggedSize) << "));\n";
     722             :   }
     723         174 :   stack->Poke(stack->AboveTop() - 1, result_name);
     724          58 : }
     725             : 
     726         124 : void CSAGenerator::EmitInstruction(
     727             :     const StoreObjectFieldInstruction& instruction, Stack<std::string>* stack) {
     728         124 :   auto value = stack->Pop();
     729         124 :   auto object = stack->Pop();
     730         248 :   stack->Push(value);
     731             :   const Field& field =
     732         248 :       instruction.class_type->LookupField(instruction.field_name);
     733         248 :   if (instruction.class_type->IsExtern()) {
     734          75 :     if (field.name_and_type.type->IsSubtypeOf(TypeOracle::GetTaggedType())) {
     735          53 :       if (field.offset == 0) {
     736          20 :         out_ << "    CodeStubAssembler(state_).StoreMap(" << object << ", "
     737          10 :              << value << ");\n";
     738             :       } else {
     739          43 :         out_ << "    CodeStubAssembler(state_).StoreObjectField(" << object
     740         129 :              << ", " << field.offset << ", " << value << ");\n";
     741             :       }
     742             :     } else {
     743             :       size_t field_size;
     744             :       std::string size_string;
     745             :       std::string machine_type;
     746          66 :       std::tie(field_size, size_string, machine_type) =
     747             :           field.GetFieldSizeInformation();
     748          22 :       if (field.offset == 0) {
     749           0 :         ReportError("the first field in a class object must be a map");
     750             :       }
     751          22 :       out_ << "    CodeStubAssembler(state_).StoreObjectFieldNoWriteBarrier("
     752          66 :            << object << ", " << field.offset << ", " << value << ", "
     753          22 :            << machine_type << ".representation());\n";
     754             :     }
     755             :   } else {
     756          49 :     out_ << "    CodeStubAssembler(state_).UnsafeStoreFixedArrayElement("
     757         147 :          << object << ", " << (field.offset / kTaggedSize) << ", " << value
     758          49 :          << ");\n";
     759             :   }
     760         124 : }
     761             : 
     762             : // static
     763       13418 : void CSAGenerator::EmitCSAValue(VisitResult result,
     764             :                                 const Stack<std::string>& values,
     765             :                                 std::ostream& out) {
     766        6719 :   if (!result.IsOnStack()) {
     767             :     out << result.constexpr_value();
     768        6699 :   } else if (auto* struct_type = StructType::DynamicCast(result.type())) {
     769          81 :     out << struct_type->GetGeneratedTypeName() << "{";
     770             :     bool first = true;
     771         131 :     for (auto& field : struct_type->fields()) {
     772          77 :       if (!first) {
     773          50 :         out << ", ";
     774             :       }
     775             :       first = false;
     776             :       EmitCSAValue(ProjectStructField(result, field.name_and_type.name), values,
     777         231 :                    out);
     778             :     }
     779          27 :     out << "}";
     780             :   } else {
     781             :     DCHECK_EQ(1, result.stack_range().Size());
     782       13344 :     out << "compiler::TNode<" << result.type()->GetGeneratedTNodeTypeName()
     783       13344 :         << ">{" << values.Peek(result.stack_range().begin()) << "}";
     784             :   }
     785        6719 : }
     786             : 
     787             : }  // namespace torque
     788             : }  // namespace internal
     789        9114 : }  // namespace v8

Generated by: LCOV version 1.10