| OLD | NEW | 
 | (Empty) | 
|    1 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file |  | 
|    2 // for details. All rights reserved. Use of this source code is governed by a |  | 
|    3 // BSD-style license that can be found in the LICENSE file. |  | 
|    4  |  | 
|    5 #include "vm/flow_graph_compiler_shared.h" |  | 
|    6  |  | 
|    7 #include "vm/debugger.h" |  | 
|    8 #include "vm/intermediate_language.h" |  | 
|    9 #include "vm/intrinsifier.h" |  | 
|   10 #include "vm/longjump.h" |  | 
|   11 #include "vm/parser.h" |  | 
|   12 #include "vm/stub_code.h" |  | 
|   13  |  | 
|   14 namespace dart { |  | 
|   15  |  | 
|   16 DECLARE_FLAG(bool, enable_type_checks); |  | 
|   17 DECLARE_FLAG(bool, intrinsify); |  | 
|   18 DECLARE_FLAG(int, optimization_counter_threshold); |  | 
|   19 DECLARE_FLAG(bool, trace_functions); |  | 
|   20 DECLARE_FLAG(bool, report_usage_count); |  | 
|   21  |  | 
|   22 FlowGraphCompilerShared::FlowGraphCompilerShared( |  | 
|   23     Assembler* assembler, |  | 
|   24     const ParsedFunction& parsed_function, |  | 
|   25     const GrowableArray<BlockEntryInstr*>& block_order, |  | 
|   26     bool is_optimizing) |  | 
|   27     : assembler_(assembler), |  | 
|   28       parsed_function_(parsed_function), |  | 
|   29       block_order_(block_order), |  | 
|   30       current_block_(NULL), |  | 
|   31       exception_handlers_list_(NULL), |  | 
|   32       pc_descriptors_list_(NULL), |  | 
|   33       stackmap_builder_(NULL), |  | 
|   34       block_info_(block_order.length()), |  | 
|   35       deopt_stubs_(), |  | 
|   36       is_optimizing_(is_optimizing) { |  | 
|   37   ASSERT(assembler != NULL); |  | 
|   38 } |  | 
|   39  |  | 
|   40  |  | 
|   41 FlowGraphCompilerShared::~FlowGraphCompilerShared() { |  | 
|   42   // BlockInfos are zone-allocated, so their destructors are not called. |  | 
|   43   // Verify the labels explicitly here. |  | 
|   44   for (int i = 0; i < block_info_.length(); ++i) { |  | 
|   45     ASSERT(!block_info_[i]->label.IsLinked()); |  | 
|   46     ASSERT(!block_info_[i]->label.HasNear()); |  | 
|   47   } |  | 
|   48 } |  | 
|   49  |  | 
|   50 void FlowGraphCompilerShared::InitCompiler() { |  | 
|   51   pc_descriptors_list_ = new DescriptorList(); |  | 
|   52   exception_handlers_list_ = new ExceptionHandlerList(); |  | 
|   53   block_info_.Clear(); |  | 
|   54   for (int i = 0; i < block_order_.length(); ++i) { |  | 
|   55     block_info_.Add(new BlockInfo()); |  | 
|   56   } |  | 
|   57 } |  | 
|   58  |  | 
|   59  |  | 
|   60 intptr_t FlowGraphCompilerShared::StackSize() const { |  | 
|   61   return parsed_function_.stack_local_count() + |  | 
|   62       parsed_function_.copied_parameter_count(); |  | 
|   63 } |  | 
|   64  |  | 
|   65  |  | 
|   66 Label* FlowGraphCompilerShared::GetBlockLabel( |  | 
|   67     BlockEntryInstr* block_entry) const { |  | 
|   68   intptr_t block_index = block_entry->postorder_number(); |  | 
|   69   return &block_info_[block_index]->label; |  | 
|   70 } |  | 
|   71  |  | 
|   72  |  | 
|   73 bool FlowGraphCompilerShared::IsNextBlock(TargetEntryInstr* block_entry) const { |  | 
|   74   intptr_t current_index = reverse_index(current_block()->postorder_number()); |  | 
|   75   return block_order_[current_index + 1] == block_entry; |  | 
|   76 } |  | 
|   77  |  | 
|   78  |  | 
|   79 void FlowGraphCompilerShared::AddExceptionHandler(intptr_t try_index, |  | 
|   80                                                   intptr_t pc_offset) { |  | 
|   81   exception_handlers_list_->AddHandler(try_index, pc_offset); |  | 
|   82 } |  | 
|   83  |  | 
|   84  |  | 
|   85 // Uses current pc position and try-index. |  | 
|   86 void FlowGraphCompilerShared::AddCurrentDescriptor(PcDescriptors::Kind kind, |  | 
|   87                                                    intptr_t cid, |  | 
|   88                                                    intptr_t token_index, |  | 
|   89                                                    intptr_t try_index) { |  | 
|   90   pc_descriptors_list()->AddDescriptor(kind, |  | 
|   91                                        assembler()->CodeSize(), |  | 
|   92                                        cid, |  | 
|   93                                        token_index, |  | 
|   94                                        try_index); |  | 
|   95 } |  | 
|   96  |  | 
|   97  |  | 
|   98 Label* FlowGraphCompilerShared::AddDeoptStub(intptr_t deopt_id, |  | 
|   99                                              intptr_t deopt_token_index, |  | 
|  100                                              intptr_t try_index, |  | 
|  101                                              DeoptReasonId reason, |  | 
|  102                                              Register reg1, |  | 
|  103                                              Register reg2) { |  | 
|  104   DeoptimizationStub* stub = |  | 
|  105       new DeoptimizationStub(deopt_id, deopt_token_index, try_index, reason); |  | 
|  106   stub->Push(reg1); |  | 
|  107   stub->Push(reg2); |  | 
|  108   deopt_stubs_.Add(stub); |  | 
|  109   return stub->entry_label(); |  | 
|  110 } |  | 
|  111  |  | 
|  112  |  | 
|  113 void FlowGraphCompilerShared::FinalizeExceptionHandlers(const Code& code) { |  | 
|  114   ASSERT(exception_handlers_list_ != NULL); |  | 
|  115   const ExceptionHandlers& handlers = ExceptionHandlers::Handle( |  | 
|  116       exception_handlers_list_->FinalizeExceptionHandlers(code.EntryPoint())); |  | 
|  117   code.set_exception_handlers(handlers); |  | 
|  118 } |  | 
|  119  |  | 
|  120  |  | 
|  121 void FlowGraphCompilerShared::FinalizePcDescriptors(const Code& code) { |  | 
|  122   ASSERT(pc_descriptors_list_ != NULL); |  | 
|  123   const PcDescriptors& descriptors = PcDescriptors::Handle( |  | 
|  124       pc_descriptors_list_->FinalizePcDescriptors(code.EntryPoint())); |  | 
|  125   descriptors.Verify(parsed_function_.function().is_optimizable()); |  | 
|  126   code.set_pc_descriptors(descriptors); |  | 
|  127 } |  | 
|  128  |  | 
|  129  |  | 
|  130 void FlowGraphCompilerShared::FinalizeStackmaps(const Code& code) { |  | 
|  131   if (stackmap_builder_ == NULL) { |  | 
|  132     // The unoptimizing compiler has no stack maps. |  | 
|  133     code.set_stackmaps(Array::Handle()); |  | 
|  134   } else { |  | 
|  135     // Finalize the stack map array and add it to the code object. |  | 
|  136     code.set_stackmaps( |  | 
|  137         Array::Handle(stackmap_builder_->FinalizeStackmaps(code))); |  | 
|  138   } |  | 
|  139 } |  | 
|  140  |  | 
|  141  |  | 
|  142 void FlowGraphCompilerShared::FinalizeVarDescriptors(const Code& code) { |  | 
|  143   const LocalVarDescriptors& var_descs = LocalVarDescriptors::Handle( |  | 
|  144           parsed_function_.node_sequence()->scope()->GetVarDescriptors()); |  | 
|  145   code.set_var_descriptors(var_descs); |  | 
|  146 } |  | 
|  147  |  | 
|  148  |  | 
|  149 void FlowGraphCompilerShared::FinalizeComments(const Code& code) { |  | 
|  150   code.set_comments(assembler()->GetCodeComments()); |  | 
|  151 } |  | 
|  152  |  | 
|  153  |  | 
|  154 void FlowGraphCompilerShared::GenerateDeferredCode() { |  | 
|  155   for (intptr_t i = 0; i < deopt_stubs_.length(); i++) { |  | 
|  156     deopt_stubs_[i]->GenerateCode(this); |  | 
|  157   } |  | 
|  158 } |  | 
|  159  |  | 
|  160  |  | 
|  161 void FlowGraphCompilerShared::GenerateInstanceCall( |  | 
|  162     intptr_t cid, |  | 
|  163     intptr_t token_index, |  | 
|  164     intptr_t try_index, |  | 
|  165     const String& function_name, |  | 
|  166     intptr_t argument_count, |  | 
|  167     const Array& argument_names, |  | 
|  168     intptr_t checked_argument_count) { |  | 
|  169   ICData& ic_data = |  | 
|  170       ICData::ZoneHandle(ICData::New(parsed_function().function(), |  | 
|  171                                      function_name, |  | 
|  172                                      cid, |  | 
|  173                                      checked_argument_count)); |  | 
|  174   const Array& arguments_descriptor = |  | 
|  175       CodeGenerator::ArgumentsDescriptor(argument_count, argument_names); |  | 
|  176   uword label_address = 0; |  | 
|  177   switch (checked_argument_count) { |  | 
|  178     case 1: |  | 
|  179       label_address = StubCode::OneArgCheckInlineCacheEntryPoint(); |  | 
|  180       break; |  | 
|  181     case 2: |  | 
|  182       label_address = StubCode::TwoArgsCheckInlineCacheEntryPoint(); |  | 
|  183       break; |  | 
|  184     default: |  | 
|  185       UNIMPLEMENTED(); |  | 
|  186   } |  | 
|  187   ExternalLabel target_label("InlineCache", label_address); |  | 
|  188  |  | 
|  189   const intptr_t descr_offset = EmitInstanceCall(&target_label, |  | 
|  190                                                  ic_data, |  | 
|  191                                                  arguments_descriptor, |  | 
|  192                                                  argument_count); |  | 
|  193   pc_descriptors_list()->AddDescriptor(PcDescriptors::kIcCall, |  | 
|  194                                        descr_offset, |  | 
|  195                                        cid, |  | 
|  196                                        token_index, |  | 
|  197                                        try_index); |  | 
|  198 } |  | 
|  199  |  | 
|  200  |  | 
|  201 void FlowGraphCompilerShared::GenerateStaticCall(intptr_t cid, |  | 
|  202                                                  intptr_t token_index, |  | 
|  203                                                  intptr_t try_index, |  | 
|  204                                                  const Function& function, |  | 
|  205                                                  intptr_t argument_count, |  | 
|  206                                                  const Array& argument_names) { |  | 
|  207   const Array& arguments_descriptor = |  | 
|  208       CodeGenerator::ArgumentsDescriptor(argument_count, argument_names); |  | 
|  209   const intptr_t descr_offset = EmitStaticCall(function, |  | 
|  210                                                arguments_descriptor, |  | 
|  211                                                argument_count); |  | 
|  212   pc_descriptors_list()->AddDescriptor(PcDescriptors::kFuncCall, |  | 
|  213                                        descr_offset, |  | 
|  214                                        cid, |  | 
|  215                                        token_index, |  | 
|  216                                        try_index); |  | 
|  217 } |  | 
|  218  |  | 
|  219  |  | 
|  220 void FlowGraphCompilerShared::Bailout(const char* reason) { |  | 
|  221   const char* kFormat = "FlowGraphCompiler Bailout: %s %s."; |  | 
|  222   const char* function_name = parsed_function().function().ToCString(); |  | 
|  223   intptr_t len = OS::SNPrint(NULL, 0, kFormat, function_name, reason) + 1; |  | 
|  224   char* chars = reinterpret_cast<char*>( |  | 
|  225       Isolate::Current()->current_zone()->Allocate(len)); |  | 
|  226   OS::SNPrint(chars, len, kFormat, function_name, reason); |  | 
|  227   const Error& error = Error::Handle( |  | 
|  228       LanguageError::New(String::Handle(String::New(chars)))); |  | 
|  229   Isolate::Current()->long_jump_base()->Jump(1, error); |  | 
|  230 } |  | 
|  231  |  | 
|  232  |  | 
|  233 static bool CanOptimize() { |  | 
|  234   return !FLAG_report_usage_count && |  | 
|  235          (FLAG_optimization_counter_threshold >= 0) && |  | 
|  236          !Isolate::Current()->debugger()->IsActive(); |  | 
|  237 } |  | 
|  238  |  | 
|  239  |  | 
|  240 // Returns 'true' if code generation for this function is complete, i.e., |  | 
|  241 // no fall-through to regular code is needed. |  | 
|  242 bool FlowGraphCompilerShared::TryIntrinsify() { |  | 
|  243   if (!CanOptimize()) return false; |  | 
|  244   // Intrinsification skips arguments checks, therefore disable if in checked |  | 
|  245   // mode. |  | 
|  246   if (FLAG_intrinsify && !FLAG_trace_functions && !FLAG_enable_type_checks) { |  | 
|  247     if ((parsed_function().function().kind() == RawFunction::kImplicitGetter)) { |  | 
|  248       // An implicit getter must have a specific AST structure. |  | 
|  249       const SequenceNode& sequence_node = *parsed_function().node_sequence(); |  | 
|  250       ASSERT(sequence_node.length() == 1); |  | 
|  251       ASSERT(sequence_node.NodeAt(0)->IsReturnNode()); |  | 
|  252       const ReturnNode& return_node = *sequence_node.NodeAt(0)->AsReturnNode(); |  | 
|  253       ASSERT(return_node.value()->IsLoadInstanceFieldNode()); |  | 
|  254       const LoadInstanceFieldNode& load_node = |  | 
|  255           *return_node.value()->AsLoadInstanceFieldNode(); |  | 
|  256       GenerateInlinedGetter(load_node.field().Offset()); |  | 
|  257       return true; |  | 
|  258     } |  | 
|  259     if ((parsed_function().function().kind() == RawFunction::kImplicitSetter)) { |  | 
|  260       // An implicit setter must have a specific AST structure. |  | 
|  261       // Sequence node has one store node and one return NULL node. |  | 
|  262       const SequenceNode& sequence_node = *parsed_function().node_sequence(); |  | 
|  263       ASSERT(sequence_node.length() == 2); |  | 
|  264       ASSERT(sequence_node.NodeAt(0)->IsStoreInstanceFieldNode()); |  | 
|  265       ASSERT(sequence_node.NodeAt(1)->IsReturnNode()); |  | 
|  266       const StoreInstanceFieldNode& store_node = |  | 
|  267           *sequence_node.NodeAt(0)->AsStoreInstanceFieldNode(); |  | 
|  268       GenerateInlinedSetter(store_node.field().Offset()); |  | 
|  269       return true; |  | 
|  270     } |  | 
|  271   } |  | 
|  272   // Even if an intrinsified version of the function was successfully |  | 
|  273   // generated, it may fall through to the non-intrinsified method body. |  | 
|  274   if (!FLAG_trace_functions) { |  | 
|  275     return Intrinsifier::Intrinsify(parsed_function().function(), assembler()); |  | 
|  276   } |  | 
|  277   return false; |  | 
|  278 } |  | 
|  279  |  | 
|  280  |  | 
|  281 void FlowGraphCompilerShared::GenerateNumberTypeCheck( |  | 
|  282     Register kClassIdReg, |  | 
|  283     const AbstractType& type, |  | 
|  284     Label* is_instance_lbl, |  | 
|  285     Label* is_not_instance_lbl) { |  | 
|  286   GrowableArray<intptr_t> args; |  | 
|  287   if (type.IsNumberInterface()) { |  | 
|  288     args.Add(kDouble); |  | 
|  289     args.Add(kMint); |  | 
|  290     args.Add(kBigint); |  | 
|  291   } else if (type.IsIntInterface()) { |  | 
|  292     args.Add(kMint); |  | 
|  293     args.Add(kBigint); |  | 
|  294   } else if (type.IsDoubleInterface()) { |  | 
|  295     args.Add(kDouble); |  | 
|  296   } |  | 
|  297   CheckClassIds(kClassIdReg, args, is_instance_lbl, is_not_instance_lbl); |  | 
|  298 } |  | 
|  299  |  | 
|  300  |  | 
|  301 void FlowGraphCompilerShared::GenerateStringTypeCheck( |  | 
|  302     Register kClassIdReg, |  | 
|  303     Label* is_instance_lbl, |  | 
|  304     Label* is_not_instance_lbl) { |  | 
|  305   GrowableArray<intptr_t> args; |  | 
|  306   args.Add(kOneByteString); |  | 
|  307   args.Add(kTwoByteString); |  | 
|  308   args.Add(kFourByteString); |  | 
|  309   args.Add(kExternalOneByteString); |  | 
|  310   args.Add(kExternalTwoByteString); |  | 
|  311   args.Add(kExternalFourByteString); |  | 
|  312   CheckClassIds(kClassIdReg, args, is_instance_lbl, is_not_instance_lbl); |  | 
|  313 } |  | 
|  314  |  | 
|  315  |  | 
|  316 void FlowGraphCompilerShared::GenerateListTypeCheck( |  | 
|  317     Register kClassIdReg, |  | 
|  318     Label* is_instance_lbl) { |  | 
|  319   Label unknown; |  | 
|  320   GrowableArray<intptr_t> args; |  | 
|  321   args.Add(kArray); |  | 
|  322   args.Add(kGrowableObjectArray); |  | 
|  323   args.Add(kImmutableArray); |  | 
|  324   CheckClassIds(kClassIdReg, args, is_instance_lbl, &unknown); |  | 
|  325   assembler()->Bind(&unknown); |  | 
|  326 } |  | 
|  327  |  | 
|  328 }  // namespace dart |  | 
|  329  |  | 
|  330  |  | 
| OLD | NEW |