Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(262)

Side by Side Diff: runtime/vm/stub_code_mips.cc

Issue 14076005: Supports FrameLookup vm test on MIPS (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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" 5 #include "vm/globals.h"
6 #if defined(TARGET_ARCH_MIPS) 6 #if defined(TARGET_ARCH_MIPS)
7 7
8 #include "vm/assembler.h" 8 #include "vm/assembler.h"
9 #include "vm/code_generator.h" 9 #include "vm/code_generator.h"
10 #include "vm/dart_entry.h" 10 #include "vm/dart_entry.h"
11 #include "vm/flow_graph_compiler.h"
11 #include "vm/instructions.h" 12 #include "vm/instructions.h"
12 #include "vm/stack_frame.h" 13 #include "vm/stack_frame.h"
13 #include "vm/stub_code.h" 14 #include "vm/stub_code.h"
14 15
15 #define __ assembler-> 16 #define __ assembler->
16 17
17 namespace dart { 18 namespace dart {
18 19
20 DEFINE_FLAG(bool, inline_alloc, true, "Inline allocation of objects.");
21 DEFINE_FLAG(bool, use_slow_path, false,
22 "Set to true for debugging & verifying the slow paths.");
23 DECLARE_FLAG(int, optimization_counter_threshold);
24 DECLARE_FLAG(bool, trace_optimized_ic_calls);
25
26
19 // Input parameters: 27 // Input parameters:
20 // RA : return address. 28 // RA : return address.
21 // SP : address of last argument in argument array. 29 // SP : address of last argument in argument array.
22 // SP + 4*S4 - 4 : address of first argument in argument array. 30 // SP + 4*S4 - 4 : address of first argument in argument array.
23 // SP + 4*S4 : address of return value. 31 // SP + 4*S4 : address of return value.
24 // S5 : address of the runtime function to call. 32 // S5 : address of the runtime function to call.
25 // S4 : number of arguments to the call. 33 // S4 : number of arguments to the call.
26 void StubCode::GenerateCallToRuntimeStub(Assembler* assembler) { 34 void StubCode::GenerateCallToRuntimeStub(Assembler* assembler) {
27 const intptr_t isolate_offset = NativeArguments::isolate_offset(); 35 const intptr_t isolate_offset = NativeArguments::isolate_offset();
28 const intptr_t argc_tag_offset = NativeArguments::argc_tag_offset(); 36 const intptr_t argc_tag_offset = NativeArguments::argc_tag_offset();
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
83 // Reset Context pointer in Isolate structure. 91 // Reset Context pointer in Isolate structure.
84 __ LoadImmediate(A3, reinterpret_cast<intptr_t>(Object::null())); 92 __ LoadImmediate(A3, reinterpret_cast<intptr_t>(Object::null()));
85 __ sw(A3, Address(CTX, Isolate::top_context_offset())); 93 __ sw(A3, Address(CTX, Isolate::top_context_offset()));
86 94
87 // Cache Context pointer into CTX while executing Dart code. 95 // Cache Context pointer into CTX while executing Dart code.
88 __ mov(CTX, A2); 96 __ mov(CTX, A2);
89 97
90 __ mov(SP, FP); 98 __ mov(SP, FP);
91 __ lw(RA, Address(SP, 1 * kWordSize)); 99 __ lw(RA, Address(SP, 1 * kWordSize));
92 __ lw(FP, Address(SP, 0 * kWordSize)); 100 __ lw(FP, Address(SP, 0 * kWordSize));
93 __ addiu(SP, SP, Immediate(2 * kWordSize));
94 __ Ret(); 101 __ Ret();
102 __ delay_slot()->addiu(SP, SP, Immediate(2 * kWordSize));
95 } 103 }
96 104
97 105
98 void StubCode::GeneratePrintStopMessageStub(Assembler* assembler) { 106 void StubCode::GeneratePrintStopMessageStub(Assembler* assembler) {
99 __ Unimplemented("PrintStopMessage stub"); 107 __ Unimplemented("PrintStopMessage stub");
100 } 108 }
101 109
102 110
103 // Input parameters: 111 // Input parameters:
104 // RA : return address. 112 // RA : return address.
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
175 // Reset Context pointer in Isolate structure. 183 // Reset Context pointer in Isolate structure.
176 __ LoadImmediate(A3, reinterpret_cast<intptr_t>(Object::null())); 184 __ LoadImmediate(A3, reinterpret_cast<intptr_t>(Object::null()));
177 __ sw(A3, Address(CTX, Isolate::top_context_offset())); 185 __ sw(A3, Address(CTX, Isolate::top_context_offset()));
178 186
179 // Cache Context pointer into CTX while executing Dart code. 187 // Cache Context pointer into CTX while executing Dart code.
180 __ mov(CTX, A2); 188 __ mov(CTX, A2);
181 189
182 __ mov(SP, FP); 190 __ mov(SP, FP);
183 __ lw(RA, Address(SP, 1 * kWordSize)); 191 __ lw(RA, Address(SP, 1 * kWordSize));
184 __ lw(FP, Address(SP, 0 * kWordSize)); 192 __ lw(FP, Address(SP, 0 * kWordSize));
185 __ addiu(SP, SP, Immediate(2 * kWordSize));
186 __ Ret(); 193 __ Ret();
194 __ delay_slot()->addiu(SP, SP, Immediate(2 * kWordSize));
187 } 195 }
188 196
189 197
190 // Input parameters: 198 // Input parameters:
191 // S4: arguments descriptor array. 199 // S4: arguments descriptor array.
192 void StubCode::GenerateCallStaticFunctionStub(Assembler* assembler) { 200 void StubCode::GenerateCallStaticFunctionStub(Assembler* assembler) {
193 __ EnterStubFrame(); 201 __ EnterStubFrame();
194 // Setup space on stack for return value and preserve arguments descriptor. 202 // Setup space on stack for return value and preserve arguments descriptor.
195 __ LoadImmediate(T0, reinterpret_cast<intptr_t>(Object::null())); 203 __ LoadImmediate(T0, reinterpret_cast<intptr_t>(Object::null()));
196 204
197 __ addiu(SP, SP, Immediate(-2 * kWordSize)); 205 __ addiu(SP, SP, Immediate(-2 * kWordSize));
198 __ sw(S4, Address(SP, 1 * kWordSize)); 206 __ sw(S4, Address(SP, 1 * kWordSize));
199 __ sw(T0, Address(SP, 0 * kWordSize)); 207 __ sw(T0, Address(SP, 0 * kWordSize));
200 208
201 __ CallRuntime(kPatchStaticCallRuntimeEntry); 209 __ CallRuntime(kPatchStaticCallRuntimeEntry);
202 210
203 // Get Code object result and restore arguments descriptor array. 211 // Get Code object result and restore arguments descriptor array.
204 __ lw(T0, Address(SP, 0 * kWordSize)); 212 __ lw(T0, Address(SP, 0 * kWordSize));
205 __ lw(S4, Address(SP, 1 * kWordSize)); 213 __ lw(S4, Address(SP, 1 * kWordSize));
206 __ addiu(SP, SP, Immediate(2 * kWordSize)); 214 __ addiu(SP, SP, Immediate(2 * kWordSize));
207 215
208 // Remove the stub frame as we are about to jump to the dart function. 216 // Remove the stub frame as we are about to jump to the dart function.
209 __ LeaveStubFrame(); 217 __ LeaveStubFrame();
210 218
211 __ lw(T0, FieldAddress(T0, Code::instructions_offset())); 219 __ lw(T0, FieldAddress(T0, Code::instructions_offset()));
212 __ addiu(T0, T0, Immediate(Instructions::HeaderSize() - kHeapObjectTag)); 220 __ AddImmediate(T0, Instructions::HeaderSize() - kHeapObjectTag);
213 __ jr(T0); 221 __ jr(T0);
214 } 222 }
215 223
216 224
217 void StubCode::GenerateFixCallersTargetStub(Assembler* assembler) { 225 void StubCode::GenerateFixCallersTargetStub(Assembler* assembler) {
218 __ Unimplemented("FixCallersTarget stub"); 226 __ Unimplemented("FixCallersTarget stub");
219 } 227 }
220 228
221 229
222 void StubCode::GenerateInstanceFunctionLookupStub(Assembler* assembler) { 230 void StubCode::GenerateInstanceFunctionLookupStub(Assembler* assembler) {
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
304 // Pushed A3, S0-7, S4, S5 = 11. 312 // Pushed A3, S0-7, S4, S5 = 11.
305 const intptr_t kSavedContextOffsetInEntryFrame = -11 * kWordSize; 313 const intptr_t kSavedContextOffsetInEntryFrame = -11 * kWordSize;
306 314
307 // Load arguments descriptor array into S4, which is passed to Dart code. 315 // Load arguments descriptor array into S4, which is passed to Dart code.
308 __ lw(S4, Address(A1, VMHandles::kOffsetOfRawPtrInHandle)); 316 __ lw(S4, Address(A1, VMHandles::kOffsetOfRawPtrInHandle));
309 317
310 // Load number of arguments into S5. 318 // Load number of arguments into S5.
311 __ lw(T1, FieldAddress(S4, ArgumentsDescriptor::count_offset())); 319 __ lw(T1, FieldAddress(S4, ArgumentsDescriptor::count_offset()));
312 __ SmiUntag(T1); 320 __ SmiUntag(T1);
313 321
322 // Compute address of 'arguments array' data area into A2.
323 __ lw(A2, Address(A2, VMHandles::kOffsetOfRawPtrInHandle));
324 __ AddImmediate(A2, Array::data_offset() - kHeapObjectTag);
325
314 // Set up arguments for the Dart call. 326 // Set up arguments for the Dart call.
315 Label push_arguments; 327 Label push_arguments;
316 Label done_push_arguments; 328 Label done_push_arguments;
317
318 // Compute address of 'arguments array' data area into A2.
319 // See also the addiu in the delay slot of the upcoming beq.
320 __ lw(A2, Address(A2, VMHandles::kOffsetOfRawPtrInHandle));
321
322 __ beq(T1, ZR, &done_push_arguments); // check if there are arguments. 329 __ beq(T1, ZR, &done_push_arguments); // check if there are arguments.
323 __ delay_slot()->addiu(A2, A2,
324 Immediate(Array::data_offset() - kHeapObjectTag));
325
326 __ mov(A1, ZR); 330 __ mov(A1, ZR);
327 __ Bind(&push_arguments); 331 __ Bind(&push_arguments);
328 __ lw(A3, Address(A2)); 332 __ lw(A3, Address(A2));
329 __ Push(A3); 333 __ Push(A3);
330 __ addiu(A2, A2, Immediate(kWordSize));
331 __ addiu(A1, A1, Immediate(1)); 334 __ addiu(A1, A1, Immediate(1));
332 __ BranchLess(A1, T1, &push_arguments); 335 __ BranchLess(A1, T1, &push_arguments);
336 __ delay_slot()->addiu(A2, A2, Immediate(kWordSize));
333 337
334 __ Bind(&done_push_arguments); 338 __ Bind(&done_push_arguments);
335 339
336 // Call the Dart code entrypoint. 340 // Call the Dart code entrypoint.
337 __ jalr(A0); // S4 is the arguments descriptor array. 341 __ jalr(A0); // S4 is the arguments descriptor array.
338 342
339 // Read the saved new Context pointer. 343 // Read the saved new Context pointer.
340 __ lw(CTX, Address(FP, kNewContextOffset)); 344 __ lw(CTX, Address(FP, kNewContextOffset));
341 __ lw(CTX, Address(CTX, VMHandles::kOffsetOfRawPtrInHandle)); 345 __ lw(CTX, Address(CTX, VMHandles::kOffsetOfRawPtrInHandle));
342 346
343 // Get rid of arguments pushed on the stack. 347 // Get rid of arguments pushed on the stack.
344 __ addiu(SP, FP, Immediate(kSavedContextOffsetInEntryFrame)); 348 __ AddImmediate(SP, FP, kSavedContextOffsetInEntryFrame);
345 349
346 // Load Isolate pointer from Context structure into CTX. Drop Context. 350 // Load Isolate pointer from Context structure into CTX. Drop Context.
347 __ lw(CTX, FieldAddress(CTX, Context::isolate_offset())); 351 __ lw(CTX, FieldAddress(CTX, Context::isolate_offset()));
348 352
349 // Restore the saved Context pointer into the Isolate structure. 353 // Restore the saved Context pointer into the Isolate structure.
350 // Uses T1 as a temporary register for this. 354 // Uses T1 as a temporary register for this.
351 // Restore the saved top exit frame info back into the Isolate structure. 355 // Restore the saved top exit frame info back into the Isolate structure.
352 // Uses T0 as a temporary register for this. 356 // Uses T0 as a temporary register for this.
353 __ lw(T1, Address(SP, 0 * kWordSize)); 357 __ lw(T1, Address(SP, 0 * kWordSize));
354 __ lw(T0, Address(SP, 1 * kWordSize)); 358 __ lw(T0, Address(SP, 1 * kWordSize));
(...skipping 17 matching lines...) Expand all
372 void StubCode::GenerateAllocateContextStub(Assembler* assembler) { 376 void StubCode::GenerateAllocateContextStub(Assembler* assembler) {
373 __ Unimplemented("AllocateContext stub"); 377 __ Unimplemented("AllocateContext stub");
374 } 378 }
375 379
376 380
377 void StubCode::GenerateUpdateStoreBufferStub(Assembler* assembler) { 381 void StubCode::GenerateUpdateStoreBufferStub(Assembler* assembler) {
378 __ Unimplemented("UpdateStoreBuffer stub"); 382 __ Unimplemented("UpdateStoreBuffer stub");
379 } 383 }
380 384
381 385
386 // Called for inline allocation of objects.
387 // Input parameters:
388 // RA : return address.
389 // SP + 4 : type arguments object (only if class is parameterized).
390 // SP + 0 : type arguments of instantiator (only if class is parameterized).
382 void StubCode::GenerateAllocationStubForClass(Assembler* assembler, 391 void StubCode::GenerateAllocationStubForClass(Assembler* assembler,
383 const Class& cls) { 392 const Class& cls) {
384 __ Unimplemented("AllocateObject stub"); 393 // The generated code is different if the class is parameterized.
394 const bool is_cls_parameterized =
395 cls.type_arguments_field_offset() != Class::kNoTypeArguments;
396 // kInlineInstanceSize is a constant used as a threshold for determining
397 // when the object initialization should be done as a loop or as
398 // straight line code.
399 const int kInlineInstanceSize = 12;
400 const intptr_t instance_size = cls.instance_size();
401 ASSERT(instance_size > 0);
402 const intptr_t type_args_size = InstantiatedTypeArguments::InstanceSize();
403 if (FLAG_inline_alloc &&
404 PageSpace::IsPageAllocatableSize(instance_size + type_args_size)) {
405 Label slow_case;
406 Heap* heap = Isolate::Current()->heap();
407 __ LoadImmediate(T5, heap->TopAddress());
408 __ lw(T2, Address(T5));
409 __ LoadImmediate(T4, instance_size);
410 __ addu(T3, T2, T4);
411 if (is_cls_parameterized) {
412 Label no_instantiator;
413 __ lw(T1, Address(SP, 1 * kWordSize));
414 __ lw(T0, Address(SP, 0 * kWordSize));
415 // A new InstantiatedTypeArguments object only needs to be allocated if
416 // the instantiator is provided (not kNoInstantiator, but may be null).
417 __ BranchEqual(T0, Smi::RawValue(StubCode::kNoInstantiator),
418 &no_instantiator);
419 __ delay_slot()->mov(T4, T3);
420 __ AddImmediate(T3, type_args_size);
421 __ Bind(&no_instantiator);
422 // T4: potential new object end and, if T4 != T3, potential new
423 // InstantiatedTypeArguments object start.
424 }
425 // Check if the allocation fits into the remaining space.
426 // T2: potential new object start.
427 // T3: potential next object start.
428 if (FLAG_use_slow_path) {
429 __ b(&slow_case);
430 } else {
431 __ BranchGreaterEqual(T3, heap->EndAddress(), &slow_case);
432 }
433
434 // Successfully allocated the object(s), now update top to point to
435 // next object start and initialize the object.
436 __ sw(T3, Address(T5));
437
438 if (is_cls_parameterized) {
439 // Initialize the type arguments field in the object.
440 // T2: new object start.
441 // T4: potential new object end and, if T4 != T3, potential new
442 // InstantiatedTypeArguments object start.
443 // T3: next object start.
444 Label type_arguments_ready;
445 __ beq(T4, T3, &type_arguments_ready);
446 // Initialize InstantiatedTypeArguments object at T4.
447 __ sw(T1, Address(T4,
448 InstantiatedTypeArguments::uninstantiated_type_arguments_offset()));
449 __ sw(T0, Address(T4,
450 InstantiatedTypeArguments::instantiator_type_arguments_offset()));
451 const Class& ita_cls =
452 Class::ZoneHandle(Object::instantiated_type_arguments_class());
453 // Set the tags.
454 uword tags = 0;
455 tags = RawObject::SizeTag::update(type_args_size, tags);
456 tags = RawObject::ClassIdTag::update(ita_cls.id(), tags);
457 __ LoadImmediate(T0, tags);
458 __ sw(T0, Address(T4, Instance::tags_offset()));
459 // Set the new InstantiatedTypeArguments object (T4) as the type
460 // arguments (T1) of the new object (T2).
461 __ addiu(T1, T4, Immediate(kHeapObjectTag));
462 // Set T3 to new object end.
463 __ mov(T3, T4);
464 __ Bind(&type_arguments_ready);
465 // T2: new object.
466 // T1: new object type arguments.
467 }
468
469 // T2: new object start.
470 // T3: next object start.
471 // T1: new object type arguments (if is_cls_parameterized).
472 // Set the tags.
473 uword tags = 0;
474 tags = RawObject::SizeTag::update(instance_size, tags);
475 ASSERT(cls.id() != kIllegalCid);
476 tags = RawObject::ClassIdTag::update(cls.id(), tags);
477 __ LoadImmediate(T0, tags);
478 __ sw(T0, Address(T2, Instance::tags_offset()));
479
480 // Initialize the remaining words of the object.
481 __ LoadImmediate(T0, reinterpret_cast<intptr_t>(Object::null()));
482
483 // T0: raw null.
484 // T2: new object start.
485 // T3: next object start.
486 // T1: new object type arguments (if is_cls_parameterized).
487 // First try inlining the initialization without a loop.
488 if (instance_size < (kInlineInstanceSize * kWordSize)) {
489 // Check if the object contains any non-header fields.
490 // Small objects are initialized using a consecutive set of writes.
491 for (intptr_t current_offset = sizeof(RawObject);
492 current_offset < instance_size;
493 current_offset += kWordSize) {
494 __ sw(T0, Address(T2, current_offset));
495 }
496 } else {
497 __ addiu(T4, T2, Immediate(sizeof(RawObject)));
498 // Loop until the whole object is initialized.
499 // T0: raw null.
500 // T2: new object.
501 // T3: next object start.
502 // T4: next word to be initialized.
503 // T1: new object type arguments (if is_cls_parameterized).
504 Label init_loop;
505 Label done;
506 __ Bind(&init_loop);
507 __ BranchGreaterEqual(T4, T3, &done); // Done if T4 >= T3.
508 __ sw(T0, Address(T4));
509 __ AddImmediate(T4, kWordSize);
510 __ b(&init_loop);
511 __ Bind(&done);
512 }
513 if (is_cls_parameterized) {
514 // R1: new object type arguments.
515 // Set the type arguments in the new object.
516 __ sw(T1, Address(T2, cls.type_arguments_field_offset()));
517 }
518 // Done allocating and initializing the instance.
519 // R2: new object still missing its heap tag.
520 __ Ret();
521 __ delay_slot()->addiu(V0, T2, Immediate(kHeapObjectTag));
522
523 __ Bind(&slow_case);
524 }
525 if (is_cls_parameterized) {
526 __ lw(T1, Address(SP, 1 * kWordSize));
527 __ lw(T0, Address(SP, 0 * kWordSize));
528 }
529 // Create a stub frame as we are pushing some objects on the stack before
530 // calling into the runtime.
531 __ EnterStubFrame(true); // Uses pool pointer to pass cls to runtime.
532 __ LoadImmediate(T2, reinterpret_cast<intptr_t>(Object::null()));
533 __ Push(T2); // Setup space on stack for return value.
534 __ PushObject(cls); // Push class of object to be allocated.
535 if (is_cls_parameterized) {
536 // Push type arguments of object to be allocated and of instantiator.
537 __ addiu(SP, SP, Immediate(-2 * kWordSize));
538 __ sw(T1, Address(SP, 1 * kWordSize));
539 __ sw(T0, Address(SP, 0 * kWordSize));
540 } else {
541 // Push null type arguments and kNoInstantiator.
542 __ LoadImmediate(T1, Smi::RawValue(StubCode::kNoInstantiator));
543 __ addiu(SP, SP, Immediate(-2 * kWordSize));
544 __ sw(T2, Address(SP, 1 * kWordSize));
545 __ sw(T1, Address(SP, 0 * kWordSize));
546 }
547 __ CallRuntime(kAllocateObjectRuntimeEntry); // Allocate object.
548 __ Drop(3); // Pop arguments.
549 __ Pop(V0); // Pop result (newly allocated object).
550 // V0: new object
551 // Restore the frame pointer.
552 __ LeaveStubFrame(true);
553 __ Ret();
385 } 554 }
386 555
387 556
388 void StubCode::GenerateAllocationStubForClosure(Assembler* assembler, 557 void StubCode::GenerateAllocationStubForClosure(Assembler* assembler,
389 const Function& func) { 558 const Function& func) {
390 __ Unimplemented("AllocateClosure stub"); 559 __ Unimplemented("AllocateClosure stub");
391 } 560 }
392 561
393 562
394 void StubCode::GenerateCallNoSuchMethodFunctionStub(Assembler* assembler) { 563 void StubCode::GenerateCallNoSuchMethodFunctionStub(Assembler* assembler) {
395 __ Unimplemented("CallNoSuchMethodFunction stub"); 564 __ Unimplemented("CallNoSuchMethodFunction stub");
396 } 565 }
397 566
398 567
399 void StubCode::GenerateOptimizedUsageCounterIncrement(Assembler* assembler) { 568 void StubCode::GenerateOptimizedUsageCounterIncrement(Assembler* assembler) {
400 __ Unimplemented("OptimizedUsageCounterIncrement stub"); 569 __ Unimplemented("OptimizedUsageCounterIncrement stub");
401 } 570 }
402 571
403 572
573 // Loads function into 'temp_reg'.
404 void StubCode::GenerateUsageCounterIncrement(Assembler* assembler, 574 void StubCode::GenerateUsageCounterIncrement(Assembler* assembler,
405 Register temp_reg) { 575 Register temp_reg) {
406 __ Unimplemented("UsageCounterIncrement stub"); 576 Register ic_reg = S5;
407 } 577 Register func_reg = temp_reg;
408 578 ASSERT(temp_reg == T0);
409 579 __ lw(func_reg, FieldAddress(ic_reg, ICData::function_offset()));
580 __ lw(T1, FieldAddress(func_reg, Function::usage_counter_offset()));
581 Label is_hot;
582 if (FlowGraphCompiler::CanOptimize()) {
583 ASSERT(FLAG_optimization_counter_threshold > 1);
584 // The usage_counter is always less than FLAG_optimization_counter_threshold
585 // except when the function gets optimized.
586 __ BranchEqual(T1, FLAG_optimization_counter_threshold, &is_hot);
587 // As long as VM has no OSR do not optimize in the middle of the function
588 // but only at exit so that we have collected all type feedback before
589 // optimizing.
590 }
591 __ addiu(T1, T1, Immediate(1));
592 __ sw(T1, FieldAddress(func_reg, Function::usage_counter_offset()));
593 __ Bind(&is_hot);
594 }
595
596
597 // Generate inline cache check for 'num_args'.
598 // AR: return address
599 // S5: Inline cache data object.
600 // S4: Arguments descriptor array.
601 // Control flow:
602 // - If receiver is null -> jump to IC miss.
603 // - If receiver is Smi -> load Smi class.
604 // - If receiver is not-Smi -> load receiver's class.
605 // - Check if 'num_args' (including receiver) match any IC data group.
606 // - Match found -> jump to target.
607 // - Match not found -> jump to IC miss.
410 void StubCode::GenerateNArgsCheckInlineCacheStub(Assembler* assembler, 608 void StubCode::GenerateNArgsCheckInlineCacheStub(Assembler* assembler,
411 intptr_t num_args) { 609 intptr_t num_args) {
412 __ Unimplemented("NArgsCheckInlineCache stub"); 610 ASSERT(num_args > 0);
413 } 611 #if defined(DEBUG)
414 612 { Label ok;
415 613 // Check that the IC data array has NumberOfArgumentsChecked() == num_args.
614 // 'num_args_tested' is stored as an untagged int.
615 __ lw(T0, FieldAddress(S5, ICData::num_args_tested_offset()));
616 __ BranchEqual(T0, num_args, &ok);
617 __ Stop("Incorrect stub for IC data");
618 __ Bind(&ok);
619 }
620 #endif // DEBUG
621
622 // Preserve return address, since LR is needed for subroutine call.
623 __ mov(T2, RA);
624 // Loop that checks if there is an IC data match.
625 Label loop, update, test, found, get_class_id_as_smi;
626 // S5: IC data object (preserved).
627 __ lw(T0, FieldAddress(S5, ICData::ic_data_offset()));
628 // T0: ic_data_array with check entries: classes and target functions.
629 __ AddImmediate(T0, Array::data_offset() - kHeapObjectTag);
630 // T0: points directly to the first ic data array element.
631
632 // Get the receiver's class ID (first read number of arguments from
633 // arguments descriptor array and then access the receiver from the stack).
634 __ lw(T1, FieldAddress(S4, ArgumentsDescriptor::count_offset()));
635 __ AddImmediate(T1, -Smi::RawValue(1));
636 __ sll(T3, T1, 1); // T1 (argument_count - 1) is smi.
637 __ addu(T3, T3, SP);
638 __ bal(&get_class_id_as_smi);
639 __ delay_slot()->lw(T3, Address(T3));
640 // T1: argument_count - 1 (smi).
641 // T3: receiver's class ID (smi).
642 __ b(&test);
643 __ delay_slot()->lw(T4, Address(T0)); // First class id (smi) to check.
644
645 __ Bind(&loop);
646 for (int i = 0; i < num_args; i++) {
647 if (i > 0) {
648 // If not the first, load the next argument's class ID.
649 __ LoadImmediate(T3, Smi::RawValue(-i));
650 __ addu(T3, T1, T3);
651 __ sll(T3, T3, 1);
652 __ addu(T3, SP, T3);
653 __ bal(&get_class_id_as_smi);
654 __ delay_slot()->lw(T3, Address(T3));
655 // T3: next argument class ID (smi).
656 __ lw(T4, Address(T0, i * kWordSize));
657 // T4: next class ID to check (smi).
658 }
659 if (i < (num_args - 1)) {
660 __ bne(T3, T4, &update); // Continue.
661 } else {
662 // Last check, all checks before matched.
663 Label skip;
664 __ bne(T3, T4, &skip);
665 __ b(&found); // Break.
666 __ delay_slot()->mov(RA, T2); // Restore return address if found.
667 __ Bind(&skip);
668 }
669 }
670 __ Bind(&update);
671 // Reload receiver class ID. It has not been destroyed when num_args == 1.
672 if (num_args > 1) {
673 __ sll(T3, T1, 1);
674 __ addu(T3, SP, T3);
675 __ bal(&get_class_id_as_smi);
676 __ delay_slot()->lw(T3, Address(T3));
677 }
678
679 const intptr_t entry_size = ICData::TestEntryLengthFor(num_args) * kWordSize;
680 __ AddImmediate(T0, entry_size); // Next entry.
681 __ lw(T4, Address(T0)); // Next class ID.
682
683 __ Bind(&test);
684 __ BranchNotEqual(T4, Smi::RawValue(kIllegalCid), &loop); // Done?
685
686 // IC miss.
687 // Restore return address.
688 __ mov(RA, T2);
689
690 // Compute address of arguments (first read number of arguments from
691 // arguments descriptor array and then compute address on the stack).
692 // T1: argument_count - 1 (smi).
693 __ sll(T1, T1, 1);
694 __ addu(T1, SP, T1); // T1 is Smi.
695 // T1: address of receiver.
696 // Create a stub frame as we are pushing some objects on the stack before
697 // calling into the runtime.
698 __ EnterStubFrame();
699 __ LoadImmediate(T3, reinterpret_cast<intptr_t>(Object::null()));
700 // Preserve IC data object and arguments descriptor array and
701 // setup space on stack for result (target code object).
702 __ addiu(SP, SP, Immediate(-3 * kWordSize));
703 __ sw(S5, Address(SP, 2 * kWordSize));
704 __ sw(S4, Address(SP, 1 * kWordSize));
705 __ sw(T3, Address(SP, 0 * kWordSize));
706 // Push call arguments.
707 for (intptr_t i = 0; i < num_args; i++) {
708 __ lw(TMP, Address(T1, -i * kWordSize));
709 __ Push(TMP);
710 }
711 // Pass IC data object and arguments descriptor array.
712 __ addiu(SP, SP, Immediate(-2 * kWordSize));
713 __ sw(S5, Address(SP, 1 * kWordSize));
714 __ sw(S4, Address(SP, 0 * kWordSize));
715
716 if (num_args == 1) {
717 __ CallRuntime(kInlineCacheMissHandlerOneArgRuntimeEntry);
718 } else if (num_args == 2) {
719 __ CallRuntime(kInlineCacheMissHandlerTwoArgsRuntimeEntry);
720 } else if (num_args == 3) {
721 __ CallRuntime(kInlineCacheMissHandlerThreeArgsRuntimeEntry);
722 } else {
723 UNIMPLEMENTED();
724 }
725 // Remove the call arguments pushed earlier, including the IC data object
726 // and the arguments descriptor array.
727 __ Drop(num_args + 2);
728 // Pop returned code object into T3 (null if not found).
729 // Restore arguments descriptor array and IC data array.
730 __ lw(T3, Address(SP, 0 * kWordSize));
731 __ lw(S4, Address(SP, 1 * kWordSize));
732 __ lw(S5, Address(SP, 2 * kWordSize));
733 __ addiu(SP, SP, Immediate(3 * kWordSize));
734 __ LeaveStubFrame();
735 Label call_target_function;
736 __ BranchNotEqual(T3, reinterpret_cast<intptr_t>(Object::null()),
737 &call_target_function);
738 // NoSuchMethod or closure.
739 // Mark IC call that it may be a closure call that does not collect
740 // type feedback.
741 __ LoadImmediate(TMP2, 1);
742 __ Branch(&StubCode::InstanceFunctionLookupLabel());
743 __ delay_slot()->sb(TMP2, FieldAddress(S5, ICData::is_closure_call_offset()));
744
745 __ Bind(&found);
746 // T0: Pointer to an IC data check group.
747 const intptr_t target_offset = ICData::TargetIndexFor(num_args) * kWordSize;
748 const intptr_t count_offset = ICData::CountIndexFor(num_args) * kWordSize;
749 __ lw(T3, Address(T0, target_offset));
750 __ lw(T4, Address(T0, count_offset));
751
752 __ AddImmediateDetectOverflow(T4, T4, Smi::RawValue(1), T5);
753
754 __ bgez(T5, &call_target_function); // No overflow.
755 __ delay_slot()->sw(T4, Address(T0, count_offset));
756
757 __ LoadImmediate(T1, Smi::RawValue(Smi::kMaxValue));
758 __ sw(T1, Address(T0, count_offset));
759
760 __ Bind(&call_target_function);
761 // T0: Target function.
762 __ lw(T3, FieldAddress(T3, Function::code_offset()));
763 __ lw(T3, FieldAddress(T3, Code::instructions_offset()));
764 __ AddImmediate(T3, Instructions::HeaderSize() - kHeapObjectTag);
765 __ jr(T3);
766
767 // Instance in T3, return its class-id in T3 as Smi.
768 __ Bind(&get_class_id_as_smi);
769 Label not_smi;
770 // Test if Smi -> load Smi class for comparison.
771 __ andi(TMP1, T3, Immediate(kSmiTagMask));
772 __ bne(TMP1, ZR, &not_smi);
773 __ LoadImmediate(T3, Smi::RawValue(kSmiCid));
774 __ jr(RA);
775
776 __ Bind(&not_smi);
777 __ LoadClassId(T3, T3);
778 __ SmiTag(T3);
779 __ jr(RA);
780 }
781
782
783 // Use inline cache data array to invoke the target or continue in inline
784 // cache miss handler. Stub for 1-argument check (receiver class).
785 // RA: Return address.
786 // S5: Inline cache data object.
787 // S4: Arguments descriptor array.
788 // Inline cache data object structure:
789 // 0: function-name
790 // 1: N, number of arguments checked.
791 // 2 .. (length - 1): group of checks, each check containing:
792 // - N classes.
793 // - 1 target function.
416 void StubCode::GenerateOneArgCheckInlineCacheStub(Assembler* assembler) { 794 void StubCode::GenerateOneArgCheckInlineCacheStub(Assembler* assembler) {
417 __ Unimplemented("GenerateOneArgCheckInlineCacheStub stub"); 795 GenerateUsageCounterIncrement(assembler, T0);
796 GenerateNArgsCheckInlineCacheStub(assembler, 1);
418 } 797 }
419 798
420 799
421 void StubCode::GenerateTwoArgsCheckInlineCacheStub(Assembler* assembler) { 800 void StubCode::GenerateTwoArgsCheckInlineCacheStub(Assembler* assembler) {
422 __ Unimplemented("GenerateTwoArgsCheckInlineCacheStub stub"); 801 GenerateUsageCounterIncrement(assembler, T0);
802 GenerateNArgsCheckInlineCacheStub(assembler, 2);
423 } 803 }
424 804
425 805
426 void StubCode::GenerateThreeArgsCheckInlineCacheStub(Assembler* assembler) { 806 void StubCode::GenerateThreeArgsCheckInlineCacheStub(Assembler* assembler) {
427 __ Unimplemented("GenerateThreeArgsCheckInlineCacheStub stub"); 807 GenerateUsageCounterIncrement(assembler, T0);
428 } 808 GenerateNArgsCheckInlineCacheStub(assembler, 3);
429 809 }
430 810
811
431 void StubCode::GenerateOneArgOptimizedCheckInlineCacheStub( 812 void StubCode::GenerateOneArgOptimizedCheckInlineCacheStub(
432 Assembler* assembler) { 813 Assembler* assembler) {
433 GenerateOptimizedUsageCounterIncrement(assembler); 814 GenerateOptimizedUsageCounterIncrement(assembler);
434 GenerateNArgsCheckInlineCacheStub(assembler, 1); 815 GenerateNArgsCheckInlineCacheStub(assembler, 1);
435 } 816 }
436 817
437 818
438 void StubCode::GenerateTwoArgsOptimizedCheckInlineCacheStub( 819 void StubCode::GenerateTwoArgsOptimizedCheckInlineCacheStub(
439 Assembler* assembler) { 820 Assembler* assembler) {
440 GenerateOptimizedUsageCounterIncrement(assembler); 821 GenerateOptimizedUsageCounterIncrement(assembler);
(...skipping 26 matching lines...) Expand all
467 void StubCode::GenerateBreakpointReturnStub(Assembler* assembler) { 848 void StubCode::GenerateBreakpointReturnStub(Assembler* assembler) {
468 __ Unimplemented("BreakpointReturn stub"); 849 __ Unimplemented("BreakpointReturn stub");
469 } 850 }
470 851
471 852
472 void StubCode::GenerateBreakpointDynamicStub(Assembler* assembler) { 853 void StubCode::GenerateBreakpointDynamicStub(Assembler* assembler) {
473 __ Unimplemented("BreakpointDynamic stub"); 854 __ Unimplemented("BreakpointDynamic stub");
474 } 855 }
475 856
476 857
477 void StubCode::GenerateSubtype1TestCacheStub(Assembler* assembler) { 858 // Used to check class and type arguments. Arguments passed in registers:
478 __ Unimplemented("Subtype1TestCache Stub"); 859 // RA: return address.
860 // A0: instance (must be preserved).
861 // A1: instantiator type arguments or NULL.
862 // A2: cache array.
863 // Result in V0: null -> not found, otherwise result (true or false).
864 static void GenerateSubtypeNTestCacheStub(Assembler* assembler, int n) {
865 ASSERT((1 <= n) && (n <= 3));
866 if (n > 1) {
867 // Get instance type arguments.
868 __ LoadClass(T0, A0);
869 // Compute instance type arguments into R4.
870 Label has_no_type_arguments;
871 __ LoadImmediate(T1, reinterpret_cast<intptr_t>(Object::null()));
872 __ lw(T2, FieldAddress(T0,
873 Class::type_arguments_field_offset_in_words_offset()));
874 __ BranchEqual(T2, Class::kNoTypeArguments, &has_no_type_arguments);
875 __ sll(T2, T2, 2);
876 __ addu(T2, A0, T2); // T2 <- A0 + T2 * 4
877 __ lw(T1, FieldAddress(T2, 0));
878 __ Bind(&has_no_type_arguments);
879 }
880 __ LoadClassId(T0, A0);
881 // A0: instance.
882 // A1: instantiator type arguments or NULL.
883 // A2: SubtypeTestCache.
884 // T0: instance class id.
885 // T1: instance type arguments (null if none), used only if n > 1.
886 __ lw(T2, FieldAddress(A2, SubtypeTestCache::cache_offset()));
887 __ AddImmediate(T2, Array::data_offset() - kHeapObjectTag);
888
889 Label loop, found, not_found, next_iteration;
890 // T0: instance class id.
891 // T1: instance type arguments.
892 // T2: Entry start.
893 __ SmiTag(T0);
894 __ Bind(&loop);
895 __ lw(T3, Address(T2, kWordSize * SubtypeTestCache::kInstanceClassId));
896 __ BranchEqual(T3, reinterpret_cast<intptr_t>(Object::null()), &not_found);
897
898 if (n == 1) {
899 __ BranchEqual(T3, T0, &found);
900 } else {
901 __ BranchNotEqual(T3, T0, &next_iteration);
902 __ lw(T3,
903 Address(T2, kWordSize * SubtypeTestCache::kInstanceTypeArguments));
904 if (n == 2) {
905 __ BranchEqual(T3, T1, &found);
906 } else {
907 __ BranchNotEqual(T3, T1, &next_iteration);
908 __ lw(T3, Address(T2, kWordSize *
909 SubtypeTestCache::kInstantiatorTypeArguments));
910 __ BranchEqual(T3, A1, &found);
911 }
912 }
913 __ Bind(&next_iteration);
914 __ AddImmediate(T2, kWordSize * SubtypeTestCache::kTestEntryLength);
915 __ b(&loop);
916 // Fall through to not found.
917 __ Bind(&not_found);
918 __ LoadImmediate(V0, reinterpret_cast<intptr_t>(Object::null()));
919 __ Ret();
920
921 __ Bind(&found);
922 __ Ret();
923 __ delay_slot()->lw(V0,
924 Address(T2, kWordSize * SubtypeTestCache::kTestResult));
479 } 925 }
480 926
481 927
482 void StubCode::GenerateSubtype2TestCacheStub(Assembler* assembler) { 928 // Used to check class and type arguments. Arguments passed in registers:
483 __ Unimplemented("Subtype2TestCache Stub"); 929 // RA: return address.
930 // A0: instance (must be preserved).
931 // A1: instantiator type arguments or NULL.
932 // A2: cache array.
933 // Result in V0: null -> not found, otherwise result (true or false).
934 void StubCode::GenerateSubtype1TestCacheStub(Assembler* assembler) {
935 GenerateSubtypeNTestCacheStub(assembler, 1);
484 } 936 }
485 937
486 938
487 void StubCode::GenerateSubtype3TestCacheStub(Assembler* assembler) { 939 // Used to check class and type arguments. Arguments passed in registers:
488 __ Unimplemented("Subtype3TestCache Stub"); 940 // LR: return address.
941 // A0: instance (must be preserved).
942 // A1: instantiator type arguments or NULL.
943 // A2: cache array.
944 // Result in V0: null -> not found, otherwise result (true or false).
945 void StubCode::GenerateSubtype2TestCacheStub(Assembler* assembler) {
946 GenerateSubtypeNTestCacheStub(assembler, 2);
489 } 947 }
490 948
491 949
950 // Used to check class and type arguments. Arguments passed in registers:
951 // RA: return address.
952 // A0: instance (must be preserved).
953 // A1: instantiator type arguments or NULL.
954 // A2: cache array.
955 // Result in V0: null -> not found, otherwise result (true or false).
956 void StubCode::GenerateSubtype3TestCacheStub(Assembler* assembler) {
957 GenerateSubtypeNTestCacheStub(assembler, 3);
958 }
959
960
492 // Return the current stack pointer address, used to stack alignment 961 // Return the current stack pointer address, used to stack alignment
493 // checks. 962 // checks.
494 void StubCode::GenerateGetStackPointerStub(Assembler* assembler) { 963 void StubCode::GenerateGetStackPointerStub(Assembler* assembler) {
495 __ Unimplemented("GetStackPointer Stub"); 964 __ Unimplemented("GetStackPointer Stub");
496 } 965 }
497 966
498 967
499 // Jump to the exception handler. 968 // Jump to the exception handler.
500 // No Result. 969 // No Result.
501 void StubCode::GenerateJumpToExceptionHandlerStub(Assembler* assembler) { 970 void StubCode::GenerateJumpToExceptionHandlerStub(Assembler* assembler) {
502 __ Unimplemented("JumpToExceptionHandler Stub"); 971 __ Unimplemented("JumpToExceptionHandler Stub");
503 } 972 }
504 973
505 974
506 // Jump to the error handler. 975 // Jump to the error handler.
507 // No Result. 976 // No Result.
508 void StubCode::GenerateJumpToErrorHandlerStub(Assembler* assembler) { 977 void StubCode::GenerateJumpToErrorHandlerStub(Assembler* assembler) {
509 __ Unimplemented("JumpToErrorHandler Stub"); 978 __ Unimplemented("JumpToErrorHandler Stub");
510 } 979 }
511 980
512 981
513 void StubCode::GenerateEqualityWithNullArgStub(Assembler* assembler) { 982 void StubCode::GenerateEqualityWithNullArgStub(Assembler* assembler) {
514 __ Unimplemented("EqualityWithNullArg stub"); 983 __ Unimplemented("EqualityWithNullArg Stub");
515 } 984 }
516 985
517 986
518 void StubCode::GenerateOptimizeFunctionStub(Assembler* assembler) { 987 void StubCode::GenerateOptimizeFunctionStub(Assembler* assembler) {
519 __ Unimplemented("OptimizeFunction stub"); 988 __ Unimplemented("OptimizeFunction Stub");
520 } 989 }
521 990
522 991
992 DECLARE_LEAF_RUNTIME_ENTRY(intptr_t,
993 BigintCompare,
994 RawBigint* left,
995 RawBigint* right);
996
997
998 // Does identical check (object references are equal or not equal) with special
999 // checks for boxed numbers.
1000 // LR: return address.
1001 // SP + 4: left operand.
1002 // SP + 0: right operand.
1003 // Return: CMPRES is zero if equal, non-zero otherwise.
1004 // Note: A Mint cannot contain a value that would fit in Smi, a Bigint
1005 // cannot contain a value that fits in Mint or Smi.
523 void StubCode::GenerateIdenticalWithNumberCheckStub(Assembler* assembler) { 1006 void StubCode::GenerateIdenticalWithNumberCheckStub(Assembler* assembler) {
524 __ Unimplemented("IdenticalWithNumberCheck stub"); 1007 const Register ret = CMPRES;
1008 const Register temp1 = TMP1;
1009 const Register temp2 = TMP2;
1010 const Register left = T1;
1011 const Register right = T0;
1012 // Preserve left, right and temp.
1013 __ addiu(SP, SP, Immediate(-2 * kWordSize));
1014 __ sw(T1, Address(SP, 1 * kWordSize));
1015 __ sw(T0, Address(SP, 0 * kWordSize));
1016 // TOS + 4: left argument.
1017 // TOS + 3: right argument.
1018 // TOS + 1: saved left
1019 // TOS + 0: saved right
1020 __ lw(left, Address(SP, 3 * kWordSize));
1021 __ lw(right, Address(SP, 2 * kWordSize));
1022 Label reference_compare, done, check_mint, check_bigint;
1023 // If any of the arguments is Smi do reference compare.
1024 __ andi(temp1, left, Immediate(kSmiTagMask));
1025 __ beq(temp1, ZR, &reference_compare);
1026 __ andi(temp1, right, Immediate(kSmiTagMask));
1027 __ beq(temp1, ZR, &reference_compare);
1028
1029 // Value compare for two doubles.
1030 __ LoadImmediate(temp1, kDoubleCid);
1031 __ LoadClassId(temp2, left);
1032 __ bne(temp1, temp2, &check_mint);
1033 __ LoadClassId(temp2, right);
1034 __ subu(ret, temp1, temp2);
1035 __ bne(ret, ZR, &done);
1036
1037 // Double values bitwise compare.
1038 __ lw(temp1, FieldAddress(left, Double::value_offset() + 0 * kWordSize));
1039 __ lw(temp1, FieldAddress(right, Double::value_offset() + 0 * kWordSize));
1040 __ subu(ret, temp1, temp2);
1041 __ bne(ret, ZR, &done);
1042 __ lw(temp1, FieldAddress(left, Double::value_offset() + 1 * kWordSize));
1043 __ lw(temp2, FieldAddress(right, Double::value_offset() + 1 * kWordSize));
1044 __ b(&done);
1045 __ delay_slot()->subu(ret, temp1, temp2);
1046
1047 __ Bind(&check_mint);
1048 __ LoadImmediate(temp1, kMintCid);
1049 __ LoadClassId(temp2, left);
1050 __ bne(temp1, temp2, &check_bigint);
1051 __ LoadClassId(temp2, right);
1052 __ subu(ret, temp1, temp2);
1053 __ bne(ret, ZR, &done);
1054
1055 __ lw(temp1, FieldAddress(left, Mint::value_offset() + 0 * kWordSize));
1056 __ lw(temp2, FieldAddress(right, Mint::value_offset() + 0 * kWordSize));
1057 __ subu(ret, temp1, temp2);
1058 __ bne(ret, ZR, &done);
1059 __ lw(temp1, FieldAddress(left, Mint::value_offset() + 1 * kWordSize));
1060 __ lw(temp2, FieldAddress(right, Mint::value_offset() + 1 * kWordSize));
1061 __ b(&done);
1062 __ delay_slot()->subu(ret, temp1, temp2);
1063
1064 __ Bind(&check_bigint);
1065 __ LoadImmediate(temp1, kBigintCid);
1066 __ LoadClassId(temp2, left);
1067 __ bne(temp1, temp2, &reference_compare);
1068 __ LoadClassId(temp2, right);
1069 __ subu(ret, temp1, temp2);
1070 __ bne(ret, ZR, &done);
1071
1072 __ EnterStubFrame(0);
1073 __ ReserveAlignedFrameSpace(2 * kWordSize);
1074 __ addiu(SP, SP, Immediate(-2 * kWordSize));
1075 __ sw(T1, Address(SP, 1 * kWordSize));
1076 __ sw(T0, Address(SP, 0 * kWordSize));
1077 __ CallRuntime(kBigintCompareRuntimeEntry);
1078 // Result in V0, 0 means equal.
1079 __ LeaveStubFrame();
1080 __ b(&done);
1081 __ delay_slot()->mov(CMPRES, V0);
1082
1083 __ Bind(&reference_compare);
1084 __ subu(ret, left, right);
1085 __ Bind(&done);
1086 __ lw(T0, Address(SP, 0 * kWordSize));
1087 __ lw(T1, Address(SP, 1 * kWordSize));
1088 __ Ret();
1089 __ delay_slot()->addiu(SP, SP, Immediate(2 * kWordSize));
525 } 1090 }
526 1091
527 } // namespace dart 1092 } // namespace dart
528 1093
529 #endif // defined TARGET_ARCH_MIPS 1094 #endif // defined TARGET_ARCH_MIPS
OLDNEW
« runtime/vm/intermediate_language_mips.cc ('K') | « runtime/vm/stub_code_arm.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698