| 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 |