| 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" | 5 #include "vm/globals.h" |
| 6 #if defined(TARGET_ARCH_X64) | 6 #if defined(TARGET_ARCH_X64) |
| 7 | 7 |
| 8 #include "vm/assembler.h" | 8 #include "vm/assembler.h" |
| 9 #include "vm/compiler.h" | 9 #include "vm/compiler.h" |
| 10 #include "vm/dart_entry.h" | 10 #include "vm/dart_entry.h" |
| 11 #include "vm/flow_graph_compiler.h" | 11 #include "vm/flow_graph_compiler.h" |
| 12 #include "vm/heap.h" | 12 #include "vm/heap.h" |
| 13 #include "vm/instructions.h" | 13 #include "vm/instructions.h" |
| 14 #include "vm/object_store.h" | 14 #include "vm/object_store.h" |
| 15 #include "vm/resolver.h" | 15 #include "vm/resolver.h" |
| 16 #include "vm/scavenger.h" | 16 #include "vm/scavenger.h" |
| 17 #include "vm/stack_frame.h" | 17 #include "vm/stack_frame.h" |
| 18 #include "vm/stub_code.h" | 18 #include "vm/stub_code.h" |
| 19 #include "vm/tags.h" | 19 #include "vm/tags.h" |
| 20 | 20 |
| 21 #define __ assembler-> | 21 #define __ assembler-> |
| 22 | 22 |
| 23 namespace dart { | 23 namespace dart { |
| 24 | 24 |
| 25 DEFINE_FLAG(bool, inline_alloc, true, "Inline allocation of objects."); | 25 DEFINE_FLAG(bool, inline_alloc, true, "Inline allocation of objects."); |
| 26 DEFINE_FLAG(bool, use_slow_path, false, | 26 DEFINE_FLAG(bool, |
| 27 "Set to true for debugging & verifying the slow paths."); | 27 use_slow_path, |
| 28 false, |
| 29 "Set to true for debugging & verifying the slow paths."); |
| 28 DECLARE_FLAG(bool, trace_optimized_ic_calls); | 30 DECLARE_FLAG(bool, trace_optimized_ic_calls); |
| 29 | 31 |
| 30 // Input parameters: | 32 // Input parameters: |
| 31 // RSP : points to return address. | 33 // RSP : points to return address. |
| 32 // RSP + 8 : address of last argument in argument array. | 34 // RSP + 8 : address of last argument in argument array. |
| 33 // RSP + 8*R10 : address of first argument in argument array. | 35 // RSP + 8*R10 : address of first argument in argument array. |
| 34 // RSP + 8*R10 + 8 : address of return value. | 36 // RSP + 8*R10 + 8 : address of return value. |
| 35 // RBX : address of the runtime function to call. | 37 // RBX : address of the runtime function to call. |
| 36 // R10 : number of arguments to the call. | 38 // R10 : number of arguments to the call. |
| 37 // Must preserve callee saved registers R12 and R13. | 39 // Must preserve callee saved registers R12 and R13. |
| 38 void StubCode::GenerateCallToRuntimeStub(Assembler* assembler) { | 40 void StubCode::GenerateCallToRuntimeStub(Assembler* assembler) { |
| 39 const intptr_t thread_offset = NativeArguments::thread_offset(); | 41 const intptr_t thread_offset = NativeArguments::thread_offset(); |
| 40 const intptr_t argc_tag_offset = NativeArguments::argc_tag_offset(); | 42 const intptr_t argc_tag_offset = NativeArguments::argc_tag_offset(); |
| 41 const intptr_t argv_offset = NativeArguments::argv_offset(); | 43 const intptr_t argv_offset = NativeArguments::argv_offset(); |
| 42 const intptr_t retval_offset = NativeArguments::retval_offset(); | 44 const intptr_t retval_offset = NativeArguments::retval_offset(); |
| 43 | 45 |
| 44 __ EnterStubFrame(); | 46 __ EnterStubFrame(); |
| 45 | 47 |
| 46 // Save exit frame information to enable stack walking as we are about | 48 // Save exit frame information to enable stack walking as we are about |
| 47 // to transition to Dart VM C++ code. | 49 // to transition to Dart VM C++ code. |
| 48 __ movq(Address(THR, Thread::top_exit_frame_info_offset()), RBP); | 50 __ movq(Address(THR, Thread::top_exit_frame_info_offset()), RBP); |
| 49 | 51 |
| 50 #if defined(DEBUG) | 52 #if defined(DEBUG) |
| 51 { Label ok; | 53 { |
| 54 Label ok; |
| 52 // Check that we are always entering from Dart code. | 55 // Check that we are always entering from Dart code. |
| 53 __ movq(RAX, Immediate(VMTag::kDartTagId)); | 56 __ movq(RAX, Immediate(VMTag::kDartTagId)); |
| 54 __ cmpq(RAX, Assembler::VMTagAddress()); | 57 __ cmpq(RAX, Assembler::VMTagAddress()); |
| 55 __ j(EQUAL, &ok, Assembler::kNearJump); | 58 __ j(EQUAL, &ok, Assembler::kNearJump); |
| 56 __ Stop("Not coming from Dart code."); | 59 __ Stop("Not coming from Dart code."); |
| 57 __ Bind(&ok); | 60 __ Bind(&ok); |
| 58 } | 61 } |
| 59 #endif | 62 #endif |
| 60 | 63 |
| 61 // Mark that the thread is executing VM code. | 64 // Mark that the thread is executing VM code. |
| 62 __ movq(Assembler::VMTagAddress(), RBX); | 65 __ movq(Assembler::VMTagAddress(), RBX); |
| 63 | 66 |
| 64 // Reserve space for arguments and align frame before entering C++ world. | 67 // Reserve space for arguments and align frame before entering C++ world. |
| 65 __ subq(RSP, Immediate(sizeof(NativeArguments))); | 68 __ subq(RSP, Immediate(sizeof(NativeArguments))); |
| 66 if (OS::ActivationFrameAlignment() > 1) { | 69 if (OS::ActivationFrameAlignment() > 1) { |
| 67 __ andq(RSP, Immediate(~(OS::ActivationFrameAlignment() - 1))); | 70 __ andq(RSP, Immediate(~(OS::ActivationFrameAlignment() - 1))); |
| 68 } | 71 } |
| 69 | 72 |
| 70 // Pass NativeArguments structure by value and call runtime. | 73 // Pass NativeArguments structure by value and call runtime. |
| 71 __ movq(Address(RSP, thread_offset), THR); // Set thread in NativeArgs. | 74 __ movq(Address(RSP, thread_offset), THR); // Set thread in NativeArgs. |
| 72 // There are no runtime calls to closures, so we do not need to set the tag | 75 // There are no runtime calls to closures, so we do not need to set the tag |
| 73 // bits kClosureFunctionBit and kInstanceFunctionBit in argc_tag_. | 76 // bits kClosureFunctionBit and kInstanceFunctionBit in argc_tag_. |
| 74 __ movq(Address(RSP, argc_tag_offset), R10); // Set argc in NativeArguments. | 77 __ movq(Address(RSP, argc_tag_offset), R10); // Set argc in NativeArguments. |
| 75 // Compute argv. | 78 // Compute argv. |
| 76 __ leaq(RAX, Address(RBP, R10, TIMES_8, kParamEndSlotFromFp * kWordSize)); | 79 __ leaq(RAX, Address(RBP, R10, TIMES_8, kParamEndSlotFromFp * kWordSize)); |
| 77 __ movq(Address(RSP, argv_offset), RAX); // Set argv in NativeArguments. | 80 __ movq(Address(RSP, argv_offset), RAX); // Set argv in NativeArguments. |
| 78 __ addq(RAX, Immediate(1 * kWordSize)); // Retval is next to 1st argument. | 81 __ addq(RAX, Immediate(1 * kWordSize)); // Retval is next to 1st argument. |
| 79 __ movq(Address(RSP, retval_offset), RAX); // Set retval in NativeArguments. | 82 __ movq(Address(RSP, retval_offset), RAX); // Set retval in NativeArguments. |
| 80 #if defined(_WIN64) | 83 #if defined(_WIN64) |
| 81 ASSERT(sizeof(NativeArguments) > CallingConventions::kRegisterTransferLimit); | 84 ASSERT(sizeof(NativeArguments) > CallingConventions::kRegisterTransferLimit); |
| 82 __ movq(CallingConventions::kArg1Reg, RSP); | 85 __ movq(CallingConventions::kArg1Reg, RSP); |
| 83 #endif | 86 #endif |
| 84 __ CallCFunction(RBX); | 87 __ CallCFunction(RBX); |
| 85 | 88 |
| 86 // Mark that the thread is executing Dart code. | 89 // Mark that the thread is executing Dart code. |
| 87 __ movq(Assembler::VMTagAddress(), Immediate(VMTag::kDartTagId)); | 90 __ movq(Assembler::VMTagAddress(), Immediate(VMTag::kDartTagId)); |
| 88 | 91 |
| (...skipping 11 matching lines...) Expand all Loading... |
| 100 } | 103 } |
| 101 END_LEAF_RUNTIME_ENTRY | 104 END_LEAF_RUNTIME_ENTRY |
| 102 | 105 |
| 103 | 106 |
| 104 // Input parameters: | 107 // Input parameters: |
| 105 // RSP : points to return address. | 108 // RSP : points to return address. |
| 106 // RDI : stop message (const char*). | 109 // RDI : stop message (const char*). |
| 107 // Must preserve all registers. | 110 // Must preserve all registers. |
| 108 void StubCode::GeneratePrintStopMessageStub(Assembler* assembler) { | 111 void StubCode::GeneratePrintStopMessageStub(Assembler* assembler) { |
| 109 __ EnterCallRuntimeFrame(0); | 112 __ EnterCallRuntimeFrame(0); |
| 110 // Call the runtime leaf function. RDI already contains the parameter. | 113 // Call the runtime leaf function. RDI already contains the parameter. |
| 111 #if defined(_WIN64) | 114 #if defined(_WIN64) |
| 112 __ movq(CallingConventions::kArg1Reg, RDI); | 115 __ movq(CallingConventions::kArg1Reg, RDI); |
| 113 #endif | 116 #endif |
| 114 __ CallRuntime(kPrintStopMessageRuntimeEntry, 1); | 117 __ CallRuntime(kPrintStopMessageRuntimeEntry, 1); |
| 115 __ LeaveCallRuntimeFrame(); | 118 __ LeaveCallRuntimeFrame(); |
| 116 __ ret(); | 119 __ ret(); |
| 117 } | 120 } |
| 118 | 121 |
| 119 | 122 |
| 120 // Input parameters: | 123 // Input parameters: |
| (...skipping 13 matching lines...) Expand all Loading... |
| 134 const intptr_t retval_offset = | 137 const intptr_t retval_offset = |
| 135 NativeArguments::retval_offset() + native_args_struct_offset; | 138 NativeArguments::retval_offset() + native_args_struct_offset; |
| 136 | 139 |
| 137 __ EnterStubFrame(); | 140 __ EnterStubFrame(); |
| 138 | 141 |
| 139 // Save exit frame information to enable stack walking as we are about | 142 // Save exit frame information to enable stack walking as we are about |
| 140 // to transition to native code. | 143 // to transition to native code. |
| 141 __ movq(Address(THR, Thread::top_exit_frame_info_offset()), RBP); | 144 __ movq(Address(THR, Thread::top_exit_frame_info_offset()), RBP); |
| 142 | 145 |
| 143 #if defined(DEBUG) | 146 #if defined(DEBUG) |
| 144 { Label ok; | 147 { |
| 148 Label ok; |
| 145 // Check that we are always entering from Dart code. | 149 // Check that we are always entering from Dart code. |
| 146 __ movq(R8, Immediate(VMTag::kDartTagId)); | 150 __ movq(R8, Immediate(VMTag::kDartTagId)); |
| 147 __ cmpq(R8, Assembler::VMTagAddress()); | 151 __ cmpq(R8, Assembler::VMTagAddress()); |
| 148 __ j(EQUAL, &ok, Assembler::kNearJump); | 152 __ j(EQUAL, &ok, Assembler::kNearJump); |
| 149 __ Stop("Not coming from Dart code."); | 153 __ Stop("Not coming from Dart code."); |
| 150 __ Bind(&ok); | 154 __ Bind(&ok); |
| 151 } | 155 } |
| 152 #endif | 156 #endif |
| 153 | 157 |
| 154 // Mark that the thread is executing native code. | 158 // Mark that the thread is executing native code. |
| 155 __ movq(Assembler::VMTagAddress(), RBX); | 159 __ movq(Assembler::VMTagAddress(), RBX); |
| 156 | 160 |
| 157 // Reserve space for the native arguments structure passed on the stack (the | 161 // Reserve space for the native arguments structure passed on the stack (the |
| 158 // outgoing pointer parameter to the native arguments structure is passed in | 162 // outgoing pointer parameter to the native arguments structure is passed in |
| 159 // RDI) and align frame before entering the C++ world. | 163 // RDI) and align frame before entering the C++ world. |
| 160 __ subq(RSP, Immediate(sizeof(NativeArguments))); | 164 __ subq(RSP, Immediate(sizeof(NativeArguments))); |
| 161 if (OS::ActivationFrameAlignment() > 1) { | 165 if (OS::ActivationFrameAlignment() > 1) { |
| 162 __ andq(RSP, Immediate(~(OS::ActivationFrameAlignment() - 1))); | 166 __ andq(RSP, Immediate(~(OS::ActivationFrameAlignment() - 1))); |
| 163 } | 167 } |
| 164 | 168 |
| 165 // Pass NativeArguments structure by value and call native function. | 169 // Pass NativeArguments structure by value and call native function. |
| 166 __ movq(Address(RSP, thread_offset), THR); // Set thread in NativeArgs. | 170 __ movq(Address(RSP, thread_offset), THR); // Set thread in NativeArgs. |
| 167 __ movq(Address(RSP, argc_tag_offset), R10); // Set argc in NativeArguments. | 171 __ movq(Address(RSP, argc_tag_offset), R10); // Set argc in NativeArguments. |
| 168 __ movq(Address(RSP, argv_offset), RAX); // Set argv in NativeArguments. | 172 __ movq(Address(RSP, argv_offset), RAX); // Set argv in NativeArguments. |
| 169 __ leaq(RAX, Address(RBP, 2 * kWordSize)); // Compute return value addr. | 173 __ leaq(RAX, Address(RBP, 2 * kWordSize)); // Compute return value addr. |
| 170 __ movq(Address(RSP, retval_offset), RAX); // Set retval in NativeArguments. | 174 __ movq(Address(RSP, retval_offset), RAX); // Set retval in NativeArguments. |
| 171 | 175 |
| 172 // Pass the pointer to the NativeArguments. | 176 // Pass the pointer to the NativeArguments. |
| 173 __ movq(CallingConventions::kArg1Reg, RSP); | 177 __ movq(CallingConventions::kArg1Reg, RSP); |
| 174 // Pass pointer to function entrypoint. | 178 // Pass pointer to function entrypoint. |
| 175 __ movq(CallingConventions::kArg2Reg, RBX); | 179 __ movq(CallingConventions::kArg2Reg, RBX); |
| 176 | 180 |
| 177 __ movq(RAX, Address(THR, Thread::native_call_wrapper_entry_point_offset())); | 181 __ movq(RAX, Address(THR, Thread::native_call_wrapper_entry_point_offset())); |
| 178 __ CallCFunction(RAX); | 182 __ CallCFunction(RAX); |
| 179 | 183 |
| (...skipping 25 matching lines...) Expand all Loading... |
| 205 const intptr_t retval_offset = | 209 const intptr_t retval_offset = |
| 206 NativeArguments::retval_offset() + native_args_struct_offset; | 210 NativeArguments::retval_offset() + native_args_struct_offset; |
| 207 | 211 |
| 208 __ EnterStubFrame(); | 212 __ EnterStubFrame(); |
| 209 | 213 |
| 210 // Save exit frame information to enable stack walking as we are about | 214 // Save exit frame information to enable stack walking as we are about |
| 211 // to transition to native code. | 215 // to transition to native code. |
| 212 __ movq(Address(THR, Thread::top_exit_frame_info_offset()), RBP); | 216 __ movq(Address(THR, Thread::top_exit_frame_info_offset()), RBP); |
| 213 | 217 |
| 214 #if defined(DEBUG) | 218 #if defined(DEBUG) |
| 215 { Label ok; | 219 { |
| 220 Label ok; |
| 216 // Check that we are always entering from Dart code. | 221 // Check that we are always entering from Dart code. |
| 217 __ movq(R8, Immediate(VMTag::kDartTagId)); | 222 __ movq(R8, Immediate(VMTag::kDartTagId)); |
| 218 __ cmpq(R8, Assembler::VMTagAddress()); | 223 __ cmpq(R8, Assembler::VMTagAddress()); |
| 219 __ j(EQUAL, &ok, Assembler::kNearJump); | 224 __ j(EQUAL, &ok, Assembler::kNearJump); |
| 220 __ Stop("Not coming from Dart code."); | 225 __ Stop("Not coming from Dart code."); |
| 221 __ Bind(&ok); | 226 __ Bind(&ok); |
| 222 } | 227 } |
| 223 #endif | 228 #endif |
| 224 | 229 |
| 225 // Mark that the thread is executing native code. | 230 // Mark that the thread is executing native code. |
| 226 __ movq(Assembler::VMTagAddress(), RBX); | 231 __ movq(Assembler::VMTagAddress(), RBX); |
| 227 | 232 |
| 228 // Reserve space for the native arguments structure passed on the stack (the | 233 // Reserve space for the native arguments structure passed on the stack (the |
| 229 // outgoing pointer parameter to the native arguments structure is passed in | 234 // outgoing pointer parameter to the native arguments structure is passed in |
| 230 // RDI) and align frame before entering the C++ world. | 235 // RDI) and align frame before entering the C++ world. |
| 231 __ subq(RSP, Immediate(sizeof(NativeArguments))); | 236 __ subq(RSP, Immediate(sizeof(NativeArguments))); |
| 232 if (OS::ActivationFrameAlignment() > 1) { | 237 if (OS::ActivationFrameAlignment() > 1) { |
| 233 __ andq(RSP, Immediate(~(OS::ActivationFrameAlignment() - 1))); | 238 __ andq(RSP, Immediate(~(OS::ActivationFrameAlignment() - 1))); |
| 234 } | 239 } |
| 235 | 240 |
| 236 // Pass NativeArguments structure by value and call native function. | 241 // Pass NativeArguments structure by value and call native function. |
| 237 __ movq(Address(RSP, thread_offset), THR); // Set thread in NativeArgs. | 242 __ movq(Address(RSP, thread_offset), THR); // Set thread in NativeArgs. |
| 238 __ movq(Address(RSP, argc_tag_offset), R10); // Set argc in NativeArguments. | 243 __ movq(Address(RSP, argc_tag_offset), R10); // Set argc in NativeArguments. |
| 239 __ movq(Address(RSP, argv_offset), RAX); // Set argv in NativeArguments. | 244 __ movq(Address(RSP, argv_offset), RAX); // Set argv in NativeArguments. |
| 240 __ leaq(RAX, Address(RBP, 2 * kWordSize)); // Compute return value addr. | 245 __ leaq(RAX, Address(RBP, 2 * kWordSize)); // Compute return value addr. |
| 241 __ movq(Address(RSP, retval_offset), RAX); // Set retval in NativeArguments. | 246 __ movq(Address(RSP, retval_offset), RAX); // Set retval in NativeArguments. |
| 242 | 247 |
| 243 // Pass the pointer to the NativeArguments. | 248 // Pass the pointer to the NativeArguments. |
| 244 __ movq(CallingConventions::kArg1Reg, RSP); | 249 __ movq(CallingConventions::kArg1Reg, RSP); |
| 245 __ CallCFunction(RBX); | 250 __ CallCFunction(RBX); |
| 246 | 251 |
| 247 // Mark that the thread is executing Dart code. | 252 // Mark that the thread is executing Dart code. |
| 248 __ movq(Assembler::VMTagAddress(), Immediate(VMTag::kDartTagId)); | 253 __ movq(Assembler::VMTagAddress(), Immediate(VMTag::kDartTagId)); |
| 249 | 254 |
| 250 // Reset exit frame information in Isolate structure. | 255 // Reset exit frame information in Isolate structure. |
| 251 __ movq(Address(THR, Thread::top_exit_frame_info_offset()), Immediate(0)); | 256 __ movq(Address(THR, Thread::top_exit_frame_info_offset()), Immediate(0)); |
| 252 | 257 |
| 253 __ LeaveStubFrame(); | 258 __ LeaveStubFrame(); |
| 254 __ ret(); | 259 __ ret(); |
| 255 } | 260 } |
| 256 | 261 |
| 257 | 262 |
| 258 // Input parameters: | 263 // Input parameters: |
| 259 // R10: arguments descriptor array. | 264 // R10: arguments descriptor array. |
| 260 void StubCode::GenerateCallStaticFunctionStub(Assembler* assembler) { | 265 void StubCode::GenerateCallStaticFunctionStub(Assembler* assembler) { |
| 261 __ EnterStubFrame(); | 266 __ EnterStubFrame(); |
| 262 __ pushq(R10); // Preserve arguments descriptor array. | 267 __ pushq(R10); // Preserve arguments descriptor array. |
| 263 // Setup space on stack for return value. | 268 // Setup space on stack for return value. |
| 264 __ pushq(Immediate(0)); | 269 __ pushq(Immediate(0)); |
| 265 __ CallRuntime(kPatchStaticCallRuntimeEntry, 0); | 270 __ CallRuntime(kPatchStaticCallRuntimeEntry, 0); |
| 266 __ popq(CODE_REG); // Get Code object result. | 271 __ popq(CODE_REG); // Get Code object result. |
| 267 __ popq(R10); // Restore arguments descriptor array. | 272 __ popq(R10); // Restore arguments descriptor array. |
| 268 // Remove the stub frame as we are about to jump to the dart function. | 273 // Remove the stub frame as we are about to jump to the dart function. |
| 269 __ LeaveStubFrame(); | 274 __ LeaveStubFrame(); |
| 270 | 275 |
| 271 __ movq(RBX, FieldAddress(CODE_REG, Code::entry_point_offset())); | 276 __ movq(RBX, FieldAddress(CODE_REG, Code::entry_point_offset())); |
| 272 __ jmp(RBX); | 277 __ jmp(RBX); |
| 273 } | 278 } |
| 274 | 279 |
| 275 | 280 |
| 276 // Called from a static call only when an invalid code has been entered | 281 // Called from a static call only when an invalid code has been entered |
| 277 // (invalid because its function was optimized or deoptimized). | 282 // (invalid because its function was optimized or deoptimized). |
| 278 // R10: arguments descriptor array. | 283 // R10: arguments descriptor array. |
| 279 void StubCode::GenerateFixCallersTargetStub(Assembler* assembler) { | 284 void StubCode::GenerateFixCallersTargetStub(Assembler* assembler) { |
| 280 // Load code pointer to this stub from the thread: | 285 // Load code pointer to this stub from the thread: |
| 281 // The one that is passed in, is not correct - it points to the code object | 286 // The one that is passed in, is not correct - it points to the code object |
| 282 // that needs to be replaced. | 287 // that needs to be replaced. |
| 283 __ movq(CODE_REG, Address(THR, Thread::fix_callers_target_code_offset())); | 288 __ movq(CODE_REG, Address(THR, Thread::fix_callers_target_code_offset())); |
| 284 __ EnterStubFrame(); | 289 __ EnterStubFrame(); |
| 285 __ pushq(R10); // Preserve arguments descriptor array. | 290 __ pushq(R10); // Preserve arguments descriptor array. |
| 286 // Setup space on stack for return value. | 291 // Setup space on stack for return value. |
| 287 __ pushq(Immediate(0)); | 292 __ pushq(Immediate(0)); |
| 288 __ CallRuntime(kFixCallersTargetRuntimeEntry, 0); | 293 __ CallRuntime(kFixCallersTargetRuntimeEntry, 0); |
| 289 __ popq(CODE_REG); // Get Code object. | 294 __ popq(CODE_REG); // Get Code object. |
| 290 __ popq(R10); // Restore arguments descriptor array. | 295 __ popq(R10); // Restore arguments descriptor array. |
| 291 __ movq(RAX, FieldAddress(CODE_REG, Code::entry_point_offset())); | 296 __ movq(RAX, FieldAddress(CODE_REG, Code::entry_point_offset())); |
| 292 __ LeaveStubFrame(); | 297 __ LeaveStubFrame(); |
| 293 __ jmp(RAX); | 298 __ jmp(RAX); |
| 294 __ int3(); | 299 __ int3(); |
| 295 } | 300 } |
| 296 | 301 |
| 297 | 302 |
| 298 // Called from object allocate instruction when the allocation stub has been | 303 // Called from object allocate instruction when the allocation stub has been |
| 299 // disabled. | 304 // disabled. |
| 300 void StubCode::GenerateFixAllocationStubTargetStub(Assembler* assembler) { | 305 void StubCode::GenerateFixAllocationStubTargetStub(Assembler* assembler) { |
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 405 __ subq(RSP, Immediate(kNumberOfXmmRegisters * kFpuRegisterSize)); | 410 __ subq(RSP, Immediate(kNumberOfXmmRegisters * kFpuRegisterSize)); |
| 406 intptr_t offset = 0; | 411 intptr_t offset = 0; |
| 407 for (intptr_t reg_idx = 0; reg_idx < kNumberOfXmmRegisters; ++reg_idx) { | 412 for (intptr_t reg_idx = 0; reg_idx < kNumberOfXmmRegisters; ++reg_idx) { |
| 408 XmmRegister xmm_reg = static_cast<XmmRegister>(reg_idx); | 413 XmmRegister xmm_reg = static_cast<XmmRegister>(reg_idx); |
| 409 __ movups(Address(RSP, offset), xmm_reg); | 414 __ movups(Address(RSP, offset), xmm_reg); |
| 410 offset += kFpuRegisterSize; | 415 offset += kFpuRegisterSize; |
| 411 } | 416 } |
| 412 | 417 |
| 413 // Pass address of saved registers block. | 418 // Pass address of saved registers block. |
| 414 __ movq(CallingConventions::kArg1Reg, RSP); | 419 __ movq(CallingConventions::kArg1Reg, RSP); |
| 415 bool is_lazy = (kind == kLazyDeoptFromReturn) || | 420 bool is_lazy = |
| 416 (kind == kLazyDeoptFromThrow); | 421 (kind == kLazyDeoptFromReturn) || (kind == kLazyDeoptFromThrow); |
| 417 __ movq(CallingConventions::kArg2Reg, Immediate(is_lazy ? 1 : 0)); | 422 __ movq(CallingConventions::kArg2Reg, Immediate(is_lazy ? 1 : 0)); |
| 418 __ ReserveAlignedFrameSpace(0); // Ensure stack is aligned before the call. | 423 __ ReserveAlignedFrameSpace(0); // Ensure stack is aligned before the call. |
| 419 __ CallRuntime(kDeoptimizeCopyFrameRuntimeEntry, 2); | 424 __ CallRuntime(kDeoptimizeCopyFrameRuntimeEntry, 2); |
| 420 // Result (RAX) is stack-size (FP - SP) in bytes. | 425 // Result (RAX) is stack-size (FP - SP) in bytes. |
| 421 | 426 |
| 422 if (kind == kLazyDeoptFromReturn) { | 427 if (kind == kLazyDeoptFromReturn) { |
| 423 // Restore result into RBX temporarily. | 428 // Restore result into RBX temporarily. |
| 424 __ movq(RBX, Address(RBP, saved_result_slot_from_fp * kWordSize)); | 429 __ movq(RBX, Address(RBP, saved_result_slot_from_fp * kWordSize)); |
| 425 } else if (kind == kLazyDeoptFromThrow) { | 430 } else if (kind == kLazyDeoptFromThrow) { |
| 426 // Restore result into RBX temporarily. | 431 // Restore result into RBX temporarily. |
| 427 __ movq(RBX, Address(RBP, saved_exception_slot_from_fp * kWordSize)); | 432 __ movq(RBX, Address(RBP, saved_exception_slot_from_fp * kWordSize)); |
| 428 __ movq(RDX, Address(RBP, saved_stacktrace_slot_from_fp * kWordSize)); | 433 __ movq(RDX, Address(RBP, saved_stacktrace_slot_from_fp * kWordSize)); |
| 429 } | 434 } |
| 430 | 435 |
| 431 // There is a Dart Frame on the stack. We must restore PP and leave frame. | 436 // There is a Dart Frame on the stack. We must restore PP and leave frame. |
| 432 __ RestoreCodePointer(); | 437 __ RestoreCodePointer(); |
| 433 __ LeaveStubFrame(); | 438 __ LeaveStubFrame(); |
| 434 | 439 |
| 435 __ popq(RCX); // Preserve return address. | 440 __ popq(RCX); // Preserve return address. |
| 436 __ movq(RSP, RBP); // Discard optimized frame. | 441 __ movq(RSP, RBP); // Discard optimized frame. |
| 437 __ subq(RSP, RAX); // Reserve space for deoptimized frame. | 442 __ subq(RSP, RAX); // Reserve space for deoptimized frame. |
| 438 __ pushq(RCX); // Restore return address. | 443 __ pushq(RCX); // Restore return address. |
| 439 | 444 |
| 440 // DeoptimizeFillFrame expects a Dart frame, i.e. EnterDartFrame(0), but there | 445 // DeoptimizeFillFrame expects a Dart frame, i.e. EnterDartFrame(0), but there |
| 441 // is no need to set the correct PC marker or load PP, since they get patched. | 446 // is no need to set the correct PC marker or load PP, since they get patched. |
| 442 __ EnterStubFrame(); | 447 __ EnterStubFrame(); |
| 443 | 448 |
| 444 if (kind == kLazyDeoptFromReturn) { | 449 if (kind == kLazyDeoptFromReturn) { |
| 445 __ pushq(RBX); // Preserve result as first local. | 450 __ pushq(RBX); // Preserve result as first local. |
| 446 } else if (kind == kLazyDeoptFromThrow) { | 451 } else if (kind == kLazyDeoptFromThrow) { |
| 447 __ pushq(RBX); // Preserve exception as first local. | 452 __ pushq(RBX); // Preserve exception as first local. |
| 448 __ pushq(RDX); // Preserve stacktrace as second local. | 453 __ pushq(RDX); // Preserve stacktrace as second local. |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 483 __ popq(RBX); | 488 __ popq(RBX); |
| 484 __ SmiUntag(RBX); | 489 __ SmiUntag(RBX); |
| 485 if (kind == kLazyDeoptFromReturn) { | 490 if (kind == kLazyDeoptFromReturn) { |
| 486 __ popq(RAX); // Restore result. | 491 __ popq(RAX); // Restore result. |
| 487 } else if (kind == kLazyDeoptFromThrow) { | 492 } else if (kind == kLazyDeoptFromThrow) { |
| 488 __ popq(RDX); // Restore stacktrace. | 493 __ popq(RDX); // Restore stacktrace. |
| 489 __ popq(RAX); // Restore exception. | 494 __ popq(RAX); // Restore exception. |
| 490 } | 495 } |
| 491 __ LeaveStubFrame(); | 496 __ LeaveStubFrame(); |
| 492 | 497 |
| 493 __ popq(RCX); // Pop return address. | 498 __ popq(RCX); // Pop return address. |
| 494 __ addq(RSP, RBX); // Remove materialization arguments. | 499 __ addq(RSP, RBX); // Remove materialization arguments. |
| 495 __ pushq(RCX); // Push return address. | 500 __ pushq(RCX); // Push return address. |
| 496 __ ret(); | 501 __ ret(); |
| 497 } | 502 } |
| 498 | 503 |
| 499 | 504 |
| 500 // RAX: result, must be preserved | 505 // RAX: result, must be preserved |
| 501 void StubCode::GenerateDeoptimizeLazyFromReturnStub(Assembler* assembler) { | 506 void StubCode::GenerateDeoptimizeLazyFromReturnStub(Assembler* assembler) { |
| 502 // Push zap value instead of CODE_REG for lazy deopt. | 507 // Push zap value instead of CODE_REG for lazy deopt. |
| 503 __ pushq(Immediate(0xf1f1f1f1)); | 508 __ pushq(Immediate(0xf1f1f1f1)); |
| 504 // Return address for "call" to deopt stub. | 509 // Return address for "call" to deopt stub. |
| 505 __ pushq(Immediate(0xe1e1e1e1)); | 510 __ pushq(Immediate(0xe1e1e1e1)); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 528 static void GenerateDispatcherCode(Assembler* assembler, | 533 static void GenerateDispatcherCode(Assembler* assembler, |
| 529 Label* call_target_function) { | 534 Label* call_target_function) { |
| 530 __ Comment("NoSuchMethodDispatch"); | 535 __ Comment("NoSuchMethodDispatch"); |
| 531 // When lazily generated invocation dispatchers are disabled, the | 536 // When lazily generated invocation dispatchers are disabled, the |
| 532 // miss-handler may return null. | 537 // miss-handler may return null. |
| 533 __ CompareObject(RAX, Object::null_object()); | 538 __ CompareObject(RAX, Object::null_object()); |
| 534 __ j(NOT_EQUAL, call_target_function); | 539 __ j(NOT_EQUAL, call_target_function); |
| 535 __ EnterStubFrame(); | 540 __ EnterStubFrame(); |
| 536 // Load the receiver. | 541 // Load the receiver. |
| 537 __ movq(RDI, FieldAddress(R10, ArgumentsDescriptor::count_offset())); | 542 __ movq(RDI, FieldAddress(R10, ArgumentsDescriptor::count_offset())); |
| 538 __ movq(RAX, Address( | 543 __ movq(RAX, Address(RBP, RDI, TIMES_HALF_WORD_SIZE, |
| 539 RBP, RDI, TIMES_HALF_WORD_SIZE, kParamEndSlotFromFp * kWordSize)); | 544 kParamEndSlotFromFp * kWordSize)); |
| 540 __ pushq(Immediate(0)); // Setup space on stack for result. | 545 __ pushq(Immediate(0)); // Setup space on stack for result. |
| 541 __ pushq(RAX); // Receiver. | 546 __ pushq(RAX); // Receiver. |
| 542 __ pushq(RBX); // ICData/MegamorphicCache. | 547 __ pushq(RBX); // ICData/MegamorphicCache. |
| 543 __ pushq(R10); // Arguments descriptor array. | 548 __ pushq(R10); // Arguments descriptor array. |
| 544 __ movq(R10, RDI); | 549 __ movq(R10, RDI); |
| 545 // EDX: Smi-tagged arguments array length. | 550 // EDX: Smi-tagged arguments array length. |
| 546 PushArgumentsArray(assembler); | 551 PushArgumentsArray(assembler); |
| 547 const intptr_t kNumArgs = 4; | 552 const intptr_t kNumArgs = 4; |
| 548 __ CallRuntime(kInvokeNoSuchMethodDispatcherRuntimeEntry, kNumArgs); | 553 __ CallRuntime(kInvokeNoSuchMethodDispatcherRuntimeEntry, kNumArgs); |
| 549 __ Drop(4); | 554 __ Drop(4); |
| 550 __ popq(RAX); // Return value. | 555 __ popq(RAX); // Return value. |
| 551 __ LeaveStubFrame(); | 556 __ LeaveStubFrame(); |
| 552 __ ret(); | 557 __ ret(); |
| 553 } | 558 } |
| 554 | 559 |
| 555 | 560 |
| 556 void StubCode::GenerateMegamorphicMissStub(Assembler* assembler) { | 561 void StubCode::GenerateMegamorphicMissStub(Assembler* assembler) { |
| 557 __ EnterStubFrame(); | 562 __ EnterStubFrame(); |
| 558 // Load the receiver into RAX. The argument count in the arguments | 563 // Load the receiver into RAX. The argument count in the arguments |
| 559 // descriptor in R10 is a smi. | 564 // descriptor in R10 is a smi. |
| 560 __ movq(RAX, FieldAddress(R10, ArgumentsDescriptor::count_offset())); | 565 __ movq(RAX, FieldAddress(R10, ArgumentsDescriptor::count_offset())); |
| 561 // Three words (saved pp, saved fp, stub's pc marker) | 566 // Three words (saved pp, saved fp, stub's pc marker) |
| 562 // in the stack above the return address. | 567 // in the stack above the return address. |
| 563 __ movq(RAX, Address(RSP, RAX, TIMES_4, | 568 __ movq(RAX, |
| 564 kSavedAboveReturnAddress * kWordSize)); | 569 Address(RSP, RAX, TIMES_4, kSavedAboveReturnAddress * kWordSize)); |
| 565 // Preserve IC data and arguments descriptor. | 570 // Preserve IC data and arguments descriptor. |
| 566 __ pushq(RBX); | 571 __ pushq(RBX); |
| 567 __ pushq(R10); | 572 __ pushq(R10); |
| 568 | 573 |
| 569 // Space for the result of the runtime call. | 574 // Space for the result of the runtime call. |
| 570 __ pushq(Immediate(0)); | 575 __ pushq(Immediate(0)); |
| 571 __ pushq(RAX); // Receiver. | 576 __ pushq(RAX); // Receiver. |
| 572 __ pushq(RBX); // IC data. | 577 __ pushq(RBX); // IC data. |
| 573 __ pushq(R10); // Arguments descriptor. | 578 __ pushq(R10); // Arguments descriptor. |
| 574 __ CallRuntime(kMegamorphicCacheMissHandlerRuntimeEntry, 3); | 579 __ CallRuntime(kMegamorphicCacheMissHandlerRuntimeEntry, 3); |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 613 } | 618 } |
| 614 __ cmpq(RDI, Immediate(0)); | 619 __ cmpq(RDI, Immediate(0)); |
| 615 __ j(LESS, &slow_case); | 620 __ j(LESS, &slow_case); |
| 616 // Check for maximum allowed length. | 621 // Check for maximum allowed length. |
| 617 const Immediate& max_len = | 622 const Immediate& max_len = |
| 618 Immediate(reinterpret_cast<int64_t>(Smi::New(Array::kMaxElements))); | 623 Immediate(reinterpret_cast<int64_t>(Smi::New(Array::kMaxElements))); |
| 619 __ cmpq(RDI, max_len); | 624 __ cmpq(RDI, max_len); |
| 620 __ j(GREATER, &slow_case); | 625 __ j(GREATER, &slow_case); |
| 621 | 626 |
| 622 // Check for allocation tracing. | 627 // Check for allocation tracing. |
| 623 NOT_IN_PRODUCT(__ MaybeTraceAllocation(kArrayCid, | 628 NOT_IN_PRODUCT( |
| 624 &slow_case, | 629 __ MaybeTraceAllocation(kArrayCid, &slow_case, Assembler::kFarJump)); |
| 625 Assembler::kFarJump)); | |
| 626 | 630 |
| 627 const intptr_t fixed_size = sizeof(RawArray) + kObjectAlignment - 1; | 631 const intptr_t fixed_size = sizeof(RawArray) + kObjectAlignment - 1; |
| 628 __ leaq(RDI, Address(RDI, TIMES_4, fixed_size)); // RDI is a Smi. | 632 __ leaq(RDI, Address(RDI, TIMES_4, fixed_size)); // RDI is a Smi. |
| 629 ASSERT(kSmiTagShift == 1); | 633 ASSERT(kSmiTagShift == 1); |
| 630 __ andq(RDI, Immediate(-kObjectAlignment)); | 634 __ andq(RDI, Immediate(-kObjectAlignment)); |
| 631 | 635 |
| 632 const intptr_t cid = kArrayCid; | 636 const intptr_t cid = kArrayCid; |
| 633 Heap::Space space = Heap::kNew; | 637 Heap::Space space = Heap::kNew; |
| 634 __ movq(R13, Address(THR, Thread::heap_offset())); | 638 __ movq(R13, Address(THR, Thread::heap_offset())); |
| 635 __ movq(RAX, Address(R13, Heap::TopOffset(space))); | 639 __ movq(RAX, Address(R13, Heap::TopOffset(space))); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 667 __ Bind(&done); | 671 __ Bind(&done); |
| 668 | 672 |
| 669 // Get the class index and insert it into the tags. | 673 // Get the class index and insert it into the tags. |
| 670 __ orq(RDI, Immediate(RawObject::ClassIdTag::encode(cid))); | 674 __ orq(RDI, Immediate(RawObject::ClassIdTag::encode(cid))); |
| 671 __ movq(FieldAddress(RAX, Array::tags_offset()), RDI); // Tags. | 675 __ movq(FieldAddress(RAX, Array::tags_offset()), RDI); // Tags. |
| 672 } | 676 } |
| 673 | 677 |
| 674 // RAX: new object start as a tagged pointer. | 678 // RAX: new object start as a tagged pointer. |
| 675 // Store the type argument field. | 679 // Store the type argument field. |
| 676 // No generetional barrier needed, since we store into a new object. | 680 // No generetional barrier needed, since we store into a new object. |
| 677 __ StoreIntoObjectNoBarrier(RAX, | 681 __ StoreIntoObjectNoBarrier( |
| 678 FieldAddress(RAX, Array::type_arguments_offset()), | 682 RAX, FieldAddress(RAX, Array::type_arguments_offset()), RBX); |
| 679 RBX); | |
| 680 | 683 |
| 681 // Set the length field. | 684 // Set the length field. |
| 682 __ StoreIntoObjectNoBarrier(RAX, | 685 __ StoreIntoObjectNoBarrier(RAX, FieldAddress(RAX, Array::length_offset()), |
| 683 FieldAddress(RAX, Array::length_offset()), | |
| 684 R10); | 686 R10); |
| 685 | 687 |
| 686 // Initialize all array elements to raw_null. | 688 // Initialize all array elements to raw_null. |
| 687 // RAX: new object start as a tagged pointer. | 689 // RAX: new object start as a tagged pointer. |
| 688 // RCX: new object end address. | 690 // RCX: new object end address. |
| 689 // RDI: iterator which initially points to the start of the variable | 691 // RDI: iterator which initially points to the start of the variable |
| 690 // data area to be initialized. | 692 // data area to be initialized. |
| 691 __ LoadObject(R12, Object::null_object()); | 693 __ LoadObject(R12, Object::null_object()); |
| 692 __ leaq(RDI, FieldAddress(RAX, sizeof(RawArray))); | 694 __ leaq(RDI, FieldAddress(RAX, sizeof(RawArray))); |
| 693 Label done; | 695 Label done; |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 731 // RSP : points to return address. | 733 // RSP : points to return address. |
| 732 // RDI : target code | 734 // RDI : target code |
| 733 // RSI : arguments descriptor array. | 735 // RSI : arguments descriptor array. |
| 734 // RDX : arguments array. | 736 // RDX : arguments array. |
| 735 // RCX : current thread. | 737 // RCX : current thread. |
| 736 void StubCode::GenerateInvokeDartCodeStub(Assembler* assembler) { | 738 void StubCode::GenerateInvokeDartCodeStub(Assembler* assembler) { |
| 737 // Save frame pointer coming in. | 739 // Save frame pointer coming in. |
| 738 __ EnterFrame(0); | 740 __ EnterFrame(0); |
| 739 | 741 |
| 740 const Register kTargetCodeReg = CallingConventions::kArg1Reg; | 742 const Register kTargetCodeReg = CallingConventions::kArg1Reg; |
| 741 const Register kArgDescReg = CallingConventions::kArg2Reg; | 743 const Register kArgDescReg = CallingConventions::kArg2Reg; |
| 742 const Register kArgsReg = CallingConventions::kArg3Reg; | 744 const Register kArgsReg = CallingConventions::kArg3Reg; |
| 743 const Register kThreadReg = CallingConventions::kArg4Reg; | 745 const Register kThreadReg = CallingConventions::kArg4Reg; |
| 744 | 746 |
| 745 // Push code object to PC marker slot. | 747 // Push code object to PC marker slot. |
| 746 __ pushq(Address(kThreadReg, Thread::invoke_dart_code_stub_offset())); | 748 __ pushq(Address(kThreadReg, Thread::invoke_dart_code_stub_offset())); |
| 747 | 749 |
| 748 // At this point, the stack looks like: | 750 // At this point, the stack looks like: |
| 749 // | stub code object | 751 // | stub code object |
| 750 // | saved RBP | <-- RBP | 752 // | saved RBP | <-- RBP |
| 751 // | saved PC (return to DartEntry::InvokeFunction) | | 753 // | saved PC (return to DartEntry::InvokeFunction) | |
| 752 | 754 |
| 753 const intptr_t kInitialOffset = 2; | 755 const intptr_t kInitialOffset = 2; |
| 754 // Save arguments descriptor array. | 756 // Save arguments descriptor array. |
| 755 const intptr_t kArgumentsDescOffset = -(kInitialOffset) * kWordSize; | 757 const intptr_t kArgumentsDescOffset = -(kInitialOffset)*kWordSize; |
| 756 __ pushq(kArgDescReg); | 758 __ pushq(kArgDescReg); |
| 757 | 759 |
| 758 // Save C++ ABI callee-saved registers. | 760 // Save C++ ABI callee-saved registers. |
| 759 __ PushRegisters(CallingConventions::kCalleeSaveCpuRegisters, | 761 __ PushRegisters(CallingConventions::kCalleeSaveCpuRegisters, |
| 760 CallingConventions::kCalleeSaveXmmRegisters); | 762 CallingConventions::kCalleeSaveXmmRegisters); |
| 761 | 763 |
| 762 // If any additional (or fewer) values are pushed, the offsets in | 764 // If any additional (or fewer) values are pushed, the offsets in |
| 763 // kExitLinkSlotFromEntryFp will need to be changed. | 765 // kExitLinkSlotFromEntryFp will need to be changed. |
| 764 | 766 |
| 765 // Set up THR, which caches the current thread in Dart code. | 767 // Set up THR, which caches the current thread in Dart code. |
| 766 if (THR != kThreadReg) { | 768 if (THR != kThreadReg) { |
| 767 __ movq(THR, kThreadReg); | 769 __ movq(THR, kThreadReg); |
| 768 } | 770 } |
| 769 | 771 |
| 770 // Save the current VMTag on the stack. | 772 // Save the current VMTag on the stack. |
| 771 __ movq(RAX, Assembler::VMTagAddress()); | 773 __ movq(RAX, Assembler::VMTagAddress()); |
| 772 __ pushq(RAX); | 774 __ pushq(RAX); |
| 773 | 775 |
| 774 // Mark that the thread is executing Dart code. | 776 // Mark that the thread is executing Dart code. |
| 775 __ movq(Assembler::VMTagAddress(), Immediate(VMTag::kDartTagId)); | 777 __ movq(Assembler::VMTagAddress(), Immediate(VMTag::kDartTagId)); |
| 776 | 778 |
| 777 // Save top resource and top exit frame info. Use RAX as a temporary register. | 779 // Save top resource and top exit frame info. Use RAX as a temporary register. |
| 778 // StackFrameIterator reads the top exit frame info saved in this frame. | 780 // StackFrameIterator reads the top exit frame info saved in this frame. |
| 779 __ movq(RAX, Address(THR, Thread::top_resource_offset())); | 781 __ movq(RAX, Address(THR, Thread::top_resource_offset())); |
| 780 __ pushq(RAX); | 782 __ pushq(RAX); |
| 781 __ movq(Address(THR, Thread::top_resource_offset()), | 783 __ movq(Address(THR, Thread::top_resource_offset()), Immediate(0)); |
| 782 Immediate(0)); | |
| 783 __ movq(RAX, Address(THR, Thread::top_exit_frame_info_offset())); | 784 __ movq(RAX, Address(THR, Thread::top_exit_frame_info_offset())); |
| 784 // The constant kExitLinkSlotFromEntryFp must be kept in sync with the | 785 // The constant kExitLinkSlotFromEntryFp must be kept in sync with the |
| 785 // code below. | 786 // code below. |
| 786 __ pushq(RAX); | 787 __ pushq(RAX); |
| 787 #if defined(DEBUG) | 788 #if defined(DEBUG) |
| 788 { | 789 { |
| 789 Label ok; | 790 Label ok; |
| 790 __ leaq(RAX, Address(RBP, kExitLinkSlotFromEntryFp * kWordSize)); | 791 __ leaq(RAX, Address(RBP, kExitLinkSlotFromEntryFp * kWordSize)); |
| 791 __ cmpq(RAX, RSP); | 792 __ cmpq(RAX, RSP); |
| 792 __ j(EQUAL, &ok); | 793 __ j(EQUAL, &ok); |
| 793 __ Stop("kExitLinkSlotFromEntryFp mismatch"); | 794 __ Stop("kExitLinkSlotFromEntryFp mismatch"); |
| 794 __ Bind(&ok); | 795 __ Bind(&ok); |
| 795 } | 796 } |
| 796 #endif | 797 #endif |
| 797 | 798 |
| 798 __ movq(Address(THR, Thread::top_exit_frame_info_offset()), | 799 __ movq(Address(THR, Thread::top_exit_frame_info_offset()), Immediate(0)); |
| 799 Immediate(0)); | |
| 800 | 800 |
| 801 // Load arguments descriptor array into R10, which is passed to Dart code. | 801 // Load arguments descriptor array into R10, which is passed to Dart code. |
| 802 __ movq(R10, Address(kArgDescReg, VMHandles::kOffsetOfRawPtrInHandle)); | 802 __ movq(R10, Address(kArgDescReg, VMHandles::kOffsetOfRawPtrInHandle)); |
| 803 | 803 |
| 804 // Push arguments. At this point we only need to preserve kTargetCodeReg. | 804 // Push arguments. At this point we only need to preserve kTargetCodeReg. |
| 805 ASSERT(kTargetCodeReg != RDX); | 805 ASSERT(kTargetCodeReg != RDX); |
| 806 | 806 |
| 807 // Load number of arguments into RBX. | 807 // Load number of arguments into RBX. |
| 808 __ movq(RBX, FieldAddress(R10, ArgumentsDescriptor::count_offset())); | 808 __ movq(RBX, FieldAddress(R10, ArgumentsDescriptor::count_offset())); |
| 809 __ SmiUntag(RBX); | 809 __ SmiUntag(RBX); |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 868 __ LoadObject(R9, Object::null_object()); | 868 __ LoadObject(R9, Object::null_object()); |
| 869 if (FLAG_inline_alloc) { | 869 if (FLAG_inline_alloc) { |
| 870 Label slow_case; | 870 Label slow_case; |
| 871 // First compute the rounded instance size. | 871 // First compute the rounded instance size. |
| 872 // R10: number of context variables. | 872 // R10: number of context variables. |
| 873 intptr_t fixed_size = (sizeof(RawContext) + kObjectAlignment - 1); | 873 intptr_t fixed_size = (sizeof(RawContext) + kObjectAlignment - 1); |
| 874 __ leaq(R13, Address(R10, TIMES_8, fixed_size)); | 874 __ leaq(R13, Address(R10, TIMES_8, fixed_size)); |
| 875 __ andq(R13, Immediate(-kObjectAlignment)); | 875 __ andq(R13, Immediate(-kObjectAlignment)); |
| 876 | 876 |
| 877 // Check for allocation tracing. | 877 // Check for allocation tracing. |
| 878 NOT_IN_PRODUCT(__ MaybeTraceAllocation(kContextCid, | 878 NOT_IN_PRODUCT( |
| 879 &slow_case, | 879 __ MaybeTraceAllocation(kContextCid, &slow_case, Assembler::kFarJump)); |
| 880 Assembler::kFarJump)); | |
| 881 | 880 |
| 882 // Now allocate the object. | 881 // Now allocate the object. |
| 883 // R10: number of context variables. | 882 // R10: number of context variables. |
| 884 const intptr_t cid = kContextCid; | 883 const intptr_t cid = kContextCid; |
| 885 Heap::Space space = Heap::kNew; | 884 Heap::Space space = Heap::kNew; |
| 886 __ movq(RCX, Address(THR, Thread::heap_offset())); | 885 __ movq(RCX, Address(THR, Thread::heap_offset())); |
| 887 __ movq(RAX, Address(RCX, Heap::TopOffset(space))); | 886 __ movq(RAX, Address(RCX, Heap::TopOffset(space))); |
| 888 __ addq(R13, RAX); | 887 __ addq(R13, RAX); |
| 889 // Check if the allocation fits into the remaining space. | 888 // Check if the allocation fits into the remaining space. |
| 890 // RAX: potential new object. | 889 // RAX: potential new object. |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 924 __ jmp(&done); | 923 __ jmp(&done); |
| 925 | 924 |
| 926 __ Bind(&size_tag_overflow); | 925 __ Bind(&size_tag_overflow); |
| 927 // Set overflow size tag value. | 926 // Set overflow size tag value. |
| 928 __ movq(R13, Immediate(0)); | 927 __ movq(R13, Immediate(0)); |
| 929 | 928 |
| 930 __ Bind(&done); | 929 __ Bind(&done); |
| 931 // RAX: new object. | 930 // RAX: new object. |
| 932 // R10: number of context variables. | 931 // R10: number of context variables. |
| 933 // R13: size and bit tags. | 932 // R13: size and bit tags. |
| 934 __ orq(R13, | 933 __ orq(R13, Immediate(RawObject::ClassIdTag::encode(cid))); |
| 935 Immediate(RawObject::ClassIdTag::encode(cid))); | |
| 936 __ movq(FieldAddress(RAX, Context::tags_offset()), R13); // Tags. | 934 __ movq(FieldAddress(RAX, Context::tags_offset()), R13); // Tags. |
| 937 } | 935 } |
| 938 | 936 |
| 939 // Setup up number of context variables field. | 937 // Setup up number of context variables field. |
| 940 // RAX: new object. | 938 // RAX: new object. |
| 941 // R10: number of context variables as integer value (not object). | 939 // R10: number of context variables as integer value (not object). |
| 942 __ movq(FieldAddress(RAX, Context::num_variables_offset()), R10); | 940 __ movq(FieldAddress(RAX, Context::num_variables_offset()), R10); |
| 943 | 941 |
| 944 // Setup the parent field. | 942 // Setup the parent field. |
| 945 // RAX: new object. | 943 // RAX: new object. |
| 946 // R10: number of context variables. | 944 // R10: number of context variables. |
| 947 // No generational barrier needed, since we are storing null. | 945 // No generational barrier needed, since we are storing null. |
| 948 __ StoreIntoObjectNoBarrier(RAX, | 946 __ StoreIntoObjectNoBarrier( |
| 949 FieldAddress(RAX, Context::parent_offset()), | 947 RAX, FieldAddress(RAX, Context::parent_offset()), R9); |
| 950 R9); | |
| 951 | 948 |
| 952 // Initialize the context variables. | 949 // Initialize the context variables. |
| 953 // RAX: new object. | 950 // RAX: new object. |
| 954 // R10: number of context variables. | 951 // R10: number of context variables. |
| 955 { | 952 { |
| 956 Label loop, entry; | 953 Label loop, entry; |
| 957 __ leaq(R13, FieldAddress(RAX, Context::variable_offset(0))); | 954 __ leaq(R13, FieldAddress(RAX, Context::variable_offset(0))); |
| 958 #if defined(DEBUG) | 955 #if defined(DEBUG) |
| 959 static const bool kJumpLength = Assembler::kFarJump; | 956 static const bool kJumpLength = Assembler::kFarJump; |
| 960 #else | 957 #else |
| 961 static const bool kJumpLength = Assembler::kNearJump; | 958 static const bool kJumpLength = Assembler::kNearJump; |
| 962 #endif // DEBUG | 959 #endif // DEBUG |
| 963 __ jmp(&entry, kJumpLength); | 960 __ jmp(&entry, kJumpLength); |
| 964 __ Bind(&loop); | 961 __ Bind(&loop); |
| 965 __ decq(R10); | 962 __ decq(R10); |
| 966 // No generational barrier needed, since we are storing null. | 963 // No generational barrier needed, since we are storing null. |
| 967 __ StoreIntoObjectNoBarrier(RAX, | 964 __ StoreIntoObjectNoBarrier(RAX, Address(R13, R10, TIMES_8, 0), R9); |
| 968 Address(R13, R10, TIMES_8, 0), | |
| 969 R9); | |
| 970 __ Bind(&entry); | 965 __ Bind(&entry); |
| 971 __ cmpq(R10, Immediate(0)); | 966 __ cmpq(R10, Immediate(0)); |
| 972 __ j(NOT_EQUAL, &loop, Assembler::kNearJump); | 967 __ j(NOT_EQUAL, &loop, Assembler::kNearJump); |
| 973 } | 968 } |
| 974 | 969 |
| 975 // Done allocating and initializing the context. | 970 // Done allocating and initializing the context. |
| 976 // RAX: new object. | 971 // RAX: new object. |
| 977 __ ret(); | 972 __ ret(); |
| 978 | 973 |
| 979 __ Bind(&slow_case); | 974 __ Bind(&slow_case); |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1116 // Initialize the remaining words of the object. | 1111 // Initialize the remaining words of the object. |
| 1117 // RAX: new object (tagged). | 1112 // RAX: new object (tagged). |
| 1118 // RBX: next object start. | 1113 // RBX: next object start. |
| 1119 // RDX: new object type arguments (if is_cls_parameterized). | 1114 // RDX: new object type arguments (if is_cls_parameterized). |
| 1120 // R9: raw null. | 1115 // R9: raw null. |
| 1121 // First try inlining the initialization without a loop. | 1116 // First try inlining the initialization without a loop. |
| 1122 if (instance_size < (kInlineInstanceSize * kWordSize)) { | 1117 if (instance_size < (kInlineInstanceSize * kWordSize)) { |
| 1123 // Check if the object contains any non-header fields. | 1118 // Check if the object contains any non-header fields. |
| 1124 // Small objects are initialized using a consecutive set of writes. | 1119 // Small objects are initialized using a consecutive set of writes. |
| 1125 for (intptr_t current_offset = Instance::NextFieldOffset(); | 1120 for (intptr_t current_offset = Instance::NextFieldOffset(); |
| 1126 current_offset < instance_size; | 1121 current_offset < instance_size; current_offset += kWordSize) { |
| 1127 current_offset += kWordSize) { | 1122 __ StoreIntoObjectNoBarrier(RAX, FieldAddress(RAX, current_offset), R9); |
| 1128 __ StoreIntoObjectNoBarrier(RAX, | |
| 1129 FieldAddress(RAX, current_offset), | |
| 1130 R9); | |
| 1131 } | 1123 } |
| 1132 } else { | 1124 } else { |
| 1133 __ leaq(RCX, FieldAddress(RAX, Instance::NextFieldOffset())); | 1125 __ leaq(RCX, FieldAddress(RAX, Instance::NextFieldOffset())); |
| 1134 // Loop until the whole object is initialized. | 1126 // Loop until the whole object is initialized. |
| 1135 // RAX: new object (tagged). | 1127 // RAX: new object (tagged). |
| 1136 // RBX: next object start. | 1128 // RBX: next object start. |
| 1137 // RCX: next word to be initialized. | 1129 // RCX: next word to be initialized. |
| 1138 // RDX: new object type arguments (if is_cls_parameterized). | 1130 // RDX: new object type arguments (if is_cls_parameterized). |
| 1139 Label init_loop; | 1131 Label init_loop; |
| 1140 Label done; | 1132 Label done; |
| (...skipping 20 matching lines...) Expand all Loading... |
| 1161 // Done allocating and initializing the instance. | 1153 // Done allocating and initializing the instance. |
| 1162 // RAX: new object (tagged). | 1154 // RAX: new object (tagged). |
| 1163 __ ret(); | 1155 __ ret(); |
| 1164 | 1156 |
| 1165 __ Bind(&slow_case); | 1157 __ Bind(&slow_case); |
| 1166 } | 1158 } |
| 1167 // If is_cls_parameterized: | 1159 // If is_cls_parameterized: |
| 1168 // RDX: new object type arguments. | 1160 // RDX: new object type arguments. |
| 1169 // Create a stub frame. | 1161 // Create a stub frame. |
| 1170 __ EnterStubFrame(); // Uses PP to access class object. | 1162 __ EnterStubFrame(); // Uses PP to access class object. |
| 1171 __ pushq(R9); // Setup space on stack for return value. | 1163 __ pushq(R9); // Setup space on stack for return value. |
| 1172 __ PushObject(cls); // Push class of object to be allocated. | 1164 __ PushObject(cls); // Push class of object to be allocated. |
| 1173 if (is_cls_parameterized) { | 1165 if (is_cls_parameterized) { |
| 1174 __ pushq(RDX); // Push type arguments of object to be allocated. | 1166 __ pushq(RDX); // Push type arguments of object to be allocated. |
| 1175 } else { | 1167 } else { |
| 1176 __ pushq(R9); // Push null type arguments. | 1168 __ pushq(R9); // Push null type arguments. |
| 1177 } | 1169 } |
| 1178 __ CallRuntime(kAllocateObjectRuntimeEntry, 2); // Allocate object. | 1170 __ CallRuntime(kAllocateObjectRuntimeEntry, 2); // Allocate object. |
| 1179 __ popq(RAX); // Pop argument (type arguments of object). | 1171 __ popq(RAX); // Pop argument (type arguments of object). |
| 1180 __ popq(RAX); // Pop argument (class of object). | 1172 __ popq(RAX); // Pop argument (class of object). |
| 1181 __ popq(RAX); // Pop result (newly allocated object). | 1173 __ popq(RAX); // Pop result (newly allocated object). |
| 1182 // RAX: new object | 1174 // RAX: new object |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1194 // RSP + 8 : address of last argument. | 1186 // RSP + 8 : address of last argument. |
| 1195 // R10 : arguments descriptor array. | 1187 // R10 : arguments descriptor array. |
| 1196 void StubCode::GenerateCallClosureNoSuchMethodStub(Assembler* assembler) { | 1188 void StubCode::GenerateCallClosureNoSuchMethodStub(Assembler* assembler) { |
| 1197 __ EnterStubFrame(); | 1189 __ EnterStubFrame(); |
| 1198 | 1190 |
| 1199 // Load the receiver. | 1191 // Load the receiver. |
| 1200 __ movq(R13, FieldAddress(R10, ArgumentsDescriptor::count_offset())); | 1192 __ movq(R13, FieldAddress(R10, ArgumentsDescriptor::count_offset())); |
| 1201 __ movq(RAX, Address(RBP, R13, TIMES_4, kParamEndSlotFromFp * kWordSize)); | 1193 __ movq(RAX, Address(RBP, R13, TIMES_4, kParamEndSlotFromFp * kWordSize)); |
| 1202 | 1194 |
| 1203 __ pushq(Immediate(0)); // Result slot. | 1195 __ pushq(Immediate(0)); // Result slot. |
| 1204 __ pushq(RAX); // Receiver. | 1196 __ pushq(RAX); // Receiver. |
| 1205 __ pushq(R10); // Arguments descriptor array. | 1197 __ pushq(R10); // Arguments descriptor array. |
| 1206 | 1198 |
| 1207 __ movq(R10, R13); // Smi-tagged arguments array length. | 1199 __ movq(R10, R13); // Smi-tagged arguments array length. |
| 1208 PushArgumentsArray(assembler); | 1200 PushArgumentsArray(assembler); |
| 1209 | 1201 |
| 1210 const intptr_t kNumArgs = 3; | 1202 const intptr_t kNumArgs = 3; |
| 1211 __ CallRuntime(kInvokeClosureNoSuchMethodRuntimeEntry, kNumArgs); | 1203 __ CallRuntime(kInvokeClosureNoSuchMethodRuntimeEntry, kNumArgs); |
| 1212 // noSuchMethod on closures always throws an error, so it will never return. | 1204 // noSuchMethod on closures always throws an error, so it will never return. |
| 1213 __ int3(); | 1205 __ int3(); |
| 1214 } | 1206 } |
| 1215 | 1207 |
| 1216 | 1208 |
| 1217 // Cannot use function object from ICData as it may be the inlined | 1209 // Cannot use function object from ICData as it may be the inlined |
| 1218 // function and not the top-scope function. | 1210 // function and not the top-scope function. |
| 1219 void StubCode::GenerateOptimizedUsageCounterIncrement(Assembler* assembler) { | 1211 void StubCode::GenerateOptimizedUsageCounterIncrement(Assembler* assembler) { |
| 1220 Register ic_reg = RBX; | 1212 Register ic_reg = RBX; |
| 1221 Register func_reg = RDI; | 1213 Register func_reg = RDI; |
| 1222 if (FLAG_trace_optimized_ic_calls) { | 1214 if (FLAG_trace_optimized_ic_calls) { |
| 1223 __ EnterStubFrame(); | 1215 __ EnterStubFrame(); |
| 1224 __ pushq(func_reg); // Preserve | 1216 __ pushq(func_reg); // Preserve |
| 1225 __ pushq(ic_reg); // Preserve. | 1217 __ pushq(ic_reg); // Preserve. |
| 1226 __ pushq(ic_reg); // Argument. | 1218 __ pushq(ic_reg); // Argument. |
| 1227 __ pushq(func_reg); // Argument. | 1219 __ pushq(func_reg); // Argument. |
| 1228 __ CallRuntime(kTraceICCallRuntimeEntry, 2); | 1220 __ CallRuntime(kTraceICCallRuntimeEntry, 2); |
| 1229 __ popq(RAX); // Discard argument; | 1221 __ popq(RAX); // Discard argument; |
| 1230 __ popq(RAX); // Discard argument; | 1222 __ popq(RAX); // Discard argument; |
| 1231 __ popq(ic_reg); // Restore. | 1223 __ popq(ic_reg); // Restore. |
| 1232 __ popq(func_reg); // Restore. | 1224 __ popq(func_reg); // Restore. |
| 1233 __ LeaveStubFrame(); | 1225 __ LeaveStubFrame(); |
| 1234 } | 1226 } |
| 1235 __ incl(FieldAddress(func_reg, Function::usage_counter_offset())); | 1227 __ incl(FieldAddress(func_reg, Function::usage_counter_offset())); |
| 1236 } | 1228 } |
| 1237 | 1229 |
| 1238 | 1230 |
| 1239 // Loads function into 'temp_reg', preserves 'ic_reg'. | 1231 // Loads function into 'temp_reg', preserves 'ic_reg'. |
| 1240 void StubCode::GenerateUsageCounterIncrement(Assembler* assembler, | 1232 void StubCode::GenerateUsageCounterIncrement(Assembler* assembler, |
| 1241 Register temp_reg) { | 1233 Register temp_reg) { |
| 1242 if (FLAG_optimization_counter_threshold >= 0) { | 1234 if (FLAG_optimization_counter_threshold >= 0) { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1253 // Note: RBX must be preserved. | 1245 // Note: RBX must be preserved. |
| 1254 // Attempt a quick Smi operation for known operations ('kind'). The ICData | 1246 // Attempt a quick Smi operation for known operations ('kind'). The ICData |
| 1255 // must have been primed with a Smi/Smi check that will be used for counting | 1247 // must have been primed with a Smi/Smi check that will be used for counting |
| 1256 // the invocations. | 1248 // the invocations. |
| 1257 static void EmitFastSmiOp(Assembler* assembler, | 1249 static void EmitFastSmiOp(Assembler* assembler, |
| 1258 Token::Kind kind, | 1250 Token::Kind kind, |
| 1259 intptr_t num_args, | 1251 intptr_t num_args, |
| 1260 Label* not_smi_or_overflow) { | 1252 Label* not_smi_or_overflow) { |
| 1261 __ Comment("Fast Smi op"); | 1253 __ Comment("Fast Smi op"); |
| 1262 ASSERT(num_args == 2); | 1254 ASSERT(num_args == 2); |
| 1263 __ movq(RCX, Address(RSP, + 1 * kWordSize)); // Right | 1255 __ movq(RCX, Address(RSP, +1 * kWordSize)); // Right |
| 1264 __ movq(RAX, Address(RSP, + 2 * kWordSize)); // Left. | 1256 __ movq(RAX, Address(RSP, +2 * kWordSize)); // Left. |
| 1265 __ movq(R13, RCX); | 1257 __ movq(R13, RCX); |
| 1266 __ orq(R13, RAX); | 1258 __ orq(R13, RAX); |
| 1267 __ testq(R13, Immediate(kSmiTagMask)); | 1259 __ testq(R13, Immediate(kSmiTagMask)); |
| 1268 __ j(NOT_ZERO, not_smi_or_overflow); | 1260 __ j(NOT_ZERO, not_smi_or_overflow); |
| 1269 switch (kind) { | 1261 switch (kind) { |
| 1270 case Token::kADD: { | 1262 case Token::kADD: { |
| 1271 __ addq(RAX, RCX); | 1263 __ addq(RAX, RCX); |
| 1272 __ j(OVERFLOW, not_smi_or_overflow); | 1264 __ j(OVERFLOW, not_smi_or_overflow); |
| 1273 break; | 1265 break; |
| 1274 } | 1266 } |
| 1275 case Token::kSUB: { | 1267 case Token::kSUB: { |
| 1276 __ subq(RAX, RCX); | 1268 __ subq(RAX, RCX); |
| 1277 __ j(OVERFLOW, not_smi_or_overflow); | 1269 __ j(OVERFLOW, not_smi_or_overflow); |
| 1278 break; | 1270 break; |
| 1279 } | 1271 } |
| 1280 case Token::kEQ: { | 1272 case Token::kEQ: { |
| 1281 Label done, is_true; | 1273 Label done, is_true; |
| 1282 __ cmpq(RAX, RCX); | 1274 __ cmpq(RAX, RCX); |
| 1283 __ j(EQUAL, &is_true, Assembler::kNearJump); | 1275 __ j(EQUAL, &is_true, Assembler::kNearJump); |
| 1284 __ LoadObject(RAX, Bool::False()); | 1276 __ LoadObject(RAX, Bool::False()); |
| 1285 __ jmp(&done, Assembler::kNearJump); | 1277 __ jmp(&done, Assembler::kNearJump); |
| 1286 __ Bind(&is_true); | 1278 __ Bind(&is_true); |
| 1287 __ LoadObject(RAX, Bool::True()); | 1279 __ LoadObject(RAX, Bool::True()); |
| 1288 __ Bind(&done); | 1280 __ Bind(&done); |
| 1289 break; | 1281 break; |
| 1290 } | 1282 } |
| 1291 default: UNIMPLEMENTED(); | 1283 default: |
| 1284 UNIMPLEMENTED(); |
| 1292 } | 1285 } |
| 1293 | 1286 |
| 1294 // RBX: IC data object (preserved). | 1287 // RBX: IC data object (preserved). |
| 1295 __ movq(R13, FieldAddress(RBX, ICData::ic_data_offset())); | 1288 __ movq(R13, FieldAddress(RBX, ICData::ic_data_offset())); |
| 1296 // R13: ic_data_array with check entries: classes and target functions. | 1289 // R13: ic_data_array with check entries: classes and target functions. |
| 1297 __ leaq(R13, FieldAddress(R13, Array::data_offset())); | 1290 __ leaq(R13, FieldAddress(R13, Array::data_offset())); |
| 1298 // R13: points directly to the first ic data array element. | 1291 // R13: points directly to the first ic data array element. |
| 1299 #if defined(DEBUG) | 1292 #if defined(DEBUG) |
| 1300 // Check that first entry is for Smi/Smi. | 1293 // Check that first entry is for Smi/Smi. |
| 1301 Label error, ok; | 1294 Label error, ok; |
| 1302 const Immediate& imm_smi_cid = | 1295 const Immediate& imm_smi_cid = |
| 1303 Immediate(reinterpret_cast<intptr_t>(Smi::New(kSmiCid))); | 1296 Immediate(reinterpret_cast<intptr_t>(Smi::New(kSmiCid))); |
| 1304 __ cmpq(Address(R13, 0 * kWordSize), imm_smi_cid); | 1297 __ cmpq(Address(R13, 0 * kWordSize), imm_smi_cid); |
| 1305 __ j(NOT_EQUAL, &error, Assembler::kNearJump); | 1298 __ j(NOT_EQUAL, &error, Assembler::kNearJump); |
| 1306 __ cmpq(Address(R13, 1 * kWordSize), imm_smi_cid); | 1299 __ cmpq(Address(R13, 1 * kWordSize), imm_smi_cid); |
| 1307 __ j(EQUAL, &ok, Assembler::kNearJump); | 1300 __ j(EQUAL, &ok, Assembler::kNearJump); |
| 1308 __ Bind(&error); | 1301 __ Bind(&error); |
| (...skipping 26 matching lines...) Expand all Loading... |
| 1335 // - Match found -> jump to target. | 1328 // - Match found -> jump to target. |
| 1336 // - Match not found -> jump to IC miss. | 1329 // - Match not found -> jump to IC miss. |
| 1337 void StubCode::GenerateNArgsCheckInlineCacheStub( | 1330 void StubCode::GenerateNArgsCheckInlineCacheStub( |
| 1338 Assembler* assembler, | 1331 Assembler* assembler, |
| 1339 intptr_t num_args, | 1332 intptr_t num_args, |
| 1340 const RuntimeEntry& handle_ic_miss, | 1333 const RuntimeEntry& handle_ic_miss, |
| 1341 Token::Kind kind, | 1334 Token::Kind kind, |
| 1342 bool optimized) { | 1335 bool optimized) { |
| 1343 ASSERT(num_args > 0); | 1336 ASSERT(num_args > 0); |
| 1344 #if defined(DEBUG) | 1337 #if defined(DEBUG) |
| 1345 { Label ok; | 1338 { |
| 1339 Label ok; |
| 1346 // Check that the IC data array has NumArgsTested() == num_args. | 1340 // Check that the IC data array has NumArgsTested() == num_args. |
| 1347 // 'NumArgsTested' is stored in the least significant bits of 'state_bits'. | 1341 // 'NumArgsTested' is stored in the least significant bits of 'state_bits'. |
| 1348 __ movl(RCX, FieldAddress(RBX, ICData::state_bits_offset())); | 1342 __ movl(RCX, FieldAddress(RBX, ICData::state_bits_offset())); |
| 1349 ASSERT(ICData::NumArgsTestedShift() == 0); // No shift needed. | 1343 ASSERT(ICData::NumArgsTestedShift() == 0); // No shift needed. |
| 1350 __ andq(RCX, Immediate(ICData::NumArgsTestedMask())); | 1344 __ andq(RCX, Immediate(ICData::NumArgsTestedMask())); |
| 1351 __ cmpq(RCX, Immediate(num_args)); | 1345 __ cmpq(RCX, Immediate(num_args)); |
| 1352 __ j(EQUAL, &ok, Assembler::kNearJump); | 1346 __ j(EQUAL, &ok, Assembler::kNearJump); |
| 1353 __ Stop("Incorrect stub for IC data"); | 1347 __ Stop("Incorrect stub for IC data"); |
| 1354 __ Bind(&ok); | 1348 __ Bind(&ok); |
| 1355 } | 1349 } |
| 1356 #endif // DEBUG | 1350 #endif // DEBUG |
| 1357 | 1351 |
| 1358 Label stepping, done_stepping; | 1352 Label stepping, done_stepping; |
| 1359 if (FLAG_support_debugger && !optimized) { | 1353 if (FLAG_support_debugger && !optimized) { |
| 1360 __ Comment("Check single stepping"); | 1354 __ Comment("Check single stepping"); |
| 1361 __ LoadIsolate(RAX); | 1355 __ LoadIsolate(RAX); |
| 1362 __ cmpb(Address(RAX, Isolate::single_step_offset()), Immediate(0)); | 1356 __ cmpb(Address(RAX, Isolate::single_step_offset()), Immediate(0)); |
| 1363 __ j(NOT_EQUAL, &stepping); | 1357 __ j(NOT_EQUAL, &stepping); |
| 1364 __ Bind(&done_stepping); | 1358 __ Bind(&done_stepping); |
| 1365 } | 1359 } |
| 1366 | 1360 |
| 1367 Label not_smi_or_overflow; | 1361 Label not_smi_or_overflow; |
| 1368 if (kind != Token::kILLEGAL) { | 1362 if (kind != Token::kILLEGAL) { |
| 1369 EmitFastSmiOp( | 1363 EmitFastSmiOp(assembler, kind, num_args, ¬_smi_or_overflow); |
| 1370 assembler, | |
| 1371 kind, | |
| 1372 num_args, | |
| 1373 ¬_smi_or_overflow); | |
| 1374 } | 1364 } |
| 1375 __ Bind(¬_smi_or_overflow); | 1365 __ Bind(¬_smi_or_overflow); |
| 1376 | 1366 |
| 1377 __ Comment("Extract ICData initial values and receiver cid"); | 1367 __ Comment("Extract ICData initial values and receiver cid"); |
| 1378 // Load arguments descriptor into R10. | 1368 // Load arguments descriptor into R10. |
| 1379 __ movq(R10, FieldAddress(RBX, ICData::arguments_descriptor_offset())); | 1369 __ movq(R10, FieldAddress(RBX, ICData::arguments_descriptor_offset())); |
| 1380 // Loop that checks if there is an IC data match. | 1370 // Loop that checks if there is an IC data match. |
| 1381 Label loop, update, test, found; | 1371 Label loop, update, test, found; |
| 1382 // RBX: IC data object (preserved). | 1372 // RBX: IC data object (preserved). |
| 1383 __ movq(R13, FieldAddress(RBX, ICData::ic_data_offset())); | 1373 __ movq(R13, FieldAddress(RBX, ICData::ic_data_offset())); |
| 1384 // R13: ic_data_array with check entries: classes and target functions. | 1374 // R13: ic_data_array with check entries: classes and target functions. |
| 1385 __ leaq(R13, FieldAddress(R13, Array::data_offset())); | 1375 __ leaq(R13, FieldAddress(R13, Array::data_offset())); |
| 1386 // R13: points directly to the first ic data array element. | 1376 // R13: points directly to the first ic data array element. |
| 1387 | 1377 |
| 1388 // Get the receiver's class ID (first read number of arguments from | 1378 // Get the receiver's class ID (first read number of arguments from |
| 1389 // arguments descriptor array and then access the receiver from the stack). | 1379 // arguments descriptor array and then access the receiver from the stack). |
| 1390 __ movq(RAX, FieldAddress(R10, ArgumentsDescriptor::count_offset())); | 1380 __ movq(RAX, FieldAddress(R10, ArgumentsDescriptor::count_offset())); |
| 1391 __ movq(R9, Address(RSP, RAX, TIMES_4, 0)); // RAX (argument count) is Smi. | 1381 __ movq(R9, Address(RSP, RAX, TIMES_4, 0)); // RAX (argument count) is Smi. |
| 1392 __ LoadTaggedClassIdMayBeSmi(RAX, R9); | 1382 __ LoadTaggedClassIdMayBeSmi(RAX, R9); |
| 1393 // RAX: receiver's class ID as smi. | 1383 // RAX: receiver's class ID as smi. |
| 1394 __ movq(R9, Address(R13, 0)); // First class ID (Smi) to check. | 1384 __ movq(R9, Address(R13, 0)); // First class ID (Smi) to check. |
| 1395 __ jmp(&test); | 1385 __ jmp(&test); |
| 1396 | 1386 |
| 1397 __ Comment("ICData loop"); | 1387 __ Comment("ICData loop"); |
| 1398 __ Bind(&loop); | 1388 __ Bind(&loop); |
| 1399 for (int i = 0; i < num_args; i++) { | 1389 for (int i = 0; i < num_args; i++) { |
| 1400 if (i > 0) { | 1390 if (i > 0) { |
| 1401 // If not the first, load the next argument's class ID. | 1391 // If not the first, load the next argument's class ID. |
| 1402 __ movq(RAX, FieldAddress(R10, ArgumentsDescriptor::count_offset())); | 1392 __ movq(RAX, FieldAddress(R10, ArgumentsDescriptor::count_offset())); |
| 1403 __ movq(R9, Address(RSP, RAX, TIMES_4, - i * kWordSize)); | 1393 __ movq(R9, Address(RSP, RAX, TIMES_4, -i * kWordSize)); |
| 1404 __ LoadTaggedClassIdMayBeSmi(RAX, R9); | 1394 __ LoadTaggedClassIdMayBeSmi(RAX, R9); |
| 1405 // RAX: next argument class ID (smi). | 1395 // RAX: next argument class ID (smi). |
| 1406 __ movq(R9, Address(R13, i * kWordSize)); | 1396 __ movq(R9, Address(R13, i * kWordSize)); |
| 1407 // R9: next class ID to check (smi). | 1397 // R9: next class ID to check (smi). |
| 1408 } | 1398 } |
| 1409 __ cmpq(RAX, R9); // Class id match? | 1399 __ cmpq(RAX, R9); // Class id match? |
| 1410 if (i < (num_args - 1)) { | 1400 if (i < (num_args - 1)) { |
| 1411 __ j(NOT_EQUAL, &update); // Continue. | 1401 __ j(NOT_EQUAL, &update); // Continue. |
| 1412 } else { | 1402 } else { |
| 1413 // Last check, all checks before matched. | 1403 // Last check, all checks before matched. |
| 1414 __ j(EQUAL, &found); // Break. | 1404 __ j(EQUAL, &found); // Break. |
| 1415 } | 1405 } |
| 1416 } | 1406 } |
| 1417 __ Bind(&update); | 1407 __ Bind(&update); |
| 1418 // Reload receiver class ID. It has not been destroyed when num_args == 1. | 1408 // Reload receiver class ID. It has not been destroyed when num_args == 1. |
| 1419 if (num_args > 1) { | 1409 if (num_args > 1) { |
| 1420 __ movq(RAX, FieldAddress(R10, ArgumentsDescriptor::count_offset())); | 1410 __ movq(RAX, FieldAddress(R10, ArgumentsDescriptor::count_offset())); |
| 1421 __ movq(R9, Address(RSP, RAX, TIMES_4, 0)); | 1411 __ movq(R9, Address(RSP, RAX, TIMES_4, 0)); |
| 1422 __ LoadTaggedClassIdMayBeSmi(RAX, R9); | 1412 __ LoadTaggedClassIdMayBeSmi(RAX, R9); |
| 1423 } | 1413 } |
| 1424 | 1414 |
| 1425 const intptr_t entry_size = ICData::TestEntryLengthFor(num_args) * kWordSize; | 1415 const intptr_t entry_size = ICData::TestEntryLengthFor(num_args) * kWordSize; |
| 1426 __ addq(R13, Immediate(entry_size)); // Next entry. | 1416 __ addq(R13, Immediate(entry_size)); // Next entry. |
| 1427 __ movq(R9, Address(R13, 0)); // Next class ID. | 1417 __ movq(R9, Address(R13, 0)); // Next class ID. |
| 1428 | 1418 |
| 1429 __ Bind(&test); | 1419 __ Bind(&test); |
| 1430 __ cmpq(R9, Immediate(Smi::RawValue(kIllegalCid))); // Done? | 1420 __ cmpq(R9, Immediate(Smi::RawValue(kIllegalCid))); // Done? |
| 1431 __ j(NOT_EQUAL, &loop, Assembler::kNearJump); | 1421 __ j(NOT_EQUAL, &loop, Assembler::kNearJump); |
| 1432 | 1422 |
| 1433 __ Comment("IC miss"); | 1423 __ Comment("IC miss"); |
| 1434 // Compute address of arguments (first read number of arguments from | 1424 // Compute address of arguments (first read number of arguments from |
| 1435 // arguments descriptor array and then compute address on the stack). | 1425 // arguments descriptor array and then compute address on the stack). |
| 1436 __ movq(RAX, FieldAddress(R10, ArgumentsDescriptor::count_offset())); | 1426 __ movq(RAX, FieldAddress(R10, ArgumentsDescriptor::count_offset())); |
| 1437 __ leaq(RAX, Address(RSP, RAX, TIMES_4, 0)); // RAX is Smi. | 1427 __ leaq(RAX, Address(RSP, RAX, TIMES_4, 0)); // RAX is Smi. |
| 1438 __ EnterStubFrame(); | 1428 __ EnterStubFrame(); |
| 1439 __ pushq(R10); // Preserve arguments descriptor array. | 1429 __ pushq(R10); // Preserve arguments descriptor array. |
| 1440 __ pushq(RBX); // Preserve IC data object. | 1430 __ pushq(RBX); // Preserve IC data object. |
| 1441 __ pushq(Immediate(0)); // Result slot. | 1431 __ pushq(Immediate(0)); // Result slot. |
| 1442 // Push call arguments. | 1432 // Push call arguments. |
| 1443 for (intptr_t i = 0; i < num_args; i++) { | 1433 for (intptr_t i = 0; i < num_args; i++) { |
| 1444 __ movq(RCX, Address(RAX, -kWordSize * i)); | 1434 __ movq(RCX, Address(RAX, -kWordSize * i)); |
| 1445 __ pushq(RCX); | 1435 __ pushq(RCX); |
| 1446 } | 1436 } |
| 1447 __ pushq(RBX); // Pass IC data object. | 1437 __ pushq(RBX); // Pass IC data object. |
| 1448 __ CallRuntime(handle_ic_miss, num_args + 1); | 1438 __ CallRuntime(handle_ic_miss, num_args + 1); |
| 1449 // Remove the call arguments pushed earlier, including the IC data object. | 1439 // Remove the call arguments pushed earlier, including the IC data object. |
| 1450 for (intptr_t i = 0; i < num_args + 1; i++) { | 1440 for (intptr_t i = 0; i < num_args + 1; i++) { |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1504 // RBX: Inline cache data object. | 1494 // RBX: Inline cache data object. |
| 1505 // TOS(0): Return address. | 1495 // TOS(0): Return address. |
| 1506 // Inline cache data object structure: | 1496 // Inline cache data object structure: |
| 1507 // 0: function-name | 1497 // 0: function-name |
| 1508 // 1: N, number of arguments checked. | 1498 // 1: N, number of arguments checked. |
| 1509 // 2 .. (length - 1): group of checks, each check containing: | 1499 // 2 .. (length - 1): group of checks, each check containing: |
| 1510 // - N classes. | 1500 // - N classes. |
| 1511 // - 1 target function. | 1501 // - 1 target function. |
| 1512 void StubCode::GenerateOneArgCheckInlineCacheStub(Assembler* assembler) { | 1502 void StubCode::GenerateOneArgCheckInlineCacheStub(Assembler* assembler) { |
| 1513 GenerateUsageCounterIncrement(assembler, RCX); | 1503 GenerateUsageCounterIncrement(assembler, RCX); |
| 1514 GenerateNArgsCheckInlineCacheStub(assembler, 1, | 1504 GenerateNArgsCheckInlineCacheStub( |
| 1515 kInlineCacheMissHandlerOneArgRuntimeEntry, | 1505 assembler, 1, kInlineCacheMissHandlerOneArgRuntimeEntry, Token::kILLEGAL); |
| 1516 Token::kILLEGAL); | |
| 1517 } | 1506 } |
| 1518 | 1507 |
| 1519 | 1508 |
| 1520 void StubCode::GenerateTwoArgsCheckInlineCacheStub(Assembler* assembler) { | 1509 void StubCode::GenerateTwoArgsCheckInlineCacheStub(Assembler* assembler) { |
| 1521 GenerateUsageCounterIncrement(assembler, RCX); | 1510 GenerateUsageCounterIncrement(assembler, RCX); |
| 1522 GenerateNArgsCheckInlineCacheStub(assembler, 2, | 1511 GenerateNArgsCheckInlineCacheStub(assembler, 2, |
| 1523 kInlineCacheMissHandlerTwoArgsRuntimeEntry, | 1512 kInlineCacheMissHandlerTwoArgsRuntimeEntry, |
| 1524 Token::kILLEGAL); | 1513 Token::kILLEGAL); |
| 1525 } | 1514 } |
| 1526 | 1515 |
| 1527 | 1516 |
| 1528 void StubCode::GenerateSmiAddInlineCacheStub(Assembler* assembler) { | 1517 void StubCode::GenerateSmiAddInlineCacheStub(Assembler* assembler) { |
| 1529 GenerateUsageCounterIncrement(assembler, RCX); | 1518 GenerateUsageCounterIncrement(assembler, RCX); |
| 1530 GenerateNArgsCheckInlineCacheStub(assembler, 2, | 1519 GenerateNArgsCheckInlineCacheStub( |
| 1531 kInlineCacheMissHandlerTwoArgsRuntimeEntry, | 1520 assembler, 2, kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kADD); |
| 1532 Token::kADD); | |
| 1533 } | 1521 } |
| 1534 | 1522 |
| 1535 | 1523 |
| 1536 void StubCode::GenerateSmiSubInlineCacheStub(Assembler* assembler) { | 1524 void StubCode::GenerateSmiSubInlineCacheStub(Assembler* assembler) { |
| 1537 GenerateUsageCounterIncrement(assembler, RCX); | 1525 GenerateUsageCounterIncrement(assembler, RCX); |
| 1538 GenerateNArgsCheckInlineCacheStub(assembler, 2, | 1526 GenerateNArgsCheckInlineCacheStub( |
| 1539 kInlineCacheMissHandlerTwoArgsRuntimeEntry, | 1527 assembler, 2, kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kSUB); |
| 1540 Token::kSUB); | |
| 1541 } | 1528 } |
| 1542 | 1529 |
| 1543 | 1530 |
| 1544 void StubCode::GenerateSmiEqualInlineCacheStub(Assembler* assembler) { | 1531 void StubCode::GenerateSmiEqualInlineCacheStub(Assembler* assembler) { |
| 1545 GenerateUsageCounterIncrement(assembler, RCX); | 1532 GenerateUsageCounterIncrement(assembler, RCX); |
| 1546 GenerateNArgsCheckInlineCacheStub(assembler, 2, | 1533 GenerateNArgsCheckInlineCacheStub( |
| 1547 kInlineCacheMissHandlerTwoArgsRuntimeEntry, | 1534 assembler, 2, kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kEQ); |
| 1548 Token::kEQ); | |
| 1549 } | 1535 } |
| 1550 | 1536 |
| 1551 | 1537 |
| 1552 // Use inline cache data array to invoke the target or continue in inline | 1538 // Use inline cache data array to invoke the target or continue in inline |
| 1553 // cache miss handler. Stub for 1-argument check (receiver class). | 1539 // cache miss handler. Stub for 1-argument check (receiver class). |
| 1554 // RDI: function which counter needs to be incremented. | 1540 // RDI: function which counter needs to be incremented. |
| 1555 // RBX: Inline cache data object. | 1541 // RBX: Inline cache data object. |
| 1556 // TOS(0): Return address. | 1542 // TOS(0): Return address. |
| 1557 // Inline cache data object structure: | 1543 // Inline cache data object structure: |
| 1558 // 0: function-name | 1544 // 0: function-name |
| 1559 // 1: N, number of arguments checked. | 1545 // 1: N, number of arguments checked. |
| 1560 // 2 .. (length - 1): group of checks, each check containing: | 1546 // 2 .. (length - 1): group of checks, each check containing: |
| 1561 // - N classes. | 1547 // - N classes. |
| 1562 // - 1 target function. | 1548 // - 1 target function. |
| 1563 void StubCode::GenerateOneArgOptimizedCheckInlineCacheStub( | 1549 void StubCode::GenerateOneArgOptimizedCheckInlineCacheStub( |
| 1564 Assembler* assembler) { | 1550 Assembler* assembler) { |
| 1565 GenerateOptimizedUsageCounterIncrement(assembler); | 1551 GenerateOptimizedUsageCounterIncrement(assembler); |
| 1566 GenerateNArgsCheckInlineCacheStub(assembler, 1, | 1552 GenerateNArgsCheckInlineCacheStub(assembler, 1, |
| 1567 kInlineCacheMissHandlerOneArgRuntimeEntry, | 1553 kInlineCacheMissHandlerOneArgRuntimeEntry, |
| 1568 Token::kILLEGAL, | 1554 Token::kILLEGAL, true /* optimized */); |
| 1569 true /* optimized */); | |
| 1570 } | 1555 } |
| 1571 | 1556 |
| 1572 | 1557 |
| 1573 void StubCode::GenerateTwoArgsOptimizedCheckInlineCacheStub( | 1558 void StubCode::GenerateTwoArgsOptimizedCheckInlineCacheStub( |
| 1574 Assembler* assembler) { | 1559 Assembler* assembler) { |
| 1575 GenerateOptimizedUsageCounterIncrement(assembler); | 1560 GenerateOptimizedUsageCounterIncrement(assembler); |
| 1576 GenerateNArgsCheckInlineCacheStub(assembler, 2, | 1561 GenerateNArgsCheckInlineCacheStub(assembler, 2, |
| 1577 kInlineCacheMissHandlerTwoArgsRuntimeEntry, | 1562 kInlineCacheMissHandlerTwoArgsRuntimeEntry, |
| 1578 Token::kILLEGAL, | 1563 Token::kILLEGAL, true /* optimized */); |
| 1579 true /* optimized */); | |
| 1580 } | 1564 } |
| 1581 | 1565 |
| 1582 | 1566 |
| 1583 // Intermediary stub between a static call and its target. ICData contains | 1567 // Intermediary stub between a static call and its target. ICData contains |
| 1584 // the target function and the call count. | 1568 // the target function and the call count. |
| 1585 // RBX: ICData | 1569 // RBX: ICData |
| 1586 void StubCode::GenerateZeroArgsUnoptimizedStaticCallStub(Assembler* assembler) { | 1570 void StubCode::GenerateZeroArgsUnoptimizedStaticCallStub(Assembler* assembler) { |
| 1587 GenerateUsageCounterIncrement(assembler, RCX); | 1571 GenerateUsageCounterIncrement(assembler, RCX); |
| 1588 #if defined(DEBUG) | 1572 #if defined(DEBUG) |
| 1589 { Label ok; | 1573 { |
| 1574 Label ok; |
| 1590 // Check that the IC data array has NumArgsTested() == 0. | 1575 // Check that the IC data array has NumArgsTested() == 0. |
| 1591 // 'NumArgsTested' is stored in the least significant bits of 'state_bits'. | 1576 // 'NumArgsTested' is stored in the least significant bits of 'state_bits'. |
| 1592 __ movl(RCX, FieldAddress(RBX, ICData::state_bits_offset())); | 1577 __ movl(RCX, FieldAddress(RBX, ICData::state_bits_offset())); |
| 1593 ASSERT(ICData::NumArgsTestedShift() == 0); // No shift needed. | 1578 ASSERT(ICData::NumArgsTestedShift() == 0); // No shift needed. |
| 1594 __ andq(RCX, Immediate(ICData::NumArgsTestedMask())); | 1579 __ andq(RCX, Immediate(ICData::NumArgsTestedMask())); |
| 1595 __ cmpq(RCX, Immediate(0)); | 1580 __ cmpq(RCX, Immediate(0)); |
| 1596 __ j(EQUAL, &ok, Assembler::kNearJump); | 1581 __ j(EQUAL, &ok, Assembler::kNearJump); |
| 1597 __ Stop("Incorrect IC data for unoptimized static call"); | 1582 __ Stop("Incorrect IC data for unoptimized static call"); |
| 1598 __ Bind(&ok); | 1583 __ Bind(&ok); |
| 1599 } | 1584 } |
| 1600 #endif // DEBUG | 1585 #endif // DEBUG |
| 1601 | 1586 |
| 1602 // Check single stepping. | 1587 // Check single stepping. |
| 1603 Label stepping, done_stepping; | 1588 Label stepping, done_stepping; |
| 1604 if (FLAG_support_debugger) { | 1589 if (FLAG_support_debugger) { |
| 1605 __ LoadIsolate(RAX); | 1590 __ LoadIsolate(RAX); |
| 1606 __ movzxb(RAX, Address(RAX, Isolate::single_step_offset())); | 1591 __ movzxb(RAX, Address(RAX, Isolate::single_step_offset())); |
| 1607 __ cmpq(RAX, Immediate(0)); | 1592 __ cmpq(RAX, Immediate(0)); |
| 1608 #if defined(DEBUG) | 1593 #if defined(DEBUG) |
| 1609 static const bool kJumpLength = Assembler::kFarJump; | 1594 static const bool kJumpLength = Assembler::kFarJump; |
| 1610 #else | 1595 #else |
| 1611 static const bool kJumpLength = Assembler::kNearJump; | 1596 static const bool kJumpLength = Assembler::kNearJump; |
| 1612 #endif // DEBUG | 1597 #endif // DEBUG |
| 1613 __ j(NOT_EQUAL, &stepping, kJumpLength); | 1598 __ j(NOT_EQUAL, &stepping, kJumpLength); |
| 1614 __ Bind(&done_stepping); | 1599 __ Bind(&done_stepping); |
| 1615 } | 1600 } |
| 1616 | 1601 |
| 1617 // RBX: IC data object (preserved). | 1602 // RBX: IC data object (preserved). |
| 1618 __ movq(R12, FieldAddress(RBX, ICData::ic_data_offset())); | 1603 __ movq(R12, FieldAddress(RBX, ICData::ic_data_offset())); |
| 1619 // R12: ic_data_array with entries: target functions and count. | 1604 // R12: ic_data_array with entries: target functions and count. |
| 1620 __ leaq(R12, FieldAddress(R12, Array::data_offset())); | 1605 __ leaq(R12, FieldAddress(R12, Array::data_offset())); |
| 1621 // R12: points directly to the first ic data array element. | 1606 // R12: points directly to the first ic data array element. |
| (...skipping 27 matching lines...) Expand all Loading... |
| 1649 __ RestoreCodePointer(); | 1634 __ RestoreCodePointer(); |
| 1650 __ LeaveStubFrame(); | 1635 __ LeaveStubFrame(); |
| 1651 __ jmp(&done_stepping, Assembler::kNearJump); | 1636 __ jmp(&done_stepping, Assembler::kNearJump); |
| 1652 } | 1637 } |
| 1653 } | 1638 } |
| 1654 | 1639 |
| 1655 | 1640 |
| 1656 void StubCode::GenerateOneArgUnoptimizedStaticCallStub(Assembler* assembler) { | 1641 void StubCode::GenerateOneArgUnoptimizedStaticCallStub(Assembler* assembler) { |
| 1657 GenerateUsageCounterIncrement(assembler, RCX); | 1642 GenerateUsageCounterIncrement(assembler, RCX); |
| 1658 GenerateNArgsCheckInlineCacheStub( | 1643 GenerateNArgsCheckInlineCacheStub( |
| 1659 assembler, | 1644 assembler, 1, kStaticCallMissHandlerOneArgRuntimeEntry, Token::kILLEGAL); |
| 1660 1, | |
| 1661 kStaticCallMissHandlerOneArgRuntimeEntry, | |
| 1662 Token::kILLEGAL); | |
| 1663 } | 1645 } |
| 1664 | 1646 |
| 1665 | 1647 |
| 1666 void StubCode::GenerateTwoArgsUnoptimizedStaticCallStub(Assembler* assembler) { | 1648 void StubCode::GenerateTwoArgsUnoptimizedStaticCallStub(Assembler* assembler) { |
| 1667 GenerateUsageCounterIncrement(assembler, RCX); | 1649 GenerateUsageCounterIncrement(assembler, RCX); |
| 1668 GenerateNArgsCheckInlineCacheStub(assembler, | 1650 GenerateNArgsCheckInlineCacheStub( |
| 1669 2, | 1651 assembler, 2, kStaticCallMissHandlerTwoArgsRuntimeEntry, Token::kILLEGAL); |
| 1670 kStaticCallMissHandlerTwoArgsRuntimeEntry, | |
| 1671 Token::kILLEGAL); | |
| 1672 } | 1652 } |
| 1673 | 1653 |
| 1674 | 1654 |
| 1675 // Stub for compiling a function and jumping to the compiled code. | 1655 // Stub for compiling a function and jumping to the compiled code. |
| 1676 // RCX: IC-Data (for methods). | 1656 // RCX: IC-Data (for methods). |
| 1677 // R10: Arguments descriptor. | 1657 // R10: Arguments descriptor. |
| 1678 // RAX: Function. | 1658 // RAX: Function. |
| 1679 void StubCode::GenerateLazyCompileStub(Assembler* assembler) { | 1659 void StubCode::GenerateLazyCompileStub(Assembler* assembler) { |
| 1680 __ EnterStubFrame(); | 1660 __ EnterStubFrame(); |
| 1681 __ pushq(R10); // Preserve arguments descriptor array. | 1661 __ pushq(R10); // Preserve arguments descriptor array. |
| 1682 __ pushq(RBX); // Preserve IC data object. | 1662 __ pushq(RBX); // Preserve IC data object. |
| 1683 __ pushq(RAX); // Pass function. | 1663 __ pushq(RAX); // Pass function. |
| 1684 __ CallRuntime(kCompileFunctionRuntimeEntry, 1); | 1664 __ CallRuntime(kCompileFunctionRuntimeEntry, 1); |
| 1685 __ popq(RAX); // Restore function. | 1665 __ popq(RAX); // Restore function. |
| 1686 __ popq(RBX); // Restore IC data array. | 1666 __ popq(RBX); // Restore IC data array. |
| 1687 __ popq(R10); // Restore arguments descriptor array. | 1667 __ popq(R10); // Restore arguments descriptor array. |
| 1688 __ LeaveStubFrame(); | 1668 __ LeaveStubFrame(); |
| 1689 | 1669 |
| 1690 __ movq(CODE_REG, FieldAddress(RAX, Function::code_offset())); | 1670 __ movq(CODE_REG, FieldAddress(RAX, Function::code_offset())); |
| 1691 __ movq(RAX, FieldAddress(RAX, Function::entry_point_offset())); | 1671 __ movq(RAX, FieldAddress(RAX, Function::entry_point_offset())); |
| 1692 __ jmp(RAX); | 1672 __ jmp(RAX); |
| 1693 } | 1673 } |
| 1694 | 1674 |
| 1695 | 1675 |
| 1696 // RBX: Contains an ICData. | 1676 // RBX: Contains an ICData. |
| 1697 // TOS(0): return address (Dart code). | 1677 // TOS(0): return address (Dart code). |
| 1698 void StubCode::GenerateICCallBreakpointStub(Assembler* assembler) { | 1678 void StubCode::GenerateICCallBreakpointStub(Assembler* assembler) { |
| 1699 __ EnterStubFrame(); | 1679 __ EnterStubFrame(); |
| 1700 __ pushq(RBX); // Preserve IC data. | 1680 __ pushq(RBX); // Preserve IC data. |
| 1701 __ pushq(Immediate(0)); // Result slot. | 1681 __ pushq(Immediate(0)); // Result slot. |
| 1702 __ CallRuntime(kBreakpointRuntimeHandlerRuntimeEntry, 0); | 1682 __ CallRuntime(kBreakpointRuntimeHandlerRuntimeEntry, 0); |
| 1703 __ popq(CODE_REG); // Original stub. | 1683 __ popq(CODE_REG); // Original stub. |
| 1704 __ popq(RBX); // Restore IC data. | 1684 __ popq(RBX); // Restore IC data. |
| 1705 __ LeaveStubFrame(); | 1685 __ LeaveStubFrame(); |
| 1706 | 1686 |
| 1707 __ movq(RAX, FieldAddress(CODE_REG, Code::entry_point_offset())); | 1687 __ movq(RAX, FieldAddress(CODE_REG, Code::entry_point_offset())); |
| 1708 __ jmp(RAX); // Jump to original stub. | 1688 __ jmp(RAX); // Jump to original stub. |
| 1709 } | 1689 } |
| 1710 | 1690 |
| 1711 | 1691 |
| 1712 // TOS(0): return address (Dart code). | 1692 // TOS(0): return address (Dart code). |
| 1713 void StubCode::GenerateRuntimeCallBreakpointStub(Assembler* assembler) { | 1693 void StubCode::GenerateRuntimeCallBreakpointStub(Assembler* assembler) { |
| 1714 __ EnterStubFrame(); | 1694 __ EnterStubFrame(); |
| 1715 __ pushq(Immediate(0)); // Result slot. | 1695 __ pushq(Immediate(0)); // Result slot. |
| 1716 __ CallRuntime(kBreakpointRuntimeHandlerRuntimeEntry, 0); | 1696 __ CallRuntime(kBreakpointRuntimeHandlerRuntimeEntry, 0); |
| 1717 __ popq(CODE_REG); // Original stub. | 1697 __ popq(CODE_REG); // Original stub. |
| 1718 __ LeaveStubFrame(); | 1698 __ LeaveStubFrame(); |
| 1719 | 1699 |
| 1720 __ movq(RAX, FieldAddress(CODE_REG, Code::entry_point_offset())); | 1700 __ movq(RAX, FieldAddress(CODE_REG, Code::entry_point_offset())); |
| 1721 __ jmp(RAX); // Jump to original stub. | 1701 __ jmp(RAX); // Jump to original stub. |
| 1722 } | 1702 } |
| 1723 | 1703 |
| 1724 | 1704 |
| 1725 // Called only from unoptimized code. | 1705 // Called only from unoptimized code. |
| 1726 void StubCode::GenerateDebugStepCheckStub(Assembler* assembler) { | 1706 void StubCode::GenerateDebugStepCheckStub(Assembler* assembler) { |
| 1727 // Check single stepping. | 1707 // Check single stepping. |
| 1728 Label stepping, done_stepping; | 1708 Label stepping, done_stepping; |
| 1729 __ LoadIsolate(RAX); | 1709 __ LoadIsolate(RAX); |
| 1730 __ movzxb(RAX, Address(RAX, Isolate::single_step_offset())); | 1710 __ movzxb(RAX, Address(RAX, Isolate::single_step_offset())); |
| 1731 __ cmpq(RAX, Immediate(0)); | 1711 __ cmpq(RAX, Immediate(0)); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 1752 const intptr_t kInstantiatorTypeArgumentsInBytes = 1 * kWordSize; | 1732 const intptr_t kInstantiatorTypeArgumentsInBytes = 1 * kWordSize; |
| 1753 const intptr_t kInstanceOffsetInBytes = 2 * kWordSize; | 1733 const intptr_t kInstanceOffsetInBytes = 2 * kWordSize; |
| 1754 const intptr_t kCacheOffsetInBytes = 3 * kWordSize; | 1734 const intptr_t kCacheOffsetInBytes = 3 * kWordSize; |
| 1755 __ movq(RAX, Address(RSP, kInstanceOffsetInBytes)); | 1735 __ movq(RAX, Address(RSP, kInstanceOffsetInBytes)); |
| 1756 __ LoadObject(R9, Object::null_object()); | 1736 __ LoadObject(R9, Object::null_object()); |
| 1757 if (n > 1) { | 1737 if (n > 1) { |
| 1758 __ LoadClass(R10, RAX); | 1738 __ LoadClass(R10, RAX); |
| 1759 // Compute instance type arguments into R13. | 1739 // Compute instance type arguments into R13. |
| 1760 Label has_no_type_arguments; | 1740 Label has_no_type_arguments; |
| 1761 __ movq(R13, R9); | 1741 __ movq(R13, R9); |
| 1762 __ movl(RDI, FieldAddress(R10, | 1742 __ movl(RDI, |
| 1763 Class::type_arguments_field_offset_in_words_offset())); | 1743 FieldAddress(R10, |
| 1744 Class::type_arguments_field_offset_in_words_offset())); |
| 1764 __ cmpl(RDI, Immediate(Class::kNoTypeArguments)); | 1745 __ cmpl(RDI, Immediate(Class::kNoTypeArguments)); |
| 1765 __ j(EQUAL, &has_no_type_arguments, Assembler::kNearJump); | 1746 __ j(EQUAL, &has_no_type_arguments, Assembler::kNearJump); |
| 1766 __ movq(R13, FieldAddress(RAX, RDI, TIMES_8, 0)); | 1747 __ movq(R13, FieldAddress(RAX, RDI, TIMES_8, 0)); |
| 1767 __ Bind(&has_no_type_arguments); | 1748 __ Bind(&has_no_type_arguments); |
| 1768 } | 1749 } |
| 1769 __ LoadClassId(R10, RAX); | 1750 __ LoadClassId(R10, RAX); |
| 1770 // RAX: instance, R10: instance class id. | 1751 // RAX: instance, R10: instance class id. |
| 1771 // R13: instance type arguments or null, used only if n > 1. | 1752 // R13: instance type arguments or null, used only if n > 1. |
| 1772 __ movq(RDX, Address(RSP, kCacheOffsetInBytes)); | 1753 __ movq(RDX, Address(RSP, kCacheOffsetInBytes)); |
| 1773 // RDX: SubtypeTestCache. | 1754 // RDX: SubtypeTestCache. |
| 1774 __ movq(RDX, FieldAddress(RDX, SubtypeTestCache::cache_offset())); | 1755 __ movq(RDX, FieldAddress(RDX, SubtypeTestCache::cache_offset())); |
| 1775 __ addq(RDX, Immediate(Array::data_offset() - kHeapObjectTag)); | 1756 __ addq(RDX, Immediate(Array::data_offset() - kHeapObjectTag)); |
| 1776 // RDX: Entry start. | 1757 // RDX: Entry start. |
| 1777 // R10: instance class id. | 1758 // R10: instance class id. |
| 1778 // R13: instance type arguments. | 1759 // R13: instance type arguments. |
| 1779 Label loop, found, not_found, next_iteration; | 1760 Label loop, found, not_found, next_iteration; |
| 1780 __ SmiTag(R10); | 1761 __ SmiTag(R10); |
| 1781 __ cmpq(R10, Immediate(Smi::RawValue(kClosureCid))); | 1762 __ cmpq(R10, Immediate(Smi::RawValue(kClosureCid))); |
| 1782 __ j(NOT_EQUAL, &loop, Assembler::kNearJump); | 1763 __ j(NOT_EQUAL, &loop, Assembler::kNearJump); |
| 1783 __ movq(R10, FieldAddress(RAX, Closure::function_offset())); | 1764 __ movq(R10, FieldAddress(RAX, Closure::function_offset())); |
| 1784 // R10: instance class id as Smi or function. | 1765 // R10: instance class id as Smi or function. |
| 1785 __ Bind(&loop); | 1766 __ Bind(&loop); |
| 1786 __ movq(RDI, | 1767 __ movq(RDI, Address(RDX, kWordSize * |
| 1787 Address(RDX, | 1768 SubtypeTestCache::kInstanceClassIdOrFunction)); |
| 1788 kWordSize * SubtypeTestCache::kInstanceClassIdOrFunction)); | |
| 1789 __ cmpq(RDI, R9); | 1769 __ cmpq(RDI, R9); |
| 1790 __ j(EQUAL, ¬_found, Assembler::kNearJump); | 1770 __ j(EQUAL, ¬_found, Assembler::kNearJump); |
| 1791 __ cmpq(RDI, R10); | 1771 __ cmpq(RDI, R10); |
| 1792 if (n == 1) { | 1772 if (n == 1) { |
| 1793 __ j(EQUAL, &found, Assembler::kNearJump); | 1773 __ j(EQUAL, &found, Assembler::kNearJump); |
| 1794 } else { | 1774 } else { |
| 1795 __ j(NOT_EQUAL, &next_iteration, Assembler::kNearJump); | 1775 __ j(NOT_EQUAL, &next_iteration, Assembler::kNearJump); |
| 1796 __ movq(RDI, | 1776 __ movq(RDI, |
| 1797 Address(RDX, kWordSize * SubtypeTestCache::kInstanceTypeArguments)); | 1777 Address(RDX, kWordSize * SubtypeTestCache::kInstanceTypeArguments)); |
| 1798 __ cmpq(RDI, R13); | 1778 __ cmpq(RDI, R13); |
| 1799 if (n == 2) { | 1779 if (n == 2) { |
| 1800 __ j(EQUAL, &found, Assembler::kNearJump); | 1780 __ j(EQUAL, &found, Assembler::kNearJump); |
| 1801 } else { | 1781 } else { |
| 1802 __ j(NOT_EQUAL, &next_iteration, Assembler::kNearJump); | 1782 __ j(NOT_EQUAL, &next_iteration, Assembler::kNearJump); |
| 1803 __ movq(RDI, | 1783 __ movq(RDI, |
| 1804 Address(RDX, | 1784 Address(RDX, kWordSize * |
| 1805 kWordSize * SubtypeTestCache::kInstantiatorTypeArguments)); | 1785 SubtypeTestCache::kInstantiatorTypeArguments)); |
| 1806 __ cmpq(RDI, Address(RSP, kInstantiatorTypeArgumentsInBytes)); | 1786 __ cmpq(RDI, Address(RSP, kInstantiatorTypeArgumentsInBytes)); |
| 1807 __ j(EQUAL, &found, Assembler::kNearJump); | 1787 __ j(EQUAL, &found, Assembler::kNearJump); |
| 1808 } | 1788 } |
| 1809 } | 1789 } |
| 1810 | 1790 |
| 1811 __ Bind(&next_iteration); | 1791 __ Bind(&next_iteration); |
| 1812 __ addq(RDX, Immediate(kWordSize * SubtypeTestCache::kTestEntryLength)); | 1792 __ addq(RDX, Immediate(kWordSize * SubtypeTestCache::kTestEntryLength)); |
| 1813 __ jmp(&loop, Assembler::kNearJump); | 1793 __ jmp(&loop, Assembler::kNearJump); |
| 1814 // Fall through to not found. | 1794 // Fall through to not found. |
| 1815 __ Bind(¬_found); | 1795 __ Bind(¬_found); |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1888 Register stacktrace_reg = CallingConventions::kArg5Reg; | 1868 Register stacktrace_reg = CallingConventions::kArg5Reg; |
| 1889 __ movq(THR, CallingConventions::kArg6Reg); | 1869 __ movq(THR, CallingConventions::kArg6Reg); |
| 1890 #endif | 1870 #endif |
| 1891 __ movq(RBP, CallingConventions::kArg3Reg); | 1871 __ movq(RBP, CallingConventions::kArg3Reg); |
| 1892 __ movq(RSP, CallingConventions::kArg2Reg); | 1872 __ movq(RSP, CallingConventions::kArg2Reg); |
| 1893 __ movq(kStackTraceObjectReg, stacktrace_reg); | 1873 __ movq(kStackTraceObjectReg, stacktrace_reg); |
| 1894 __ movq(kExceptionObjectReg, CallingConventions::kArg4Reg); | 1874 __ movq(kExceptionObjectReg, CallingConventions::kArg4Reg); |
| 1895 // Set the tag. | 1875 // Set the tag. |
| 1896 __ movq(Assembler::VMTagAddress(), Immediate(VMTag::kDartTagId)); | 1876 __ movq(Assembler::VMTagAddress(), Immediate(VMTag::kDartTagId)); |
| 1897 // Clear top exit frame. | 1877 // Clear top exit frame. |
| 1898 __ movq(Address(THR, Thread::top_exit_frame_info_offset()), | 1878 __ movq(Address(THR, Thread::top_exit_frame_info_offset()), Immediate(0)); |
| 1899 Immediate(0)); | |
| 1900 // Restore the pool pointer. | 1879 // Restore the pool pointer. |
| 1901 __ RestoreCodePointer(); | 1880 __ RestoreCodePointer(); |
| 1902 __ LoadPoolPointer(PP); | 1881 __ LoadPoolPointer(PP); |
| 1903 __ jmp(CallingConventions::kArg1Reg); // Jump to the exception handler code. | 1882 __ jmp(CallingConventions::kArg1Reg); // Jump to the exception handler code. |
| 1904 } | 1883 } |
| 1905 | 1884 |
| 1906 | 1885 |
| 1907 // Calls to the runtime to optimize the given function. | 1886 // Calls to the runtime to optimize the given function. |
| 1908 // RDI: function to be reoptimized. | 1887 // RDI: function to be reoptimized. |
| 1909 // R10: argument descriptor (preserved). | 1888 // R10: argument descriptor (preserved). |
| 1910 void StubCode::GenerateOptimizeFunctionStub(Assembler* assembler) { | 1889 void StubCode::GenerateOptimizeFunctionStub(Assembler* assembler) { |
| 1911 __ EnterStubFrame(); | 1890 __ EnterStubFrame(); |
| 1912 __ pushq(R10); // Preserve args descriptor. | 1891 __ pushq(R10); // Preserve args descriptor. |
| 1913 __ pushq(Immediate(0)); // Result slot. | 1892 __ pushq(Immediate(0)); // Result slot. |
| 1914 __ pushq(RDI); // Arg0: function to optimize | 1893 __ pushq(RDI); // Arg0: function to optimize |
| 1915 __ CallRuntime(kOptimizeInvokedFunctionRuntimeEntry, 1); | 1894 __ CallRuntime(kOptimizeInvokedFunctionRuntimeEntry, 1); |
| 1916 __ popq(RAX); // Disard argument. | 1895 __ popq(RAX); // Disard argument. |
| 1917 __ popq(RAX); // Get Code object. | 1896 __ popq(RAX); // Get Code object. |
| 1918 __ popq(R10); // Restore argument descriptor. | 1897 __ popq(R10); // Restore argument descriptor. |
| 1919 __ LeaveStubFrame(); | 1898 __ LeaveStubFrame(); |
| 1920 __ movq(CODE_REG, FieldAddress(RAX, Function::code_offset())); | 1899 __ movq(CODE_REG, FieldAddress(RAX, Function::code_offset())); |
| 1921 __ movq(RCX, FieldAddress(RAX, Function::entry_point_offset())); | 1900 __ movq(RCX, FieldAddress(RAX, Function::entry_point_offset())); |
| 1922 __ jmp(RCX); | 1901 __ jmp(RCX); |
| 1923 __ int3(); | 1902 __ int3(); |
| 1924 } | 1903 } |
| (...skipping 342 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2267 } | 2246 } |
| 2268 | 2247 |
| 2269 | 2248 |
| 2270 void StubCode::GenerateFrameAwaitingMaterializationStub(Assembler* assembler) { | 2249 void StubCode::GenerateFrameAwaitingMaterializationStub(Assembler* assembler) { |
| 2271 __ int3(); | 2250 __ int3(); |
| 2272 } | 2251 } |
| 2273 | 2252 |
| 2274 } // namespace dart | 2253 } // namespace dart |
| 2275 | 2254 |
| 2276 #endif // defined TARGET_ARCH_X64 | 2255 #endif // defined TARGET_ARCH_X64 |
| OLD | NEW |