| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_XXX. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_XXX. |
| 6 | 6 |
| 7 #include "vm/flow_graph_compiler.h" | 7 #include "vm/flow_graph_compiler.h" |
| 8 | 8 |
| 9 #include "vm/bit_vector.h" | 9 #include "vm/bit_vector.h" |
| 10 #include "vm/cha.h" | 10 #include "vm/cha.h" |
| (...skipping 12 matching lines...) Expand all Loading... |
| 23 #include "vm/object_store.h" | 23 #include "vm/object_store.h" |
| 24 #include "vm/parser.h" | 24 #include "vm/parser.h" |
| 25 #include "vm/raw_object.h" | 25 #include "vm/raw_object.h" |
| 26 #include "vm/stack_frame.h" | 26 #include "vm/stack_frame.h" |
| 27 #include "vm/stub_code.h" | 27 #include "vm/stub_code.h" |
| 28 #include "vm/symbols.h" | 28 #include "vm/symbols.h" |
| 29 #include "vm/timeline.h" | 29 #include "vm/timeline.h" |
| 30 | 30 |
| 31 namespace dart { | 31 namespace dart { |
| 32 | 32 |
| 33 DEFINE_FLAG(bool, enable_simd_inline, true, | 33 DEFINE_FLAG(bool, |
| 34 "Enable inlining of SIMD related method calls."); | 34 enable_simd_inline, |
| 35 DEFINE_FLAG(bool, inline_smi_string_hashcode, true, | 35 true, |
| 36 "Enable inlining of SIMD related method calls."); |
| 37 DEFINE_FLAG( |
| 38 bool, |
| 39 inline_smi_string_hashcode, |
| 40 true, |
| 36 "Inline hashcode for Smi and one-byte strings in case of megamorphic call"); | 41 "Inline hashcode for Smi and one-byte strings in case of megamorphic call"); |
| 37 DEFINE_FLAG(int, inline_smi_string_hashcode_ratio, 50, | 42 DEFINE_FLAG( |
| 43 int, |
| 44 inline_smi_string_hashcode_ratio, |
| 45 50, |
| 38 "Minimal hotness (0..100) of one-byte-string before inlining its hashcode"); | 46 "Minimal hotness (0..100) of one-byte-string before inlining its hashcode"); |
| 39 DEFINE_FLAG(int, min_optimization_counter_threshold, 5000, | 47 DEFINE_FLAG(int, |
| 40 "The minimum invocation count for a function."); | 48 min_optimization_counter_threshold, |
| 41 DEFINE_FLAG(int, optimization_counter_scale, 2000, | 49 5000, |
| 42 "The scale of invocation count, by size of the function."); | 50 "The minimum invocation count for a function."); |
| 51 DEFINE_FLAG(int, |
| 52 optimization_counter_scale, |
| 53 2000, |
| 54 "The scale of invocation count, by size of the function."); |
| 43 DEFINE_FLAG(bool, source_lines, false, "Emit source line as assembly comment."); | 55 DEFINE_FLAG(bool, source_lines, false, "Emit source line as assembly comment."); |
| 44 DEFINE_FLAG(bool, trace_inlining_intervals, false, | 56 DEFINE_FLAG(bool, |
| 45 "Inlining interval diagnostics"); | 57 trace_inlining_intervals, |
| 58 false, |
| 59 "Inlining interval diagnostics"); |
| 46 | 60 |
| 47 DECLARE_FLAG(bool, code_comments); | 61 DECLARE_FLAG(bool, code_comments); |
| 48 DECLARE_FLAG(charp, deoptimize_filter); | 62 DECLARE_FLAG(charp, deoptimize_filter); |
| 49 DECLARE_FLAG(bool, intrinsify); | 63 DECLARE_FLAG(bool, intrinsify); |
| 50 DECLARE_FLAG(bool, propagate_ic_data); | 64 DECLARE_FLAG(bool, propagate_ic_data); |
| 51 DECLARE_FLAG(int, regexp_optimization_counter_threshold); | 65 DECLARE_FLAG(int, regexp_optimization_counter_threshold); |
| 52 DECLARE_FLAG(int, reoptimization_counter_threshold); | 66 DECLARE_FLAG(int, reoptimization_counter_threshold); |
| 53 DECLARE_FLAG(int, stacktrace_every); | 67 DECLARE_FLAG(int, stacktrace_every); |
| 54 DECLARE_FLAG(charp, stacktrace_filter); | 68 DECLARE_FLAG(charp, stacktrace_filter); |
| 55 DECLARE_FLAG(bool, trace_compiler); | 69 DECLARE_FLAG(bool, trace_compiler); |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 157 } | 171 } |
| 158 } | 172 } |
| 159 } | 173 } |
| 160 | 174 |
| 161 | 175 |
| 162 // Returns true if OnebyteString is a frequent receiver class. We inline | 176 // Returns true if OnebyteString is a frequent receiver class. We inline |
| 163 // Smi check as well, since a Smi check must be done anyway. | 177 // Smi check as well, since a Smi check must be done anyway. |
| 164 // TODO(srdjan): Add check and code if Smi class is hot. | 178 // TODO(srdjan): Add check and code if Smi class is hot. |
| 165 bool FlowGraphCompiler::ShouldInlineSmiStringHashCode(const ICData& ic_data) { | 179 bool FlowGraphCompiler::ShouldInlineSmiStringHashCode(const ICData& ic_data) { |
| 166 if (!FLAG_inline_smi_string_hashcode || | 180 if (!FLAG_inline_smi_string_hashcode || |
| 167 (ic_data.target_name() != Symbols::hashCode().raw())) { | 181 (ic_data.target_name() != Symbols::hashCode().raw())) { |
| 168 return false; | 182 return false; |
| 169 } | 183 } |
| 170 // Precompiled code has no ICData, optimistically inline it. | 184 // Precompiled code has no ICData, optimistically inline it. |
| 171 if (ic_data.IsNull() || (ic_data.NumberOfChecks() == 0)) { | 185 if (ic_data.IsNull() || (ic_data.NumberOfChecks() == 0)) { |
| 172 return true; | 186 return true; |
| 173 } | 187 } |
| 174 // Check if OneByteString is hot enough. | 188 // Check if OneByteString is hot enough. |
| 175 const ICData& ic_data_sorted = | 189 const ICData& ic_data_sorted = |
| 176 ICData::Handle(ic_data.AsUnaryClassChecksSortedByCount()); | 190 ICData::Handle(ic_data.AsUnaryClassChecksSortedByCount()); |
| 177 ASSERT(ic_data_sorted.NumberOfChecks() > 0); | 191 ASSERT(ic_data_sorted.NumberOfChecks() > 0); |
| 178 if (ic_data_sorted.GetReceiverClassIdAt(0) == kOneByteStringCid) { | 192 if (ic_data_sorted.GetReceiverClassIdAt(0) == kOneByteStringCid) { |
| 179 const intptr_t total_count = ic_data_sorted.AggregateCount(); | 193 const intptr_t total_count = ic_data_sorted.AggregateCount(); |
| 180 const intptr_t ratio = (ic_data_sorted.GetCountAt(0) * 100) / total_count; | 194 const intptr_t ratio = (ic_data_sorted.GetCountAt(0) * 100) / total_count; |
| 181 return ratio > FLAG_inline_smi_string_hashcode_ratio; | 195 return ratio > FLAG_inline_smi_string_hashcode_ratio; |
| 182 } | 196 } |
| 183 return false; | 197 return false; |
| 184 } | 198 } |
| 185 | 199 |
| 186 | 200 |
| 187 FlowGraphCompiler::FlowGraphCompiler( | 201 FlowGraphCompiler::FlowGraphCompiler( |
| 188 Assembler* assembler, | 202 Assembler* assembler, |
| 189 FlowGraph* flow_graph, | 203 FlowGraph* flow_graph, |
| 190 const ParsedFunction& parsed_function, | 204 const ParsedFunction& parsed_function, |
| 191 bool is_optimizing, | 205 bool is_optimizing, |
| 192 const GrowableArray<const Function*>& inline_id_to_function, | 206 const GrowableArray<const Function*>& inline_id_to_function, |
| 193 const GrowableArray<TokenPosition>& inline_id_to_token_pos, | 207 const GrowableArray<TokenPosition>& inline_id_to_token_pos, |
| 194 const GrowableArray<intptr_t>& caller_inline_id) | 208 const GrowableArray<intptr_t>& caller_inline_id) |
| 195 : thread_(Thread::Current()), | 209 : thread_(Thread::Current()), |
| 196 zone_(Thread::Current()->zone()), | 210 zone_(Thread::Current()->zone()), |
| 197 assembler_(assembler), | 211 assembler_(assembler), |
| 198 parsed_function_(parsed_function), | 212 parsed_function_(parsed_function), |
| 199 flow_graph_(*flow_graph), | 213 flow_graph_(*flow_graph), |
| 200 block_order_(*flow_graph->CodegenBlockOrder(is_optimizing)), | 214 block_order_(*flow_graph->CodegenBlockOrder(is_optimizing)), |
| 201 current_block_(NULL), | 215 current_block_(NULL), |
| 202 exception_handlers_list_(NULL), | 216 exception_handlers_list_(NULL), |
| 203 pc_descriptors_list_(NULL), | 217 pc_descriptors_list_(NULL), |
| 204 stackmap_table_builder_(NULL), | 218 stackmap_table_builder_(NULL), |
| 205 code_source_map_builder_(NULL), | 219 code_source_map_builder_(NULL), |
| 206 saved_code_size_(0), | 220 saved_code_size_(0), |
| 207 block_info_(block_order_.length()), | 221 block_info_(block_order_.length()), |
| 208 deopt_infos_(), | 222 deopt_infos_(), |
| 209 static_calls_target_table_(), | 223 static_calls_target_table_(), |
| 210 is_optimizing_(is_optimizing), | 224 is_optimizing_(is_optimizing), |
| 211 may_reoptimize_(false), | 225 may_reoptimize_(false), |
| 212 intrinsic_mode_(false), | 226 intrinsic_mode_(false), |
| 213 double_class_(Class::ZoneHandle( | 227 double_class_( |
| 214 isolate()->object_store()->double_class())), | 228 Class::ZoneHandle(isolate()->object_store()->double_class())), |
| 215 mint_class_(Class::ZoneHandle( | 229 mint_class_(Class::ZoneHandle(isolate()->object_store()->mint_class())), |
| 216 isolate()->object_store()->mint_class())), | 230 float32x4_class_( |
| 217 float32x4_class_(Class::ZoneHandle( | 231 Class::ZoneHandle(isolate()->object_store()->float32x4_class())), |
| 218 isolate()->object_store()->float32x4_class())), | 232 float64x2_class_( |
| 219 float64x2_class_(Class::ZoneHandle( | 233 Class::ZoneHandle(isolate()->object_store()->float64x2_class())), |
| 220 isolate()->object_store()->float64x2_class())), | 234 int32x4_class_( |
| 221 int32x4_class_(Class::ZoneHandle( | 235 Class::ZoneHandle(isolate()->object_store()->int32x4_class())), |
| 222 isolate()->object_store()->int32x4_class())), | 236 list_class_(Class::ZoneHandle(Library::Handle(Library::CoreLibrary()) |
| 223 list_class_(Class::ZoneHandle( | 237 .LookupClass(Symbols::List()))), |
| 224 Library::Handle(Library::CoreLibrary()). | 238 parallel_move_resolver_(this), |
| 225 LookupClass(Symbols::List()))), | 239 pending_deoptimization_env_(NULL), |
| 226 parallel_move_resolver_(this), | 240 deopt_id_to_ic_data_(NULL), |
| 227 pending_deoptimization_env_(NULL), | 241 edge_counters_array_(Array::ZoneHandle()), |
| 228 deopt_id_to_ic_data_(NULL), | 242 inlined_code_intervals_(Array::ZoneHandle(Object::empty_array().raw())), |
| 229 edge_counters_array_(Array::ZoneHandle()), | 243 inline_id_to_function_(inline_id_to_function), |
| 230 inlined_code_intervals_(Array::ZoneHandle(Object::empty_array().raw())), | 244 inline_id_to_token_pos_(inline_id_to_token_pos), |
| 231 inline_id_to_function_(inline_id_to_function), | 245 caller_inline_id_(caller_inline_id) { |
| 232 inline_id_to_token_pos_(inline_id_to_token_pos), | |
| 233 caller_inline_id_(caller_inline_id) { | |
| 234 ASSERT(flow_graph->parsed_function().function().raw() == | 246 ASSERT(flow_graph->parsed_function().function().raw() == |
| 235 parsed_function.function().raw()); | 247 parsed_function.function().raw()); |
| 236 if (!is_optimizing) { | 248 if (!is_optimizing) { |
| 237 const intptr_t len = thread()->deopt_id(); | 249 const intptr_t len = thread()->deopt_id(); |
| 238 deopt_id_to_ic_data_ = new(zone()) ZoneGrowableArray<const ICData*>(len); | 250 deopt_id_to_ic_data_ = new (zone()) ZoneGrowableArray<const ICData*>(len); |
| 239 deopt_id_to_ic_data_->SetLength(len); | 251 deopt_id_to_ic_data_->SetLength(len); |
| 240 for (intptr_t i = 0; i < len; i++) { | 252 for (intptr_t i = 0; i < len; i++) { |
| 241 (*deopt_id_to_ic_data_)[i] = NULL; | 253 (*deopt_id_to_ic_data_)[i] = NULL; |
| 242 } | 254 } |
| 243 // TODO(fschneider): Abstract iteration into ICDataArrayIterator. | 255 // TODO(fschneider): Abstract iteration into ICDataArrayIterator. |
| 244 const Array& old_saved_ic_data = Array::Handle(zone(), | 256 const Array& old_saved_ic_data = |
| 245 flow_graph->function().ic_data_array()); | 257 Array::Handle(zone(), flow_graph->function().ic_data_array()); |
| 246 const intptr_t saved_len = | 258 const intptr_t saved_len = |
| 247 old_saved_ic_data.IsNull() ? 0 : old_saved_ic_data.Length(); | 259 old_saved_ic_data.IsNull() ? 0 : old_saved_ic_data.Length(); |
| 248 for (intptr_t i = 1; i < saved_len; i++) { | 260 for (intptr_t i = 1; i < saved_len; i++) { |
| 249 ICData& ic_data = ICData::ZoneHandle(zone()); | 261 ICData& ic_data = ICData::ZoneHandle(zone()); |
| 250 ic_data ^= old_saved_ic_data.At(i); | 262 ic_data ^= old_saved_ic_data.At(i); |
| 251 (*deopt_id_to_ic_data_)[ic_data.deopt_id()] = &ic_data; | 263 (*deopt_id_to_ic_data_)[ic_data.deopt_id()] = &ic_data; |
| 252 } | 264 } |
| 253 } | 265 } |
| 254 ASSERT(assembler != NULL); | 266 ASSERT(assembler != NULL); |
| 255 ASSERT(!list_class_.IsNull()); | 267 ASSERT(!list_class_.IsNull()); |
| 256 } | 268 } |
| 257 | 269 |
| 258 | 270 |
| 259 bool FlowGraphCompiler::IsUnboxedField(const Field& field) { | 271 bool FlowGraphCompiler::IsUnboxedField(const Field& field) { |
| 260 bool valid_class = (SupportsUnboxedDoubles() && | 272 bool valid_class = |
| 261 (field.guarded_cid() == kDoubleCid)) || | 273 (SupportsUnboxedDoubles() && (field.guarded_cid() == kDoubleCid)) || |
| 262 (SupportsUnboxedSimd128() && | 274 (SupportsUnboxedSimd128() && (field.guarded_cid() == kFloat32x4Cid)) || |
| 263 (field.guarded_cid() == kFloat32x4Cid)) || | 275 (SupportsUnboxedSimd128() && (field.guarded_cid() == kFloat64x2Cid)); |
| 264 (SupportsUnboxedSimd128() && | 276 return field.is_unboxing_candidate() && !field.is_final() && |
| 265 (field.guarded_cid() == kFloat64x2Cid)); | 277 !field.is_nullable() && valid_class; |
| 266 return field.is_unboxing_candidate() | |
| 267 && !field.is_final() | |
| 268 && !field.is_nullable() | |
| 269 && valid_class; | |
| 270 } | 278 } |
| 271 | 279 |
| 272 | 280 |
| 273 bool FlowGraphCompiler::IsPotentialUnboxedField(const Field& field) { | 281 bool FlowGraphCompiler::IsPotentialUnboxedField(const Field& field) { |
| 274 return field.is_unboxing_candidate() && | 282 return field.is_unboxing_candidate() && |
| 275 (FlowGraphCompiler::IsUnboxedField(field) || | 283 (FlowGraphCompiler::IsUnboxedField(field) || |
| 276 (!field.is_final() && (field.guarded_cid() == kIllegalCid))); | 284 (!field.is_final() && (field.guarded_cid() == kIllegalCid))); |
| 277 } | 285 } |
| 278 | 286 |
| 279 | 287 |
| 280 void FlowGraphCompiler::InitCompiler() { | 288 void FlowGraphCompiler::InitCompiler() { |
| 281 pc_descriptors_list_ = new(zone()) DescriptorList(64); | 289 pc_descriptors_list_ = new (zone()) DescriptorList(64); |
| 282 exception_handlers_list_ = new(zone()) ExceptionHandlerList(); | 290 exception_handlers_list_ = new (zone()) ExceptionHandlerList(); |
| 283 block_info_.Clear(); | 291 block_info_.Clear(); |
| 284 // Conservative detection of leaf routines used to remove the stack check | 292 // Conservative detection of leaf routines used to remove the stack check |
| 285 // on function entry. | 293 // on function entry. |
| 286 bool is_leaf = is_optimizing() && !flow_graph().IsCompiledForOsr(); | 294 bool is_leaf = is_optimizing() && !flow_graph().IsCompiledForOsr(); |
| 287 // Initialize block info and search optimized (non-OSR) code for calls | 295 // Initialize block info and search optimized (non-OSR) code for calls |
| 288 // indicating a non-leaf routine and calls without IC data indicating | 296 // indicating a non-leaf routine and calls without IC data indicating |
| 289 // possible reoptimization. | 297 // possible reoptimization. |
| 290 for (int i = 0; i < block_order_.length(); ++i) { | 298 for (int i = 0; i < block_order_.length(); ++i) { |
| 291 block_info_.Add(new(zone()) BlockInfo()); | 299 block_info_.Add(new (zone()) BlockInfo()); |
| 292 if (is_optimizing() && !flow_graph().IsCompiledForOsr()) { | 300 if (is_optimizing() && !flow_graph().IsCompiledForOsr()) { |
| 293 BlockEntryInstr* entry = block_order_[i]; | 301 BlockEntryInstr* entry = block_order_[i]; |
| 294 for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) { | 302 for (ForwardInstructionIterator it(entry); !it.Done(); it.Advance()) { |
| 295 Instruction* current = it.Current(); | 303 Instruction* current = it.Current(); |
| 296 if (current->IsBranch()) { | 304 if (current->IsBranch()) { |
| 297 current = current->AsBranch()->comparison(); | 305 current = current->AsBranch()->comparison(); |
| 298 } | 306 } |
| 299 // In optimized code, ICData is always set in the instructions. | 307 // In optimized code, ICData is always set in the instructions. |
| 300 const ICData* ic_data = NULL; | 308 const ICData* ic_data = NULL; |
| 301 if (current->IsInstanceCall()) { | 309 if (current->IsInstanceCall()) { |
| 302 ic_data = current->AsInstanceCall()->ic_data(); | 310 ic_data = current->AsInstanceCall()->ic_data(); |
| 303 } | 311 } |
| 304 if ((ic_data != NULL) && (ic_data->NumberOfUsedChecks() == 0)) { | 312 if ((ic_data != NULL) && (ic_data->NumberOfUsedChecks() == 0)) { |
| 305 may_reoptimize_ = true; | 313 may_reoptimize_ = true; |
| 306 } | 314 } |
| 307 if (is_leaf && | 315 if (is_leaf && !current->IsCheckStackOverflow() && |
| 308 !current->IsCheckStackOverflow() && | |
| 309 !current->IsParallelMove()) { | 316 !current->IsParallelMove()) { |
| 310 // Note that we do not care if the code contains instructions that | 317 // Note that we do not care if the code contains instructions that |
| 311 // can deoptimize. | 318 // can deoptimize. |
| 312 LocationSummary* locs = current->locs(); | 319 LocationSummary* locs = current->locs(); |
| 313 if ((locs != NULL) && locs->can_call()) { | 320 if ((locs != NULL) && locs->can_call()) { |
| 314 is_leaf = false; | 321 is_leaf = false; |
| 315 } | 322 } |
| 316 } | 323 } |
| 317 } | 324 } |
| 318 } | 325 } |
| (...skipping 26 matching lines...) Expand all Loading... |
| 345 return CanOptimize() && !parsed_function().function().HasBreakpoint(); | 352 return CanOptimize() && !parsed_function().function().HasBreakpoint(); |
| 346 } | 353 } |
| 347 | 354 |
| 348 | 355 |
| 349 bool FlowGraphCompiler::CanOSRFunction() const { | 356 bool FlowGraphCompiler::CanOSRFunction() const { |
| 350 return FLAG_use_osr & CanOptimizeFunction() && !is_optimizing(); | 357 return FLAG_use_osr & CanOptimizeFunction() && !is_optimizing(); |
| 351 } | 358 } |
| 352 | 359 |
| 353 | 360 |
| 354 bool FlowGraphCompiler::ForceSlowPathForStackOverflow() const { | 361 bool FlowGraphCompiler::ForceSlowPathForStackOverflow() const { |
| 355 if ((FLAG_stacktrace_every > 0) || | 362 if ((FLAG_stacktrace_every > 0) || (FLAG_deoptimize_every > 0) || |
| 356 (FLAG_deoptimize_every > 0) || | |
| 357 (isolate()->reload_every_n_stack_overflow_checks() > 0)) { | 363 (isolate()->reload_every_n_stack_overflow_checks() > 0)) { |
| 358 return true; | 364 return true; |
| 359 } | 365 } |
| 360 if (FLAG_stacktrace_filter != NULL && | 366 if (FLAG_stacktrace_filter != NULL && |
| 361 strstr(parsed_function().function().ToFullyQualifiedCString(), | 367 strstr(parsed_function().function().ToFullyQualifiedCString(), |
| 362 FLAG_stacktrace_filter) != NULL) { | 368 FLAG_stacktrace_filter) != NULL) { |
| 363 return true; | 369 return true; |
| 364 } | 370 } |
| 365 if (is_optimizing() && | 371 if (is_optimizing() && FLAG_deoptimize_filter != NULL && |
| 366 FLAG_deoptimize_filter != NULL && | |
| 367 strstr(parsed_function().function().ToFullyQualifiedCString(), | 372 strstr(parsed_function().function().ToFullyQualifiedCString(), |
| 368 FLAG_deoptimize_filter) != NULL) { | 373 FLAG_deoptimize_filter) != NULL) { |
| 369 return true; | 374 return true; |
| 370 } | 375 } |
| 371 return false; | 376 return false; |
| 372 } | 377 } |
| 373 | 378 |
| 374 | 379 |
| 375 static bool IsEmptyBlock(BlockEntryInstr* block) { | 380 static bool IsEmptyBlock(BlockEntryInstr* block) { |
| 376 return !block->IsCatchBlockEntry() && | 381 return !block->IsCatchBlockEntry() && !block->HasNonRedundantParallelMove() && |
| 377 !block->HasNonRedundantParallelMove() && | |
| 378 block->next()->IsGoto() && | 382 block->next()->IsGoto() && |
| 379 !block->next()->AsGoto()->HasNonRedundantParallelMove() && | 383 !block->next()->AsGoto()->HasNonRedundantParallelMove() && |
| 380 !block->IsIndirectEntry(); | 384 !block->IsIndirectEntry(); |
| 381 } | 385 } |
| 382 | 386 |
| 383 | 387 |
| 384 void FlowGraphCompiler::CompactBlock(BlockEntryInstr* block) { | 388 void FlowGraphCompiler::CompactBlock(BlockEntryInstr* block) { |
| 385 BlockInfo* block_info = block_info_[block->postorder_number()]; | 389 BlockInfo* block_info = block_info_[block->postorder_number()]; |
| 386 | 390 |
| 387 // Break out of cycles in the control flow graph. | 391 // Break out of cycles in the control flow graph. |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 428 block_info->set_next_nonempty_label(nonempty_label); | 432 block_info->set_next_nonempty_label(nonempty_label); |
| 429 } | 433 } |
| 430 | 434 |
| 431 | 435 |
| 432 void FlowGraphCompiler::EmitInstructionPrologue(Instruction* instr) { | 436 void FlowGraphCompiler::EmitInstructionPrologue(Instruction* instr) { |
| 433 if (!is_optimizing()) { | 437 if (!is_optimizing()) { |
| 434 if (instr->CanBecomeDeoptimizationTarget() && !instr->IsGoto()) { | 438 if (instr->CanBecomeDeoptimizationTarget() && !instr->IsGoto()) { |
| 435 // Instructions that can be deoptimization targets need to record kDeopt | 439 // Instructions that can be deoptimization targets need to record kDeopt |
| 436 // PcDescriptor corresponding to their deopt id. GotoInstr records its | 440 // PcDescriptor corresponding to their deopt id. GotoInstr records its |
| 437 // own so that it can control the placement. | 441 // own so that it can control the placement. |
| 438 AddCurrentDescriptor(RawPcDescriptors::kDeopt, | 442 AddCurrentDescriptor(RawPcDescriptors::kDeopt, instr->deopt_id(), |
| 439 instr->deopt_id(), | |
| 440 instr->token_pos()); | 443 instr->token_pos()); |
| 441 } | 444 } |
| 442 AllocateRegistersLocally(instr); | 445 AllocateRegistersLocally(instr); |
| 443 } else if (instr->MayThrow() && | 446 } else if (instr->MayThrow() && |
| 444 (CurrentTryIndex() != CatchClauseNode::kInvalidTryIndex)) { | 447 (CurrentTryIndex() != CatchClauseNode::kInvalidTryIndex)) { |
| 445 // Optimized try-block: Sync locals to fixed stack locations. | 448 // Optimized try-block: Sync locals to fixed stack locations. |
| 446 EmitTrySync(instr, CurrentTryIndex()); | 449 EmitTrySync(instr, CurrentTryIndex()); |
| 447 } | 450 } |
| 448 } | 451 } |
| 449 | 452 |
| 450 | 453 |
| 451 | |
| 452 void FlowGraphCompiler::EmitSourceLine(Instruction* instr) { | 454 void FlowGraphCompiler::EmitSourceLine(Instruction* instr) { |
| 453 if (!instr->token_pos().IsReal() || (instr->env() == NULL)) { | 455 if (!instr->token_pos().IsReal() || (instr->env() == NULL)) { |
| 454 return; | 456 return; |
| 455 } | 457 } |
| 456 const Script& script = | 458 const Script& script = |
| 457 Script::Handle(zone(), instr->env()->function().script()); | 459 Script::Handle(zone(), instr->env()->function().script()); |
| 458 intptr_t line_nr; | 460 intptr_t line_nr; |
| 459 intptr_t column_nr; | 461 intptr_t column_nr; |
| 460 script.GetTokenLocation(instr->token_pos(), &line_nr, &column_nr); | 462 script.GetTokenLocation(instr->token_pos(), &line_nr, &column_nr); |
| 461 const String& line = String::Handle(zone(), script.GetLine(line_nr)); | 463 const String& line = String::Handle(zone(), script.GetLine(line_nr)); |
| 462 assembler()->Comment("Line %" Pd " in '%s':\n %s", | 464 assembler()->Comment("Line %" Pd " in '%s':\n %s", line_nr, |
| 463 line_nr, | 465 instr->env()->function().ToFullyQualifiedCString(), |
| 464 instr->env()->function().ToFullyQualifiedCString(), | 466 line.ToCString()); |
| 465 line.ToCString()); | |
| 466 } | 467 } |
| 467 | 468 |
| 468 | 469 |
| 469 static void LoopInfoComment( | 470 static void LoopInfoComment( |
| 470 Assembler* assembler, | 471 Assembler* assembler, |
| 471 const BlockEntryInstr& block, | 472 const BlockEntryInstr& block, |
| 472 const ZoneGrowableArray<BlockEntryInstr*>& loop_headers) { | 473 const ZoneGrowableArray<BlockEntryInstr*>& loop_headers) { |
| 473 if (Assembler::EmittingComments()) { | 474 if (Assembler::EmittingComments()) { |
| 474 for (intptr_t loop_id = 0; loop_id < loop_headers.length(); ++loop_id) { | 475 for (intptr_t loop_id = 0; loop_id < loop_headers.length(); ++loop_id) { |
| 475 for (BitVector::Iterator loop_it(loop_headers[loop_id]->loop_info()); | 476 for (BitVector::Iterator loop_it(loop_headers[loop_id]->loop_info()); |
| 476 !loop_it.Done(); | 477 !loop_it.Done(); loop_it.Advance()) { |
| 477 loop_it.Advance()) { | |
| 478 if (loop_it.Current() == block.preorder_number()) { | 478 if (loop_it.Current() == block.preorder_number()) { |
| 479 assembler->Comment(" Loop %" Pd "", loop_id); | 479 assembler->Comment(" Loop %" Pd "", loop_id); |
| 480 } | 480 } |
| 481 } | 481 } |
| 482 } | 482 } |
| 483 } | 483 } |
| 484 } | 484 } |
| 485 | 485 |
| 486 | 486 |
| 487 // We collect intervals while generating code. | 487 // We collect intervals while generating code. |
| 488 struct IntervalStruct { | 488 struct IntervalStruct { |
| 489 // 'start' is the pc-offsets where the inlined code started. | 489 // 'start' is the pc-offsets where the inlined code started. |
| 490 // 'pos' is the token position where the inlined call occured. | 490 // 'pos' is the token position where the inlined call occured. |
| 491 intptr_t start; | 491 intptr_t start; |
| 492 TokenPosition pos; | 492 TokenPosition pos; |
| 493 intptr_t inlining_id; | 493 intptr_t inlining_id; |
| 494 IntervalStruct(intptr_t s, TokenPosition tp, intptr_t id) | 494 IntervalStruct(intptr_t s, TokenPosition tp, intptr_t id) |
| 495 : start(s), pos(tp), inlining_id(id) {} | 495 : start(s), pos(tp), inlining_id(id) {} |
| 496 void Dump() { | 496 void Dump() { |
| 497 THR_Print("start: 0x%" Px " iid: %" Pd " pos: %s", | 497 THR_Print("start: 0x%" Px " iid: %" Pd " pos: %s", start, inlining_id, |
| 498 start, inlining_id, pos.ToCString()); | 498 pos.ToCString()); |
| 499 } | 499 } |
| 500 }; | 500 }; |
| 501 | 501 |
| 502 | 502 |
| 503 void FlowGraphCompiler::VisitBlocks() { | 503 void FlowGraphCompiler::VisitBlocks() { |
| 504 CompactBlocks(); | 504 CompactBlocks(); |
| 505 const ZoneGrowableArray<BlockEntryInstr*>* loop_headers = NULL; | 505 const ZoneGrowableArray<BlockEntryInstr*>* loop_headers = NULL; |
| 506 if (Assembler::EmittingComments()) { | 506 if (Assembler::EmittingComments()) { |
| 507 // 'loop_headers' were cleared, recompute. | 507 // 'loop_headers' were cleared, recompute. |
| 508 loop_headers = flow_graph().ComputeLoops(); | 508 loop_headers = flow_graph().ComputeLoops(); |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 555 } else { | 555 } else { |
| 556 // We will add this token position later when generating the | 556 // We will add this token position later when generating the |
| 557 // profile. | 557 // profile. |
| 558 prev_inlining_pos = TokenPosition::kNoSource; | 558 prev_inlining_pos = TokenPosition::kNoSource; |
| 559 } | 559 } |
| 560 if (prev_inlining_id > max_inlining_id) { | 560 if (prev_inlining_id > max_inlining_id) { |
| 561 max_inlining_id = prev_inlining_id; | 561 max_inlining_id = prev_inlining_id; |
| 562 } | 562 } |
| 563 } | 563 } |
| 564 } | 564 } |
| 565 if (FLAG_code_comments || | 565 if (FLAG_code_comments || FLAG_disassemble || |
| 566 FLAG_disassemble || FLAG_disassemble_optimized) { | 566 FLAG_disassemble_optimized) { |
| 567 if (FLAG_source_lines) { | 567 if (FLAG_source_lines) { |
| 568 EmitSourceLine(instr); | 568 EmitSourceLine(instr); |
| 569 } | 569 } |
| 570 EmitComment(instr); | 570 EmitComment(instr); |
| 571 } | 571 } |
| 572 if (instr->IsParallelMove()) { | 572 if (instr->IsParallelMove()) { |
| 573 parallel_move_resolver_.EmitNativeCode(instr->AsParallelMove()); | 573 parallel_move_resolver_.EmitNativeCode(instr->AsParallelMove()); |
| 574 } else { | 574 } else { |
| 575 BeginCodeSourceRange(); | 575 BeginCodeSourceRange(); |
| 576 EmitInstructionPrologue(instr); | 576 EmitInstructionPrologue(instr); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 602 Array::New(intervals.length() * Code::kInlIntNumEntries, Heap::kOld); | 602 Array::New(intervals.length() * Code::kInlIntNumEntries, Heap::kOld); |
| 603 Smi& start_h = Smi::Handle(); | 603 Smi& start_h = Smi::Handle(); |
| 604 Smi& caller_inline_id = Smi::Handle(); | 604 Smi& caller_inline_id = Smi::Handle(); |
| 605 Smi& inline_id = Smi::Handle(); | 605 Smi& inline_id = Smi::Handle(); |
| 606 for (intptr_t i = 0; i < intervals.length(); i++) { | 606 for (intptr_t i = 0; i < intervals.length(); i++) { |
| 607 if (FLAG_trace_inlining_intervals && is_optimizing()) { | 607 if (FLAG_trace_inlining_intervals && is_optimizing()) { |
| 608 const Function& function = | 608 const Function& function = |
| 609 *inline_id_to_function_.At(intervals[i].inlining_id); | 609 *inline_id_to_function_.At(intervals[i].inlining_id); |
| 610 intervals[i].Dump(); | 610 intervals[i].Dump(); |
| 611 THR_Print(" parent iid %" Pd " %s\n", | 611 THR_Print(" parent iid %" Pd " %s\n", |
| 612 caller_inline_id_[intervals[i].inlining_id], | 612 caller_inline_id_[intervals[i].inlining_id], |
| 613 function.ToQualifiedCString()); | 613 function.ToQualifiedCString()); |
| 614 } | 614 } |
| 615 | 615 |
| 616 const intptr_t id = intervals[i].inlining_id; | 616 const intptr_t id = intervals[i].inlining_id; |
| 617 start_h = Smi::New(intervals[i].start); | 617 start_h = Smi::New(intervals[i].start); |
| 618 inline_id = Smi::New(id); | 618 inline_id = Smi::New(id); |
| 619 caller_inline_id = Smi::New(caller_inline_id_[intervals[i].inlining_id]); | 619 caller_inline_id = Smi::New(caller_inline_id_[intervals[i].inlining_id]); |
| 620 | 620 |
| 621 const intptr_t p = i * Code::kInlIntNumEntries; | 621 const intptr_t p = i * Code::kInlIntNumEntries; |
| 622 inlined_code_intervals_.SetAt(p + Code::kInlIntStart, start_h); | 622 inlined_code_intervals_.SetAt(p + Code::kInlIntStart, start_h); |
| 623 inlined_code_intervals_.SetAt(p + Code::kInlIntInliningId, inline_id); | 623 inlined_code_intervals_.SetAt(p + Code::kInlIntInliningId, inline_id); |
| 624 } | 624 } |
| 625 } | 625 } |
| 626 set_current_block(NULL); | 626 set_current_block(NULL); |
| 627 if (FLAG_trace_inlining_intervals && is_optimizing()) { | 627 if (FLAG_trace_inlining_intervals && is_optimizing()) { |
| 628 LogBlock lb; | 628 LogBlock lb; |
| 629 THR_Print("Intervals:\n"); | 629 THR_Print("Intervals:\n"); |
| 630 for (intptr_t cc = 0; cc < caller_inline_id_.length(); cc++) { | 630 for (intptr_t cc = 0; cc < caller_inline_id_.length(); cc++) { |
| 631 THR_Print(" iid: %" Pd " caller iid: %" Pd "\n", | 631 THR_Print(" iid: %" Pd " caller iid: %" Pd "\n", cc, |
| 632 cc, caller_inline_id_[cc]); | 632 caller_inline_id_[cc]); |
| 633 } | 633 } |
| 634 Smi& temp = Smi::Handle(); | 634 Smi& temp = Smi::Handle(); |
| 635 for (intptr_t i = 0; i < inlined_code_intervals_.Length(); | 635 for (intptr_t i = 0; i < inlined_code_intervals_.Length(); |
| 636 i += Code::kInlIntNumEntries) { | 636 i += Code::kInlIntNumEntries) { |
| 637 temp ^= inlined_code_intervals_.At(i + Code::kInlIntStart); | 637 temp ^= inlined_code_intervals_.At(i + Code::kInlIntStart); |
| 638 ASSERT(!temp.IsNull()); | 638 ASSERT(!temp.IsNull()); |
| 639 THR_Print("% " Pd " start: 0x%" Px " ", i, temp.Value()); | 639 THR_Print("% " Pd " start: 0x%" Px " ", i, temp.Value()); |
| 640 temp ^= inlined_code_intervals_.At(i + Code::kInlIntInliningId); | 640 temp ^= inlined_code_intervals_.At(i + Code::kInlIntInliningId); |
| 641 THR_Print("iid: %" Pd " ", temp.Value()); | 641 THR_Print("iid: %" Pd " ", temp.Value()); |
| 642 } | 642 } |
| (...skipping 14 matching lines...) Expand all Loading... |
| 657 const GrowableArray<Definition*>* idefs = catch_block->initial_definitions(); | 657 const GrowableArray<Definition*>* idefs = catch_block->initial_definitions(); |
| 658 | 658 |
| 659 // Construct a ParallelMove instruction for parameters and locals. Skip the | 659 // Construct a ParallelMove instruction for parameters and locals. Skip the |
| 660 // special locals exception_var and stacktrace_var since they will be filled | 660 // special locals exception_var and stacktrace_var since they will be filled |
| 661 // when an exception is thrown. Constant locations are known to be the same | 661 // when an exception is thrown. Constant locations are known to be the same |
| 662 // at all instructions that may throw, and do not need to be materialized. | 662 // at all instructions that may throw, and do not need to be materialized. |
| 663 | 663 |
| 664 // Parameters first. | 664 // Parameters first. |
| 665 intptr_t i = 0; | 665 intptr_t i = 0; |
| 666 const intptr_t num_non_copied_params = flow_graph().num_non_copied_params(); | 666 const intptr_t num_non_copied_params = flow_graph().num_non_copied_params(); |
| 667 ParallelMoveInstr* move_instr = new(zone()) ParallelMoveInstr(); | 667 ParallelMoveInstr* move_instr = new (zone()) ParallelMoveInstr(); |
| 668 for (; i < num_non_copied_params; ++i) { | 668 for (; i < num_non_copied_params; ++i) { |
| 669 // Don't sync captured parameters. They are not in the environment. | 669 // Don't sync captured parameters. They are not in the environment. |
| 670 if (flow_graph().captured_parameters()->Contains(i)) continue; | 670 if (flow_graph().captured_parameters()->Contains(i)) continue; |
| 671 if ((*idefs)[i]->IsConstant()) continue; // Common constants | 671 if ((*idefs)[i]->IsConstant()) continue; // Common constants |
| 672 Location src = env->LocationAt(i); | 672 Location src = env->LocationAt(i); |
| 673 #if defined(TARGET_ARCH_DBC) | 673 #if defined(TARGET_ARCH_DBC) |
| 674 intptr_t dest_index = kNumberOfCpuRegisters - 1 - i; | 674 intptr_t dest_index = kNumberOfCpuRegisters - 1 - i; |
| 675 Location dest = Location::RegisterLocation(dest_index); | 675 Location dest = Location::RegisterLocation(dest_index); |
| 676 // Update safepoint bitmap to indicate that the target location | 676 // Update safepoint bitmap to indicate that the target location |
| 677 // now contains a pointer. With DBC parameters are copied into | 677 // now contains a pointer. With DBC parameters are copied into |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 710 } | 710 } |
| 711 parallel_move_resolver()->EmitNativeCode(move_instr); | 711 parallel_move_resolver()->EmitNativeCode(move_instr); |
| 712 } | 712 } |
| 713 | 713 |
| 714 | 714 |
| 715 intptr_t FlowGraphCompiler::StackSize() const { | 715 intptr_t FlowGraphCompiler::StackSize() const { |
| 716 if (is_optimizing_) { | 716 if (is_optimizing_) { |
| 717 return flow_graph_.graph_entry()->spill_slot_count(); | 717 return flow_graph_.graph_entry()->spill_slot_count(); |
| 718 } else { | 718 } else { |
| 719 return parsed_function_.num_stack_locals() + | 719 return parsed_function_.num_stack_locals() + |
| 720 parsed_function_.num_copied_params(); | 720 parsed_function_.num_copied_params(); |
| 721 } | 721 } |
| 722 } | 722 } |
| 723 | 723 |
| 724 | 724 |
| 725 Label* FlowGraphCompiler::GetJumpLabel( | 725 Label* FlowGraphCompiler::GetJumpLabel(BlockEntryInstr* block_entry) const { |
| 726 BlockEntryInstr* block_entry) const { | |
| 727 const intptr_t block_index = block_entry->postorder_number(); | 726 const intptr_t block_index = block_entry->postorder_number(); |
| 728 return block_info_[block_index]->jump_label(); | 727 return block_info_[block_index]->jump_label(); |
| 729 } | 728 } |
| 730 | 729 |
| 731 | 730 |
| 732 bool FlowGraphCompiler::WasCompacted( | 731 bool FlowGraphCompiler::WasCompacted(BlockEntryInstr* block_entry) const { |
| 733 BlockEntryInstr* block_entry) const { | |
| 734 const intptr_t block_index = block_entry->postorder_number(); | 732 const intptr_t block_index = block_entry->postorder_number(); |
| 735 return block_info_[block_index]->WasCompacted(); | 733 return block_info_[block_index]->WasCompacted(); |
| 736 } | 734 } |
| 737 | 735 |
| 738 | 736 |
| 739 Label* FlowGraphCompiler::NextNonEmptyLabel() const { | 737 Label* FlowGraphCompiler::NextNonEmptyLabel() const { |
| 740 const intptr_t current_index = current_block()->postorder_number(); | 738 const intptr_t current_index = current_block()->postorder_number(); |
| 741 return block_info_[current_index]->next_nonempty_label(); | 739 return block_info_[current_index]->next_nonempty_label(); |
| 742 } | 740 } |
| 743 | 741 |
| 744 | 742 |
| 745 bool FlowGraphCompiler::CanFallThroughTo(BlockEntryInstr* block_entry) const { | 743 bool FlowGraphCompiler::CanFallThroughTo(BlockEntryInstr* block_entry) const { |
| 746 return NextNonEmptyLabel() == GetJumpLabel(block_entry); | 744 return NextNonEmptyLabel() == GetJumpLabel(block_entry); |
| 747 } | 745 } |
| 748 | 746 |
| 749 | 747 |
| 750 BranchLabels FlowGraphCompiler::CreateBranchLabels(BranchInstr* branch) const { | 748 BranchLabels FlowGraphCompiler::CreateBranchLabels(BranchInstr* branch) const { |
| 751 Label* true_label = GetJumpLabel(branch->true_successor()); | 749 Label* true_label = GetJumpLabel(branch->true_successor()); |
| 752 Label* false_label = GetJumpLabel(branch->false_successor()); | 750 Label* false_label = GetJumpLabel(branch->false_successor()); |
| 753 Label* fall_through = NextNonEmptyLabel(); | 751 Label* fall_through = NextNonEmptyLabel(); |
| 754 BranchLabels result = { true_label, false_label, fall_through }; | 752 BranchLabels result = {true_label, false_label, fall_through}; |
| 755 return result; | 753 return result; |
| 756 } | 754 } |
| 757 | 755 |
| 758 | 756 |
| 759 void FlowGraphCompiler::AddSlowPathCode(SlowPathCode* code) { | 757 void FlowGraphCompiler::AddSlowPathCode(SlowPathCode* code) { |
| 760 slow_path_code_.Add(code); | 758 slow_path_code_.Add(code); |
| 761 } | 759 } |
| 762 | 760 |
| 763 | 761 |
| 764 void FlowGraphCompiler::GenerateDeferredCode() { | 762 void FlowGraphCompiler::GenerateDeferredCode() { |
| 765 for (intptr_t i = 0; i < slow_path_code_.length(); i++) { | 763 for (intptr_t i = 0; i < slow_path_code_.length(); i++) { |
| 766 BeginCodeSourceRange(); | 764 BeginCodeSourceRange(); |
| 767 slow_path_code_[i]->GenerateCode(this); | 765 slow_path_code_[i]->GenerateCode(this); |
| 768 EndCodeSourceRange(TokenPosition::kDeferredSlowPath); | 766 EndCodeSourceRange(TokenPosition::kDeferredSlowPath); |
| 769 } | 767 } |
| 770 for (intptr_t i = 0; i < deopt_infos_.length(); i++) { | 768 for (intptr_t i = 0; i < deopt_infos_.length(); i++) { |
| 771 BeginCodeSourceRange(); | 769 BeginCodeSourceRange(); |
| 772 deopt_infos_[i]->GenerateCode(this, i); | 770 deopt_infos_[i]->GenerateCode(this, i); |
| 773 EndCodeSourceRange(TokenPosition::kDeferredDeoptInfo); | 771 EndCodeSourceRange(TokenPosition::kDeferredDeoptInfo); |
| 774 } | 772 } |
| 775 } | 773 } |
| 776 | 774 |
| 777 | 775 |
| 778 void FlowGraphCompiler::AddExceptionHandler(intptr_t try_index, | 776 void FlowGraphCompiler::AddExceptionHandler(intptr_t try_index, |
| 779 intptr_t outer_try_index, | 777 intptr_t outer_try_index, |
| 780 intptr_t pc_offset, | 778 intptr_t pc_offset, |
| 781 const Array& handler_types, | 779 const Array& handler_types, |
| 782 bool needs_stacktrace) { | 780 bool needs_stacktrace) { |
| 783 exception_handlers_list_->AddHandler(try_index, | 781 exception_handlers_list_->AddHandler(try_index, outer_try_index, pc_offset, |
| 784 outer_try_index, | 782 handler_types, needs_stacktrace); |
| 785 pc_offset, | |
| 786 handler_types, | |
| 787 needs_stacktrace); | |
| 788 } | 783 } |
| 789 | 784 |
| 790 | 785 |
| 791 void FlowGraphCompiler::SetNeedsStacktrace(intptr_t try_index) { | 786 void FlowGraphCompiler::SetNeedsStacktrace(intptr_t try_index) { |
| 792 exception_handlers_list_->SetNeedsStacktrace(try_index); | 787 exception_handlers_list_->SetNeedsStacktrace(try_index); |
| 793 } | 788 } |
| 794 | 789 |
| 795 | 790 |
| 796 // Uses current pc position and try-index. | 791 // Uses current pc position and try-index. |
| 797 void FlowGraphCompiler::AddCurrentDescriptor(RawPcDescriptors::Kind kind, | 792 void FlowGraphCompiler::AddCurrentDescriptor(RawPcDescriptors::Kind kind, |
| 798 intptr_t deopt_id, | 793 intptr_t deopt_id, |
| 799 TokenPosition token_pos) { | 794 TokenPosition token_pos) { |
| 800 // When running with optimizations disabled, don't emit deopt-descriptors. | 795 // When running with optimizations disabled, don't emit deopt-descriptors. |
| 801 if (!CanOptimize() && (kind == RawPcDescriptors::kDeopt)) return; | 796 if (!CanOptimize() && (kind == RawPcDescriptors::kDeopt)) return; |
| 802 pc_descriptors_list()->AddDescriptor(kind, | 797 pc_descriptors_list()->AddDescriptor(kind, assembler()->CodeSize(), deopt_id, |
| 803 assembler()->CodeSize(), | 798 token_pos, CurrentTryIndex()); |
| 804 deopt_id, | |
| 805 token_pos, | |
| 806 CurrentTryIndex()); | |
| 807 } | 799 } |
| 808 | 800 |
| 809 | 801 |
| 810 void FlowGraphCompiler::AddStaticCallTarget(const Function& func) { | 802 void FlowGraphCompiler::AddStaticCallTarget(const Function& func) { |
| 811 ASSERT(func.IsZoneHandle()); | 803 ASSERT(func.IsZoneHandle()); |
| 812 static_calls_target_table_.Add( | 804 static_calls_target_table_.Add( |
| 813 new(zone()) StaticCallsStruct(assembler()->CodeSize(), &func, NULL)); | 805 new (zone()) StaticCallsStruct(assembler()->CodeSize(), &func, NULL)); |
| 814 } | 806 } |
| 815 | 807 |
| 816 | 808 |
| 817 void FlowGraphCompiler::AddStubCallTarget(const Code& code) { | 809 void FlowGraphCompiler::AddStubCallTarget(const Code& code) { |
| 818 ASSERT(code.IsZoneHandle()); | 810 ASSERT(code.IsZoneHandle()); |
| 819 static_calls_target_table_.Add( | 811 static_calls_target_table_.Add( |
| 820 new(zone()) StaticCallsStruct(assembler()->CodeSize(), NULL, &code)); | 812 new (zone()) StaticCallsStruct(assembler()->CodeSize(), NULL, &code)); |
| 821 } | 813 } |
| 822 | 814 |
| 823 | 815 |
| 824 void FlowGraphCompiler::AddDeoptIndexAtCall(intptr_t deopt_id) { | 816 void FlowGraphCompiler::AddDeoptIndexAtCall(intptr_t deopt_id) { |
| 825 ASSERT(is_optimizing()); | 817 ASSERT(is_optimizing()); |
| 826 ASSERT(!intrinsic_mode()); | 818 ASSERT(!intrinsic_mode()); |
| 827 CompilerDeoptInfo* info = | 819 CompilerDeoptInfo* info = |
| 828 new(zone()) CompilerDeoptInfo(deopt_id, | 820 new (zone()) CompilerDeoptInfo(deopt_id, ICData::kDeoptAtCall, |
| 829 ICData::kDeoptAtCall, | 821 0, // No flags. |
| 830 0, // No flags. | 822 pending_deoptimization_env_); |
| 831 pending_deoptimization_env_); | |
| 832 info->set_pc_offset(assembler()->CodeSize()); | 823 info->set_pc_offset(assembler()->CodeSize()); |
| 833 deopt_infos_.Add(info); | 824 deopt_infos_.Add(info); |
| 834 } | 825 } |
| 835 | 826 |
| 836 | 827 |
| 837 // This function must be in sync with FlowGraphCompiler::SaveLiveRegisters | 828 // This function must be in sync with FlowGraphCompiler::SaveLiveRegisters |
| 838 // and FlowGraphCompiler::SlowPathEnvironmentFor. | 829 // and FlowGraphCompiler::SlowPathEnvironmentFor. |
| 839 // See StackFrame::VisitObjectPointers for the details of how stack map is | 830 // See StackFrame::VisitObjectPointers for the details of how stack map is |
| 840 // interpreted. | 831 // interpreted. |
| 841 void FlowGraphCompiler::RecordSafepoint(LocationSummary* locs, | 832 void FlowGraphCompiler::RecordSafepoint(LocationSummary* locs, |
| 842 intptr_t slow_path_argument_count) { | 833 intptr_t slow_path_argument_count) { |
| 843 if (is_optimizing() || locs->live_registers()->HasUntaggedValues()) { | 834 if (is_optimizing() || locs->live_registers()->HasUntaggedValues()) { |
| 844 const intptr_t spill_area_size = is_optimizing() ? | 835 const intptr_t spill_area_size = |
| 845 flow_graph_.graph_entry()->spill_slot_count() : 0; | 836 is_optimizing() ? flow_graph_.graph_entry()->spill_slot_count() : 0; |
| 846 | 837 |
| 847 RegisterSet* registers = locs->live_registers(); | 838 RegisterSet* registers = locs->live_registers(); |
| 848 ASSERT(registers != NULL); | 839 ASSERT(registers != NULL); |
| 849 const intptr_t kFpuRegisterSpillFactor = | 840 const intptr_t kFpuRegisterSpillFactor = kFpuRegisterSize / kWordSize; |
| 850 kFpuRegisterSize / kWordSize; | 841 const intptr_t live_registers_size = |
| 851 const intptr_t live_registers_size = registers->CpuRegisterCount() + | 842 registers->CpuRegisterCount() + |
| 852 (registers->FpuRegisterCount() * kFpuRegisterSpillFactor); | 843 (registers->FpuRegisterCount() * kFpuRegisterSpillFactor); |
| 853 | 844 |
| 854 BitmapBuilder* bitmap = locs->stack_bitmap(); | 845 BitmapBuilder* bitmap = locs->stack_bitmap(); |
| 855 | 846 |
| 856 // An instruction may have two safepoints in deferred code. The | 847 // An instruction may have two safepoints in deferred code. The |
| 857 // call to RecordSafepoint has the side-effect of appending the live | 848 // call to RecordSafepoint has the side-effect of appending the live |
| 858 // registers to the bitmap. This is why the second call to RecordSafepoint | 849 // registers to the bitmap. This is why the second call to RecordSafepoint |
| 859 // with the same instruction (and same location summary) sees a bitmap that | 850 // with the same instruction (and same location summary) sees a bitmap that |
| 860 // is larger that StackSize(). It will never be larger than StackSize() + | 851 // is larger that StackSize(). It will never be larger than StackSize() + |
| 861 // live_registers_size. | 852 // live_registers_size. |
| 862 // The first safepoint will grow the bitmap to be the size of | 853 // The first safepoint will grow the bitmap to be the size of |
| 863 // spill_area_size but the second safepoint will truncate the bitmap and | 854 // spill_area_size but the second safepoint will truncate the bitmap and |
| 864 // append the live registers to it again. The bitmap produced by both calls | 855 // append the live registers to it again. The bitmap produced by both calls |
| 865 // will be the same. | 856 // will be the same. |
| 866 #if !defined(TARGET_ARCH_DBC) | 857 #if !defined(TARGET_ARCH_DBC) |
| 867 ASSERT(bitmap->Length() <= (spill_area_size + live_registers_size)); | 858 ASSERT(bitmap->Length() <= (spill_area_size + live_registers_size)); |
| 868 bitmap->SetLength(spill_area_size); | 859 bitmap->SetLength(spill_area_size); |
| 869 #else | 860 #else |
| 870 if (bitmap->Length() <= (spill_area_size + live_registers_size)) { | 861 if (bitmap->Length() <= (spill_area_size + live_registers_size)) { |
| 871 bitmap->SetLength(Utils::Maximum(bitmap->Length(), spill_area_size)); | 862 bitmap->SetLength(Utils::Maximum(bitmap->Length(), spill_area_size)); |
| 872 } | 863 } |
| 873 #endif | 864 #endif |
| 874 | 865 |
| 875 // Mark the bits in the stack map in the same order we push registers in | 866 // Mark the bits in the stack map in the same order we push registers in |
| (...skipping 30 matching lines...) Expand all Loading... |
| 906 } | 897 } |
| 907 | 898 |
| 908 // Arguments pushed on top of live registers in the slow path are tagged. | 899 // Arguments pushed on top of live registers in the slow path are tagged. |
| 909 for (intptr_t i = 0; i < slow_path_argument_count; ++i) { | 900 for (intptr_t i = 0; i < slow_path_argument_count; ++i) { |
| 910 bitmap->Set(bitmap->Length(), true); | 901 bitmap->Set(bitmap->Length(), true); |
| 911 } | 902 } |
| 912 | 903 |
| 913 // The slow path area Outside the spill area contains are live registers | 904 // The slow path area Outside the spill area contains are live registers |
| 914 // and pushed arguments for calls inside the slow path. | 905 // and pushed arguments for calls inside the slow path. |
| 915 intptr_t slow_path_bit_count = bitmap->Length() - spill_area_size; | 906 intptr_t slow_path_bit_count = bitmap->Length() - spill_area_size; |
| 916 stackmap_table_builder()->AddEntry(assembler()->CodeSize(), | 907 stackmap_table_builder()->AddEntry(assembler()->CodeSize(), bitmap, |
| 917 bitmap, | |
| 918 slow_path_bit_count); | 908 slow_path_bit_count); |
| 919 } | 909 } |
| 920 } | 910 } |
| 921 | 911 |
| 922 | 912 |
| 923 // This function must be kept in sync with: | 913 // This function must be kept in sync with: |
| 924 // | 914 // |
| 925 // FlowGraphCompiler::RecordSafepoint | 915 // FlowGraphCompiler::RecordSafepoint |
| 926 // FlowGraphCompiler::SaveLiveRegisters | 916 // FlowGraphCompiler::SaveLiveRegisters |
| 927 // MaterializeObjectInstr::RemapRegisters | 917 // MaterializeObjectInstr::RemapRegisters |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 962 } else { | 952 } else { |
| 963 cpu_reg_slots[i] = -1; | 953 cpu_reg_slots[i] = -1; |
| 964 } | 954 } |
| 965 } | 955 } |
| 966 | 956 |
| 967 // 2. Iterate the environment and replace register locations with the | 957 // 2. Iterate the environment and replace register locations with the |
| 968 // corresponding spill slot locations. | 958 // corresponding spill slot locations. |
| 969 for (Environment::DeepIterator it(env); !it.Done(); it.Advance()) { | 959 for (Environment::DeepIterator it(env); !it.Done(); it.Advance()) { |
| 970 Location loc = it.CurrentLocation(); | 960 Location loc = it.CurrentLocation(); |
| 971 Value* value = it.CurrentValue(); | 961 Value* value = it.CurrentValue(); |
| 972 it.SetCurrentLocation(loc.RemapForSlowPath( | 962 it.SetCurrentLocation(loc.RemapForSlowPath(value->definition(), |
| 973 value->definition(), cpu_reg_slots, fpu_reg_slots)); | 963 cpu_reg_slots, fpu_reg_slots)); |
| 974 } | 964 } |
| 975 | 965 |
| 976 return env; | 966 return env; |
| 977 } | 967 } |
| 978 | 968 |
| 979 | 969 |
| 980 Label* FlowGraphCompiler::AddDeoptStub(intptr_t deopt_id, | 970 Label* FlowGraphCompiler::AddDeoptStub(intptr_t deopt_id, |
| 981 ICData::DeoptReasonId reason, | 971 ICData::DeoptReasonId reason, |
| 982 uint32_t flags) { | 972 uint32_t flags) { |
| 983 if (intrinsic_mode()) { | 973 if (intrinsic_mode()) { |
| 984 return &intrinsic_slow_path_label_; | 974 return &intrinsic_slow_path_label_; |
| 985 } | 975 } |
| 986 | 976 |
| 987 // No deoptimization allowed when 'FLAG_precompiled_mode' is set. | 977 // No deoptimization allowed when 'FLAG_precompiled_mode' is set. |
| 988 if (FLAG_precompiled_mode) { | 978 if (FLAG_precompiled_mode) { |
| 989 if (FLAG_trace_compiler) { | 979 if (FLAG_trace_compiler) { |
| 990 THR_Print( | 980 THR_Print( |
| 991 "Retrying compilation %s, suppressing inlining of deopt_id:%" Pd "\n", | 981 "Retrying compilation %s, suppressing inlining of deopt_id:%" Pd "\n", |
| 992 parsed_function_.function().ToFullyQualifiedCString(), deopt_id); | 982 parsed_function_.function().ToFullyQualifiedCString(), deopt_id); |
| 993 } | 983 } |
| 994 ASSERT(deopt_id != 0); // longjmp must return non-zero value. | 984 ASSERT(deopt_id != 0); // longjmp must return non-zero value. |
| 995 Thread::Current()->long_jump_base()->Jump( | 985 Thread::Current()->long_jump_base()->Jump( |
| 996 deopt_id, Object::speculative_inlining_error()); | 986 deopt_id, Object::speculative_inlining_error()); |
| 997 } | 987 } |
| 998 | 988 |
| 999 ASSERT(is_optimizing_); | 989 ASSERT(is_optimizing_); |
| 1000 CompilerDeoptInfoWithStub* stub = | 990 CompilerDeoptInfoWithStub* stub = new (zone()) CompilerDeoptInfoWithStub( |
| 1001 new(zone()) CompilerDeoptInfoWithStub(deopt_id, | 991 deopt_id, reason, flags, pending_deoptimization_env_); |
| 1002 reason, | |
| 1003 flags, | |
| 1004 pending_deoptimization_env_); | |
| 1005 deopt_infos_.Add(stub); | 992 deopt_infos_.Add(stub); |
| 1006 return stub->entry_label(); | 993 return stub->entry_label(); |
| 1007 } | 994 } |
| 1008 | 995 |
| 1009 | 996 |
| 1010 #if defined(TARGET_ARCH_DBC) | 997 #if defined(TARGET_ARCH_DBC) |
| 1011 void FlowGraphCompiler::EmitDeopt(intptr_t deopt_id, | 998 void FlowGraphCompiler::EmitDeopt(intptr_t deopt_id, |
| 1012 ICData::DeoptReasonId reason, | 999 ICData::DeoptReasonId reason, |
| 1013 uint32_t flags) { | 1000 uint32_t flags) { |
| 1014 ASSERT(is_optimizing()); | 1001 ASSERT(is_optimizing()); |
| 1015 ASSERT(!intrinsic_mode()); | 1002 ASSERT(!intrinsic_mode()); |
| 1016 // The pending deoptimization environment may be changed after this deopt is | 1003 // The pending deoptimization environment may be changed after this deopt is |
| 1017 // emitted, so we need to make a copy. | 1004 // emitted, so we need to make a copy. |
| 1018 Environment* env_copy = | 1005 Environment* env_copy = pending_deoptimization_env_->DeepCopy(zone()); |
| 1019 pending_deoptimization_env_->DeepCopy(zone()); | |
| 1020 CompilerDeoptInfo* info = | 1006 CompilerDeoptInfo* info = |
| 1021 new(zone()) CompilerDeoptInfo(deopt_id, | 1007 new (zone()) CompilerDeoptInfo(deopt_id, reason, flags, env_copy); |
| 1022 reason, | |
| 1023 flags, | |
| 1024 env_copy); | |
| 1025 deopt_infos_.Add(info); | 1008 deopt_infos_.Add(info); |
| 1026 assembler()->Deopt(0, /*is_eager =*/ 1); | 1009 assembler()->Deopt(0, /*is_eager =*/1); |
| 1027 info->set_pc_offset(assembler()->CodeSize()); | 1010 info->set_pc_offset(assembler()->CodeSize()); |
| 1028 } | 1011 } |
| 1029 #endif // defined(TARGET_ARCH_DBC) | 1012 #endif // defined(TARGET_ARCH_DBC) |
| 1030 | 1013 |
| 1031 | 1014 |
| 1032 void FlowGraphCompiler::FinalizeExceptionHandlers(const Code& code) { | 1015 void FlowGraphCompiler::FinalizeExceptionHandlers(const Code& code) { |
| 1033 ASSERT(exception_handlers_list_ != NULL); | 1016 ASSERT(exception_handlers_list_ != NULL); |
| 1034 const ExceptionHandlers& handlers = ExceptionHandlers::Handle( | 1017 const ExceptionHandlers& handlers = ExceptionHandlers::Handle( |
| 1035 exception_handlers_list_->FinalizeExceptionHandlers(code.PayloadStart())); | 1018 exception_handlers_list_->FinalizeExceptionHandlers(code.PayloadStart())); |
| 1036 code.set_exception_handlers(handlers); | 1019 code.set_exception_handlers(handlers); |
| 1037 if (FLAG_compiler_stats) { | 1020 if (FLAG_compiler_stats) { |
| 1038 Thread* thread = Thread::Current(); | 1021 Thread* thread = Thread::Current(); |
| 1039 INC_STAT(thread, total_code_size, | 1022 INC_STAT(thread, total_code_size, |
| 1040 ExceptionHandlers::InstanceSize(handlers.num_entries())); | 1023 ExceptionHandlers::InstanceSize(handlers.num_entries())); |
| 1041 INC_STAT(thread, total_code_size, handlers.num_entries() * sizeof(uword)); | 1024 INC_STAT(thread, total_code_size, handlers.num_entries() * sizeof(uword)); |
| 1042 } | 1025 } |
| 1043 } | 1026 } |
| 1044 | 1027 |
| 1045 | 1028 |
| 1046 void FlowGraphCompiler::FinalizePcDescriptors(const Code& code) { | 1029 void FlowGraphCompiler::FinalizePcDescriptors(const Code& code) { |
| 1047 ASSERT(pc_descriptors_list_ != NULL); | 1030 ASSERT(pc_descriptors_list_ != NULL); |
| 1048 const PcDescriptors& descriptors = PcDescriptors::Handle( | 1031 const PcDescriptors& descriptors = PcDescriptors::Handle( |
| 1049 pc_descriptors_list_->FinalizePcDescriptors(code.PayloadStart())); | 1032 pc_descriptors_list_->FinalizePcDescriptors(code.PayloadStart())); |
| 1050 if (!is_optimizing_) descriptors.Verify(parsed_function_.function()); | 1033 if (!is_optimizing_) descriptors.Verify(parsed_function_.function()); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 1070 } else { | 1053 } else { |
| 1071 const Array& array = | 1054 const Array& array = |
| 1072 Array::Handle(Array::New(deopt_info_table_size, Heap::kOld)); | 1055 Array::Handle(Array::New(deopt_info_table_size, Heap::kOld)); |
| 1073 Smi& offset = Smi::Handle(); | 1056 Smi& offset = Smi::Handle(); |
| 1074 TypedData& info = TypedData::Handle(); | 1057 TypedData& info = TypedData::Handle(); |
| 1075 Smi& reason_and_flags = Smi::Handle(); | 1058 Smi& reason_and_flags = Smi::Handle(); |
| 1076 for (intptr_t i = 0; i < deopt_infos_.length(); i++) { | 1059 for (intptr_t i = 0; i < deopt_infos_.length(); i++) { |
| 1077 offset = Smi::New(deopt_infos_[i]->pc_offset()); | 1060 offset = Smi::New(deopt_infos_[i]->pc_offset()); |
| 1078 info = deopt_infos_[i]->CreateDeoptInfo(this, &builder, array); | 1061 info = deopt_infos_[i]->CreateDeoptInfo(this, &builder, array); |
| 1079 reason_and_flags = DeoptTable::EncodeReasonAndFlags( | 1062 reason_and_flags = DeoptTable::EncodeReasonAndFlags( |
| 1080 deopt_infos_[i]->reason(), | 1063 deopt_infos_[i]->reason(), deopt_infos_[i]->flags()); |
| 1081 deopt_infos_[i]->flags()); | |
| 1082 DeoptTable::SetEntry(array, i, offset, info, reason_and_flags); | 1064 DeoptTable::SetEntry(array, i, offset, info, reason_and_flags); |
| 1083 } | 1065 } |
| 1084 return array.raw(); | 1066 return array.raw(); |
| 1085 } | 1067 } |
| 1086 } | 1068 } |
| 1087 | 1069 |
| 1088 | 1070 |
| 1089 void FlowGraphCompiler::FinalizeStackmaps(const Code& code) { | 1071 void FlowGraphCompiler::FinalizeStackmaps(const Code& code) { |
| 1090 if (stackmap_table_builder_ == NULL) { | 1072 if (stackmap_table_builder_ == NULL) { |
| 1091 code.set_stackmaps(Object::null_array()); | 1073 code.set_stackmaps(Object::null_array()); |
| (...skipping 27 matching lines...) Expand all Loading... |
| 1119 info.end_pos = TokenPosition::kMinSource; | 1101 info.end_pos = TokenPosition::kMinSource; |
| 1120 info.set_index(parsed_function().current_context_var()->index()); | 1102 info.set_index(parsed_function().current_context_var()->index()); |
| 1121 var_descs.SetVar(0, Symbols::CurrentContextVar(), &info); | 1103 var_descs.SetVar(0, Symbols::CurrentContextVar(), &info); |
| 1122 } | 1104 } |
| 1123 code.set_var_descriptors(var_descs); | 1105 code.set_var_descriptors(var_descs); |
| 1124 } | 1106 } |
| 1125 | 1107 |
| 1126 | 1108 |
| 1127 void FlowGraphCompiler::FinalizeStaticCallTargetsTable(const Code& code) { | 1109 void FlowGraphCompiler::FinalizeStaticCallTargetsTable(const Code& code) { |
| 1128 ASSERT(code.static_calls_target_table() == Array::null()); | 1110 ASSERT(code.static_calls_target_table() == Array::null()); |
| 1129 const Array& targets = Array::Handle(zone(), Array::New( | 1111 const Array& targets = |
| 1130 (static_calls_target_table_.length() * Code::kSCallTableEntryLength), | 1112 Array::Handle(zone(), Array::New((static_calls_target_table_.length() * |
| 1131 Heap::kOld)); | 1113 Code::kSCallTableEntryLength), |
| 1114 Heap::kOld)); |
| 1132 Smi& smi_offset = Smi::Handle(zone()); | 1115 Smi& smi_offset = Smi::Handle(zone()); |
| 1133 for (intptr_t i = 0; i < static_calls_target_table_.length(); i++) { | 1116 for (intptr_t i = 0; i < static_calls_target_table_.length(); i++) { |
| 1134 const intptr_t target_ix = Code::kSCallTableEntryLength * i; | 1117 const intptr_t target_ix = Code::kSCallTableEntryLength * i; |
| 1135 smi_offset = Smi::New(static_calls_target_table_[i]->offset); | 1118 smi_offset = Smi::New(static_calls_target_table_[i]->offset); |
| 1136 targets.SetAt(target_ix + Code::kSCallTableOffsetEntry, smi_offset); | 1119 targets.SetAt(target_ix + Code::kSCallTableOffsetEntry, smi_offset); |
| 1137 if (static_calls_target_table_[i]->function != NULL) { | 1120 if (static_calls_target_table_[i]->function != NULL) { |
| 1138 targets.SetAt(target_ix + Code::kSCallTableFunctionEntry, | 1121 targets.SetAt(target_ix + Code::kSCallTableFunctionEntry, |
| 1139 *static_calls_target_table_[i]->function); | 1122 *static_calls_target_table_[i]->function); |
| 1140 } | 1123 } |
| 1141 if (static_calls_target_table_[i]->code != NULL) { | 1124 if (static_calls_target_table_[i]->code != NULL) { |
| 1142 targets.SetAt(target_ix + Code::kSCallTableCodeEntry, | 1125 targets.SetAt(target_ix + Code::kSCallTableCodeEntry, |
| 1143 *static_calls_target_table_[i]->code); | 1126 *static_calls_target_table_[i]->code); |
| 1144 } | 1127 } |
| 1145 } | 1128 } |
| 1146 code.set_static_calls_target_table(targets); | 1129 code.set_static_calls_target_table(targets); |
| 1147 INC_STAT(Thread::Current(), | 1130 INC_STAT(Thread::Current(), total_code_size, |
| 1148 total_code_size, | |
| 1149 targets.Length() * sizeof(uword)); | 1131 targets.Length() * sizeof(uword)); |
| 1150 } | 1132 } |
| 1151 | 1133 |
| 1152 | 1134 |
| 1153 // Returns 'true' if regular code generation should be skipped. | 1135 // Returns 'true' if regular code generation should be skipped. |
| 1154 bool FlowGraphCompiler::TryIntrinsify() { | 1136 bool FlowGraphCompiler::TryIntrinsify() { |
| 1155 // Intrinsification skips arguments checks, therefore disable if in checked | 1137 // Intrinsification skips arguments checks, therefore disable if in checked |
| 1156 // mode. | 1138 // mode. |
| 1157 if (FLAG_intrinsify && !isolate()->type_checks()) { | 1139 if (FLAG_intrinsify && !isolate()->type_checks()) { |
| 1158 const Class& owner = Class::Handle(parsed_function().function().Owner()); | 1140 const Class& owner = Class::Handle(parsed_function().function().Owner()); |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1201 // before any deoptimization point. | 1183 // before any deoptimization point. |
| 1202 ASSERT(!intrinsic_slow_path_label_.IsBound()); | 1184 ASSERT(!intrinsic_slow_path_label_.IsBound()); |
| 1203 assembler()->Bind(&intrinsic_slow_path_label_); | 1185 assembler()->Bind(&intrinsic_slow_path_label_); |
| 1204 return complete; | 1186 return complete; |
| 1205 } | 1187 } |
| 1206 | 1188 |
| 1207 | 1189 |
| 1208 // DBC is very different from other architectures in how it performs instance | 1190 // DBC is very different from other architectures in how it performs instance |
| 1209 // and static calls because it does not use stubs. | 1191 // and static calls because it does not use stubs. |
| 1210 #if !defined(TARGET_ARCH_DBC) | 1192 #if !defined(TARGET_ARCH_DBC) |
| 1211 void FlowGraphCompiler::GenerateInstanceCall( | 1193 void FlowGraphCompiler::GenerateInstanceCall(intptr_t deopt_id, |
| 1212 intptr_t deopt_id, | 1194 TokenPosition token_pos, |
| 1213 TokenPosition token_pos, | 1195 intptr_t argument_count, |
| 1214 intptr_t argument_count, | 1196 LocationSummary* locs, |
| 1215 LocationSummary* locs, | 1197 const ICData& ic_data_in) { |
| 1216 const ICData& ic_data_in) { | |
| 1217 ICData& ic_data = ICData::ZoneHandle(ic_data_in.Original()); | 1198 ICData& ic_data = ICData::ZoneHandle(ic_data_in.Original()); |
| 1218 if (FLAG_precompiled_mode) { | 1199 if (FLAG_precompiled_mode) { |
| 1219 ic_data = ic_data.AsUnaryClassChecks(); | 1200 ic_data = ic_data.AsUnaryClassChecks(); |
| 1220 EmitSwitchableInstanceCall(ic_data, argument_count, | 1201 EmitSwitchableInstanceCall(ic_data, argument_count, deopt_id, token_pos, |
| 1221 deopt_id, token_pos, locs); | 1202 locs); |
| 1222 return; | 1203 return; |
| 1223 } | 1204 } |
| 1224 ASSERT(!ic_data.IsNull()); | 1205 ASSERT(!ic_data.IsNull()); |
| 1225 if (is_optimizing() && (ic_data_in.NumberOfUsedChecks() == 0)) { | 1206 if (is_optimizing() && (ic_data_in.NumberOfUsedChecks() == 0)) { |
| 1226 // Emit IC call that will count and thus may need reoptimization at | 1207 // Emit IC call that will count and thus may need reoptimization at |
| 1227 // function entry. | 1208 // function entry. |
| 1228 ASSERT(may_reoptimize() || flow_graph().IsCompiledForOsr()); | 1209 ASSERT(may_reoptimize() || flow_graph().IsCompiledForOsr()); |
| 1229 switch (ic_data.NumArgsTested()) { | 1210 switch (ic_data.NumArgsTested()) { |
| 1230 case 1: | 1211 case 1: |
| 1231 EmitOptimizedInstanceCall( | 1212 EmitOptimizedInstanceCall( |
| 1232 *StubCode::OneArgOptimizedCheckInlineCache_entry(), ic_data, | 1213 *StubCode::OneArgOptimizedCheckInlineCache_entry(), ic_data, |
| 1233 argument_count, deopt_id, token_pos, locs); | 1214 argument_count, deopt_id, token_pos, locs); |
| 1234 return; | 1215 return; |
| 1235 case 2: | 1216 case 2: |
| 1236 EmitOptimizedInstanceCall( | 1217 EmitOptimizedInstanceCall( |
| 1237 *StubCode::TwoArgsOptimizedCheckInlineCache_entry(), ic_data, | 1218 *StubCode::TwoArgsOptimizedCheckInlineCache_entry(), ic_data, |
| 1238 argument_count, deopt_id, token_pos, locs); | 1219 argument_count, deopt_id, token_pos, locs); |
| 1239 return; | 1220 return; |
| 1240 default: | 1221 default: |
| 1241 UNIMPLEMENTED(); | 1222 UNIMPLEMENTED(); |
| 1242 } | 1223 } |
| 1243 return; | 1224 return; |
| 1244 } | 1225 } |
| 1245 | 1226 |
| 1246 if (is_optimizing()) { | 1227 if (is_optimizing()) { |
| 1247 EmitMegamorphicInstanceCall(ic_data_in, argument_count, | 1228 EmitMegamorphicInstanceCall(ic_data_in, argument_count, deopt_id, token_pos, |
| 1248 deopt_id, token_pos, locs, | 1229 locs, CatchClauseNode::kInvalidTryIndex); |
| 1249 CatchClauseNode::kInvalidTryIndex); | |
| 1250 return; | 1230 return; |
| 1251 } | 1231 } |
| 1252 | 1232 |
| 1253 switch (ic_data.NumArgsTested()) { | 1233 switch (ic_data.NumArgsTested()) { |
| 1254 case 1: | 1234 case 1: |
| 1255 EmitInstanceCall( | 1235 EmitInstanceCall(*StubCode::OneArgCheckInlineCache_entry(), ic_data, |
| 1256 *StubCode::OneArgCheckInlineCache_entry(), ic_data, argument_count, | 1236 argument_count, deopt_id, token_pos, locs); |
| 1257 deopt_id, token_pos, locs); | |
| 1258 break; | 1237 break; |
| 1259 case 2: | 1238 case 2: |
| 1260 EmitInstanceCall( | 1239 EmitInstanceCall(*StubCode::TwoArgsCheckInlineCache_entry(), ic_data, |
| 1261 *StubCode::TwoArgsCheckInlineCache_entry(), ic_data, argument_count, | 1240 argument_count, deopt_id, token_pos, locs); |
| 1262 deopt_id, token_pos, locs); | |
| 1263 break; | 1241 break; |
| 1264 default: | 1242 default: |
| 1265 UNIMPLEMENTED(); | 1243 UNIMPLEMENTED(); |
| 1266 } | 1244 } |
| 1267 } | 1245 } |
| 1268 | 1246 |
| 1269 | 1247 |
| 1270 void FlowGraphCompiler::GenerateStaticCall(intptr_t deopt_id, | 1248 void FlowGraphCompiler::GenerateStaticCall(intptr_t deopt_id, |
| 1271 TokenPosition token_pos, | 1249 TokenPosition token_pos, |
| 1272 const Function& function, | 1250 const Function& function, |
| 1273 intptr_t argument_count, | 1251 intptr_t argument_count, |
| 1274 const Array& argument_names, | 1252 const Array& argument_names, |
| 1275 LocationSummary* locs, | 1253 LocationSummary* locs, |
| 1276 const ICData& ic_data_in) { | 1254 const ICData& ic_data_in) { |
| 1277 const ICData& ic_data = ICData::ZoneHandle(ic_data_in.Original()); | 1255 const ICData& ic_data = ICData::ZoneHandle(ic_data_in.Original()); |
| 1278 const Array& arguments_descriptor = Array::ZoneHandle( | 1256 const Array& arguments_descriptor = |
| 1279 ic_data.IsNull() ? ArgumentsDescriptor::New(argument_count, | 1257 Array::ZoneHandle(ic_data.IsNull() ? ArgumentsDescriptor::New( |
| 1280 argument_names) | 1258 argument_count, argument_names) |
| 1281 : ic_data.arguments_descriptor()); | 1259 : ic_data.arguments_descriptor()); |
| 1282 if (is_optimizing()) { | 1260 if (is_optimizing()) { |
| 1283 EmitOptimizedStaticCall(function, arguments_descriptor, | 1261 EmitOptimizedStaticCall(function, arguments_descriptor, argument_count, |
| 1284 argument_count, deopt_id, token_pos, locs); | 1262 deopt_id, token_pos, locs); |
| 1285 } else { | 1263 } else { |
| 1286 ICData& call_ic_data = ICData::ZoneHandle(ic_data.raw()); | 1264 ICData& call_ic_data = ICData::ZoneHandle(ic_data.raw()); |
| 1287 if (call_ic_data.IsNull()) { | 1265 if (call_ic_data.IsNull()) { |
| 1288 const intptr_t kNumArgsChecked = 0; | 1266 const intptr_t kNumArgsChecked = 0; |
| 1289 call_ic_data = GetOrAddStaticCallICData(deopt_id, | 1267 call_ic_data = |
| 1290 function, | 1268 GetOrAddStaticCallICData(deopt_id, function, arguments_descriptor, |
| 1291 arguments_descriptor, | 1269 kNumArgsChecked) |
| 1292 kNumArgsChecked)->raw(); | 1270 ->raw(); |
| 1293 } | 1271 } |
| 1294 EmitUnoptimizedStaticCall(argument_count, deopt_id, token_pos, locs, | 1272 EmitUnoptimizedStaticCall(argument_count, deopt_id, token_pos, locs, |
| 1295 call_ic_data); | 1273 call_ic_data); |
| 1296 } | 1274 } |
| 1297 } | 1275 } |
| 1298 | 1276 |
| 1299 | 1277 |
| 1300 void FlowGraphCompiler::GenerateNumberTypeCheck(Register kClassIdReg, | 1278 void FlowGraphCompiler::GenerateNumberTypeCheck(Register kClassIdReg, |
| 1301 const AbstractType& type, | 1279 const AbstractType& type, |
| 1302 Label* is_instance_lbl, | 1280 Label* is_instance_lbl, |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1354 assembler()->Comment("%s", buffer); | 1332 assembler()->Comment("%s", buffer); |
| 1355 #endif | 1333 #endif |
| 1356 } | 1334 } |
| 1357 | 1335 |
| 1358 | 1336 |
| 1359 #if !defined(TARGET_ARCH_DBC) | 1337 #if !defined(TARGET_ARCH_DBC) |
| 1360 // TODO(vegorov) enable edge-counters on DBC if we consider them beneficial. | 1338 // TODO(vegorov) enable edge-counters on DBC if we consider them beneficial. |
| 1361 bool FlowGraphCompiler::NeedsEdgeCounter(TargetEntryInstr* block) { | 1339 bool FlowGraphCompiler::NeedsEdgeCounter(TargetEntryInstr* block) { |
| 1362 // Only emit an edge counter if there is not goto at the end of the block, | 1340 // Only emit an edge counter if there is not goto at the end of the block, |
| 1363 // except for the entry block. | 1341 // except for the entry block. |
| 1364 return (FLAG_reorder_basic_blocks | 1342 return (FLAG_reorder_basic_blocks && |
| 1365 && (!block->last_instruction()->IsGoto() | 1343 (!block->last_instruction()->IsGoto() || |
| 1366 || (block == flow_graph().graph_entry()->normal_entry()))); | 1344 (block == flow_graph().graph_entry()->normal_entry()))); |
| 1367 } | 1345 } |
| 1368 | 1346 |
| 1369 | 1347 |
| 1370 // Allocate a register that is not explicitly blocked. | 1348 // Allocate a register that is not explicitly blocked. |
| 1371 static Register AllocateFreeRegister(bool* blocked_registers) { | 1349 static Register AllocateFreeRegister(bool* blocked_registers) { |
| 1372 for (intptr_t regno = 0; regno < kNumberOfCpuRegisters; regno++) { | 1350 for (intptr_t regno = 0; regno < kNumberOfCpuRegisters; regno++) { |
| 1373 if (!blocked_registers[regno]) { | 1351 if (!blocked_registers[regno]) { |
| 1374 blocked_registers[regno] = true; | 1352 blocked_registers[regno] = true; |
| 1375 return static_cast<Register>(regno); | 1353 return static_cast<Register>(regno); |
| 1376 } | 1354 } |
| 1377 } | 1355 } |
| 1378 UNREACHABLE(); | 1356 UNREACHABLE(); |
| 1379 return kNoRegister; | 1357 return kNoRegister; |
| 1380 } | 1358 } |
| 1381 #endif | 1359 #endif |
| 1382 | 1360 |
| 1383 | 1361 |
| 1384 void FlowGraphCompiler::AllocateRegistersLocally(Instruction* instr) { | 1362 void FlowGraphCompiler::AllocateRegistersLocally(Instruction* instr) { |
| 1385 ASSERT(!is_optimizing()); | 1363 ASSERT(!is_optimizing()); |
| 1386 instr->InitializeLocationSummary(zone(), | 1364 instr->InitializeLocationSummary(zone(), false); // Not optimizing. |
| 1387 false); // Not optimizing. | |
| 1388 | 1365 |
| 1389 // No need to allocate registers based on LocationSummary on DBC as in | 1366 // No need to allocate registers based on LocationSummary on DBC as in |
| 1390 // unoptimized mode it's a stack based bytecode just like IR itself. | 1367 // unoptimized mode it's a stack based bytecode just like IR itself. |
| 1391 #if !defined(TARGET_ARCH_DBC) | 1368 #if !defined(TARGET_ARCH_DBC) |
| 1392 LocationSummary* locs = instr->locs(); | 1369 LocationSummary* locs = instr->locs(); |
| 1393 | 1370 |
| 1394 bool blocked_registers[kNumberOfCpuRegisters]; | 1371 bool blocked_registers[kNumberOfCpuRegisters]; |
| 1395 | 1372 |
| 1396 // Block all registers globally reserved by the assembler, etc and mark | 1373 // Block all registers globally reserved by the assembler, etc and mark |
| 1397 // the rest as free. | 1374 // the rest as free. |
| 1398 for (intptr_t i = 0; i < kNumberOfCpuRegisters; i++) { | 1375 for (intptr_t i = 0; i < kNumberOfCpuRegisters; i++) { |
| 1399 blocked_registers[i] = (kDartAvailableCpuRegs & (1 << i)) == 0; | 1376 blocked_registers[i] = (kDartAvailableCpuRegs & (1 << i)) == 0; |
| 1400 } | 1377 } |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1446 if (should_pop) { | 1423 if (should_pop) { |
| 1447 assembler()->PopRegister(reg); | 1424 assembler()->PopRegister(reg); |
| 1448 } | 1425 } |
| 1449 } | 1426 } |
| 1450 | 1427 |
| 1451 // Allocate all unallocated temp locations. | 1428 // Allocate all unallocated temp locations. |
| 1452 for (intptr_t i = 0; i < locs->temp_count(); i++) { | 1429 for (intptr_t i = 0; i < locs->temp_count(); i++) { |
| 1453 Location loc = locs->temp(i); | 1430 Location loc = locs->temp(i); |
| 1454 if (loc.IsUnallocated()) { | 1431 if (loc.IsUnallocated()) { |
| 1455 ASSERT(loc.policy() == Location::kRequiresRegister); | 1432 ASSERT(loc.policy() == Location::kRequiresRegister); |
| 1456 loc = Location::RegisterLocation( | 1433 loc = Location::RegisterLocation(AllocateFreeRegister(blocked_registers)); |
| 1457 AllocateFreeRegister(blocked_registers)); | |
| 1458 locs->set_temp(i, loc); | 1434 locs->set_temp(i, loc); |
| 1459 } | 1435 } |
| 1460 } | 1436 } |
| 1461 | 1437 |
| 1462 Location result_location = locs->out(0); | 1438 Location result_location = locs->out(0); |
| 1463 if (result_location.IsUnallocated()) { | 1439 if (result_location.IsUnallocated()) { |
| 1464 switch (result_location.policy()) { | 1440 switch (result_location.policy()) { |
| 1465 case Location::kAny: | 1441 case Location::kAny: |
| 1466 case Location::kPrefersRegister: | 1442 case Location::kPrefersRegister: |
| 1467 case Location::kRequiresRegister: | 1443 case Location::kRequiresRegister: |
| 1468 case Location::kWritableRegister: | 1444 case Location::kWritableRegister: |
| 1469 result_location = Location::RegisterLocation( | 1445 result_location = |
| 1470 AllocateFreeRegister(blocked_registers)); | 1446 Location::RegisterLocation(AllocateFreeRegister(blocked_registers)); |
| 1471 break; | 1447 break; |
| 1472 case Location::kSameAsFirstInput: | 1448 case Location::kSameAsFirstInput: |
| 1473 result_location = locs->in(0); | 1449 result_location = locs->in(0); |
| 1474 break; | 1450 break; |
| 1475 case Location::kRequiresFpuRegister: | 1451 case Location::kRequiresFpuRegister: |
| 1476 UNREACHABLE(); | 1452 UNREACHABLE(); |
| 1477 break; | 1453 break; |
| 1478 } | 1454 } |
| 1479 locs->set_out(0, result_location); | 1455 locs->set_out(0, result_location); |
| 1480 } | 1456 } |
| (...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1647 } | 1623 } |
| 1648 } else { | 1624 } else { |
| 1649 *spilled = false; | 1625 *spilled = false; |
| 1650 } | 1626 } |
| 1651 | 1627 |
| 1652 return scratch; | 1628 return scratch; |
| 1653 } | 1629 } |
| 1654 | 1630 |
| 1655 | 1631 |
| 1656 ParallelMoveResolver::ScratchFpuRegisterScope::ScratchFpuRegisterScope( | 1632 ParallelMoveResolver::ScratchFpuRegisterScope::ScratchFpuRegisterScope( |
| 1657 ParallelMoveResolver* resolver, FpuRegister blocked) | 1633 ParallelMoveResolver* resolver, |
| 1658 : resolver_(resolver), | 1634 FpuRegister blocked) |
| 1659 reg_(kNoFpuRegister), | 1635 : resolver_(resolver), reg_(kNoFpuRegister), spilled_(false) { |
| 1660 spilled_(false) { | |
| 1661 COMPILE_ASSERT(FpuTMP != kNoFpuRegister); | 1636 COMPILE_ASSERT(FpuTMP != kNoFpuRegister); |
| 1662 uword blocked_mask = ((blocked != kNoFpuRegister) ? 1 << blocked : 0) | 1637 uword blocked_mask = |
| 1663 | 1 << FpuTMP; | 1638 ((blocked != kNoFpuRegister) ? 1 << blocked : 0) | 1 << FpuTMP; |
| 1664 reg_ = static_cast<FpuRegister>( | 1639 reg_ = static_cast<FpuRegister>(resolver_->AllocateScratchRegister( |
| 1665 resolver_->AllocateScratchRegister(Location::kFpuRegister, | 1640 Location::kFpuRegister, blocked_mask, 0, kNumberOfFpuRegisters - 1, |
| 1666 blocked_mask, | 1641 &spilled_)); |
| 1667 0, | |
| 1668 kNumberOfFpuRegisters - 1, | |
| 1669 &spilled_)); | |
| 1670 | 1642 |
| 1671 if (spilled_) { | 1643 if (spilled_) { |
| 1672 resolver->SpillFpuScratch(reg_); | 1644 resolver->SpillFpuScratch(reg_); |
| 1673 } | 1645 } |
| 1674 } | 1646 } |
| 1675 | 1647 |
| 1676 | 1648 |
| 1677 ParallelMoveResolver::ScratchFpuRegisterScope::~ScratchFpuRegisterScope() { | 1649 ParallelMoveResolver::ScratchFpuRegisterScope::~ScratchFpuRegisterScope() { |
| 1678 if (spilled_) { | 1650 if (spilled_) { |
| 1679 resolver_->RestoreFpuScratch(reg_); | 1651 resolver_->RestoreFpuScratch(reg_); |
| 1680 } | 1652 } |
| 1681 } | 1653 } |
| 1682 | 1654 |
| 1683 | 1655 |
| 1684 ParallelMoveResolver::ScratchRegisterScope::ScratchRegisterScope( | 1656 ParallelMoveResolver::ScratchRegisterScope::ScratchRegisterScope( |
| 1685 ParallelMoveResolver* resolver, Register blocked) | 1657 ParallelMoveResolver* resolver, |
| 1686 : resolver_(resolver), | 1658 Register blocked) |
| 1687 reg_(kNoRegister), | 1659 : resolver_(resolver), reg_(kNoRegister), spilled_(false) { |
| 1688 spilled_(false) { | |
| 1689 uword blocked_mask = RegMaskBit(blocked) | kReservedCpuRegisters; | 1660 uword blocked_mask = RegMaskBit(blocked) | kReservedCpuRegisters; |
| 1690 if (resolver->compiler_->intrinsic_mode()) { | 1661 if (resolver->compiler_->intrinsic_mode()) { |
| 1691 // Block additional registers that must be preserved for intrinsics. | 1662 // Block additional registers that must be preserved for intrinsics. |
| 1692 blocked_mask |= RegMaskBit(ARGS_DESC_REG); | 1663 blocked_mask |= RegMaskBit(ARGS_DESC_REG); |
| 1693 #if !defined(TARGET_ARCH_IA32) | 1664 #if !defined(TARGET_ARCH_IA32) |
| 1694 // Need to preserve CODE_REG to be able to store the PC marker | 1665 // Need to preserve CODE_REG to be able to store the PC marker |
| 1695 // and load the pool pointer. | 1666 // and load the pool pointer. |
| 1696 blocked_mask |= RegMaskBit(CODE_REG); | 1667 blocked_mask |= RegMaskBit(CODE_REG); |
| 1697 #endif | 1668 #endif |
| 1698 } | 1669 } |
| 1699 reg_ = static_cast<Register>( | 1670 reg_ = static_cast<Register>( |
| 1700 resolver_->AllocateScratchRegister(Location::kRegister, | 1671 resolver_->AllocateScratchRegister(Location::kRegister, blocked_mask, 0, |
| 1701 blocked_mask, | 1672 kNumberOfCpuRegisters - 1, &spilled_)); |
| 1702 0, | |
| 1703 kNumberOfCpuRegisters - 1, | |
| 1704 &spilled_)); | |
| 1705 | 1673 |
| 1706 if (spilled_) { | 1674 if (spilled_) { |
| 1707 resolver->SpillScratch(reg_); | 1675 resolver->SpillScratch(reg_); |
| 1708 } | 1676 } |
| 1709 } | 1677 } |
| 1710 | 1678 |
| 1711 | 1679 |
| 1712 ParallelMoveResolver::ScratchRegisterScope::~ScratchRegisterScope() { | 1680 ParallelMoveResolver::ScratchRegisterScope::~ScratchRegisterScope() { |
| 1713 if (spilled_) { | 1681 if (spilled_) { |
| 1714 resolver_->RestoreScratch(reg_); | 1682 resolver_->RestoreScratch(reg_); |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1749 intptr_t num_args_tested) { | 1717 intptr_t num_args_tested) { |
| 1750 if ((deopt_id_to_ic_data_ != NULL) && | 1718 if ((deopt_id_to_ic_data_ != NULL) && |
| 1751 ((*deopt_id_to_ic_data_)[deopt_id] != NULL)) { | 1719 ((*deopt_id_to_ic_data_)[deopt_id] != NULL)) { |
| 1752 const ICData* res = (*deopt_id_to_ic_data_)[deopt_id]; | 1720 const ICData* res = (*deopt_id_to_ic_data_)[deopt_id]; |
| 1753 ASSERT(res->deopt_id() == deopt_id); | 1721 ASSERT(res->deopt_id() == deopt_id); |
| 1754 ASSERT(res->target_name() == target_name.raw()); | 1722 ASSERT(res->target_name() == target_name.raw()); |
| 1755 ASSERT(res->NumArgsTested() == num_args_tested); | 1723 ASSERT(res->NumArgsTested() == num_args_tested); |
| 1756 ASSERT(!res->is_static_call()); | 1724 ASSERT(!res->is_static_call()); |
| 1757 return res; | 1725 return res; |
| 1758 } | 1726 } |
| 1759 const ICData& ic_data = ICData::ZoneHandle(zone(), ICData::New( | 1727 const ICData& ic_data = |
| 1760 parsed_function().function(), target_name, | 1728 ICData::ZoneHandle(zone(), ICData::New(parsed_function().function(), |
| 1761 arguments_descriptor, deopt_id, num_args_tested, false)); | 1729 target_name, arguments_descriptor, |
| 1730 deopt_id, num_args_tested, false)); |
| 1762 #if defined(TAG_IC_DATA) | 1731 #if defined(TAG_IC_DATA) |
| 1763 ic_data.set_tag(Instruction::kInstanceCall); | 1732 ic_data.set_tag(Instruction::kInstanceCall); |
| 1764 #endif | 1733 #endif |
| 1765 if (deopt_id_to_ic_data_ != NULL) { | 1734 if (deopt_id_to_ic_data_ != NULL) { |
| 1766 (*deopt_id_to_ic_data_)[deopt_id] = &ic_data; | 1735 (*deopt_id_to_ic_data_)[deopt_id] = &ic_data; |
| 1767 } | 1736 } |
| 1768 ASSERT(!ic_data.is_static_call()); | 1737 ASSERT(!ic_data.is_static_call()); |
| 1769 return &ic_data; | 1738 return &ic_data; |
| 1770 } | 1739 } |
| 1771 | 1740 |
| 1772 | 1741 |
| 1773 const ICData* FlowGraphCompiler::GetOrAddStaticCallICData( | 1742 const ICData* FlowGraphCompiler::GetOrAddStaticCallICData( |
| 1774 intptr_t deopt_id, | 1743 intptr_t deopt_id, |
| 1775 const Function& target, | 1744 const Function& target, |
| 1776 const Array& arguments_descriptor, | 1745 const Array& arguments_descriptor, |
| 1777 intptr_t num_args_tested) { | 1746 intptr_t num_args_tested) { |
| 1778 if ((deopt_id_to_ic_data_ != NULL) && | 1747 if ((deopt_id_to_ic_data_ != NULL) && |
| 1779 ((*deopt_id_to_ic_data_)[deopt_id] != NULL)) { | 1748 ((*deopt_id_to_ic_data_)[deopt_id] != NULL)) { |
| 1780 const ICData* res = (*deopt_id_to_ic_data_)[deopt_id]; | 1749 const ICData* res = (*deopt_id_to_ic_data_)[deopt_id]; |
| 1781 ASSERT(res->deopt_id() == deopt_id); | 1750 ASSERT(res->deopt_id() == deopt_id); |
| 1782 ASSERT(res->target_name() == target.name()); | 1751 ASSERT(res->target_name() == target.name()); |
| 1783 ASSERT(res->NumArgsTested() == num_args_tested); | 1752 ASSERT(res->NumArgsTested() == num_args_tested); |
| 1784 ASSERT(res->is_static_call()); | 1753 ASSERT(res->is_static_call()); |
| 1785 return res; | 1754 return res; |
| 1786 } | 1755 } |
| 1787 const ICData& ic_data = ICData::ZoneHandle(zone(), ICData::New( | 1756 const ICData& ic_data = ICData::ZoneHandle( |
| 1788 parsed_function().function(), String::Handle(zone(), target.name()), | 1757 zone(), |
| 1789 arguments_descriptor, deopt_id, num_args_tested, true)); | 1758 ICData::New(parsed_function().function(), |
| 1759 String::Handle(zone(), target.name()), arguments_descriptor, |
| 1760 deopt_id, num_args_tested, true)); |
| 1790 ic_data.AddTarget(target); | 1761 ic_data.AddTarget(target); |
| 1791 #if defined(TAG_IC_DATA) | 1762 #if defined(TAG_IC_DATA) |
| 1792 ic_data.set_tag(Instruction::kStaticCall); | 1763 ic_data.set_tag(Instruction::kStaticCall); |
| 1793 #endif | 1764 #endif |
| 1794 if (deopt_id_to_ic_data_ != NULL) { | 1765 if (deopt_id_to_ic_data_ != NULL) { |
| 1795 (*deopt_id_to_ic_data_)[deopt_id] = &ic_data; | 1766 (*deopt_id_to_ic_data_)[deopt_id] = &ic_data; |
| 1796 } | 1767 } |
| 1797 return &ic_data; | 1768 return &ic_data; |
| 1798 } | 1769 } |
| 1799 | 1770 |
| 1800 | 1771 |
| 1801 intptr_t FlowGraphCompiler::GetOptimizationThreshold() const { | 1772 intptr_t FlowGraphCompiler::GetOptimizationThreshold() const { |
| 1802 intptr_t threshold; | 1773 intptr_t threshold; |
| 1803 if (is_optimizing()) { | 1774 if (is_optimizing()) { |
| 1804 threshold = FLAG_reoptimization_counter_threshold; | 1775 threshold = FLAG_reoptimization_counter_threshold; |
| 1805 } else if (parsed_function_.function().IsIrregexpFunction()) { | 1776 } else if (parsed_function_.function().IsIrregexpFunction()) { |
| 1806 threshold = FLAG_regexp_optimization_counter_threshold; | 1777 threshold = FLAG_regexp_optimization_counter_threshold; |
| 1807 } else { | 1778 } else { |
| 1808 const intptr_t basic_blocks = flow_graph().preorder().length(); | 1779 const intptr_t basic_blocks = flow_graph().preorder().length(); |
| 1809 ASSERT(basic_blocks > 0); | 1780 ASSERT(basic_blocks > 0); |
| 1810 threshold = FLAG_optimization_counter_scale * basic_blocks + | 1781 threshold = FLAG_optimization_counter_scale * basic_blocks + |
| 1811 FLAG_min_optimization_counter_threshold; | 1782 FLAG_min_optimization_counter_threshold; |
| 1812 if (threshold > FLAG_optimization_counter_threshold) { | 1783 if (threshold > FLAG_optimization_counter_threshold) { |
| 1813 threshold = FLAG_optimization_counter_threshold; | 1784 threshold = FLAG_optimization_counter_threshold; |
| 1814 } | 1785 } |
| 1815 } | 1786 } |
| 1816 return threshold; | 1787 return threshold; |
| 1817 } | 1788 } |
| 1818 | 1789 |
| 1819 | 1790 |
| 1820 const Class& FlowGraphCompiler::BoxClassFor(Representation rep) { | 1791 const Class& FlowGraphCompiler::BoxClassFor(Representation rep) { |
| 1821 switch (rep) { | 1792 switch (rep) { |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1833 UNREACHABLE(); | 1804 UNREACHABLE(); |
| 1834 return Class::ZoneHandle(); | 1805 return Class::ZoneHandle(); |
| 1835 } | 1806 } |
| 1836 } | 1807 } |
| 1837 | 1808 |
| 1838 | 1809 |
| 1839 RawArray* FlowGraphCompiler::InliningIdToFunction() const { | 1810 RawArray* FlowGraphCompiler::InliningIdToFunction() const { |
| 1840 if (inline_id_to_function_.length() == 0) { | 1811 if (inline_id_to_function_.length() == 0) { |
| 1841 return Object::empty_array().raw(); | 1812 return Object::empty_array().raw(); |
| 1842 } | 1813 } |
| 1843 const Array& res = Array::Handle( | 1814 const Array& res = |
| 1844 Array::New(inline_id_to_function_.length(), Heap::kOld)); | 1815 Array::Handle(Array::New(inline_id_to_function_.length(), Heap::kOld)); |
| 1845 for (intptr_t i = 0; i < inline_id_to_function_.length(); i++) { | 1816 for (intptr_t i = 0; i < inline_id_to_function_.length(); i++) { |
| 1846 res.SetAt(i, *inline_id_to_function_[i]); | 1817 res.SetAt(i, *inline_id_to_function_[i]); |
| 1847 } | 1818 } |
| 1848 return res.raw(); | 1819 return res.raw(); |
| 1849 } | 1820 } |
| 1850 | 1821 |
| 1851 | 1822 |
| 1852 RawArray* FlowGraphCompiler::InliningIdToTokenPos() const { | 1823 RawArray* FlowGraphCompiler::InliningIdToTokenPos() const { |
| 1853 if (inline_id_to_token_pos_.length() == 0) { | 1824 if (inline_id_to_token_pos_.length() == 0) { |
| 1854 return Object::empty_array().raw(); | 1825 return Object::empty_array().raw(); |
| 1855 } | 1826 } |
| 1856 const Array& res = Array::Handle(zone(), | 1827 const Array& res = Array::Handle( |
| 1857 Array::New(inline_id_to_token_pos_.length(), Heap::kOld)); | 1828 zone(), Array::New(inline_id_to_token_pos_.length(), Heap::kOld)); |
| 1858 Smi& smi = Smi::Handle(zone()); | 1829 Smi& smi = Smi::Handle(zone()); |
| 1859 for (intptr_t i = 0; i < inline_id_to_token_pos_.length(); i++) { | 1830 for (intptr_t i = 0; i < inline_id_to_token_pos_.length(); i++) { |
| 1860 smi = Smi::New(inline_id_to_token_pos_[i].value()); | 1831 smi = Smi::New(inline_id_to_token_pos_[i].value()); |
| 1861 res.SetAt(i, smi); | 1832 res.SetAt(i, smi); |
| 1862 } | 1833 } |
| 1863 return res.raw(); | 1834 return res.raw(); |
| 1864 } | 1835 } |
| 1865 | 1836 |
| 1866 | 1837 |
| 1867 RawArray* FlowGraphCompiler::CallerInliningIdMap() const { | 1838 RawArray* FlowGraphCompiler::CallerInliningIdMap() const { |
| 1868 if (caller_inline_id_.length() == 0) { | 1839 if (caller_inline_id_.length() == 0) { |
| 1869 return Object::empty_array().raw(); | 1840 return Object::empty_array().raw(); |
| 1870 } | 1841 } |
| 1871 const Array& res = Array::Handle( | 1842 const Array& res = |
| 1872 Array::New(caller_inline_id_.length(), Heap::kOld)); | 1843 Array::Handle(Array::New(caller_inline_id_.length(), Heap::kOld)); |
| 1873 Smi& smi = Smi::Handle(); | 1844 Smi& smi = Smi::Handle(); |
| 1874 for (intptr_t i = 0; i < caller_inline_id_.length(); i++) { | 1845 for (intptr_t i = 0; i < caller_inline_id_.length(); i++) { |
| 1875 smi = Smi::New(caller_inline_id_[i]); | 1846 smi = Smi::New(caller_inline_id_[i]); |
| 1876 res.SetAt(i, smi); | 1847 res.SetAt(i, smi); |
| 1877 } | 1848 } |
| 1878 return res.raw(); | 1849 return res.raw(); |
| 1879 } | 1850 } |
| 1880 | 1851 |
| 1881 | 1852 |
| 1882 void FlowGraphCompiler::BeginCodeSourceRange() { | 1853 void FlowGraphCompiler::BeginCodeSourceRange() { |
| 1883 NOT_IN_PRODUCT( | 1854 #if !defined(PRODUCT) |
| 1884 // Remember how many bytes of code we emitted so far. This function | 1855 // Remember how many bytes of code we emitted so far. This function |
| 1885 // is called before we call into an instruction's EmitNativeCode. | 1856 // is called before we call into an instruction's EmitNativeCode. |
| 1886 saved_code_size_ = assembler()->CodeSize(); | 1857 saved_code_size_ = assembler()->CodeSize(); |
| 1887 ); | 1858 #endif // !defined(PRODUCT) |
| 1888 } | 1859 } |
| 1889 | 1860 |
| 1890 | 1861 |
| 1891 bool FlowGraphCompiler::EndCodeSourceRange(TokenPosition token_pos) { | 1862 bool FlowGraphCompiler::EndCodeSourceRange(TokenPosition token_pos) { |
| 1892 NOT_IN_PRODUCT( | 1863 #if !defined(PRODUCT) |
| 1893 // This function is called after each instructions' EmitNativeCode. | 1864 // This function is called after each instructions' EmitNativeCode. |
| 1894 if (saved_code_size_ < assembler()->CodeSize()) { | 1865 if (saved_code_size_ < assembler()->CodeSize()) { |
| 1895 // We emitted more code, now associate the emitted code chunk with | 1866 // We emitted more code, now associate the emitted code chunk with |
| 1896 // |token_pos|. | 1867 // |token_pos|. |
| 1897 code_source_map_builder()->AddEntry(saved_code_size_, token_pos); | 1868 code_source_map_builder()->AddEntry(saved_code_size_, token_pos); |
| 1898 BeginCodeSourceRange(); | 1869 BeginCodeSourceRange(); |
| 1899 return true; | 1870 return true; |
| 1900 } | 1871 } |
| 1901 ); | 1872 #endif // !defined(PRODUCT) |
| 1902 return false; | 1873 return false; |
| 1903 } | 1874 } |
| 1904 | 1875 |
| 1905 | 1876 |
| 1906 #if !defined(TARGET_ARCH_DBC) | 1877 #if !defined(TARGET_ARCH_DBC) |
| 1907 // DBC emits calls very differently from other architectures due to its | 1878 // DBC emits calls very differently from other architectures due to its |
| 1908 // interpreted nature. | 1879 // interpreted nature. |
| 1909 void FlowGraphCompiler::EmitPolymorphicInstanceCall( | 1880 void FlowGraphCompiler::EmitPolymorphicInstanceCall(const ICData& ic_data, |
| 1910 const ICData& ic_data, | 1881 intptr_t argument_count, |
| 1911 intptr_t argument_count, | 1882 const Array& argument_names, |
| 1912 const Array& argument_names, | 1883 intptr_t deopt_id, |
| 1913 intptr_t deopt_id, | 1884 TokenPosition token_pos, |
| 1914 TokenPosition token_pos, | 1885 LocationSummary* locs, |
| 1915 LocationSummary* locs, | 1886 bool complete) { |
| 1916 bool complete) { | |
| 1917 if (FLAG_polymorphic_with_deopt) { | 1887 if (FLAG_polymorphic_with_deopt) { |
| 1918 Label* deopt = AddDeoptStub(deopt_id, | 1888 Label* deopt = |
| 1919 ICData::kDeoptPolymorphicInstanceCallTestFail); | 1889 AddDeoptStub(deopt_id, ICData::kDeoptPolymorphicInstanceCallTestFail); |
| 1920 Label ok; | 1890 Label ok; |
| 1921 EmitTestAndCall(ic_data, argument_count, argument_names, | 1891 EmitTestAndCall(ic_data, argument_count, argument_names, |
| 1922 deopt, // No cid match. | 1892 deopt, // No cid match. |
| 1923 &ok, // Found cid. | 1893 &ok, // Found cid. |
| 1924 deopt_id, token_pos, locs, complete); | 1894 deopt_id, token_pos, locs, complete); |
| 1925 assembler()->Bind(&ok); | 1895 assembler()->Bind(&ok); |
| 1926 } else { | 1896 } else { |
| 1927 if (complete) { | 1897 if (complete) { |
| 1928 Label ok; | 1898 Label ok; |
| 1929 EmitTestAndCall(ic_data, argument_count, argument_names, | 1899 EmitTestAndCall(ic_data, argument_count, argument_names, |
| 1930 NULL, // No cid match. | 1900 NULL, // No cid match. |
| 1931 &ok, // Found cid. | 1901 &ok, // Found cid. |
| 1932 deopt_id, token_pos, locs, true); | 1902 deopt_id, token_pos, locs, true); |
| 1933 assembler()->Bind(&ok); | 1903 assembler()->Bind(&ok); |
| 1934 } else { | 1904 } else { |
| 1935 EmitSwitchableInstanceCall(ic_data, argument_count, | 1905 EmitSwitchableInstanceCall(ic_data, argument_count, deopt_id, token_pos, |
| 1936 deopt_id, token_pos, locs); | 1906 locs); |
| 1937 } | 1907 } |
| 1938 } | 1908 } |
| 1939 } | 1909 } |
| 1940 #endif | 1910 #endif |
| 1941 | 1911 |
| 1942 #if defined(DEBUG) && !defined(TARGET_ARCH_DBC) | 1912 #if defined(DEBUG) && !defined(TARGET_ARCH_DBC) |
| 1943 // TODO(vegorov) re-enable frame state tracking on DBC. It is | 1913 // TODO(vegorov) re-enable frame state tracking on DBC. It is |
| 1944 // currently disabled because it relies on LocationSummaries and | 1914 // currently disabled because it relies on LocationSummaries and |
| 1945 // we don't use them during unoptimized compilation on DBC. | 1915 // we don't use them during unoptimized compilation on DBC. |
| 1946 void FlowGraphCompiler::FrameStateUpdateWith(Instruction* instr) { | 1916 void FlowGraphCompiler::FrameStateUpdateWith(Instruction* instr) { |
| 1947 ASSERT(!is_optimizing()); | 1917 ASSERT(!is_optimizing()); |
| 1948 | 1918 |
| 1949 switch (instr->tag()) { | 1919 switch (instr->tag()) { |
| 1950 case Instruction::kPushArgument: | 1920 case Instruction::kPushArgument: |
| 1951 // Do nothing. | 1921 // Do nothing. |
| 1952 break; | 1922 break; |
| 1953 | 1923 |
| 1954 case Instruction::kDropTemps: | 1924 case Instruction::kDropTemps: |
| 1955 FrameStatePop(instr->locs()->input_count() + | 1925 FrameStatePop(instr->locs()->input_count() + |
| 1956 instr->AsDropTemps()->num_temps()); | 1926 instr->AsDropTemps()->num_temps()); |
| 1957 break; | 1927 break; |
| 1958 | 1928 |
| 1959 default: | 1929 default: |
| 1960 FrameStatePop(instr->locs()->input_count()); | 1930 FrameStatePop(instr->locs()->input_count()); |
| 1961 break; | 1931 break; |
| 1962 } | 1932 } |
| 1963 | 1933 |
| 1964 ASSERT(!instr->locs()->can_call() || FrameStateIsSafeToCall()); | 1934 ASSERT(!instr->locs()->can_call() || FrameStateIsSafeToCall()); |
| 1965 | 1935 |
| 1966 FrameStatePop(instr->ArgumentCount()); | 1936 FrameStatePop(instr->ArgumentCount()); |
| 1967 Definition* defn = instr->AsDefinition(); | 1937 Definition* defn = instr->AsDefinition(); |
| 1968 if ((defn != NULL) && defn->HasTemp()) { | 1938 if ((defn != NULL) && defn->HasTemp()) { |
| 1969 FrameStatePush(defn); | 1939 FrameStatePush(defn); |
| 1970 } | 1940 } |
| 1971 } | 1941 } |
| 1972 | 1942 |
| 1973 | 1943 |
| 1974 void FlowGraphCompiler::FrameStatePush(Definition* defn) { | 1944 void FlowGraphCompiler::FrameStatePush(Definition* defn) { |
| 1975 Representation rep = defn->representation(); | 1945 Representation rep = defn->representation(); |
| 1976 if ((rep == kUnboxedDouble) || | 1946 if ((rep == kUnboxedDouble) || (rep == kUnboxedFloat64x2) || |
| 1977 (rep == kUnboxedFloat64x2) || | |
| 1978 (rep == kUnboxedFloat32x4)) { | 1947 (rep == kUnboxedFloat32x4)) { |
| 1979 // LoadField instruction lies about its representation in the unoptimized | 1948 // LoadField instruction lies about its representation in the unoptimized |
| 1980 // code because Definition::representation() can't depend on the type of | 1949 // code because Definition::representation() can't depend on the type of |
| 1981 // compilation but MakeLocationSummary and EmitNativeCode can. | 1950 // compilation but MakeLocationSummary and EmitNativeCode can. |
| 1982 ASSERT(defn->IsLoadField() && defn->AsLoadField()->IsUnboxedLoad()); | 1951 ASSERT(defn->IsLoadField() && defn->AsLoadField()->IsUnboxedLoad()); |
| 1983 ASSERT(defn->locs()->out(0).IsRegister()); | 1952 ASSERT(defn->locs()->out(0).IsRegister()); |
| 1984 rep = kTagged; | 1953 rep = kTagged; |
| 1985 } | 1954 } |
| 1986 ASSERT(!is_optimizing()); | 1955 ASSERT(!is_optimizing()); |
| 1987 ASSERT((rep == kTagged) || (rep == kUntagged)); | 1956 ASSERT((rep == kTagged) || (rep == kUntagged)); |
| 1988 ASSERT(rep != kUntagged || flow_graph_.IsIrregexpFunction()); | 1957 ASSERT(rep != kUntagged || flow_graph_.IsIrregexpFunction()); |
| 1989 frame_state_.Add(rep); | 1958 frame_state_.Add(rep); |
| 1990 } | 1959 } |
| 1991 | 1960 |
| 1992 | 1961 |
| 1993 void FlowGraphCompiler::FrameStatePop(intptr_t count) { | 1962 void FlowGraphCompiler::FrameStatePop(intptr_t count) { |
| 1994 ASSERT(!is_optimizing()); | 1963 ASSERT(!is_optimizing()); |
| 1995 frame_state_.TruncateTo(Utils::Maximum(static_cast<intptr_t>(0), | 1964 frame_state_.TruncateTo( |
| 1996 frame_state_.length() - count)); | 1965 Utils::Maximum(static_cast<intptr_t>(0), frame_state_.length() - count)); |
| 1997 } | 1966 } |
| 1998 | 1967 |
| 1999 | 1968 |
| 2000 bool FlowGraphCompiler::FrameStateIsSafeToCall() { | 1969 bool FlowGraphCompiler::FrameStateIsSafeToCall() { |
| 2001 ASSERT(!is_optimizing()); | 1970 ASSERT(!is_optimizing()); |
| 2002 for (intptr_t i = 0; i < frame_state_.length(); i++) { | 1971 for (intptr_t i = 0; i < frame_state_.length(); i++) { |
| 2003 if (frame_state_[i] != kTagged) { | 1972 if (frame_state_[i] != kTagged) { |
| 2004 return false; | 1973 return false; |
| 2005 } | 1974 } |
| 2006 } | 1975 } |
| 2007 return true; | 1976 return true; |
| 2008 } | 1977 } |
| 2009 | 1978 |
| 2010 | 1979 |
| 2011 void FlowGraphCompiler::FrameStateClear() { | 1980 void FlowGraphCompiler::FrameStateClear() { |
| 2012 ASSERT(!is_optimizing()); | 1981 ASSERT(!is_optimizing()); |
| 2013 frame_state_.TruncateTo(0); | 1982 frame_state_.TruncateTo(0); |
| 2014 } | 1983 } |
| 2015 #endif // defined(DEBUG) && !defined(TARGET_ARCH_DBC) | 1984 #endif // defined(DEBUG) && !defined(TARGET_ARCH_DBC) |
| 2016 | 1985 |
| 2017 | 1986 |
| 2018 } // namespace dart | 1987 } // namespace dart |
| OLD | NEW |