| 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" | 5 #include "vm/globals.h" |
| 6 #if defined(TARGET_ARCH_ARM64) | 6 #if defined(TARGET_ARCH_ARM64) |
| 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/compiler.h" | 10 #include "vm/compiler.h" |
| 11 #include "vm/dart_entry.h" | 11 #include "vm/dart_entry.h" |
| 12 #include "vm/flow_graph_compiler.h" | 12 #include "vm/flow_graph_compiler.h" |
| 13 #include "vm/heap.h" | 13 #include "vm/heap.h" |
| 14 #include "vm/instructions.h" | 14 #include "vm/instructions.h" |
| 15 #include "vm/object_store.h" | 15 #include "vm/object_store.h" |
| 16 #include "vm/stack_frame.h" | 16 #include "vm/stack_frame.h" |
| 17 #include "vm/stub_code.h" | 17 #include "vm/stub_code.h" |
| 18 #include "vm/tags.h" | 18 #include "vm/tags.h" |
| 19 | 19 |
| 20 #define __ assembler-> | 20 #define __ assembler-> |
| 21 | 21 |
| 22 namespace dart { | 22 namespace dart { |
| 23 | 23 |
| 24 DEFINE_FLAG(bool, inline_alloc, true, "Inline allocation of objects."); | 24 DEFINE_FLAG(bool, inline_alloc, true, "Inline allocation of objects."); |
| 25 DEFINE_FLAG(bool, use_slow_path, false, | 25 DEFINE_FLAG(bool, use_slow_path, false, |
| 26 "Set to true for debugging & verifying the slow paths."); | 26 "Set to true for debugging & verifying the slow paths."); |
| 27 DECLARE_FLAG(bool, trace_optimized_ic_calls); |
| 27 | 28 |
| 28 // Input parameters: | 29 // Input parameters: |
| 29 // LR : return address. | 30 // LR : return address. |
| 30 // SP : address of last argument in argument array. | 31 // SP : address of last argument in argument array. |
| 31 // SP + 8*R4 - 8 : address of first argument in argument array. | 32 // SP + 8*R4 - 8 : address of first argument in argument array. |
| 32 // SP + 8*R4 : address of return value. | 33 // SP + 8*R4 : address of return value. |
| 33 // R5 : address of the runtime function to call. | 34 // R5 : address of the runtime function to call. |
| 34 // R4 : number of arguments to the call. | 35 // R4 : number of arguments to the call. |
| 35 void StubCode::GenerateCallToRuntimeStub(Assembler* assembler) { | 36 void StubCode::GenerateCallToRuntimeStub(Assembler* assembler) { |
| 36 const intptr_t isolate_offset = NativeArguments::isolate_offset(); | 37 const intptr_t isolate_offset = NativeArguments::isolate_offset(); |
| (...skipping 309 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 346 __ StoreToOffset(R3, CTX, Isolate::top_context_offset()); | 347 __ StoreToOffset(R3, CTX, Isolate::top_context_offset()); |
| 347 | 348 |
| 348 // Cache Context pointer into CTX while executing Dart code. | 349 // Cache Context pointer into CTX while executing Dart code. |
| 349 __ mov(CTX, R2); | 350 __ mov(CTX, R2); |
| 350 | 351 |
| 351 __ LeaveFrame(); | 352 __ LeaveFrame(); |
| 352 __ ret(); | 353 __ ret(); |
| 353 } | 354 } |
| 354 | 355 |
| 355 | 356 |
| 357 // Input parameters: |
| 358 // R4: arguments descriptor array. |
| 356 void StubCode::GenerateCallStaticFunctionStub(Assembler* assembler) { | 359 void StubCode::GenerateCallStaticFunctionStub(Assembler* assembler) { |
| 357 __ Stop("GenerateCallStaticFunctionStub"); | 360 // Create a stub frame as we are pushing some objects on the stack before |
| 358 } | 361 // calling into the runtime. |
| 359 | 362 __ EnterStubFrame(); |
| 360 | 363 // Setup space on stack for return value and preserve arguments descriptor. |
| 364 __ Push(R4); |
| 365 __ PushObject(Object::null_object(), PP); |
| 366 __ CallRuntime(kPatchStaticCallRuntimeEntry, 0); |
| 367 // Get Code object result and restore arguments descriptor array. |
| 368 __ Pop(R0); |
| 369 __ Pop(R4); |
| 370 // Remove the stub frame. |
| 371 __ LeaveStubFrame(); |
| 372 // Jump to the dart function. |
| 373 __ LoadFieldFromOffset(R0, R0, Code::instructions_offset()); |
| 374 __ AddImmediate(R0, R0, Instructions::HeaderSize() - kHeapObjectTag, kNoPP); |
| 375 __ br(R0); |
| 376 } |
| 377 |
| 378 |
| 379 // Called from a static call only when an invalid code has been entered |
| 380 // (invalid because its function was optimized or deoptimized). |
| 381 // R4: arguments descriptor array. |
| 361 void StubCode::GenerateFixCallersTargetStub(Assembler* assembler) { | 382 void StubCode::GenerateFixCallersTargetStub(Assembler* assembler) { |
| 362 __ Stop("GenerateFixCallersTargetStub"); | 383 // Create a stub frame as we are pushing some objects on the stack before |
| 384 // calling into the runtime. |
| 385 __ EnterStubFrame(); |
| 386 // Setup space on stack for return value and preserve arguments descriptor. |
| 387 __ Push(R4); |
| 388 __ PushObject(Object::null_object(), PP); |
| 389 __ CallRuntime(kFixCallersTargetRuntimeEntry, 0); |
| 390 // Get Code object result and restore arguments descriptor array. |
| 391 __ Pop(R0); |
| 392 __ Pop(R4); |
| 393 // Remove the stub frame. |
| 394 __ LeaveStubFrame(); |
| 395 // Jump to the dart function. |
| 396 __ LoadFieldFromOffset(R0, R0, Code::instructions_offset()); |
| 397 __ AddImmediate(R0, R0, Instructions::HeaderSize() - kHeapObjectTag, kNoPP); |
| 398 __ br(R0); |
| 399 } |
| 400 |
| 401 |
| 402 DECLARE_LEAF_RUNTIME_ENTRY(intptr_t, DeoptimizeCopyFrame, |
| 403 intptr_t deopt_reason, |
| 404 uword saved_registers_address); |
| 405 |
| 406 DECLARE_LEAF_RUNTIME_ENTRY(void, DeoptimizeFillFrame, uword last_fp); |
| 407 |
| 408 |
| 409 // Used by eager and lazy deoptimization. Preserve result in RAX if necessary. |
| 410 // This stub translates optimized frame into unoptimized frame. The optimized |
| 411 // frame can contain values in registers and on stack, the unoptimized |
| 412 // frame contains all values on stack. |
| 413 // Deoptimization occurs in following steps: |
| 414 // - Push all registers that can contain values. |
| 415 // - Call C routine to copy the stack and saved registers into temporary buffer. |
| 416 // - Adjust caller's frame to correct unoptimized frame size. |
| 417 // - Fill the unoptimized frame. |
| 418 // - Materialize objects that require allocation (e.g. Double instances). |
| 419 // GC can occur only after frame is fully rewritten. |
| 420 // Stack after TagAndPushPP() below: |
| 421 // +------------------+ |
| 422 // | Saved PP | <- PP |
| 423 // +------------------+ |
| 424 // | PC marker | <- TOS |
| 425 // +------------------+ |
| 426 // | Saved FP | <- FP of stub |
| 427 // +------------------+ |
| 428 // | return-address | (deoptimization point) |
| 429 // +------------------+ |
| 430 // | ... | <- SP of optimized frame |
| 431 // |
| 432 // Parts of the code cannot GC, part of the code can GC. |
| 433 static void GenerateDeoptimizationSequence(Assembler* assembler, |
| 434 bool preserve_result) { |
| 435 // DeoptimizeCopyFrame expects a Dart frame, i.e. EnterDartFrame(0), but there |
| 436 // is no need to set the correct PC marker or load PP, since they get patched. |
| 437 __ EnterFrame(0); |
| 438 __ Push(ZR); |
| 439 __ TagAndPushPP(); |
| 440 |
| 441 // The code in this frame may not cause GC. kDeoptimizeCopyFrameRuntimeEntry |
| 442 // and kDeoptimizeFillFrameRuntimeEntry are leaf runtime calls. |
| 443 const intptr_t saved_result_slot_from_fp = |
| 444 kFirstLocalSlotFromFp + 1 - (kNumberOfCpuRegisters - R0); |
| 445 // Result in R0 is preserved as part of pushing all registers below. |
| 446 |
| 447 // Push registers in their enumeration order: lowest register number at |
| 448 // lowest address. |
| 449 for (intptr_t i = kNumberOfCpuRegisters - 1; i >= 0; i--) { |
| 450 const Register r = static_cast<Register>(i); |
| 451 __ str(r, Address(SP, -1 * kWordSize, Address::PreIndex)); |
| 452 } |
| 453 |
| 454 for (intptr_t reg_idx = kNumberOfVRegisters - 1; reg_idx >= 0; reg_idx--) { |
| 455 VRegister vreg = static_cast<VRegister>(reg_idx); |
| 456 // TODO(zra): Save whole V registers. For now, push twice. |
| 457 __ PushDouble(vreg); |
| 458 __ PushDouble(vreg); |
| 459 } |
| 460 |
| 461 __ mov(R0, SP); // Pass address of saved registers block. |
| 462 __ ReserveAlignedFrameSpace(0); |
| 463 __ CallRuntime(kDeoptimizeCopyFrameRuntimeEntry, 1); |
| 464 // Result (R0) is stack-size (FP - SP) in bytes. |
| 465 |
| 466 if (preserve_result) { |
| 467 // Restore result into R1 temporarily. |
| 468 __ LoadFromOffset(R1, FP, saved_result_slot_from_fp * kWordSize); |
| 469 } |
| 470 |
| 471 // There is a Dart Frame on the stack. We must restore PP and leave frame. |
| 472 __ LeaveDartFrame(); |
| 473 __ sub(TMP, FP, Operand(R0)); |
| 474 __ mov(SP, TMP); |
| 475 |
| 476 // DeoptimizeFillFrame expects a Dart frame, i.e. EnterDartFrame(0), but there |
| 477 // is no need to set the correct PC marker or load PP, since they get patched. |
| 478 __ EnterFrame(0); |
| 479 __ Push(ZR); |
| 480 __ TagAndPushPP(); |
| 481 |
| 482 if (preserve_result) { |
| 483 __ Push(R1); // Preserve result as first local. |
| 484 } |
| 485 __ ReserveAlignedFrameSpace(0); |
| 486 __ mov(R0, FP); // Pass last FP as parameter in R0. |
| 487 __ CallRuntime(kDeoptimizeFillFrameRuntimeEntry, 1); |
| 488 if (preserve_result) { |
| 489 // Restore result into R1. |
| 490 __ LoadFromOffset(R1, FP, kFirstLocalSlotFromFp * kWordSize); |
| 491 } |
| 492 // Code above cannot cause GC. |
| 493 // There is a Dart Frame on the stack. We must restore PP and leave frame. |
| 494 __ LeaveDartFrame(); |
| 495 |
| 496 // Frame is fully rewritten at this point and it is safe to perform a GC. |
| 497 // Materialize any objects that were deferred by FillFrame because they |
| 498 // require allocation. |
| 499 __ EnterStubFrame(); |
| 500 if (preserve_result) { |
| 501 __ Push(ZR); // Workaround for dropped stack slot during GC. |
| 502 __ Push(R1); // Preserve result, it will be GC-d here. |
| 503 } |
| 504 __ Push(ZR); // Space for the result. |
| 505 __ CallRuntime(kDeoptimizeMaterializeRuntimeEntry, 0); |
| 506 // Result tells stub how many bytes to remove from the expression stack |
| 507 // of the bottom-most frame. They were used as materialization arguments. |
| 508 __ Pop(R1); |
| 509 __ SmiUntag(R1); |
| 510 if (preserve_result) { |
| 511 __ Pop(R0); // Restore result. |
| 512 __ Drop(1); // Workaround for dropped stack slot during GC. |
| 513 } |
| 514 __ LeaveStubFrame(); |
| 515 // Remove materialization arguments. |
| 516 __ add(TMP, SP, Operand(R1, UXTX, 0)); |
| 517 __ mov(SP, TMP); |
| 518 __ ret(); |
| 363 } | 519 } |
| 364 | 520 |
| 365 | 521 |
| 366 void StubCode::GenerateDeoptimizeLazyStub(Assembler* assembler) { | 522 void StubCode::GenerateDeoptimizeLazyStub(Assembler* assembler) { |
| 367 __ Stop("GenerateDeoptimizeLazyStub"); | 523 // Correct return address to point just after the call that is being |
| 524 // deoptimized. |
| 525 __ AddImmediate(LR, LR, -CallPattern::kLengthInBytes, kNoPP); |
| 526 GenerateDeoptimizationSequence(assembler, true); // Preserve R0. |
| 368 } | 527 } |
| 369 | 528 |
| 370 | 529 |
| 371 void StubCode::GenerateDeoptimizeStub(Assembler* assembler) { | 530 void StubCode::GenerateDeoptimizeStub(Assembler* assembler) { |
| 372 __ Stop("GenerateDeoptimizeStub"); | 531 GenerateDeoptimizationSequence(assembler, false); // Don't preserve R0. |
| 373 } | 532 } |
| 374 | 533 |
| 375 | 534 |
| 376 void StubCode::GenerateMegamorphicMissStub(Assembler* assembler) { | 535 void StubCode::GenerateMegamorphicMissStub(Assembler* assembler) { |
| 377 __ Stop("GenerateMegamorphicMissStub"); | 536 __ EnterStubFrame(); |
| 378 } | 537 |
| 379 | 538 // Load the receiver. |
| 380 | 539 __ LoadFieldFromOffset(R2, R4, ArgumentsDescriptor::count_offset()); |
| 540 __ add(TMP, FP, Operand(R2, LSL, 2)); // R2 is Smi. |
| 541 __ LoadFromOffset(R6, TMP, kParamEndSlotFromFp * kWordSize); |
| 542 |
| 543 // Preserve IC data and arguments descriptor. |
| 544 __ Push(R5); |
| 545 __ Push(R4); |
| 546 |
| 547 // Push space for the return value. |
| 548 // Push the receiver. |
| 549 // Push IC data object. |
| 550 // Push arguments descriptor array. |
| 551 __ PushObject(Object::null_object(), PP); |
| 552 __ Push(R6); |
| 553 __ Push(R5); |
| 554 __ Push(R4); |
| 555 __ CallRuntime(kMegamorphicCacheMissHandlerRuntimeEntry, 3); |
| 556 // Remove arguments. |
| 557 __ Drop(3); |
| 558 __ Pop(R0); // Get result into R0 (target function). |
| 559 |
| 560 // Restore IC data and arguments descriptor. |
| 561 __ Pop(R4); |
| 562 __ Pop(R5); |
| 563 |
| 564 __ LeaveStubFrame(); |
| 565 |
| 566 // Tail-call to target function. |
| 567 __ LoadFieldFromOffset(R2, R0, Function::code_offset()); |
| 568 __ LoadFieldFromOffset(R2, R2, Code::instructions_offset()); |
| 569 __ AddImmediate(R2, R2, Instructions::HeaderSize() - kHeapObjectTag, PP); |
| 570 __ br(R2); |
| 571 } |
| 572 |
| 573 |
| 381 // Called for inline allocation of arrays. | 574 // Called for inline allocation of arrays. |
| 382 // Input parameters: | 575 // Input parameters: |
| 383 // LR: return address. | 576 // LR: return address. |
| 384 // R2: array length as Smi. | 577 // R2: array length as Smi. |
| 385 // R1: array element type (either NULL or an instantiated type). | 578 // R1: array element type (either NULL or an instantiated type). |
| 386 // NOTE: R2 cannot be clobbered here as the caller relies on it being saved. | 579 // NOTE: R2 cannot be clobbered here as the caller relies on it being saved. |
| 387 // The newly allocated object is returned in R0. | 580 // The newly allocated object is returned in R0. |
| 388 void StubCode::GenerateAllocateArrayStub(Assembler* assembler) { | 581 void StubCode::GenerateAllocateArrayStub(Assembler* assembler) { |
| 389 Label slow_case; | 582 Label slow_case; |
| 390 if (FLAG_inline_alloc) { | 583 if (FLAG_inline_alloc) { |
| (...skipping 575 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 966 // calling into the runtime. | 1159 // calling into the runtime. |
| 967 __ EnterStubFrame(true); // Uses pool pointer to pass cls to runtime. | 1160 __ EnterStubFrame(true); // Uses pool pointer to pass cls to runtime. |
| 968 // Setup space on stack for return value. | 1161 // Setup space on stack for return value. |
| 969 __ PushObject(Object::null_object(), PP); | 1162 __ PushObject(Object::null_object(), PP); |
| 970 __ PushObject(cls, PP); // Push class of object to be allocated. | 1163 __ PushObject(cls, PP); // Push class of object to be allocated. |
| 971 if (is_cls_parameterized) { | 1164 if (is_cls_parameterized) { |
| 972 // Push type arguments. | 1165 // Push type arguments. |
| 973 __ Push(R1); | 1166 __ Push(R1); |
| 974 } else { | 1167 } else { |
| 975 // Push null type arguments. | 1168 // Push null type arguments. |
| 976 __ Push(R2); | 1169 __ PushObject(Object::null_object(), PP); |
| 977 } | 1170 } |
| 978 __ CallRuntime(kAllocateObjectRuntimeEntry, 2); // Allocate object. | 1171 __ CallRuntime(kAllocateObjectRuntimeEntry, 2); // Allocate object. |
| 979 __ Drop(2); // Pop arguments. | 1172 __ Drop(2); // Pop arguments. |
| 980 __ Pop(R0); // Pop result (newly allocated object). | 1173 __ Pop(R0); // Pop result (newly allocated object). |
| 981 // R0: new object | 1174 // R0: new object |
| 982 // Restore the frame pointer. | 1175 // Restore the frame pointer. |
| 983 __ LeaveStubFrame(); | 1176 __ LeaveStubFrame(); |
| 984 __ ret(); | 1177 __ ret(); |
| 985 } | 1178 } |
| 986 | 1179 |
| 987 | 1180 |
| 988 void StubCode::GenerateCallNoSuchMethodFunctionStub(Assembler* assembler) { | 1181 void StubCode::GenerateCallNoSuchMethodFunctionStub(Assembler* assembler) { |
| 989 __ Stop("GenerateCallNoSuchMethodFunctionStub"); | 1182 __ Stop("GenerateCallNoSuchMethodFunctionStub"); |
| 990 } | 1183 } |
| 991 | 1184 |
| 992 | 1185 |
| 1186 // R6: function object. |
| 1187 // R5: inline cache data object. |
| 1188 // Cannot use function object from ICData as it may be the inlined |
| 1189 // function and not the top-scope function. |
| 993 void StubCode::GenerateOptimizedUsageCounterIncrement(Assembler* assembler) { | 1190 void StubCode::GenerateOptimizedUsageCounterIncrement(Assembler* assembler) { |
| 994 __ Stop("GenerateOptimizedUsageCounterIncrement"); | 1191 Register ic_reg = R5; |
| 1192 Register func_reg = R6; |
| 1193 if (FLAG_trace_optimized_ic_calls) { |
| 1194 __ EnterStubFrame(); |
| 1195 __ Push(R6); // Preserve. |
| 1196 __ Push(R5); // Preserve. |
| 1197 __ Push(ic_reg); // Argument. |
| 1198 __ Push(func_reg); // Argument. |
| 1199 __ CallRuntime(kTraceICCallRuntimeEntry, 2); |
| 1200 __ Drop(2); // Discard argument; |
| 1201 __ Pop(R5); // Restore. |
| 1202 __ Pop(R6); // Restore. |
| 1203 __ LeaveStubFrame(); |
| 1204 } |
| 1205 __ LoadFieldFromOffset(R7, func_reg, Function::usage_counter_offset()); |
| 1206 __ add(R7, R7, Operand(1)); |
| 1207 __ StoreFieldToOffset(R7, func_reg, Function::usage_counter_offset()); |
| 995 } | 1208 } |
| 996 | 1209 |
| 997 | 1210 |
| 998 // Loads function into 'temp_reg'. | 1211 // Loads function into 'temp_reg'. |
| 999 void StubCode::GenerateUsageCounterIncrement(Assembler* assembler, | 1212 void StubCode::GenerateUsageCounterIncrement(Assembler* assembler, |
| 1000 Register temp_reg) { | 1213 Register temp_reg) { |
| 1001 Register ic_reg = R5; | 1214 Register ic_reg = R5; |
| 1002 Register func_reg = temp_reg; | 1215 Register func_reg = temp_reg; |
| 1003 ASSERT(temp_reg == R6); | 1216 ASSERT(temp_reg == R6); |
| 1004 __ LoadFieldFromOffset(func_reg, ic_reg, ICData::owner_offset()); | 1217 __ LoadFieldFromOffset(func_reg, ic_reg, ICData::owner_offset()); |
| (...skipping 30 matching lines...) Expand all Loading... |
| 1035 __ b(&ok, EQ); | 1248 __ b(&ok, EQ); |
| 1036 __ Stop("Incorrect stub for IC data"); | 1249 __ Stop("Incorrect stub for IC data"); |
| 1037 __ Bind(&ok); | 1250 __ Bind(&ok); |
| 1038 } | 1251 } |
| 1039 #endif // DEBUG | 1252 #endif // DEBUG |
| 1040 | 1253 |
| 1041 // Check single stepping. | 1254 // Check single stepping. |
| 1042 Label not_stepping; | 1255 Label not_stepping; |
| 1043 __ LoadFieldFromOffset(R6, CTX, Context::isolate_offset()); | 1256 __ LoadFieldFromOffset(R6, CTX, Context::isolate_offset()); |
| 1044 __ LoadFromOffset(R6, R6, Isolate::single_step_offset(), kUnsignedByte); | 1257 __ LoadFromOffset(R6, R6, Isolate::single_step_offset(), kUnsignedByte); |
| 1045 __ CompareImmediate(R6, 0, kNoPP); | 1258 __ CompareRegisters(R6, ZR); |
| 1046 __ b(¬_stepping, EQ); | 1259 __ b(¬_stepping, EQ); |
| 1047 __ EnterStubFrame(); | 1260 __ EnterStubFrame(); |
| 1048 __ Push(R5); // Preserve IC data. | 1261 __ Push(R5); // Preserve IC data. |
| 1049 __ CallRuntime(kSingleStepHandlerRuntimeEntry, 0); | 1262 __ CallRuntime(kSingleStepHandlerRuntimeEntry, 0); |
| 1050 __ Pop(R5); | 1263 __ Pop(R5); |
| 1051 __ LeaveStubFrame(); | 1264 __ LeaveStubFrame(); |
| 1052 __ Bind(¬_stepping); | 1265 __ Bind(¬_stepping); |
| 1053 | 1266 |
| 1054 // Load arguments descriptor into R4. | 1267 // Load arguments descriptor into R4. |
| 1055 __ LoadFieldFromOffset(R4, R5, ICData::arguments_descriptor_offset()); | 1268 __ LoadFieldFromOffset(R4, R5, ICData::arguments_descriptor_offset()); |
| (...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1235 | 1448 |
| 1236 void StubCode::GenerateThreeArgsCheckInlineCacheStub(Assembler* assembler) { | 1449 void StubCode::GenerateThreeArgsCheckInlineCacheStub(Assembler* assembler) { |
| 1237 GenerateUsageCounterIncrement(assembler, R6); | 1450 GenerateUsageCounterIncrement(assembler, R6); |
| 1238 GenerateNArgsCheckInlineCacheStub( | 1451 GenerateNArgsCheckInlineCacheStub( |
| 1239 assembler, 3, kInlineCacheMissHandlerThreeArgsRuntimeEntry); | 1452 assembler, 3, kInlineCacheMissHandlerThreeArgsRuntimeEntry); |
| 1240 } | 1453 } |
| 1241 | 1454 |
| 1242 | 1455 |
| 1243 void StubCode::GenerateOneArgOptimizedCheckInlineCacheStub( | 1456 void StubCode::GenerateOneArgOptimizedCheckInlineCacheStub( |
| 1244 Assembler* assembler) { | 1457 Assembler* assembler) { |
| 1245 __ Stop("GenerateOneArgOptimizedCheckInlineCacheStub"); | 1458 GenerateOptimizedUsageCounterIncrement(assembler); |
| 1459 GenerateNArgsCheckInlineCacheStub( |
| 1460 assembler, 1, kInlineCacheMissHandlerOneArgRuntimeEntry); |
| 1246 } | 1461 } |
| 1247 | 1462 |
| 1248 | 1463 |
| 1249 void StubCode::GenerateTwoArgsOptimizedCheckInlineCacheStub( | 1464 void StubCode::GenerateTwoArgsOptimizedCheckInlineCacheStub( |
| 1250 Assembler* assembler) { | 1465 Assembler* assembler) { |
| 1251 __ Stop("GenerateTwoArgsOptimizedCheckInlineCacheStub"); | 1466 GenerateOptimizedUsageCounterIncrement(assembler); |
| 1467 GenerateNArgsCheckInlineCacheStub( |
| 1468 assembler, 2, kInlineCacheMissHandlerTwoArgsRuntimeEntry); |
| 1252 } | 1469 } |
| 1253 | 1470 |
| 1254 | 1471 |
| 1255 void StubCode::GenerateThreeArgsOptimizedCheckInlineCacheStub( | 1472 void StubCode::GenerateThreeArgsOptimizedCheckInlineCacheStub( |
| 1256 Assembler* assembler) { | 1473 Assembler* assembler) { |
| 1257 __ Stop("GenerateThreeArgsOptimizedCheckInlineCacheStub"); | 1474 GenerateOptimizedUsageCounterIncrement(assembler); |
| 1475 GenerateNArgsCheckInlineCacheStub( |
| 1476 assembler, 3, kInlineCacheMissHandlerThreeArgsRuntimeEntry); |
| 1258 } | 1477 } |
| 1259 | 1478 |
| 1260 | 1479 |
| 1261 void StubCode::GenerateClosureCallInlineCacheStub(Assembler* assembler) { | 1480 void StubCode::GenerateClosureCallInlineCacheStub(Assembler* assembler) { |
| 1262 __ Stop("GenerateClosureCallInlineCacheStub"); | 1481 __ Stop("GenerateClosureCallInlineCacheStub"); |
| 1263 } | 1482 } |
| 1264 | 1483 |
| 1265 | 1484 |
| 1266 void StubCode::GenerateZeroArgsUnoptimizedStaticCallStub(Assembler* assembler) { | 1485 void StubCode::GenerateZeroArgsUnoptimizedStaticCallStub(Assembler* assembler) { |
| 1267 GenerateUsageCounterIncrement(assembler, R6); | 1486 GenerateUsageCounterIncrement(assembler, R6); |
| (...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1487 void StubCode::GenerateGetStackPointerStub(Assembler* assembler) { | 1706 void StubCode::GenerateGetStackPointerStub(Assembler* assembler) { |
| 1488 __ Stop("GenerateGetStackPointerStub"); | 1707 __ Stop("GenerateGetStackPointerStub"); |
| 1489 } | 1708 } |
| 1490 | 1709 |
| 1491 | 1710 |
| 1492 void StubCode::GenerateJumpToExceptionHandlerStub(Assembler* assembler) { | 1711 void StubCode::GenerateJumpToExceptionHandlerStub(Assembler* assembler) { |
| 1493 __ Stop("GenerateJumpToExceptionHandlerStub"); | 1712 __ Stop("GenerateJumpToExceptionHandlerStub"); |
| 1494 } | 1713 } |
| 1495 | 1714 |
| 1496 | 1715 |
| 1716 // Calls to the runtime to optimize the given function. |
| 1717 // R6: function to be re-optimized. |
| 1718 // R4: argument descriptor (preserved). |
| 1497 void StubCode::GenerateOptimizeFunctionStub(Assembler* assembler) { | 1719 void StubCode::GenerateOptimizeFunctionStub(Assembler* assembler) { |
| 1498 __ Stop("GenerateOptimizeFunctionStub"); | 1720 __ EnterStubFrame(); |
| 1721 __ Push(R4); |
| 1722 // Setup space on stack for the return value. |
| 1723 __ PushObject(Object::null_object(), PP); |
| 1724 __ Push(R6); |
| 1725 __ CallRuntime(kOptimizeInvokedFunctionRuntimeEntry, 1); |
| 1726 __ Pop(R0); // Discard argument. |
| 1727 __ Pop(R0); // Get Code object |
| 1728 __ Pop(R4); // Restore argument descriptor. |
| 1729 __ LoadFieldFromOffset(R0, R0, Code::instructions_offset()); |
| 1730 __ AddImmediate(R0, R0, Instructions::HeaderSize() - kHeapObjectTag, PP); |
| 1731 __ LeaveStubFrame(); |
| 1732 __ br(R0); |
| 1733 __ hlt(0); |
| 1499 } | 1734 } |
| 1500 | 1735 |
| 1501 | 1736 |
| 1502 DECLARE_LEAF_RUNTIME_ENTRY(intptr_t, | 1737 DECLARE_LEAF_RUNTIME_ENTRY(intptr_t, |
| 1503 BigintCompare, | 1738 BigintCompare, |
| 1504 RawBigint* left, | 1739 RawBigint* left, |
| 1505 RawBigint* right); | 1740 RawBigint* right); |
| 1506 | 1741 |
| 1507 | 1742 |
| 1508 // Does identical check (object references are equal or not equal) with special | 1743 // Does identical check (object references are equal or not equal) with special |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1585 | 1820 |
| 1586 const Register left = R1; | 1821 const Register left = R1; |
| 1587 const Register right = R0; | 1822 const Register right = R0; |
| 1588 __ LoadFromOffset(left, SP, 1 * kWordSize); | 1823 __ LoadFromOffset(left, SP, 1 * kWordSize); |
| 1589 __ LoadFromOffset(right, SP, 0 * kWordSize); | 1824 __ LoadFromOffset(right, SP, 0 * kWordSize); |
| 1590 GenerateIdenticalWithNumberCheckStub(assembler, left, right); | 1825 GenerateIdenticalWithNumberCheckStub(assembler, left, right); |
| 1591 __ ret(); | 1826 __ ret(); |
| 1592 } | 1827 } |
| 1593 | 1828 |
| 1594 | 1829 |
| 1830 // Called from optimized code only. |
| 1831 // LR: return address. |
| 1832 // SP + 4: left operand. |
| 1833 // SP + 0: right operand. |
| 1834 // Return Zero condition flag set if equal. |
| 1595 void StubCode::GenerateOptimizedIdenticalWithNumberCheckStub( | 1835 void StubCode::GenerateOptimizedIdenticalWithNumberCheckStub( |
| 1596 Assembler* assembler) { | 1836 Assembler* assembler) { |
| 1597 __ Stop("GenerateOptimizedIdenticalWithNumberCheckStub"); | 1837 const Register temp = R2; |
| 1838 const Register left = R1; |
| 1839 const Register right = R0; |
| 1840 __ LoadFromOffset(left, SP, 1 * kWordSize); |
| 1841 __ LoadFromOffset(right, SP, 0 * kWordSize); |
| 1842 GenerateIdenticalWithNumberCheckStub(assembler, left, right, temp); |
| 1843 __ ret(); |
| 1598 } | 1844 } |
| 1599 | 1845 |
| 1600 } // namespace dart | 1846 } // namespace dart |
| 1601 | 1847 |
| 1602 #endif // defined TARGET_ARCH_ARM64 | 1848 #endif // defined TARGET_ARCH_ARM64 |
| OLD | NEW |