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

Side by Side Diff: src/x64/builtins-x64.cc

Issue 660095: Merge revision 3813 to 3930 from bleeding_edge to partial snapshots branch. (Closed) Base URL: http://v8.googlecode.com/svn/branches/experimental/partial_snapshots/
Patch Set: '' Created 10 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/x64/assembler-x64.cc ('k') | src/x64/codegen-x64.h » ('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 2009 the V8 project authors. All rights reserved. 1 // Copyright 2009 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after
178 // ------------------------------------------- 178 // -------------------------------------------
179 // Dont adapt arguments. 179 // Dont adapt arguments.
180 // ------------------------------------------- 180 // -------------------------------------------
181 __ bind(&dont_adapt_arguments); 181 __ bind(&dont_adapt_arguments);
182 __ jmp(rdx); 182 __ jmp(rdx);
183 } 183 }
184 184
185 185
186 void Builtins::Generate_FunctionCall(MacroAssembler* masm) { 186 void Builtins::Generate_FunctionCall(MacroAssembler* masm) {
187 // Stack Layout: 187 // Stack Layout:
188 // rsp: return address 188 // rsp[0]: Return address
189 // +1: Argument n 189 // rsp[1]: Argument n
190 // +2: Argument n-1 190 // rsp[2]: Argument n-1
191 // ... 191 // ...
192 // +n: Argument 1 = receiver 192 // rsp[n]: Argument 1
193 // +n+1: Argument 0 = function to call 193 // rsp[n+1]: Receiver (function to call)
194 // 194 //
195 // rax contains the number of arguments, n, not counting the function. 195 // rax contains the number of arguments, n, not counting the receiver.
196 // 196 //
197 // 1. Make sure we have at least one argument. 197 // 1. Make sure we have at least one argument.
198 { Label done; 198 { Label done;
199 __ testq(rax, rax); 199 __ testq(rax, rax);
200 __ j(not_zero, &done); 200 __ j(not_zero, &done);
201 __ pop(rbx); 201 __ pop(rbx);
202 __ Push(Factory::undefined_value()); 202 __ Push(Factory::undefined_value());
203 __ push(rbx); 203 __ push(rbx);
204 __ incq(rax); 204 __ incq(rax);
205 __ bind(&done); 205 __ bind(&done);
206 } 206 }
207 207
208 // 2. Get the function to call from the stack. 208 // 2. Get the function to call (passed as receiver) from the stack, check
209 { Label done, non_function, function; 209 // if it is a function.
210 // The function to call is at position n+1 on the stack. 210 Label non_function;
211 __ movq(rdi, Operand(rsp, rax, times_pointer_size, +1 * kPointerSize)); 211 // The function to call is at position n+1 on the stack.
212 __ JumpIfSmi(rdi, &non_function); 212 __ movq(rdi, Operand(rsp, rax, times_pointer_size, 1 * kPointerSize));
213 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx); 213 __ JumpIfSmi(rdi, &non_function);
214 __ j(equal, &function); 214 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
215 __ j(not_equal, &non_function);
215 216
216 // Non-function called: Clear the function to force exception. 217 // 3a. Patch the first argument if necessary when calling a function.
217 __ bind(&non_function); 218 Label shift_arguments;
218 __ xor_(rdi, rdi); 219 { Label convert_to_object, use_global_receiver, patch_receiver;
219 __ jmp(&done); 220 // Change context eagerly in case we need the global receiver.
220
221 // Function called: Change context eagerly to get the right global object.
222 __ bind(&function);
223 __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset)); 221 __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset));
224 222
225 __ bind(&done);
226 }
227
228 // 3. Make sure first argument is an object; convert if necessary.
229 { Label call_to_object, use_global_receiver, patch_receiver, done;
230 __ movq(rbx, Operand(rsp, rax, times_pointer_size, 0)); 223 __ movq(rbx, Operand(rsp, rax, times_pointer_size, 0));
231 224 __ JumpIfSmi(rbx, &convert_to_object);
232 __ JumpIfSmi(rbx, &call_to_object);
233 225
234 __ CompareRoot(rbx, Heap::kNullValueRootIndex); 226 __ CompareRoot(rbx, Heap::kNullValueRootIndex);
235 __ j(equal, &use_global_receiver); 227 __ j(equal, &use_global_receiver);
236 __ CompareRoot(rbx, Heap::kUndefinedValueRootIndex); 228 __ CompareRoot(rbx, Heap::kUndefinedValueRootIndex);
237 __ j(equal, &use_global_receiver); 229 __ j(equal, &use_global_receiver);
238 230
239 __ CmpObjectType(rbx, FIRST_JS_OBJECT_TYPE, rcx); 231 __ CmpObjectType(rbx, FIRST_JS_OBJECT_TYPE, rcx);
240 __ j(below, &call_to_object); 232 __ j(below, &convert_to_object);
241 __ CmpInstanceType(rcx, LAST_JS_OBJECT_TYPE); 233 __ CmpInstanceType(rcx, LAST_JS_OBJECT_TYPE);
242 __ j(below_equal, &done); 234 __ j(below_equal, &shift_arguments);
243 235
244 __ bind(&call_to_object); 236 __ bind(&convert_to_object);
245 __ EnterInternalFrame(); // preserves rax, rbx, rdi 237 __ EnterInternalFrame(); // In order to preserve argument count.
246
247 // Store the arguments count on the stack (smi tagged).
248 __ Integer32ToSmi(rax, rax); 238 __ Integer32ToSmi(rax, rax);
249 __ push(rax); 239 __ push(rax);
250 240
251 __ push(rdi); // save edi across the call
252 __ push(rbx); 241 __ push(rbx);
253 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); 242 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
254 __ movq(rbx, rax); 243 __ movq(rbx, rax);
255 __ pop(rdi); // restore edi after the call
256 244
257 // Get the arguments count and untag it.
258 __ pop(rax); 245 __ pop(rax);
259 __ SmiToInteger32(rax, rax); 246 __ SmiToInteger32(rax, rax);
260
261 __ LeaveInternalFrame(); 247 __ LeaveInternalFrame();
248 // Restore the function to rdi.
249 __ movq(rdi, Operand(rsp, rax, times_pointer_size, 1 * kPointerSize));
262 __ jmp(&patch_receiver); 250 __ jmp(&patch_receiver);
263 251
264 // Use the global receiver object from the called function as the receiver. 252 // Use the global receiver object from the called function as the
253 // receiver.
265 __ bind(&use_global_receiver); 254 __ bind(&use_global_receiver);
266 const int kGlobalIndex = 255 const int kGlobalIndex =
267 Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize; 256 Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize;
268 __ movq(rbx, FieldOperand(rsi, kGlobalIndex)); 257 __ movq(rbx, FieldOperand(rsi, kGlobalIndex));
269 __ movq(rbx, FieldOperand(rbx, GlobalObject::kGlobalContextOffset)); 258 __ movq(rbx, FieldOperand(rbx, GlobalObject::kGlobalContextOffset));
270 __ movq(rbx, FieldOperand(rbx, kGlobalIndex)); 259 __ movq(rbx, FieldOperand(rbx, kGlobalIndex));
271 __ movq(rbx, FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset)); 260 __ movq(rbx, FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset));
272 261
273 __ bind(&patch_receiver); 262 __ bind(&patch_receiver);
274 __ movq(Operand(rsp, rax, times_pointer_size, 0), rbx); 263 __ movq(Operand(rsp, rax, times_pointer_size, 0), rbx);
275 264
276 __ bind(&done); 265 __ jmp(&shift_arguments);
277 } 266 }
278 267
279 // 4. Shift stuff one slot down the stack. 268
269 // 3b. Patch the first argument when calling a non-function. The
270 // CALL_NON_FUNCTION builtin expects the non-function callee as
271 // receiver, so overwrite the first argument which will ultimately
272 // become the receiver.
273 __ bind(&non_function);
274 __ movq(Operand(rsp, rax, times_pointer_size, 0), rdi);
275 __ xor_(rdi, rdi);
276
277 // 4. Shift arguments and return address one slot down on the stack
278 // (overwriting the original receiver). Adjust argument count to make
279 // the original first argument the new receiver.
280 __ bind(&shift_arguments);
280 { Label loop; 281 { Label loop;
281 __ lea(rcx, Operand(rax, +1)); // +1 ~ copy receiver too 282 __ movq(rcx, rax);
282 __ bind(&loop); 283 __ bind(&loop);
283 __ movq(rbx, Operand(rsp, rcx, times_pointer_size, 0)); 284 __ movq(rbx, Operand(rsp, rcx, times_pointer_size, 0));
284 __ movq(Operand(rsp, rcx, times_pointer_size, 1 * kPointerSize), rbx); 285 __ movq(Operand(rsp, rcx, times_pointer_size, 1 * kPointerSize), rbx);
285 __ decq(rcx); 286 __ decq(rcx);
286 __ j(not_zero, &loop); 287 __ j(not_sign, &loop); // While non-negative (to copy return address).
288 __ pop(rbx); // Discard copy of return address.
289 __ decq(rax); // One fewer argument (first argument is new receiver).
287 } 290 }
288 291
289 // 5. Remove TOS (copy of last arguments), but keep return address. 292 // 5a. Call non-function via tail call to CALL_NON_FUNCTION builtin.
290 __ pop(rbx); 293 { Label function;
291 __ pop(rcx);
292 __ push(rbx);
293 __ decq(rax);
294
295 // 6. Check that function really was a function and get the code to
296 // call from the function and check that the number of expected
297 // arguments matches what we're providing.
298 { Label invoke, trampoline;
299 __ testq(rdi, rdi); 294 __ testq(rdi, rdi);
300 __ j(not_zero, &invoke); 295 __ j(not_zero, &function);
301 __ xor_(rbx, rbx); 296 __ xor_(rbx, rbx);
302 __ GetBuiltinEntry(rdx, Builtins::CALL_NON_FUNCTION); 297 __ GetBuiltinEntry(rdx, Builtins::CALL_NON_FUNCTION);
303 __ bind(&trampoline);
304 __ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)), 298 __ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
305 RelocInfo::CODE_TARGET); 299 RelocInfo::CODE_TARGET);
306 300 __ bind(&function);
307 __ bind(&invoke);
308 __ movq(rdx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset));
309 __ movsxlq(rbx,
310 FieldOperand(rdx, SharedFunctionInfo::kFormalParameterCountOffset));
311 __ movq(rdx, FieldOperand(rdx, SharedFunctionInfo::kCodeOffset));
312 __ lea(rdx, FieldOperand(rdx, Code::kHeaderSize));
313 __ cmpq(rax, rbx);
314 __ j(not_equal, &trampoline);
315 } 301 }
316 302
317 // 7. Jump (tail-call) to the code in register edx without checking arguments. 303 // 5b. Get the code to call from the function and check that the number of
304 // expected arguments matches what we're providing. If so, jump
305 // (tail-call) to the code in register edx without checking arguments.
306 __ movq(rdx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset));
307 __ movsxlq(rbx,
308 FieldOperand(rdx, SharedFunctionInfo::kFormalParameterCountOffset));
309 __ movq(rdx, FieldOperand(rdx, SharedFunctionInfo::kCodeOffset));
310 __ lea(rdx, FieldOperand(rdx, Code::kHeaderSize));
311 __ cmpq(rax, rbx);
312 __ j(not_equal,
313 Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
314 RelocInfo::CODE_TARGET);
315
318 ParameterCount expected(0); 316 ParameterCount expected(0);
319 __ InvokeCode(rdx, expected, expected, JUMP_FUNCTION); 317 __ InvokeCode(rdx, expected, expected, JUMP_FUNCTION);
320 } 318 }
321 319
322 320
323 void Builtins::Generate_FunctionApply(MacroAssembler* masm) { 321 void Builtins::Generate_FunctionApply(MacroAssembler* masm) {
324 // Stack at entry: 322 // Stack at entry:
325 // rsp: return address 323 // rsp: return address
326 // rsp+8: arguments 324 // rsp+8: arguments
327 // rsp+16: receiver ("this") 325 // rsp+16: receiver ("this")
(...skipping 251 matching lines...) Expand 10 before | Expand all | Expand 10 after
579 bool fill_with_hole, 577 bool fill_with_hole,
580 Label* gc_required) { 578 Label* gc_required) {
581 Label not_empty, allocated; 579 Label not_empty, allocated;
582 580
583 // Load the initial map from the array function. 581 // Load the initial map from the array function.
584 __ movq(elements_array, 582 __ movq(elements_array,
585 FieldOperand(array_function, 583 FieldOperand(array_function,
586 JSFunction::kPrototypeOrInitialMapOffset)); 584 JSFunction::kPrototypeOrInitialMapOffset));
587 585
588 // Check whether an empty sized array is requested. 586 // Check whether an empty sized array is requested.
587 __ SmiToInteger64(array_size, array_size);
589 __ testq(array_size, array_size); 588 __ testq(array_size, array_size);
590 __ j(not_zero, &not_empty); 589 __ j(not_zero, &not_empty);
591 590
592 // If an empty array is requested allocate a small elements array anyway. This 591 // If an empty array is requested allocate a small elements array anyway. This
593 // keeps the code below free of special casing for the empty array. 592 // keeps the code below free of special casing for the empty array.
594 int size = JSArray::kSize + FixedArray::SizeFor(kPreallocatedArrayElements); 593 int size = JSArray::kSize + FixedArray::SizeFor(kPreallocatedArrayElements);
595 __ AllocateInNewSpace(size, 594 __ AllocateInNewSpace(size,
596 result, 595 result,
597 elements_array_end, 596 elements_array_end,
598 scratch, 597 scratch,
599 gc_required, 598 gc_required,
600 TAG_OBJECT); 599 TAG_OBJECT);
601 __ jmp(&allocated); 600 __ jmp(&allocated);
602 601
603 // Allocate the JSArray object together with space for a FixedArray with the 602 // Allocate the JSArray object together with space for a FixedArray with the
604 // requested elements. 603 // requested elements.
605 __ bind(&not_empty); 604 __ bind(&not_empty);
606 ASSERT(kSmiTagSize == 1 && kSmiTag == 0); 605 ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
607 __ AllocateInNewSpace(JSArray::kSize + FixedArray::kHeaderSize, 606 __ AllocateInNewSpace(JSArray::kSize + FixedArray::kHeaderSize,
608 times_half_pointer_size, // array_size is a smi. 607 times_pointer_size,
609 array_size, 608 array_size,
610 result, 609 result,
611 elements_array_end, 610 elements_array_end,
612 scratch, 611 scratch,
613 gc_required, 612 gc_required,
614 TAG_OBJECT); 613 TAG_OBJECT);
615 614
616 // Allocated the JSArray. Now initialize the fields except for the elements 615 // Allocated the JSArray. Now initialize the fields except for the elements
617 // array. 616 // array.
618 // result: JSObject 617 // result: JSObject
619 // elements_array: initial map 618 // elements_array: initial map
620 // elements_array_end: start of next object 619 // elements_array_end: start of next object
621 // array_size: size of array (smi) 620 // array_size: size of array
622 __ bind(&allocated); 621 __ bind(&allocated);
623 __ movq(FieldOperand(result, JSObject::kMapOffset), elements_array); 622 __ movq(FieldOperand(result, JSObject::kMapOffset), elements_array);
624 __ Move(elements_array, Factory::empty_fixed_array()); 623 __ Move(elements_array, Factory::empty_fixed_array());
625 __ movq(FieldOperand(result, JSArray::kPropertiesOffset), elements_array); 624 __ movq(FieldOperand(result, JSArray::kPropertiesOffset), elements_array);
626 // Field JSArray::kElementsOffset is initialized later. 625 // Field JSArray::kElementsOffset is initialized later.
627 __ movq(FieldOperand(result, JSArray::kLengthOffset), array_size); 626 __ Integer32ToSmi(scratch, array_size);
627 __ movq(FieldOperand(result, JSArray::kLengthOffset), scratch);
628 628
629 // Calculate the location of the elements array and set elements array member 629 // Calculate the location of the elements array and set elements array member
630 // of the JSArray. 630 // of the JSArray.
631 // result: JSObject 631 // result: JSObject
632 // elements_array_end: start of next object 632 // elements_array_end: start of next object
633 // array_size: size of array (smi) 633 // array_size: size of array
634 __ lea(elements_array, Operand(result, JSArray::kSize)); 634 __ lea(elements_array, Operand(result, JSArray::kSize));
635 __ movq(FieldOperand(result, JSArray::kElementsOffset), elements_array); 635 __ movq(FieldOperand(result, JSArray::kElementsOffset), elements_array);
636 636
637 // Initialize the fixed array. FixedArray length is not stored as a smi. 637 // Initialize the fixed array. FixedArray length is not stored as a smi.
638 // result: JSObject 638 // result: JSObject
639 // elements_array: elements array 639 // elements_array: elements array
640 // elements_array_end: start of next object 640 // elements_array_end: start of next object
641 // array_size: size of array (smi) 641 // array_size: size of array
642 ASSERT(kSmiTag == 0); 642 ASSERT(kSmiTag == 0);
643 __ SmiToInteger64(array_size, array_size);
644 __ Move(FieldOperand(elements_array, JSObject::kMapOffset), 643 __ Move(FieldOperand(elements_array, JSObject::kMapOffset),
645 Factory::fixed_array_map()); 644 Factory::fixed_array_map());
646 Label not_empty_2, fill_array; 645 Label not_empty_2, fill_array;
647 __ testq(array_size, array_size); 646 __ testq(array_size, array_size);
648 __ j(not_zero, &not_empty_2); 647 __ j(not_zero, &not_empty_2);
649 // Length of the FixedArray is the number of pre-allocated elements even 648 // Length of the FixedArray is the number of pre-allocated elements even
650 // though the actual JSArray has length 0. 649 // though the actual JSArray has length 0.
651 __ movq(FieldOperand(elements_array, Array::kLengthOffset), 650 __ movq(FieldOperand(elements_array, Array::kLengthOffset),
652 Immediate(kPreallocatedArrayElements)); 651 Immediate(kPreallocatedArrayElements));
653 __ jmp(&fill_array); 652 __ jmp(&fill_array);
(...skipping 239 matching lines...) Expand 10 before | Expand all | Expand 10 after
893 892
894 // Jump to the function-specific construct stub. 893 // Jump to the function-specific construct stub.
895 __ movq(rbx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset)); 894 __ movq(rbx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset));
896 __ movq(rbx, FieldOperand(rbx, SharedFunctionInfo::kConstructStubOffset)); 895 __ movq(rbx, FieldOperand(rbx, SharedFunctionInfo::kConstructStubOffset));
897 __ lea(rbx, FieldOperand(rbx, Code::kHeaderSize)); 896 __ lea(rbx, FieldOperand(rbx, Code::kHeaderSize));
898 __ jmp(rbx); 897 __ jmp(rbx);
899 898
900 // edi: called object 899 // edi: called object
901 // eax: number of arguments 900 // eax: number of arguments
902 __ bind(&non_function_call); 901 __ bind(&non_function_call);
903 // Set expected number of arguments to zero (not changing eax). 902 // CALL_NON_FUNCTION expects the non-function constructor as receiver
903 // (instead of the original receiver from the call site). The receiver is
904 // stack element argc+1.
905 __ movq(Operand(rsp, rax, times_pointer_size, kPointerSize), rdi);
906 // Set expected number of arguments to zero (not changing rax).
904 __ movq(rbx, Immediate(0)); 907 __ movq(rbx, Immediate(0));
905 __ GetBuiltinEntry(rdx, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR); 908 __ GetBuiltinEntry(rdx, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR);
906 __ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)), 909 __ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)),
907 RelocInfo::CODE_TARGET); 910 RelocInfo::CODE_TARGET);
908 } 911 }
909 912
910 913
911 static void Generate_JSConstructStubHelper(MacroAssembler* masm, 914 static void Generate_JSConstructStubHelper(MacroAssembler* masm,
912 bool is_api_function) { 915 bool is_api_function) {
913 // Enter a construct frame. 916 // Enter a construct frame.
(...skipping 372 matching lines...) Expand 10 before | Expand all | Expand 10 after
1286 void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) { 1289 void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) {
1287 Generate_JSEntryTrampolineHelper(masm, false); 1290 Generate_JSEntryTrampolineHelper(masm, false);
1288 } 1291 }
1289 1292
1290 1293
1291 void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) { 1294 void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) {
1292 Generate_JSEntryTrampolineHelper(masm, true); 1295 Generate_JSEntryTrampolineHelper(masm, true);
1293 } 1296 }
1294 1297
1295 } } // namespace v8::internal 1298 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/x64/assembler-x64.cc ('k') | src/x64/codegen-x64.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698