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

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

Issue 8984003: Port code generator to x64. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: '' Created 9 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/vm/stub_code_ia32.cc ('k') | runtime/vm/vm_sources.gypi » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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, &not_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(&not_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
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, &not_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(&not_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
OLDNEW
« no previous file with comments | « runtime/vm/stub_code_ia32.cc ('k') | runtime/vm/vm_sources.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698