OLD | NEW |
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, 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/native_entry.h" | 8 #include "vm/code_generator.h" |
| 9 #include "vm/compiler.h" |
| 10 #include "vm/ic_data.h" |
| 11 #include "vm/object_store.h" |
| 12 #include "vm/pages.h" |
| 13 #include "vm/resolver.h" |
| 14 #include "vm/scavenger.h" |
9 #include "vm/stub_code.h" | 15 #include "vm/stub_code.h" |
10 | 16 |
| 17 |
11 #define __ assembler-> | 18 #define __ assembler-> |
12 | 19 |
13 namespace dart { | 20 namespace dart { |
14 | 21 |
| 22 DEFINE_FLAG(bool, inline_alloc, true, "Inline allocation of objects."); |
| 23 DEFINE_FLAG(bool, use_slow_path, false, |
| 24 "Set to true for debugging & verifying the slow paths."); |
| 25 |
15 // Input parameters: | 26 // Input parameters: |
16 // RSP : points to return address. | 27 // RSP : points to return address. |
17 // RSP + 8 : address of last argument in argument array. | 28 // RSP + 8 : address of last argument in argument array. |
18 // RSP + 8*R10 : address of first argument in argument array. | 29 // RSP + 8*R10 : address of first argument in argument array. |
19 // RSP + 8*R10 + 8 : address of return value. | 30 // RSP + 8*R10 + 8 : address of return value. |
20 // RBX : address of the runtime function to call. | 31 // RBX : address of the runtime function to call. |
21 // R10 : number of arguments to the call. | 32 // R10 : number of arguments to the call. |
| 33 // Must preserve callee saved registers R12 and R13. |
22 static void GenerateCallRuntimeStub(Assembler* assembler) { | 34 static void GenerateCallRuntimeStub(Assembler* assembler) { |
| 35 ASSERT((R12 != CTX) && (R13 != CTX)); |
23 const intptr_t isolate_offset = NativeArguments::isolate_offset(); | 36 const intptr_t isolate_offset = NativeArguments::isolate_offset(); |
24 const intptr_t argc_offset = NativeArguments::argc_offset(); | 37 const intptr_t argc_offset = NativeArguments::argc_offset(); |
25 const intptr_t argv_offset = NativeArguments::argv_offset(); | 38 const intptr_t argv_offset = NativeArguments::argv_offset(); |
26 const intptr_t retval_offset = NativeArguments::retval_offset(); | 39 const intptr_t retval_offset = NativeArguments::retval_offset(); |
27 | 40 |
28 __ EnterFrame(0); | 41 __ EnterFrame(0); |
29 | 42 |
30 // Load current Isolate pointer from Context structure into RAX. | 43 // Load current Isolate pointer from Context structure into RAX. |
31 __ movq(RAX, FieldAddress(CTX, Context::isolate_offset())); | 44 __ movq(RAX, FieldAddress(CTX, Context::isolate_offset())); |
32 | 45 |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
74 } | 87 } |
75 | 88 |
76 | 89 |
77 // Input parameters: | 90 // Input parameters: |
78 // RSP : points to return address. | 91 // RSP : points to return address. |
79 // RSP + 8 : address of last argument in argument array. | 92 // RSP + 8 : address of last argument in argument array. |
80 // RSP + 8*R10 : address of first argument in argument array. | 93 // RSP + 8*R10 : address of first argument in argument array. |
81 // RSP + 8*R10 + 8 : address of return value. | 94 // RSP + 8*R10 + 8 : address of return value. |
82 // RBX : address of the runtime function to call. | 95 // RBX : address of the runtime function to call. |
83 // R10 : number of arguments to the call. | 96 // R10 : number of arguments to the call. |
| 97 // Must preserve callee saved registers R12 and R13. |
84 void StubCode::GenerateDartCallToRuntimeStub(Assembler* assembler) { | 98 void StubCode::GenerateDartCallToRuntimeStub(Assembler* assembler) { |
85 GenerateCallRuntimeStub(assembler); | 99 GenerateCallRuntimeStub(assembler); |
86 } | 100 } |
87 | 101 |
88 | 102 |
89 // Input parameters: | 103 // Input parameters: |
90 // RSP : points to return address. | 104 // RSP : points to return address. |
91 // RSP + 8 : address of last argument in argument array. | 105 // RSP + 8 : address of last argument in argument array. |
92 // RSP + 8*R10 : address of first argument in argument array. | 106 // RSP + 8*R10 : address of first argument in argument array. |
93 // RSP + 8*R10 + 8 : address of return value. | 107 // RSP + 8*R10 + 8 : address of return value. |
94 // RBX : address of the runtime function to call. | 108 // RBX : address of the runtime function to call. |
95 // R10 : number of arguments to the call. | 109 // R10 : number of arguments to the call. |
| 110 // Must preserve callee saved registers R12 and R13. |
96 void StubCode::GenerateStubCallToRuntimeStub(Assembler* assembler) { | 111 void StubCode::GenerateStubCallToRuntimeStub(Assembler* assembler) { |
97 GenerateCallRuntimeStub(assembler); | 112 GenerateCallRuntimeStub(assembler); |
98 } | 113 } |
99 | 114 |
100 | 115 |
101 // Input parameters: | 116 // Input parameters: |
102 // RSP : points to return address. | 117 // RSP : points to return address. |
103 // RSP + 8 : address of return value. | 118 // RSP + 8 : address of return value. |
104 // RAX : address of first argument in argument array. | 119 // RAX : address of first argument in argument array. |
105 // RAX - 8*R10 + 8 : address of last argument in argument array. | 120 // RAX - 8*R10 + 8 : address of last argument in argument array. |
106 // RBX : address of the native function to call. | 121 // RBX : address of the native function to call. |
107 // R10 : number of arguments to the call. | 122 // R10 : number of arguments to the call. |
| 123 // Uses R8. |
108 void StubCode::GenerateCallNativeCFunctionStub(Assembler* assembler) { | 124 void StubCode::GenerateCallNativeCFunctionStub(Assembler* assembler) { |
109 const intptr_t native_args_struct_offset = 0; | 125 const intptr_t native_args_struct_offset = 0; |
110 const intptr_t isolate_offset = | 126 const intptr_t isolate_offset = |
111 NativeArguments::isolate_offset() + native_args_struct_offset; | 127 NativeArguments::isolate_offset() + native_args_struct_offset; |
112 const intptr_t argc_offset = | 128 const intptr_t argc_offset = |
113 NativeArguments::argc_offset() + native_args_struct_offset; | 129 NativeArguments::argc_offset() + native_args_struct_offset; |
114 const intptr_t argv_offset = | 130 const intptr_t argv_offset = |
115 NativeArguments::argv_offset() + native_args_struct_offset; | 131 NativeArguments::argv_offset() + native_args_struct_offset; |
116 const intptr_t retval_offset = | 132 const intptr_t retval_offset = |
117 NativeArguments::retval_offset() + native_args_struct_offset; | 133 NativeArguments::retval_offset() + native_args_struct_offset; |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
160 __ movq(Address(CTX, Isolate::top_context_offset()), raw_null); | 176 __ movq(Address(CTX, Isolate::top_context_offset()), raw_null); |
161 | 177 |
162 // Cache Context pointer into CTX while executing Dart code. | 178 // Cache Context pointer into CTX while executing Dart code. |
163 __ movq(CTX, R8); | 179 __ movq(CTX, R8); |
164 | 180 |
165 __ LeaveFrame(); | 181 __ LeaveFrame(); |
166 __ ret(); | 182 __ ret(); |
167 } | 183 } |
168 | 184 |
169 | 185 |
| 186 // Input parameters: |
| 187 // RBX: function object. |
| 188 // R10: arguments descriptor array (num_args is first Smi element). |
170 void StubCode::GenerateCallStaticFunctionStub(Assembler* assembler) { | 189 void StubCode::GenerateCallStaticFunctionStub(Assembler* assembler) { |
171 __ Unimplemented("CallStaticFunction stub"); | 190 const Immediate raw_null = |
| 191 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 192 |
| 193 __ movq(RAX, FieldAddress(RBX, Function::code_offset())); |
| 194 __ cmpq(RAX, raw_null); |
| 195 Label function_compiled; |
| 196 __ j(NOT_EQUAL, &function_compiled, Assembler::kNearJump); |
| 197 |
| 198 // Create a stub frame as we are pushing some objects on the stack before |
| 199 // calling into the runtime. |
| 200 __ EnterFrame(0); |
| 201 |
| 202 __ pushq(R10); // Preserve arguments descriptor array. |
| 203 __ pushq(RBX); |
| 204 __ CallRuntimeFromStub(kCompileFunctionRuntimeEntry); |
| 205 __ popq(RBX); // Restore read-only function object argument in RBX. |
| 206 __ popq(R10); // Restore arguments descriptor array. |
| 207 // Restore RAX. |
| 208 __ movq(RAX, FieldAddress(RBX, Function::code_offset())); |
| 209 |
| 210 // Remove the stub frame as we are about to jump to the dart function. |
| 211 __ LeaveFrame(); |
| 212 |
| 213 __ Bind(&function_compiled); |
| 214 // Patch caller. |
| 215 __ EnterFrame(0); |
| 216 |
| 217 __ pushq(R10); // Preserve arguments descriptor array. |
| 218 __ pushq(RBX); // Preserve function object. |
| 219 __ CallRuntimeFromStub(kPatchStaticCallRuntimeEntry); |
| 220 __ popq(RBX); // Restore function object argument in RBX. |
| 221 __ popq(R10); // Restore arguments descriptor array. |
| 222 // Remove the stub frame as we are about to jump to the dart function. |
| 223 __ LeaveFrame(); |
| 224 __ movq(RAX, FieldAddress(RBX, Function::code_offset())); |
| 225 |
| 226 __ movq(RBX, FieldAddress(RAX, Code::instructions_offset())); |
| 227 __ addq(RBX, Immediate(Instructions::HeaderSize() - kHeapObjectTag)); |
| 228 __ jmp(RBX); |
172 } | 229 } |
173 | 230 |
174 | 231 |
175 void StubCode::GenerateOptimizeInvokedFunctionStub(Assembler* assembler) { | 232 void StubCode::GenerateOptimizeInvokedFunctionStub(Assembler* assembler) { |
176 __ Unimplemented("OptimizeInvokedFunction stub"); | 233 __ Unimplemented("OptimizeInvokedFunction stub"); |
177 } | 234 } |
178 | 235 |
179 | 236 |
180 void StubCode::GenerateFixCallersTargetStub(Assembler* assembler) { | 237 void StubCode::GenerateFixCallersTargetStub(Assembler* assembler) { |
181 __ Unimplemented("FixCallersTarget stub"); | 238 __ Unimplemented("FixCallersTarget stub"); |
182 } | 239 } |
183 | 240 |
184 | 241 |
| 242 // Lookup for [function-name, arg count] in 'functions_map_'. |
| 243 // Input parameters (to be treated as read only, unless calling to target!): |
| 244 // RBX: ic-data array. |
| 245 // R10: arguments descriptor array (num_args is first Smi element). |
| 246 // Stack: return address, arguments. |
| 247 // If the lookup succeeds we jump to the target method from here, otherwise |
| 248 // we continue in code generated by the caller of 'MegamorphicLookup'. |
| 249 static void MegamorphicLookup(Assembler* assembler) { |
| 250 const Immediate raw_null = |
| 251 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 252 Label class_in_rax, smi_receiver, null_receiver, not_found; |
| 253 // Total number of args is the first Smi in args descriptor array (R10). |
| 254 __ movq(RAX, FieldAddress(R10, Array::data_offset())); |
| 255 __ movq(RAX, Address(RSP, RAX, TIMES_4, 0)); // Get receiver. RAX is a Smi. |
| 256 // TODO(srdjan): Remove the special casing below for null receiver, once |
| 257 // NullClass is implemented. |
| 258 __ cmpq(RAX, raw_null); |
| 259 // Use Object class if receiver is null. |
| 260 __ j(EQUAL, &null_receiver, Assembler::kNearJump); |
| 261 __ testq(RAX, Immediate(kSmiTagMask)); |
| 262 __ j(ZERO, &smi_receiver, Assembler::kNearJump); |
| 263 __ movq(RAX, FieldAddress(RAX, Object::class_offset())); |
| 264 __ jmp(&class_in_rax, Assembler::kNearJump); |
| 265 __ Bind(&smi_receiver); |
| 266 // For Smis we need to get the class from the isolate. |
| 267 // Load current Isolate pointer from Context structure into RAX. |
| 268 __ movq(RAX, FieldAddress(CTX, Context::isolate_offset())); |
| 269 __ movq(RAX, Address(RAX, Isolate::object_store_offset())); |
| 270 __ movq(RAX, Address(RAX, ObjectStore::smi_class_offset())); |
| 271 __ jmp(&class_in_rax, Assembler::kNearJump); |
| 272 __ Bind(&null_receiver); |
| 273 __ movq(RAX, FieldAddress(CTX, Context::isolate_offset())); |
| 274 __ movq(RAX, Address(RAX, Isolate::object_store_offset())); |
| 275 __ movq(RAX, Address(RAX, ObjectStore::object_class_offset())); |
| 276 |
| 277 __ Bind(&class_in_rax); |
| 278 // Class is in RAX. |
| 279 |
| 280 Label loop, next_iteration; |
| 281 // Get functions_cache, since it is allocated lazily it maybe null. |
| 282 __ movq(RAX, FieldAddress(RAX, Class::functions_cache_offset())); |
| 283 // Iterate and search for identical name. |
| 284 __ leaq(R12, FieldAddress(RAX, Array::data_offset())); |
| 285 |
| 286 // R12 is pointing into content of functions_map_ array. |
| 287 __ Bind(&loop); |
| 288 __ movq(R13, Address(R12, FunctionsCache::kFunctionName * kWordSize)); |
| 289 |
| 290 __ cmpq(R13, raw_null); |
| 291 __ j(EQUAL, ¬_found, Assembler::kNearJump); |
| 292 |
| 293 ASSERT(ICData::kNameIndex == 0); |
| 294 __ cmpq(R13, FieldAddress(RBX, Array::data_offset())); |
| 295 __ j(NOT_EQUAL, &next_iteration, Assembler::kNearJump); |
| 296 |
| 297 // Name found, check total argument count and named argument count. |
| 298 __ movq(RAX, FieldAddress(R10, Array::data_offset())); |
| 299 // RAX is total argument count as Smi. |
| 300 __ movq(R13, Address(R12, FunctionsCache::kArgCount * kWordSize)); |
| 301 __ cmpq(RAX, R13); // Compare total argument counts. |
| 302 __ j(NOT_EQUAL, &next_iteration, Assembler::kNearJump); |
| 303 __ subq(RAX, FieldAddress(R10, Array::data_offset() + kWordSize)); |
| 304 // RAX is named argument count as Smi. |
| 305 __ movq(R13, Address(R12, FunctionsCache::kNamedArgCount * kWordSize)); |
| 306 __ cmpq(RAX, R13); // Compare named argument counts. |
| 307 __ j(NOT_EQUAL, &next_iteration, Assembler::kNearJump); |
| 308 |
| 309 // Argument count matches, jump to target. |
| 310 // R10: arguments descriptor array. |
| 311 __ movq(RBX, Address(R12, FunctionsCache::kFunction * kWordSize)); |
| 312 __ movq(RBX, FieldAddress(RBX, Function::code_offset())); |
| 313 __ movq(RBX, FieldAddress(RBX, Code::instructions_offset())); |
| 314 __ addq(RBX, Immediate(Instructions::HeaderSize() - kHeapObjectTag)); |
| 315 __ jmp(RBX); |
| 316 |
| 317 __ Bind(&next_iteration); |
| 318 __ AddImmediate(R12, Immediate(FunctionsCache::kNumEntries * kWordSize)); |
| 319 __ jmp(&loop, Assembler::kNearJump); |
| 320 |
| 321 __ Bind(¬_found); |
| 322 } |
| 323 |
| 324 |
| 325 // Input parameters: |
| 326 // R13: argument count, may be zero. |
| 327 // Uses RAX, RBX, R10, R12. |
| 328 static void PushArgumentsArray(Assembler* assembler, intptr_t arg_offset) { |
| 329 const Immediate raw_null = |
| 330 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 331 |
| 332 // Allocate array to store arguments of caller. |
| 333 __ movq(R10, R13); // Arguments array length. |
| 334 __ SmiTag(R10); // Convert to Smi. |
| 335 __ movq(RBX, raw_null); // Null element type for raw Array. |
| 336 __ call(&StubCode::AllocateArrayLabel()); |
| 337 __ SmiUntag(R10); |
| 338 // RAX: newly allocated array. |
| 339 // R10: length of the array (was preserved by the stub). |
| 340 __ pushq(RAX); // Array is in RAX and on top of stack. |
| 341 __ leaq(R12, Address(RSP, R10, TIMES_8, arg_offset)); // Addr of first arg. |
| 342 __ leaq(RBX, FieldAddress(RAX, Array::data_offset())); |
| 343 Label loop, loop_condition; |
| 344 __ jmp(&loop_condition, Assembler::kNearJump); |
| 345 __ Bind(&loop); |
| 346 __ movq(RAX, Address(R12, 0)); |
| 347 __ movq(Address(RBX, 0), RAX); |
| 348 __ AddImmediate(RBX, Immediate(kWordSize)); |
| 349 __ AddImmediate(R12, Immediate(-kWordSize)); |
| 350 __ Bind(&loop_condition); |
| 351 __ decq(R10); |
| 352 __ j(POSITIVE, &loop, Assembler::kNearJump); |
| 353 } |
| 354 |
| 355 |
| 356 // Input parameters: |
| 357 // RBX: ic-data array. |
| 358 // R10: arguments descriptor array (num_args is first Smi element). |
| 359 // Note: The receiver object is the first argument to the function being |
| 360 // called, the stub accesses the receiver from this location directly |
| 361 // when trying to resolve the call. |
| 362 // Uses R13. |
185 void StubCode::GenerateMegamorphicLookupStub(Assembler* assembler) { | 363 void StubCode::GenerateMegamorphicLookupStub(Assembler* assembler) { |
186 __ Unimplemented("MegamorphicLookup stub"); | 364 const Immediate raw_null = |
| 365 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 366 |
| 367 MegamorphicLookup(assembler); |
| 368 // Lookup in function_table_ failed, resolve, compile and enter function |
| 369 // into function_table_. |
| 370 |
| 371 // Create a stub frame as we are pushing some objects on the stack before |
| 372 // calling into the runtime. |
| 373 __ EnterFrame(0); |
| 374 |
| 375 // Preserve values across call to resolving. |
| 376 // Stack at this point: |
| 377 // TOS + 0: Saved RBP of previous frame. <== RBP |
| 378 // TOS + 1: Dart code return address |
| 379 // TOS + 2: Last argument of caller. |
| 380 // .... |
| 381 // Total number of args is the first Smi in args descriptor array (R10). |
| 382 __ movq(RAX, FieldAddress(R10, Array::data_offset())); |
| 383 __ movq(RAX, Address(RSP, RAX, TIMES_4, kWordSize)); // Get receiver. |
| 384 __ pushq(R10); // Preserve arguments descriptor array. |
| 385 __ pushq(RAX); // Preserve receiver. |
| 386 __ pushq(RBX); // Preserve ic-data array. |
| 387 // First resolve the function to get the function object. |
| 388 |
| 389 // Setup space for return value on stack by pushing smi 0. |
| 390 __ pushq(Immediate(0)); |
| 391 __ pushq(RAX); // Push receiver. |
| 392 __ CallRuntimeFromStub(kResolveCompileInstanceFunctionRuntimeEntry); |
| 393 __ popq(RAX); // Remove receiver pushed earlier. |
| 394 __ popq(RBX); // Pop returned code object into RBX. |
| 395 // Pop preserved values |
| 396 __ popq(R10); // Restore ic-data array. |
| 397 __ popq(RAX); // Restore receiver. |
| 398 __ popq(R13); // Restore arguments descriptor array. |
| 399 |
| 400 __ cmpq(RBX, raw_null); |
| 401 Label check_implicit_closure; |
| 402 __ j(EQUAL, &check_implicit_closure, Assembler::kNearJump); |
| 403 |
| 404 // Remove the stub frame as we are about to jump to the dart function. |
| 405 __ LeaveFrame(); |
| 406 |
| 407 __ movq(R10, R13); |
| 408 __ movq(RBX, FieldAddress(RBX, Code::instructions_offset())); |
| 409 __ addq(RBX, Immediate(Instructions::HeaderSize() - kHeapObjectTag)); |
| 410 __ jmp(RBX); |
| 411 |
| 412 __ Bind(&check_implicit_closure); |
| 413 // RAX: receiver. |
| 414 // R10: ic-data array. |
| 415 // RBX: raw_null. |
| 416 // R13: arguments descriptor array. |
| 417 // The target function was not found. |
| 418 // First check to see if this is a getter function and we are |
| 419 // trying to create a closure of an instance function. |
| 420 // Push values that need to be preserved across runtime call. |
| 421 __ pushq(RAX); // Preserve receiver. |
| 422 __ pushq(R10); // Preserve ic-data array. |
| 423 __ pushq(R13); // Preserve arguments descriptor array. |
| 424 |
| 425 __ pushq(Immediate(0)); |
| 426 __ pushq(RAX); // Push receiver. |
| 427 __ pushq(R10); // Ic-data array. |
| 428 __ CallRuntimeFromStub(kResolveImplicitClosureFunctionRuntimeEntry); |
| 429 __ popq(RAX); |
| 430 __ popq(RAX); |
| 431 __ popq(RBX); // Get return value into RBX, might be Closure object. |
| 432 |
| 433 // Pop preserved values. |
| 434 __ popq(R13); // Restore arguments descriptor array. |
| 435 __ popq(R10); // Restore ic-data array. |
| 436 __ popq(RAX); // Restore receiver. |
| 437 |
| 438 __ cmpq(RBX, raw_null); |
| 439 Label check_implicit_closure_through_getter; |
| 440 __ j(EQUAL, &check_implicit_closure_through_getter, Assembler::kNearJump); |
| 441 |
| 442 __ movq(RAX, RBX); // Return value is the closure object. |
| 443 // Remove the stub frame as we are about return. |
| 444 __ LeaveFrame(); |
| 445 __ ret(); |
| 446 |
| 447 __ Bind(&check_implicit_closure_through_getter); |
| 448 // RAX: receiver. |
| 449 // R10: ic-data array. |
| 450 // RBX: raw_null. |
| 451 // R13: arguments descriptor array. |
| 452 // This is not the case of an instance so invoke the getter of the |
| 453 // same name and see if we get a closure back which we are then |
| 454 // supposed to invoke. |
| 455 // Push values that need to be preserved across runtime call. |
| 456 __ pushq(RAX); // Preserve receiver. |
| 457 __ pushq(R10); // Preserve ic-data array. |
| 458 __ pushq(R13); // Preserve arguments descriptor array. |
| 459 |
| 460 __ pushq(Immediate(0)); |
| 461 __ pushq(RAX); // Push receiver. |
| 462 __ pushq(R10); // Ic-data array. |
| 463 __ CallRuntimeFromStub(kResolveImplicitClosureThroughGetterRuntimeEntry); |
| 464 __ popq(R10); // Pop argument. |
| 465 __ popq(RAX); // Pop argument. |
| 466 __ popq(RBX); // get return value into RBX, might be Closure object. |
| 467 |
| 468 // Pop preserved values. |
| 469 __ popq(R13); // Restore arguments descriptor array. |
| 470 __ popq(R10); // Restore ic-data array. |
| 471 __ popq(RAX); // Restore receiver. |
| 472 |
| 473 __ cmpq(RBX, raw_null); |
| 474 Label function_not_found; |
| 475 __ j(EQUAL, &function_not_found, Assembler::kNearJump); |
| 476 |
| 477 // RBX: Closure object. |
| 478 // R13: Arguments descriptor array. |
| 479 __ pushq(Immediate(0)); // Result from invoking Closure. |
| 480 __ pushq(RBX); // Closure object. |
| 481 __ pushq(R13); // Arguments descriptor. |
| 482 __ movq(R13, FieldAddress(R13, Array::data_offset())); |
| 483 __ SmiUntag(R13); |
| 484 __ subq(R13, Immediate(1)); // Arguments array length, minus the receiver. |
| 485 PushArgumentsArray(assembler, (kWordSize * 5)); |
| 486 // Stack layout explaining "(kWordSize * 5)" offset. |
| 487 // TOS + 0: Argument array. |
| 488 // TOS + 1: Arguments descriptor array. |
| 489 // TOS + 2: Closure object. |
| 490 // TOS + 3: Place for result from closure function. |
| 491 // TOS + 4: Saved RBP of previous frame. <== RBP |
| 492 // TOS + 5: Dart code return address |
| 493 // TOS + 6: Last argument of caller. |
| 494 // .... |
| 495 |
| 496 __ CallRuntimeFromStub(kInvokeImplicitClosureFunctionRuntimeEntry); |
| 497 // Remove arguments. |
| 498 __ popq(RAX); |
| 499 __ popq(RAX); |
| 500 __ popq(RAX); |
| 501 __ popq(RAX); // Get result into RAX. |
| 502 |
| 503 // Remove the stub frame as we are about to return. |
| 504 __ LeaveFrame(); |
| 505 __ ret(); |
| 506 |
| 507 __ Bind(&function_not_found); |
| 508 // The target function was not found, so invoke method |
| 509 // "void noSuchMethod(function_name, args_array)". |
| 510 // RAX: receiver. |
| 511 // R10: ic-data array. |
| 512 // RBX: raw_null. |
| 513 // R13: argument descriptor array. |
| 514 |
| 515 // Setup space for return value on stack by pushing smi 0. |
| 516 __ pushq(Immediate(0)); // Result from noSuchMethod. |
| 517 __ pushq(RAX); // Receiver. |
| 518 __ pushq(R10); // IC-data array. |
| 519 __ pushq(R13); // Argument descriptor array. |
| 520 __ movq(R13, FieldAddress(R13, Array::data_offset())); |
| 521 __ SmiUntag(R13); |
| 522 __ subq(R13, Immediate(1)); // Arguments array length, minus the receiver. |
| 523 // See stack layout below explaining "wordSize * 6" offset. |
| 524 PushArgumentsArray(assembler, (kWordSize * 6)); |
| 525 |
| 526 // Stack: |
| 527 // TOS + 0: Argument array. |
| 528 // TOS + 1: Argument descriptor array. |
| 529 // TOS + 2: IC-data array. |
| 530 // TOS + 3: Receiver. |
| 531 // TOS + 4: Place for result from noSuchMethod. |
| 532 // TOS + 5: Saved RBP of previous frame. <== RBP |
| 533 // TOS + 6: Dart code return address |
| 534 // TOS + 7: Last argument of caller. |
| 535 // .... |
| 536 |
| 537 __ CallRuntimeFromStub(kInvokeNoSuchMethodFunctionRuntimeEntry); |
| 538 // Remove arguments. |
| 539 __ popq(RAX); |
| 540 __ popq(RAX); |
| 541 __ popq(RAX); |
| 542 __ popq(RAX); |
| 543 __ popq(RAX); // Get result into RAX. |
| 544 |
| 545 // Remove the stub frame as we are about to return. |
| 546 __ LeaveFrame(); |
| 547 __ ret(); |
187 } | 548 } |
188 | 549 |
189 | 550 |
190 void StubCode::GenerateDeoptimizeStub(Assembler* assembler) { | 551 void StubCode::GenerateDeoptimizeStub(Assembler* assembler) { |
191 __ Unimplemented("Deoptimize stub"); | 552 __ Unimplemented("Deoptimize stub"); |
192 } | 553 } |
193 | 554 |
194 | 555 |
| 556 // Called for inline allocation of arrays. |
| 557 // Input parameters: |
| 558 // R10 : Array length as Smi. |
| 559 // RBX : array element type (either NULL or an instantiated type). |
| 560 // NOTE: R10 cannot be clobbered here as the caller relies on it being saved. |
| 561 // The newly allocated object is returned in RAX. |
195 void StubCode::GenerateAllocateArrayStub(Assembler* assembler) { | 562 void StubCode::GenerateAllocateArrayStub(Assembler* assembler) { |
196 __ Unimplemented("AllocateArray stub"); | 563 Label slow_case; |
| 564 const Immediate raw_null = |
| 565 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 566 |
| 567 if (FLAG_inline_alloc) { |
| 568 // Compute the size to be allocated, it is based on the array length |
| 569 // and it computed as: |
| 570 // RoundedAllocationSize((array_length * kwordSize) + sizeof(RawArray)). |
| 571 // Assert that length is a Smi. |
| 572 __ testq(R10, Immediate(kSmiTagSize)); |
| 573 if (FLAG_use_slow_path) { |
| 574 __ jmp(&slow_case); |
| 575 } else { |
| 576 __ j(NOT_ZERO, &slow_case, Assembler::kNearJump); |
| 577 } |
| 578 __ movq(R13, FieldAddress(CTX, Context::isolate_offset())); |
| 579 __ movq(R13, Address(R13, Isolate::heap_offset())); |
| 580 __ movq(R13, Address(R13, Heap::new_space_offset())); |
| 581 |
| 582 // Calculate and align allocation size. |
| 583 // Load new object start and calculate next object start. |
| 584 // RBX: array element type. |
| 585 // R10: Array length as Smi. |
| 586 // R13: Points to new space object. |
| 587 __ movq(RAX, Address(R13, Scavenger::top_offset())); |
| 588 intptr_t fixed_size = sizeof(RawArray) + kObjectAlignment - 1; |
| 589 __ leaq(R12, Address(R10, TIMES_4, fixed_size)); // R10 is Smi. |
| 590 ASSERT(kSmiTagShift == 1); |
| 591 __ andq(R12, Immediate(-kObjectAlignment)); |
| 592 __ leaq(R12, Address(RAX, R12, TIMES_1, 0)); |
| 593 |
| 594 // Check if the allocation fits into the remaining space. |
| 595 // RAX: potential new object start. |
| 596 // R12: potential next object start. |
| 597 // RBX: array element type. |
| 598 // R10: Array length as Smi. |
| 599 // R13: Points to new space object. |
| 600 __ cmpq(R12, Address(R13, Scavenger::end_offset())); |
| 601 __ j(ABOVE_EQUAL, &slow_case, Assembler::kNearJump); |
| 602 |
| 603 // Successfully allocated the object(s), now update top to point to |
| 604 // next object start and initialize the object. |
| 605 // RAX: potential new object start. |
| 606 // R12: potential next object start. |
| 607 // R13: Points to new space object. |
| 608 __ movq(Address(R13, Scavenger::top_offset()), R12); |
| 609 __ addq(RAX, Immediate(kHeapObjectTag)); |
| 610 |
| 611 // RAX: new object start as a tagged pointer. |
| 612 // R12: new object end address. |
| 613 // RBX: array element type. |
| 614 // R10: Array length as Smi. |
| 615 |
| 616 // Store the type argument field. |
| 617 __ movq(FieldAddress(RAX, Array::type_arguments_offset()), RBX); |
| 618 |
| 619 // Set the length field. |
| 620 __ movq(FieldAddress(RAX, Array::length_offset()), R10); |
| 621 |
| 622 // Store class value for array. |
| 623 __ movq(RBX, FieldAddress(CTX, Context::isolate_offset())); |
| 624 __ movq(RBX, Address(RBX, Isolate::object_store_offset())); |
| 625 __ movq(RBX, Address(RBX, ObjectStore::array_class_offset())); |
| 626 __ movq(FieldAddress(RAX, Array::class_offset()), RBX); |
| 627 __ movq(FieldAddress(RAX, Array::tags_offset()), Immediate(0)); // Tags. |
| 628 |
| 629 // Initialize all array elements to raw_null. |
| 630 // RAX: new object start as a tagged pointer. |
| 631 // R12: new object end address. |
| 632 // RBX: iterator which initially points to the start of the variable |
| 633 // data area to be initialized. |
| 634 __ leaq(RBX, FieldAddress(RAX, Array::data_offset())); |
| 635 Label done; |
| 636 Label init_loop; |
| 637 __ Bind(&init_loop); |
| 638 __ cmpq(RBX, R12); |
| 639 __ j(ABOVE_EQUAL, &done, Assembler::kNearJump); |
| 640 __ movq(Address(RBX, 0), raw_null); |
| 641 __ addq(RBX, Immediate(kWordSize)); |
| 642 __ jmp(&init_loop, Assembler::kNearJump); |
| 643 __ Bind(&done); |
| 644 |
| 645 // Done allocating and initializing the array. |
| 646 // RAX: new object. |
| 647 __ ret(); |
| 648 } |
| 649 |
| 650 // Unable to allocate the array using the fast inline code, just call |
| 651 // into the runtime. |
| 652 __ Bind(&slow_case); |
| 653 __ EnterFrame(0); |
| 654 __ pushq(raw_null); // Push Null object for return value. |
| 655 __ pushq(R10); // Array length as Smi. |
| 656 __ pushq(RBX); // Element type. |
| 657 __ pushq(raw_null); // Null instantiator. |
| 658 __ CallRuntimeFromStub(kAllocateArrayRuntimeEntry); |
| 659 __ popq(RAX); // Pop instantiator. |
| 660 __ popq(RAX); // Pop element type argument. |
| 661 __ popq(R10); // Pop array length argument. |
| 662 __ popq(RAX); // Pop return value from return slot. |
| 663 __ LeaveFrame(); |
| 664 __ ret(); |
197 } | 665 } |
198 | 666 |
199 | 667 |
200 void StubCode::GenerateCallClosureFunctionStub(Assembler* assembler) { | 668 void StubCode::GenerateCallClosureFunctionStub(Assembler* assembler) { |
201 __ Unimplemented("CallClosureFunction stub"); | 669 __ Unimplemented("CallClosureFunction stub"); |
202 } | 670 } |
203 | 671 |
204 | 672 |
205 // Called when invoking Dart code from C++ (VM code). | 673 // Called when invoking Dart code from C++ (VM code). |
206 // Input parameters: | 674 // Input parameters: |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
316 | 784 |
317 __ ret(); | 785 __ ret(); |
318 } | 786 } |
319 | 787 |
320 | 788 |
321 void StubCode::GenerateAllocateContextStub(Assembler* assembler) { | 789 void StubCode::GenerateAllocateContextStub(Assembler* assembler) { |
322 __ Unimplemented("AllocateContext stub"); | 790 __ Unimplemented("AllocateContext stub"); |
323 } | 791 } |
324 | 792 |
325 | 793 |
| 794 |
| 795 |
| 796 // Called for inline allocation of objects. |
| 797 // Input parameters: |
| 798 // RSP + 16 : type arguments object (only if class is parameterized). |
| 799 // RSP + 8 : type arguments of instantiator (only if class is parameterized). |
| 800 // RSP : points to return address. |
| 801 // Uses RAX, RBX, RCX, RDX, RDI as temporary registers. |
326 void StubCode::GenerateAllocationStubForClass(Assembler* assembler, | 802 void StubCode::GenerateAllocationStubForClass(Assembler* assembler, |
327 const Class& cls) { | 803 const Class& cls) { |
328 __ Unimplemented("AllocateObject stub"); | 804 const intptr_t kObjectTypeArgumentsOffset = 2 * kWordSize; |
| 805 const intptr_t kInstantiatorTypeArgumentsOffset = 1 * kWordSize; |
| 806 const Immediate raw_null = |
| 807 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 808 // The generated code is different if the class is parameterized. |
| 809 const bool is_cls_parameterized = |
| 810 cls.type_arguments_instance_field_offset() != Class::kNoTypeArguments; |
| 811 // kInlineInstanceSize is a constant used as a threshold for determining |
| 812 // when the object initialization should be done as a loop or as |
| 813 // straight line code. |
| 814 const int kInlineInstanceSize = 12; // In words. |
| 815 const intptr_t instance_size = cls.instance_size(); |
| 816 ASSERT(instance_size > 0); |
| 817 const intptr_t type_args_size = InstantiatedTypeArguments::InstanceSize(); |
| 818 if (FLAG_inline_alloc && |
| 819 PageSpace::IsPageAllocatableSize(instance_size + type_args_size)) { |
| 820 Label slow_case; |
| 821 Heap* heap = Isolate::Current()->heap(); |
| 822 __ movq(RAX, Immediate(heap->TopAddress())); |
| 823 __ movq(RAX, Address(RAX, 0)); |
| 824 __ leaq(RBX, Address(RAX, instance_size)); |
| 825 if (is_cls_parameterized) { |
| 826 __ movq(RCX, RBX); |
| 827 // A new InstantiatedTypeArguments object only needs to be allocated if |
| 828 // the instantiator is non-null. |
| 829 Label null_instantiator; |
| 830 __ cmpq(Address(RSP, kInstantiatorTypeArgumentsOffset), raw_null); |
| 831 __ j(EQUAL, &null_instantiator, Assembler::kNearJump); |
| 832 __ addq(RBX, Immediate(type_args_size)); |
| 833 __ Bind(&null_instantiator); |
| 834 // RCX: potential new object end and, if RCX != RBX, potential new |
| 835 // InstantiatedTypeArguments object start. |
| 836 } |
| 837 // Check if the allocation fits into the remaining space. |
| 838 // RAX: potential new object start. |
| 839 // RBX: potential next object start. |
| 840 __ movq(RDI, Immediate(heap->EndAddress())); |
| 841 __ cmpq(RBX, Address(RDI, 0)); |
| 842 if (FLAG_use_slow_path) { |
| 843 __ jmp(&slow_case); |
| 844 } else { |
| 845 __ j(ABOVE_EQUAL, &slow_case, Assembler::kNearJump); |
| 846 } |
| 847 |
| 848 // Successfully allocated the object(s), now update top to point to |
| 849 // next object start and initialize the object. |
| 850 __ movq(RDI, Immediate(heap->TopAddress())); |
| 851 __ movq(Address(RDI, 0), RBX); |
| 852 |
| 853 if (is_cls_parameterized) { |
| 854 // Initialize the type arguments field in the object. |
| 855 // RAX: new object start. |
| 856 // RCX: potential new object end and, if RCX != RBX, potential new |
| 857 // InstantiatedTypeArguments object start. |
| 858 // RBX: next object start. |
| 859 Label type_arguments_ready; |
| 860 __ movq(RDI, Address(RSP, kObjectTypeArgumentsOffset)); |
| 861 __ cmpq(RCX, RBX); |
| 862 __ j(EQUAL, &type_arguments_ready, Assembler::kNearJump); |
| 863 // Initialize InstantiatedTypeArguments object at RCX. |
| 864 __ movq(Address(RCX, |
| 865 InstantiatedTypeArguments::uninstantiated_type_arguments_offset()), |
| 866 RDI); |
| 867 __ movq(RDX, Address(RSP, kInstantiatorTypeArgumentsOffset)); |
| 868 __ movq(Address(RCX, |
| 869 InstantiatedTypeArguments::instantiator_type_arguments_offset()), |
| 870 RDX); |
| 871 __ LoadObject(RDX, |
| 872 Class::ZoneHandle(Object::instantiated_type_arguments_class())); |
| 873 __ movq(Address(RCX, Instance::class_offset()), RDX); // Set its class. |
| 874 __ movq(Address(RCX, Instance::tags_offset()), Immediate(0)); // Tags. |
| 875 // Set the new InstantiatedTypeArguments object (RCX) as the type |
| 876 // arguments (RDI) of the new object (RAX). |
| 877 __ movq(RDI, RCX); |
| 878 __ addq(RDI, Immediate(kHeapObjectTag)); |
| 879 // Set RBX to new object end. |
| 880 __ movq(RBX, RCX); |
| 881 __ Bind(&type_arguments_ready); |
| 882 // RAX: new object. |
| 883 // RDI: new object type arguments. |
| 884 } |
| 885 |
| 886 // Initialize the class field in the object. |
| 887 // RAX: new object start. |
| 888 // RBX: next object start. |
| 889 // RDI: new object type arguments (if is_cls_parameterized). |
| 890 __ LoadObject(RDX, cls); // Load class of object to be allocated. |
| 891 __ movq(Address(RAX, Instance::class_offset()), RDX); |
| 892 __ movq(Address(RAX, Instance::tags_offset()), Immediate(0)); // Tags. |
| 893 |
| 894 // Initialize the remaining words of the object. |
| 895 const Immediate raw_null = |
| 896 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 897 |
| 898 // RAX: new object start. |
| 899 // RBX: next object start. |
| 900 // RDX: class of the object to be allocated. |
| 901 // First try inlining the initialization without a loop. |
| 902 if (instance_size < (kInlineInstanceSize * kWordSize) && |
| 903 cls.num_native_fields() == 0) { |
| 904 // Check if the object contains any non-header fields. |
| 905 // Small objects are initialized using a consecutive set of writes. |
| 906 for (intptr_t current_offset = sizeof(RawObject); |
| 907 current_offset < instance_size; |
| 908 current_offset += kWordSize) { |
| 909 __ movq(Address(RAX, current_offset), raw_null); |
| 910 } |
| 911 } else { |
| 912 __ leaq(RCX, Address(RAX, sizeof(RawObject))); |
| 913 // Loop until the whole object is initialized. |
| 914 Label init_loop; |
| 915 if (cls.num_native_fields() > 0) { |
| 916 // Initialize native fields. |
| 917 // RAX: new object. |
| 918 // RBX: next object start. |
| 919 // RDX: class of the object to be allocated. |
| 920 // RCX: next word to be initialized. |
| 921 intptr_t offset = Class::num_native_fields_offset() - kHeapObjectTag; |
| 922 __ movq(RDX, Address(RDX, offset)); |
| 923 __ leaq(RDX, Address(RAX, RDX, TIMES_8, sizeof(RawObject))); |
| 924 |
| 925 // RDX: start of dart fields. |
| 926 // RCX: next word to be initialized. |
| 927 Label init_native_loop; |
| 928 __ Bind(&init_native_loop); |
| 929 __ cmpq(RCX, RDX); |
| 930 __ j(ABOVE_EQUAL, &init_loop, Assembler::kNearJump); |
| 931 __ movq(Address(RCX, 0), Immediate(0)); |
| 932 __ addq(RCX, Immediate(kWordSize)); |
| 933 __ jmp(&init_native_loop, Assembler::kNearJump); |
| 934 } |
| 935 // Now initialize the dart fields. |
| 936 // RAX: new object. |
| 937 // RBX: next object start. |
| 938 // RCX: next word to be initialized. |
| 939 Label done; |
| 940 __ Bind(&init_loop); |
| 941 __ cmpq(RCX, RBX); |
| 942 __ j(ABOVE_EQUAL, &done, Assembler::kNearJump); |
| 943 __ movq(Address(RCX, 0), raw_null); |
| 944 __ addq(RCX, Immediate(kWordSize)); |
| 945 __ jmp(&init_loop, Assembler::kNearJump); |
| 946 __ Bind(&done); |
| 947 } |
| 948 if (is_cls_parameterized) { |
| 949 // RDI: new object type arguments. |
| 950 // Set the type arguments in the new object. |
| 951 __ movq(Address(RAX, cls.type_arguments_instance_field_offset()), RDI); |
| 952 } |
| 953 // Done allocating and initializing the instance. |
| 954 // RAX: new object. |
| 955 __ addq(RAX, Immediate(kHeapObjectTag)); |
| 956 __ ret(); |
| 957 |
| 958 __ Bind(&slow_case); |
| 959 } |
| 960 if (is_cls_parameterized) { |
| 961 __ movq(RAX, Address(RSP, kObjectTypeArgumentsOffset)); |
| 962 __ movq(RDX, Address(RSP, kInstantiatorTypeArgumentsOffset)); |
| 963 } |
| 964 // Create a stub frame. |
| 965 __ EnterFrame(0); |
| 966 const Object& new_object = Object::ZoneHandle(); |
| 967 __ PushObject(new_object); // Push Null object for return value. |
| 968 __ PushObject(cls); // Push class of object to be allocated. |
| 969 if (is_cls_parameterized) { |
| 970 __ pushq(RAX); // Push type arguments of object to be allocated. |
| 971 __ pushq(RDX); // Push type arguments of instantiator. |
| 972 } else { |
| 973 __ pushq(raw_null); // Push null type arguments. |
| 974 __ pushq(raw_null); // Push null instantiator. |
| 975 } |
| 976 __ CallRuntimeFromStub(kAllocateObjectRuntimeEntry); // Allocate object. |
| 977 __ popq(RAX); // Pop argument (instantiator). |
| 978 __ popq(RAX); // Pop argument (type arguments of object). |
| 979 __ popq(RAX); // Pop argument (class of object). |
| 980 __ popq(RAX); // Pop result (newly allocated object). |
| 981 // RAX: new object |
| 982 // Restore the frame pointer. |
| 983 __ LeaveFrame(); |
| 984 __ ret(); |
329 } | 985 } |
330 | 986 |
331 | 987 |
332 void StubCode::GenerateAllocationStubForClosure(Assembler* assembler, | 988 void StubCode::GenerateAllocationStubForClosure(Assembler* assembler, |
333 const Function& func) { | 989 const Function& func) { |
334 __ Unimplemented("AllocateClosure stub"); | 990 __ Unimplemented("AllocateClosure stub"); |
335 } | 991 } |
336 | 992 |
337 | 993 |
338 void StubCode::GenerateCallNoSuchMethodFunctionStub(Assembler* assembler) { | 994 void StubCode::GenerateCallNoSuchMethodFunctionStub(Assembler* assembler) { |
339 __ Unimplemented("CallNoSuchMethodFunction stub"); | 995 __ Unimplemented("CallNoSuchMethodFunction stub"); |
340 } | 996 } |
341 | 997 |
342 | 998 |
| 999 // Generate inline cache check for 'num_args'. |
| 1000 // RBX: Inline cache data array. |
| 1001 // R10: Arguments array. |
| 1002 // TOS(0): return address |
| 1003 // Control flow: |
| 1004 // - If receiver is null -> jump to IC miss. |
| 1005 // - If receiver is Smi -> load Smi class. |
| 1006 // - If receiver is not-Smi -> load receiver's class. |
| 1007 // - Check if 'num_args' (including receiver) match any IC data group. |
| 1008 // - Match found -> jump to target. |
| 1009 // - Match not found -> jump to IC miss. |
| 1010 void StubCode::GenerateNArgsCheckInlineCacheStub(Assembler* assembler, |
| 1011 intptr_t num_args) { |
| 1012 ASSERT(num_args > 0); |
| 1013 // Get receiver. |
| 1014 __ movq(RAX, FieldAddress(R10, Array::data_offset())); |
| 1015 __ movq(RAX, Address(RSP, RAX, TIMES_4, 0)); // RAX is Smi. |
| 1016 |
| 1017 Label get_class, ic_miss; |
| 1018 __ call(&get_class); |
| 1019 // RAX: receiver's class |
| 1020 // RBX: IC data array. |
| 1021 |
| 1022 #if defined(DEBUG) |
| 1023 { Label ok; |
| 1024 // Check that the IC data array has NumberOfArgumentsChecked() == num_args. |
| 1025 __ movq(RCX, FieldAddress(RBX, |
| 1026 Array::data_offset() + ICData::kNumArgsCheckedIndex * kWordSize)); |
| 1027 const Immediate value = |
| 1028 Immediate(reinterpret_cast<int64_t>(Smi::New(num_args))); |
| 1029 __ cmpq(RCX, value); |
| 1030 __ j(EQUAL, &ok, Assembler::kNearJump); |
| 1031 __ Stop("Incorrect stub for IC data"); |
| 1032 __ Bind(&ok); |
| 1033 } |
| 1034 #endif // DEBUG |
| 1035 |
| 1036 // Loop that checks if there is an IC data match. |
| 1037 // RAX: receiver's class. |
| 1038 // RBX: IC data array (preserved). |
| 1039 __ leaq(R12, FieldAddress(RBX, |
| 1040 Array::data_offset() + ICData::kChecksStartIndex * kWordSize)); |
| 1041 // R12: pointing to a class to check against (into IC data array). |
| 1042 const Immediate raw_null = |
| 1043 Immediate(reinterpret_cast<intptr_t>(Object::null())); |
| 1044 Label loop, found; |
| 1045 if (num_args == 1) { |
| 1046 __ Bind(&loop); |
| 1047 __ movq(R13, Address(R12, 0)); // Get class to check. |
| 1048 __ cmpq(RAX, R13); // Match? |
| 1049 __ j(EQUAL, &found, Assembler::kNearJump); |
| 1050 __ addq(R12, Immediate(kWordSize * 2)); // Next element (class + target). |
| 1051 __ cmpq(R13, raw_null); // Done? |
| 1052 __ j(NOT_EQUAL, &loop, Assembler::kNearJump); |
| 1053 } else if (num_args == 2) { |
| 1054 Label no_match; |
| 1055 __ Bind(&loop); |
| 1056 __ movq(R13, Address(R12, 0)); // Get class from IC data to check. |
| 1057 // Get receiver. |
| 1058 __ movq(RAX, FieldAddress(R10, Array::data_offset())); |
| 1059 __ movq(RAX, Address(RSP, RAX, TIMES_4, 0)); // RAX is Smi. |
| 1060 __ call(&get_class); |
| 1061 __ cmpq(RAX, R13); // Match? |
| 1062 __ j(NOT_EQUAL, &no_match, Assembler::kNearJump); |
| 1063 // Check second. |
| 1064 __ movq(R13, Address(R12, kWordSize)); // Get class from IC data to check. |
| 1065 // Get next argument. |
| 1066 __ movq(RAX, FieldAddress(R10, Array::data_offset())); |
| 1067 __ movq(RAX, Address(RSP, RAX, TIMES_4, -kWordSize)); // RAX is Smi. |
| 1068 __ call(&get_class); |
| 1069 __ cmpq(RAX, R13); // Match? |
| 1070 __ j(EQUAL, &found, Assembler::kNearJump); |
| 1071 __ Bind(&no_match); |
| 1072 __ addq(R12, Immediate(kWordSize * (1 + num_args))); // Next element. |
| 1073 __ cmpq(R13, raw_null); // Done? |
| 1074 __ j(NOT_EQUAL, &loop, Assembler::kNearJump); |
| 1075 } |
| 1076 |
| 1077 __ Bind(&ic_miss); |
| 1078 // Get receiver, again. |
| 1079 __ movq(RAX, FieldAddress(R10, Array::data_offset())); |
| 1080 __ leaq(RAX, Address(RSP, RAX, TIMES_4, 0)); // RAX is Smi. |
| 1081 __ EnterFrame(0); |
| 1082 // Setup space for return value on stack by pushing smi 0. |
| 1083 __ pushq(R10); // Preserve arguments array. |
| 1084 __ pushq(RBX); // Preserve IC data array |
| 1085 __ pushq(Immediate(0)); // Space for result (target code object). |
| 1086 __ movq(R10, FieldAddress(R10, Array::data_offset())); |
| 1087 // Push call arguments. |
| 1088 for (intptr_t i = 0; i < num_args; i++) { |
| 1089 __ movq(R10, Address(RAX, -kWordSize * i)); |
| 1090 __ pushq(R10); |
| 1091 } |
| 1092 if (num_args == 1) { |
| 1093 __ CallRuntimeFromStub(kInlineCacheMissHandlerOneArgRuntimeEntry); |
| 1094 } else if (num_args == 2) { |
| 1095 __ CallRuntimeFromStub(kInlineCacheMissHandlerTwoArgsRuntimeEntry); |
| 1096 } else { |
| 1097 UNIMPLEMENTED(); |
| 1098 } |
| 1099 // Remove call arguments pushed earlier. |
| 1100 for (intptr_t i = 0; i < num_args; i++) { |
| 1101 __ popq(RAX); |
| 1102 } |
| 1103 __ popq(RAX); // Pop returned code object into RAX (null if not found). |
| 1104 __ popq(RBX); // Restore IC data array. |
| 1105 __ popq(R10); // Restore arguments array. |
| 1106 __ LeaveFrame(); |
| 1107 Label call_target_function; |
| 1108 __ cmpq(RAX, raw_null); |
| 1109 __ j(NOT_EQUAL, &call_target_function, Assembler::kNearJump); |
| 1110 // NoSuchMethod or closure. |
| 1111 __ jmp(&StubCode::MegamorphicLookupLabel()); |
| 1112 |
| 1113 __ Bind(&found); |
| 1114 // R12: Pointer to an IC data check group (classes + target) |
| 1115 __ movq(RAX, Address(R12, kWordSize * num_args)); // Target function. |
| 1116 |
| 1117 __ Bind(&call_target_function); |
| 1118 // RAX: Target function. |
| 1119 __ movq(RAX, FieldAddress(RAX, Function::code_offset())); |
| 1120 __ movq(RAX, FieldAddress(RAX, Code::instructions_offset())); |
| 1121 __ addq(RAX, Immediate(Instructions::HeaderSize() - kHeapObjectTag)); |
| 1122 __ jmp(RAX); |
| 1123 |
| 1124 __ Bind(&get_class); |
| 1125 Label not_smi; |
| 1126 // Test if Smi -> load Smi class for comparison. |
| 1127 __ testq(RAX, Immediate(kSmiTagMask)); |
| 1128 __ j(NOT_ZERO, ¬_smi, Assembler::kNearJump); |
| 1129 const Class& smi_class = |
| 1130 Class::ZoneHandle(Isolate::Current()->object_store()->smi_class()); |
| 1131 __ LoadObject(RAX, smi_class); |
| 1132 __ ret(); |
| 1133 |
| 1134 __ Bind(¬_smi); |
| 1135 __ movq(RAX, FieldAddress(RAX, Object::class_offset())); |
| 1136 __ ret(); |
| 1137 } |
| 1138 |
| 1139 |
| 1140 // Use inline cache data array to invoke the target or continue in inline |
| 1141 // cache miss handler. Stub for 1-argument check (receiver class). |
| 1142 // RCX: Inline cache data array |
| 1143 // RDX: Arguments array |
| 1144 // TOS(0): return address |
| 1145 // Inline cache data array structure: |
| 1146 // 0: function-name |
| 1147 // 1: N, number of arguments checked. |
| 1148 // 2 .. (length - 1): group of checks, each check containing: |
| 1149 // - N classes. |
| 1150 // - 1 target function. |
343 void StubCode::GenerateOneArgCheckInlineCacheStub(Assembler* assembler) { | 1151 void StubCode::GenerateOneArgCheckInlineCacheStub(Assembler* assembler) { |
344 __ Unimplemented("GenerateOneArgCheckInlineCacheStub stub"); | 1152 return GenerateNArgsCheckInlineCacheStub(assembler, 1); |
345 } | 1153 } |
346 | 1154 |
347 | 1155 |
348 void StubCode::GenerateTwoArgsCheckInlineCacheStub(Assembler* assembler) { | 1156 void StubCode::GenerateTwoArgsCheckInlineCacheStub(Assembler* assembler) { |
349 __ Unimplemented("GenerateTwoArgsCheckInlineCacheStub stub"); | 1157 return GenerateNArgsCheckInlineCacheStub(assembler, 2); |
350 } | 1158 } |
351 | 1159 |
352 | 1160 |
353 void StubCode::GenerateBreakpointStaticStub(Assembler* assembler) { | 1161 void StubCode::GenerateBreakpointStaticStub(Assembler* assembler) { |
354 __ Unimplemented("BreakpointStatic stub"); | 1162 __ Unimplemented("BreakpointStatic stub"); |
355 } | 1163 } |
356 | 1164 |
357 | 1165 |
358 void StubCode::GenerateBreakpointDynamicStub(Assembler* assembler) { | 1166 void StubCode::GenerateBreakpointDynamicStub(Assembler* assembler) { |
359 __ Unimplemented("BreakpointDynamic stub"); | 1167 __ Unimplemented("BreakpointDynamic stub"); |
360 } | 1168 } |
361 | 1169 |
362 } // namespace dart | 1170 } // namespace dart |
363 | 1171 |
364 #endif // defined TARGET_ARCH_X64 | 1172 #endif // defined TARGET_ARCH_X64 |
OLD | NEW |