LCOV - code coverage report
Current view: top level - src/torque - csa-generator.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 461 497 92.8 %
Date: 2019-03-21 Functions: 29 31 93.5 %

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

Generated by: LCOV version 1.10