Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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_ARM64. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM64. |
| 6 #if defined(TARGET_ARCH_ARM64) | 6 #if defined(TARGET_ARCH_ARM64) |
| 7 | 7 |
| 8 #include "vm/flow_graph_compiler.h" | 8 #include "vm/flow_graph_compiler.h" |
| 9 | 9 |
| 10 #include "vm/ast_printer.h" | 10 #include "vm/ast_printer.h" |
| 11 #include "vm/compiler.h" | 11 #include "vm/compiler.h" |
| 12 #include "vm/cpu.h" | 12 #include "vm/cpu.h" |
| 13 #include "vm/dart_entry.h" | 13 #include "vm/dart_entry.h" |
| 14 #include "vm/deopt_instructions.h" | 14 #include "vm/deopt_instructions.h" |
| 15 #include "vm/il_printer.h" | 15 #include "vm/il_printer.h" |
| 16 #include "vm/locations.h" | 16 #include "vm/locations.h" |
| 17 #include "vm/object_store.h" | 17 #include "vm/object_store.h" |
| 18 #include "vm/parser.h" | 18 #include "vm/parser.h" |
| 19 #include "vm/stack_frame.h" | 19 #include "vm/stack_frame.h" |
| 20 #include "vm/stub_code.h" | 20 #include "vm/stub_code.h" |
| 21 #include "vm/symbols.h" | 21 #include "vm/symbols.h" |
| 22 | 22 |
| 23 namespace dart { | 23 namespace dart { |
| 24 | 24 |
| 25 DECLARE_FLAG(int, optimization_counter_threshold); | |
| 26 DECLARE_FLAG(int, reoptimization_counter_threshold); | |
| 27 | |
| 25 FlowGraphCompiler::~FlowGraphCompiler() { | 28 FlowGraphCompiler::~FlowGraphCompiler() { |
| 26 // BlockInfos are zone-allocated, so their destructors are not called. | 29 // BlockInfos are zone-allocated, so their destructors are not called. |
| 27 // Verify the labels explicitly here. | 30 // Verify the labels explicitly here. |
| 28 for (int i = 0; i < block_info_.length(); ++i) { | 31 for (int i = 0; i < block_info_.length(); ++i) { |
| 29 ASSERT(!block_info_[i]->jump_label()->IsLinked()); | 32 ASSERT(!block_info_[i]->jump_label()->IsLinked()); |
| 30 } | 33 } |
| 31 } | 34 } |
| 32 | 35 |
| 33 | 36 |
| 34 bool FlowGraphCompiler::SupportsUnboxedMints() { | 37 bool FlowGraphCompiler::SupportsUnboxedMints() { |
| (...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 154 void FlowGraphCompiler::GenerateAssertAssignable(intptr_t token_pos, | 157 void FlowGraphCompiler::GenerateAssertAssignable(intptr_t token_pos, |
| 155 intptr_t deopt_id, | 158 intptr_t deopt_id, |
| 156 const AbstractType& dst_type, | 159 const AbstractType& dst_type, |
| 157 const String& dst_name, | 160 const String& dst_name, |
| 158 LocationSummary* locs) { | 161 LocationSummary* locs) { |
| 159 UNIMPLEMENTED(); | 162 UNIMPLEMENTED(); |
| 160 } | 163 } |
| 161 | 164 |
| 162 | 165 |
| 163 void FlowGraphCompiler::EmitInstructionEpilogue(Instruction* instr) { | 166 void FlowGraphCompiler::EmitInstructionEpilogue(Instruction* instr) { |
| 164 UNIMPLEMENTED(); | 167 if (is_optimizing()) { |
| 168 return; | |
| 169 } | |
| 170 Definition* defn = instr->AsDefinition(); | |
| 171 if ((defn != NULL) && defn->is_used()) { | |
| 172 __ Push(defn->locs()->out(0).reg()); | |
| 173 } | |
| 165 } | 174 } |
| 166 | 175 |
| 167 | 176 |
| 168 void FlowGraphCompiler::CopyParameters() { | 177 void FlowGraphCompiler::CopyParameters() { |
| 169 UNIMPLEMENTED(); | 178 UNIMPLEMENTED(); |
| 170 } | 179 } |
| 171 | 180 |
| 172 | 181 |
| 173 void FlowGraphCompiler::GenerateInlinedGetter(intptr_t offset) { | 182 void FlowGraphCompiler::GenerateInlinedGetter(intptr_t offset) { |
| 174 UNIMPLEMENTED(); | 183 UNIMPLEMENTED(); |
| 175 } | 184 } |
| 176 | 185 |
| 177 | 186 |
| 178 void FlowGraphCompiler::GenerateInlinedSetter(intptr_t offset) { | 187 void FlowGraphCompiler::GenerateInlinedSetter(intptr_t offset) { |
| 179 UNIMPLEMENTED(); | 188 UNIMPLEMENTED(); |
| 180 } | 189 } |
| 181 | 190 |
| 182 | 191 |
| 183 void FlowGraphCompiler::EmitFrameEntry() { | 192 void FlowGraphCompiler::EmitFrameEntry() { |
| 184 UNIMPLEMENTED(); | 193 const Function& function = parsed_function().function(); |
| 194 Register new_pp = kNoRegister; | |
| 195 if (CanOptimizeFunction() && | |
| 196 function.IsOptimizable() && | |
| 197 (!is_optimizing() || may_reoptimize())) { | |
| 198 const Register function_reg = R6; | |
| 199 new_pp = R13; | |
| 200 | |
| 201 // Set up pool pointer in new_pp. | |
| 202 __ LoadPoolPointer(new_pp); | |
| 203 | |
| 204 // Load function object using the callee's pool pointer. | |
| 205 __ LoadObject(function_reg, function, new_pp); | |
| 206 | |
| 207 // Patch point is after the eventually inlined function object. | |
| 208 AddCurrentDescriptor(PcDescriptors::kEntryPatch, | |
| 209 Isolate::kNoDeoptId, | |
| 210 0); // No token position. | |
| 211 intptr_t threshold = FLAG_optimization_counter_threshold; | |
| 212 __ LoadFieldFromOffset(R7, function_reg, Function::usage_counter_offset()); | |
| 213 if (is_optimizing()) { | |
| 214 // Reoptimization of an optimized function is triggered by counting in | |
| 215 // IC stubs, but not at the entry of the function. | |
| 216 threshold = FLAG_reoptimization_counter_threshold; | |
| 217 } else { | |
| 218 __ add(R7, R7, Operand(1)); | |
| 219 __ StoreFieldToOffset(R7, function_reg, Function::usage_counter_offset()); | |
| 220 } | |
| 221 __ CompareImmediate(R7, threshold, new_pp); | |
| 222 ASSERT(function_reg == R6); | |
| 223 Label dont_optimize; | |
| 224 __ b(&dont_optimize, LT); | |
| 225 __ Branch(&StubCode::OptimizeFunctionLabel(), new_pp); | |
| 226 __ Bind(&dont_optimize); | |
| 227 } else if (!flow_graph().IsCompiledForOsr()) { | |
| 228 // We have to load the PP here too because a load of an external label | |
| 229 // may be patched at the AddCurrentDescriptor below. | |
| 230 new_pp = R13; | |
| 231 | |
| 232 __ LoadPoolPointer(new_pp); | |
| 233 | |
| 234 AddCurrentDescriptor(PcDescriptors::kEntryPatch, | |
| 235 Isolate::kNoDeoptId, | |
| 236 0); // No token position. | |
| 237 } | |
| 238 __ Comment("Enter frame"); | |
| 239 if (flow_graph().IsCompiledForOsr()) { | |
| 240 intptr_t extra_slots = StackSize() | |
| 241 - flow_graph().num_stack_locals() | |
| 242 - flow_graph().num_copied_params(); | |
| 243 ASSERT(extra_slots >= 0); | |
| 244 __ EnterOsrFrame(extra_slots * kWordSize, new_pp); | |
| 245 } else { | |
| 246 ASSERT(StackSize() >= 0); | |
| 247 __ EnterDartFrameWithInfo(StackSize() * kWordSize, new_pp); | |
| 248 } | |
| 185 } | 249 } |
| 186 | 250 |
| 187 | 251 |
| 252 // Input parameters: | |
| 253 // LR: return address. | |
| 254 // SP: address of last argument. | |
| 255 // FP: caller's frame pointer. | |
| 256 // PP: caller's pool pointer. | |
| 257 // R5: ic-data. | |
| 258 // R4: arguments descriptor array. | |
| 188 void FlowGraphCompiler::CompileGraph() { | 259 void FlowGraphCompiler::CompileGraph() { |
| 189 UNIMPLEMENTED(); | 260 InitCompiler(); |
| 261 | |
| 262 TryIntrinsify(); | |
| 263 | |
| 264 EmitFrameEntry(); | |
| 265 | |
| 266 const Function& function = parsed_function().function(); | |
| 267 | |
| 268 const int num_fixed_params = function.num_fixed_parameters(); | |
| 269 const int num_copied_params = parsed_function().num_copied_params(); | |
| 270 const int num_locals = parsed_function().num_stack_locals(); | |
| 271 | |
| 272 // We check the number of passed arguments when we have to copy them due to | |
| 273 // the presence of optional parameters. | |
| 274 // No such checking code is generated if only fixed parameters are declared, | |
| 275 // unless we are in debug mode or unless we are compiling a closure. | |
| 276 if (num_copied_params == 0) { | |
| 277 #ifdef DEBUG | |
| 278 ASSERT(!parsed_function().function().HasOptionalParameters()); | |
| 279 const bool check_arguments = !flow_graph().IsCompiledForOsr(); | |
| 280 #else | |
| 281 const bool check_arguments = | |
| 282 function.IsClosureFunction() && !flow_graph().IsCompiledForOsr(); | |
| 283 #endif | |
| 284 if (check_arguments) { | |
| 285 __ Comment("Check argument count"); | |
| 286 // Check that exactly num_fixed arguments are passed in. | |
| 287 Label correct_num_arguments, wrong_num_arguments; | |
| 288 __ LoadFieldFromOffset(R0, R4, ArgumentsDescriptor::count_offset()); | |
| 289 __ CompareImmediate(R0, Smi::RawValue(num_fixed_params), PP); | |
| 290 __ b(&wrong_num_arguments, NE); | |
| 291 __ LoadFieldFromOffset(R1, R4, | |
| 292 ArgumentsDescriptor::positional_count_offset()); | |
| 293 __ CompareRegisters(R0, R1); | |
| 294 __ b(&correct_num_arguments, EQ); | |
| 295 __ Bind(&wrong_num_arguments); | |
| 296 if (function.IsClosureFunction()) { | |
| 297 // Invoke noSuchMethod function passing the original function name. | |
| 298 // For closure functions, use "call" as the original name. | |
| 299 const String& name = | |
| 300 String::Handle(function.IsClosureFunction() | |
| 301 ? Symbols::Call().raw() | |
| 302 : function.name()); | |
| 303 const int kNumArgsChecked = 1; | |
| 304 const ICData& ic_data = ICData::ZoneHandle( | |
| 305 ICData::New(function, name, Object::empty_array(), | |
| 306 Isolate::kNoDeoptId, kNumArgsChecked)); | |
| 307 __ LoadObject(R5, ic_data, PP); | |
| 308 __ LeaveDartFrame(); // The arguments are still on the stack. | |
| 309 __ Branch(&StubCode::CallNoSuchMethodFunctionLabel(), PP); | |
| 310 // The noSuchMethod call may return to the caller, but not here. | |
| 311 __ hlt(0); | |
| 312 } else { | |
| 313 __ Stop("Wrong number of arguments"); | |
| 314 } | |
| 315 __ Bind(&correct_num_arguments); | |
| 316 } | |
| 317 } else if (!flow_graph().IsCompiledForOsr()) { | |
| 318 CopyParameters(); | |
| 319 } | |
| 320 | |
| 321 // In unoptimized code, initialize (non-argument) stack allocated slots to | |
| 322 // null. | |
| 323 if (!is_optimizing() && (num_locals > 0)) { | |
| 324 __ Comment("Initialize spill slots"); | |
| 325 const intptr_t slot_base = parsed_function().first_stack_local_index(); | |
| 326 __ LoadObject(R0, Object::null_object(), PP); | |
| 327 for (intptr_t i = 0; i < num_locals; ++i) { | |
| 328 // Subtract index i (locals lie at lower addresses than FP). | |
| 329 __ StoreToOffset(R0, FP, (slot_base - i) * kWordSize); | |
| 330 } | |
| 331 } | |
| 332 | |
| 333 VisitBlocks(); | |
| 334 | |
| 335 __ hlt(0); | |
| 336 GenerateDeferredCode(); | |
| 337 // Emit function patching code. This will be swapped with the first 3 | |
| 338 // instructions at entry point. | |
| 339 AddCurrentDescriptor(PcDescriptors::kPatchCode, | |
| 340 Isolate::kNoDeoptId, | |
| 341 0); // No token position. | |
| 342 // This is patched up to a point in FrameEntry where the PP for the | |
| 343 // current function is in R13 instead of PP. | |
| 344 __ BranchPatchable(&StubCode::FixCallersTargetLabel(), R13); | |
| 345 | |
| 346 AddCurrentDescriptor(PcDescriptors::kLazyDeoptJump, | |
| 347 Isolate::kNoDeoptId, | |
| 348 0); // No token position. | |
| 349 // TODO(zra): Can I use a normal BranchPatchable here? Probably have to change | |
| 350 // the CodePatcher. | |
|
regis
2014/04/22 23:38:10
Sorry, I do not know or do not remember. Ask Srdja
| |
| 351 __ BranchFixed(&StubCode::DeoptimizeLazyLabel()); | |
| 190 } | 352 } |
| 191 | 353 |
| 192 | 354 |
| 193 void FlowGraphCompiler::GenerateCall(intptr_t token_pos, | 355 void FlowGraphCompiler::GenerateCall(intptr_t token_pos, |
| 194 const ExternalLabel* label, | 356 const ExternalLabel* label, |
| 195 PcDescriptors::Kind kind, | 357 PcDescriptors::Kind kind, |
| 196 LocationSummary* locs) { | 358 LocationSummary* locs) { |
| 197 UNIMPLEMENTED(); | 359 UNIMPLEMENTED(); |
| 198 } | 360 } |
| 199 | 361 |
| 200 | 362 |
| 201 void FlowGraphCompiler::GenerateDartCall(intptr_t deopt_id, | 363 void FlowGraphCompiler::GenerateDartCall(intptr_t deopt_id, |
| 202 intptr_t token_pos, | 364 intptr_t token_pos, |
| 203 const ExternalLabel* label, | 365 const ExternalLabel* label, |
| 204 PcDescriptors::Kind kind, | 366 PcDescriptors::Kind kind, |
| 205 LocationSummary* locs) { | 367 LocationSummary* locs) { |
| 206 UNIMPLEMENTED(); | 368 UNIMPLEMENTED(); |
| 207 } | 369 } |
| 208 | 370 |
| 209 | 371 |
| 210 void FlowGraphCompiler::GenerateRuntimeCall(intptr_t token_pos, | 372 void FlowGraphCompiler::GenerateRuntimeCall(intptr_t token_pos, |
| 211 intptr_t deopt_id, | 373 intptr_t deopt_id, |
| 212 const RuntimeEntry& entry, | 374 const RuntimeEntry& entry, |
| 213 intptr_t argument_count, | 375 intptr_t argument_count, |
| 214 LocationSummary* locs) { | 376 LocationSummary* locs) { |
| 215 UNIMPLEMENTED(); | 377 __ CallRuntime(entry, argument_count); |
| 378 AddCurrentDescriptor(PcDescriptors::kOther, deopt_id, token_pos); | |
| 379 RecordSafepoint(locs); | |
| 380 if (deopt_id != Isolate::kNoDeoptId) { | |
| 381 // Marks either the continuation point in unoptimized code or the | |
| 382 // deoptimization point in optimized code, after call. | |
| 383 const intptr_t deopt_id_after = Isolate::ToDeoptAfter(deopt_id); | |
| 384 if (is_optimizing()) { | |
| 385 AddDeoptIndexAtCall(deopt_id_after, token_pos); | |
| 386 } else { | |
| 387 // Add deoptimization continuation point after the call and before the | |
| 388 // arguments are removed. | |
| 389 AddCurrentDescriptor(PcDescriptors::kDeopt, deopt_id_after, token_pos); | |
| 390 } | |
| 391 } | |
| 216 } | 392 } |
| 217 | 393 |
| 218 | 394 |
| 219 void FlowGraphCompiler::EmitEdgeCounter() { | 395 void FlowGraphCompiler::EmitEdgeCounter() { |
| 220 UNIMPLEMENTED(); | 396 // We do not check for overflow when incrementing the edge counter. The |
| 397 // function should normally be optimized long before the counter can | |
| 398 // overflow; and though we do not reset the counters when we optimize or | |
| 399 // deoptimize, there is a bound on the number of | |
| 400 // optimization/deoptimization cycles we will attempt. | |
| 401 const Array& counter = Array::ZoneHandle(Array::New(1, Heap::kOld)); | |
| 402 counter.SetAt(0, Smi::Handle(Smi::New(0))); | |
| 403 __ Comment("Edge counter"); | |
| 404 __ LoadObject(R0, counter, PP); | |
| 405 __ LoadFieldFromOffset(TMP, R0, Array::element_offset(0)); | |
| 406 __ add(TMP, TMP, Operand(Smi::RawValue(1))); | |
| 407 __ StoreFieldToOffset(TMP, R0, Array::element_offset(0)); | |
| 221 } | 408 } |
| 222 | 409 |
| 223 | 410 |
| 224 void FlowGraphCompiler::EmitOptimizedInstanceCall( | 411 void FlowGraphCompiler::EmitOptimizedInstanceCall( |
| 225 ExternalLabel* target_label, | 412 ExternalLabel* target_label, |
| 226 const ICData& ic_data, | 413 const ICData& ic_data, |
| 227 intptr_t argument_count, | 414 intptr_t argument_count, |
| 228 intptr_t deopt_id, | 415 intptr_t deopt_id, |
| 229 intptr_t token_pos, | 416 intptr_t token_pos, |
| 230 LocationSummary* locs) { | 417 LocationSummary* locs) { |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 286 Register right, | 473 Register right, |
| 287 bool needs_number_check, | 474 bool needs_number_check, |
| 288 intptr_t token_pos) { | 475 intptr_t token_pos) { |
| 289 UNIMPLEMENTED(); | 476 UNIMPLEMENTED(); |
| 290 } | 477 } |
| 291 | 478 |
| 292 | 479 |
| 293 // This function must be in sync with FlowGraphCompiler::RecordSafepoint and | 480 // This function must be in sync with FlowGraphCompiler::RecordSafepoint and |
| 294 // FlowGraphCompiler::SlowPathEnvironmentFor. | 481 // FlowGraphCompiler::SlowPathEnvironmentFor. |
| 295 void FlowGraphCompiler::SaveLiveRegisters(LocationSummary* locs) { | 482 void FlowGraphCompiler::SaveLiveRegisters(LocationSummary* locs) { |
| 296 UNIMPLEMENTED(); | 483 // TODO(zra): Save live FPU Registers. |
| 484 | |
| 485 // Store general purpose registers with the highest register number at the | |
| 486 // lowest address. | |
| 487 for (intptr_t reg_idx = 0; reg_idx < kNumberOfCpuRegisters; ++reg_idx) { | |
| 488 Register reg = static_cast<Register>(reg_idx); | |
| 489 if (locs->live_registers()->ContainsRegister(reg)) { | |
| 490 __ Push(reg); | |
| 491 } | |
| 492 } | |
| 297 } | 493 } |
| 298 | 494 |
| 299 | 495 |
| 300 void FlowGraphCompiler::RestoreLiveRegisters(LocationSummary* locs) { | 496 void FlowGraphCompiler::RestoreLiveRegisters(LocationSummary* locs) { |
| 301 UNIMPLEMENTED(); | 497 // General purpose registers have the highest register number at the |
| 498 // lowest address. | |
| 499 for (intptr_t reg_idx = kNumberOfCpuRegisters - 1; reg_idx >= 0; --reg_idx) { | |
| 500 Register reg = static_cast<Register>(reg_idx); | |
| 501 if (locs->live_registers()->ContainsRegister(reg)) { | |
| 502 __ Pop(reg); | |
| 503 } | |
| 504 } | |
| 505 | |
| 506 // TODO(zra): Restore live FPU registers. | |
| 302 } | 507 } |
| 303 | 508 |
| 304 | 509 |
| 305 void FlowGraphCompiler::EmitTestAndCall(const ICData& ic_data, | 510 void FlowGraphCompiler::EmitTestAndCall(const ICData& ic_data, |
| 306 Register class_id_reg, | 511 Register class_id_reg, |
| 307 intptr_t argument_count, | 512 intptr_t argument_count, |
| 308 const Array& argument_names, | 513 const Array& argument_names, |
| 309 Label* deopt, | 514 Label* deopt, |
| 310 intptr_t deopt_id, | 515 intptr_t deopt_id, |
| 311 intptr_t token_index, | 516 intptr_t token_index, |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 420 void ParallelMoveResolver::RestoreFpuScratch(FpuRegister reg) { | 625 void ParallelMoveResolver::RestoreFpuScratch(FpuRegister reg) { |
| 421 UNIMPLEMENTED(); | 626 UNIMPLEMENTED(); |
| 422 } | 627 } |
| 423 | 628 |
| 424 | 629 |
| 425 #undef __ | 630 #undef __ |
| 426 | 631 |
| 427 } // namespace dart | 632 } // namespace dart |
| 428 | 633 |
| 429 #endif // defined TARGET_ARCH_ARM64 | 634 #endif // defined TARGET_ARCH_ARM64 |
| OLD | NEW |