OLD | NEW |
---|---|
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 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
54 | 54 |
55 // Store the arguments adaptor context sentinel. | 55 // Store the arguments adaptor context sentinel. |
56 __ push(Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); | 56 __ push(Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))); |
57 | 57 |
58 // Push the function on the stack. | 58 // Push the function on the stack. |
59 __ push(rdi); | 59 __ push(rdi); |
60 | 60 |
61 // Preserve the number of arguments on the stack. Must preserve both | 61 // Preserve the number of arguments on the stack. Must preserve both |
62 // rax and rbx because these registers are used when copying the | 62 // rax and rbx because these registers are used when copying the |
63 // arguments and the receiver. | 63 // arguments and the receiver. |
64 ASSERT(kSmiTagSize == 1); | 64 __ Integer32ToSmi(rcx, rax); |
65 __ lea(rcx, Operand(rax, rax, times_1, kSmiTag)); | |
66 __ push(rcx); | 65 __ push(rcx); |
67 } | 66 } |
68 | 67 |
69 | 68 |
70 static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) { | 69 static void LeaveArgumentsAdaptorFrame(MacroAssembler* masm) { |
71 // Retrieve the number of arguments from the stack. Number is a Smi. | 70 // Retrieve the number of arguments from the stack. Number is a Smi. |
72 __ movq(rbx, Operand(rbp, ArgumentsAdaptorFrameConstants::kLengthOffset)); | 71 __ movq(rbx, Operand(rbp, ArgumentsAdaptorFrameConstants::kLengthOffset)); |
73 | 72 |
74 // Leave the frame. | 73 // Leave the frame. |
75 __ movq(rsp, rbp); | 74 __ movq(rsp, rbp); |
76 __ pop(rbp); | 75 __ pop(rbp); |
77 | 76 |
78 // Remove caller arguments from the stack. | 77 // Remove caller arguments from the stack. |
79 // rbx holds a Smi, so we convery to dword offset by multiplying by 4. | 78 // rbx holds a Smi, so we convery to dword offset by multiplying by 4. |
79 // TODO(smi): Find a way to abstract indexing by a smi. | |
80 ASSERT_EQ(kSmiTagSize, 1 && kSmiTag == 0); | 80 ASSERT_EQ(kSmiTagSize, 1 && kSmiTag == 0); |
81 ASSERT_EQ(kPointerSize, (1 << kSmiTagSize) * 4); | 81 ASSERT_EQ(kPointerSize, (1 << kSmiTagSize) * 4); |
82 // TODO(smi): Find way to abstract indexing by a smi. | |
82 __ pop(rcx); | 83 __ pop(rcx); |
83 __ lea(rsp, Operand(rsp, rbx, times_4, 1 * kPointerSize)); // 1 ~ receiver | 84 // 1 * kPointerSize is offset of receiver. |
85 __ lea(rsp, Operand(rsp, rbx, times_half_pointer_size, 1 * kPointerSize)); | |
84 __ push(rcx); | 86 __ push(rcx); |
85 } | 87 } |
86 | 88 |
87 | 89 |
88 void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { | 90 void Builtins::Generate_ArgumentsAdaptorTrampoline(MacroAssembler* masm) { |
89 // ----------- S t a t e ------------- | 91 // ----------- S t a t e ------------- |
90 // -- rax : actual number of arguments | 92 // -- rax : actual number of arguments |
91 // -- rbx : expected number of arguments | 93 // -- rbx : expected number of arguments |
92 // -- rdx : code entry to call | 94 // -- rdx : code entry to call |
93 // ----------------------------------- | 95 // ----------------------------------- |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
185 __ Push(Factory::undefined_value()); | 187 __ Push(Factory::undefined_value()); |
186 __ push(rbx); | 188 __ push(rbx); |
187 __ incq(rax); | 189 __ incq(rax); |
188 __ bind(&done); | 190 __ bind(&done); |
189 } | 191 } |
190 | 192 |
191 // 2. Get the function to call from the stack. | 193 // 2. Get the function to call from the stack. |
192 { Label done, non_function, function; | 194 { Label done, non_function, function; |
193 // The function to call is at position n+1 on the stack. | 195 // The function to call is at position n+1 on the stack. |
194 __ movq(rdi, Operand(rsp, rax, times_pointer_size, +1 * kPointerSize)); | 196 __ movq(rdi, Operand(rsp, rax, times_pointer_size, +1 * kPointerSize)); |
195 __ testl(rdi, Immediate(kSmiTagMask)); | 197 __ JumpIfSmi(rdi, &non_function); |
196 __ j(zero, &non_function); | |
197 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx); | 198 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx); |
198 __ j(equal, &function); | 199 __ j(equal, &function); |
199 | 200 |
200 // Non-function called: Clear the function to force exception. | 201 // Non-function called: Clear the function to force exception. |
201 __ bind(&non_function); | 202 __ bind(&non_function); |
202 __ xor_(rdi, rdi); | 203 __ xor_(rdi, rdi); |
203 __ jmp(&done); | 204 __ jmp(&done); |
204 | 205 |
205 // Function called: Change context eagerly to get the right global object. | 206 // Function called: Change context eagerly to get the right global object. |
206 __ bind(&function); | 207 __ bind(&function); |
207 __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset)); | 208 __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset)); |
208 | 209 |
209 __ bind(&done); | 210 __ bind(&done); |
210 } | 211 } |
211 | 212 |
212 // 3. Make sure first argument is an object; convert if necessary. | 213 // 3. Make sure first argument is an object; convert if necessary. |
213 { Label call_to_object, use_global_receiver, patch_receiver, done; | 214 { Label call_to_object, use_global_receiver, patch_receiver, done; |
214 __ movq(rbx, Operand(rsp, rax, times_pointer_size, 0)); | 215 __ movq(rbx, Operand(rsp, rax, times_pointer_size, 0)); |
215 | 216 |
216 __ testl(rbx, Immediate(kSmiTagMask)); | 217 __ JumpIfSmi(rbx, &call_to_object); |
217 __ j(zero, &call_to_object); | |
218 | 218 |
219 __ CompareRoot(rbx, Heap::kNullValueRootIndex); | 219 __ CompareRoot(rbx, Heap::kNullValueRootIndex); |
220 __ j(equal, &use_global_receiver); | 220 __ j(equal, &use_global_receiver); |
221 __ CompareRoot(rbx, Heap::kUndefinedValueRootIndex); | 221 __ CompareRoot(rbx, Heap::kUndefinedValueRootIndex); |
222 __ j(equal, &use_global_receiver); | 222 __ j(equal, &use_global_receiver); |
223 | 223 |
224 __ CmpObjectType(rbx, FIRST_JS_OBJECT_TYPE, rcx); | 224 __ CmpObjectType(rbx, FIRST_JS_OBJECT_TYPE, rcx); |
225 __ j(below, &call_to_object); | 225 __ j(below, &call_to_object); |
226 __ CmpInstanceType(rcx, LAST_JS_OBJECT_TYPE); | 226 __ CmpInstanceType(rcx, LAST_JS_OBJECT_TYPE); |
227 __ j(below_equal, &done); | 227 __ j(below_equal, &done); |
228 | 228 |
229 __ bind(&call_to_object); | 229 __ bind(&call_to_object); |
230 __ EnterInternalFrame(); // preserves rax, rbx, rdi | 230 __ EnterInternalFrame(); // preserves rax, rbx, rdi |
231 | 231 |
232 // Store the arguments count on the stack (smi tagged). | 232 // Store the arguments count on the stack (smi tagged). |
233 ASSERT(kSmiTag == 0); | 233 __ Integer32ToSmi(rax, rax); |
234 __ shl(rax, Immediate(kSmiTagSize)); | |
235 __ push(rax); | 234 __ push(rax); |
236 | 235 |
237 __ push(rdi); // save edi across the call | 236 __ push(rdi); // save edi across the call |
238 __ push(rbx); | 237 __ push(rbx); |
239 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); | 238 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); |
240 __ movq(rbx, rax); | 239 __ movq(rbx, rax); |
241 __ pop(rdi); // restore edi after the call | 240 __ pop(rdi); // restore edi after the call |
242 | 241 |
243 // Get the arguments count and untag it. | 242 // Get the arguments count and untag it. |
244 __ pop(rax); | 243 __ pop(rax); |
245 __ shr(rax, Immediate(kSmiTagSize)); | 244 __ SmiToInteger32(rax, rax); |
246 | 245 |
247 __ LeaveInternalFrame(); | 246 __ LeaveInternalFrame(); |
248 __ jmp(&patch_receiver); | 247 __ jmp(&patch_receiver); |
249 | 248 |
250 // Use the global receiver object from the called function as the receiver. | 249 // Use the global receiver object from the called function as the receiver. |
251 __ bind(&use_global_receiver); | 250 __ bind(&use_global_receiver); |
252 const int kGlobalIndex = | 251 const int kGlobalIndex = |
253 Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize; | 252 Context::kHeaderSize + Context::GLOBAL_INDEX * kPointerSize; |
254 __ movq(rbx, FieldOperand(rsi, kGlobalIndex)); | 253 __ movq(rbx, FieldOperand(rsi, kGlobalIndex)); |
255 __ movq(rbx, FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset)); | 254 __ movq(rbx, FieldOperand(rbx, GlobalObject::kGlobalReceiverOffset)); |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
349 __ CallRuntime(Runtime::kStackGuard, 1); | 348 __ CallRuntime(Runtime::kStackGuard, 1); |
350 __ pop(rax); | 349 __ pop(rax); |
351 __ jmp(&retry_preemption); | 350 __ jmp(&retry_preemption); |
352 | 351 |
353 __ bind(&no_preemption); | 352 __ bind(&no_preemption); |
354 | 353 |
355 Label okay; | 354 Label okay; |
356 // Make rdx the space we need for the array when it is unrolled onto the | 355 // Make rdx the space we need for the array when it is unrolled onto the |
357 // stack. | 356 // stack. |
358 __ movq(rdx, rax); | 357 __ movq(rdx, rax); |
359 __ shl(rdx, Immediate(kPointerSizeLog2 - kSmiTagSize)); | 358 __ PositiveSmiTimesPowerOfTwoToInteger64(rdx, rdx, kPointerSizeLog2); |
William Hesse
2009/09/10 11:13:22
Does this assume that the smi is zero-extended? I
Lasse Reichstein
2009/09/10 12:28:11
It should not assume anything except that rdx cont
Lasse Reichstein
2009/09/10 12:45:35
Ah, you were referring to the implementation. That
| |
360 __ cmpq(rcx, rdx); | 359 __ cmpq(rcx, rdx); |
361 __ j(greater, &okay); | 360 __ j(greater, &okay); |
362 | 361 |
363 // Too bad: Out of stack space. | 362 // Too bad: Out of stack space. |
364 __ push(Operand(rbp, kFunctionOffset)); | 363 __ push(Operand(rbp, kFunctionOffset)); |
365 __ push(rax); | 364 __ push(rax); |
366 __ InvokeBuiltin(Builtins::APPLY_OVERFLOW, CALL_FUNCTION); | 365 __ InvokeBuiltin(Builtins::APPLY_OVERFLOW, CALL_FUNCTION); |
367 __ bind(&okay); | 366 __ bind(&okay); |
368 } | 367 } |
369 | 368 |
370 // Push current index and limit. | 369 // Push current index and limit. |
371 const int kLimitOffset = | 370 const int kLimitOffset = |
372 StandardFrameConstants::kExpressionsOffset - 1 * kPointerSize; | 371 StandardFrameConstants::kExpressionsOffset - 1 * kPointerSize; |
373 const int kIndexOffset = kLimitOffset - 1 * kPointerSize; | 372 const int kIndexOffset = kLimitOffset - 1 * kPointerSize; |
374 __ push(rax); // limit | 373 __ push(rax); // limit |
375 __ push(Immediate(0)); // index | 374 __ push(Immediate(0)); // index |
376 | 375 |
377 // Change context eagerly to get the right global object if | 376 // Change context eagerly to get the right global object if |
378 // necessary. | 377 // necessary. |
379 __ movq(rdi, Operand(rbp, kFunctionOffset)); | 378 __ movq(rdi, Operand(rbp, kFunctionOffset)); |
380 __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset)); | 379 __ movq(rsi, FieldOperand(rdi, JSFunction::kContextOffset)); |
381 | 380 |
382 // Compute the receiver. | 381 // Compute the receiver. |
383 Label call_to_object, use_global_receiver, push_receiver; | 382 Label call_to_object, use_global_receiver, push_receiver; |
384 __ movq(rbx, Operand(rbp, kReceiverOffset)); | 383 __ movq(rbx, Operand(rbp, kReceiverOffset)); |
385 __ testl(rbx, Immediate(kSmiTagMask)); | 384 __ JumpIfSmi(rbx, &call_to_object); |
386 __ j(zero, &call_to_object); | |
387 __ CompareRoot(rbx, Heap::kNullValueRootIndex); | 385 __ CompareRoot(rbx, Heap::kNullValueRootIndex); |
388 __ j(equal, &use_global_receiver); | 386 __ j(equal, &use_global_receiver); |
389 __ CompareRoot(rbx, Heap::kUndefinedValueRootIndex); | 387 __ CompareRoot(rbx, Heap::kUndefinedValueRootIndex); |
390 __ j(equal, &use_global_receiver); | 388 __ j(equal, &use_global_receiver); |
391 | 389 |
392 // If given receiver is already a JavaScript object then there's no | 390 // If given receiver is already a JavaScript object then there's no |
393 // reason for converting it. | 391 // reason for converting it. |
394 __ CmpObjectType(rbx, FIRST_JS_OBJECT_TYPE, rcx); | 392 __ CmpObjectType(rbx, FIRST_JS_OBJECT_TYPE, rcx); |
395 __ j(below, &call_to_object); | 393 __ j(below, &call_to_object); |
396 __ CmpInstanceType(rcx, LAST_JS_OBJECT_TYPE); | 394 __ CmpInstanceType(rcx, LAST_JS_OBJECT_TYPE); |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
439 __ movq(rax, Operand(rbp, kIndexOffset)); | 437 __ movq(rax, Operand(rbp, kIndexOffset)); |
440 __ addq(rax, Immediate(Smi::FromInt(1))); | 438 __ addq(rax, Immediate(Smi::FromInt(1))); |
441 __ movq(Operand(rbp, kIndexOffset), rax); | 439 __ movq(Operand(rbp, kIndexOffset), rax); |
442 | 440 |
443 __ bind(&entry); | 441 __ bind(&entry); |
444 __ cmpq(rax, Operand(rbp, kLimitOffset)); | 442 __ cmpq(rax, Operand(rbp, kLimitOffset)); |
445 __ j(not_equal, &loop); | 443 __ j(not_equal, &loop); |
446 | 444 |
447 // Invoke the function. | 445 // Invoke the function. |
448 ParameterCount actual(rax); | 446 ParameterCount actual(rax); |
449 __ shr(rax, Immediate(kSmiTagSize)); | 447 __ SmiToInteger32(rax, rax); |
450 __ movq(rdi, Operand(rbp, kFunctionOffset)); | 448 __ movq(rdi, Operand(rbp, kFunctionOffset)); |
451 __ InvokeFunction(rdi, actual, CALL_FUNCTION); | 449 __ InvokeFunction(rdi, actual, CALL_FUNCTION); |
452 | 450 |
453 __ LeaveInternalFrame(); | 451 __ LeaveInternalFrame(); |
454 __ ret(3 * kPointerSize); // remove function, receiver, and arguments | 452 __ ret(3 * kPointerSize); // remove function, receiver, and arguments |
455 } | 453 } |
456 | 454 |
457 | 455 |
458 void Builtins::Generate_JSConstructCall(MacroAssembler* masm) { | 456 void Builtins::Generate_JSConstructCall(MacroAssembler* masm) { |
459 // ----------- S t a t e ------------- | 457 // ----------- S t a t e ------------- |
460 // -- rax: number of arguments | 458 // -- rax: number of arguments |
461 // -- rdi: constructor function | 459 // -- rdi: constructor function |
462 // ----------------------------------- | 460 // ----------------------------------- |
463 | 461 |
464 Label non_function_call; | 462 Label non_function_call; |
465 // Check that function is not a smi. | 463 // Check that function is not a smi. |
466 __ testl(rdi, Immediate(kSmiTagMask)); | 464 __ JumpIfSmi(rdi, &non_function_call); |
467 __ j(zero, &non_function_call); | |
468 // Check that function is a JSFunction. | 465 // Check that function is a JSFunction. |
469 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx); | 466 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx); |
470 __ j(not_equal, &non_function_call); | 467 __ j(not_equal, &non_function_call); |
471 | 468 |
472 // Jump to the function-specific construct stub. | 469 // Jump to the function-specific construct stub. |
473 __ movq(rbx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset)); | 470 __ movq(rbx, FieldOperand(rdi, JSFunction::kSharedFunctionInfoOffset)); |
474 __ movq(rbx, FieldOperand(rbx, SharedFunctionInfo::kConstructStubOffset)); | 471 __ movq(rbx, FieldOperand(rbx, SharedFunctionInfo::kConstructStubOffset)); |
475 __ lea(rbx, FieldOperand(rbx, Code::kHeaderSize)); | 472 __ lea(rbx, FieldOperand(rbx, Code::kHeaderSize)); |
476 __ jmp(rbx); | 473 __ jmp(rbx); |
477 | 474 |
478 // edi: called object | 475 // edi: called object |
479 // eax: number of arguments | 476 // eax: number of arguments |
480 __ bind(&non_function_call); | 477 __ bind(&non_function_call); |
481 | 478 |
482 // Set expected number of arguments to zero (not changing eax). | 479 // Set expected number of arguments to zero (not changing eax). |
483 __ movq(rbx, Immediate(0)); | 480 __ movq(rbx, Immediate(0)); |
484 __ GetBuiltinEntry(rdx, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR); | 481 __ GetBuiltinEntry(rdx, Builtins::CALL_NON_FUNCTION_AS_CONSTRUCTOR); |
485 __ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)), | 482 __ Jump(Handle<Code>(builtin(ArgumentsAdaptorTrampoline)), |
486 RelocInfo::CODE_TARGET); | 483 RelocInfo::CODE_TARGET); |
487 } | 484 } |
488 | 485 |
489 | 486 |
490 void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { | 487 void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { |
491 // Enter a construct frame. | 488 // Enter a construct frame. |
492 __ EnterConstructFrame(); | 489 __ EnterConstructFrame(); |
493 | 490 |
494 // Store a smi-tagged arguments count on the stack. | 491 // Store a smi-tagged arguments count on the stack. |
495 __ shl(rax, Immediate(kSmiTagSize)); | 492 __ Integer32ToSmi(rax, rax); |
496 __ push(rax); | 493 __ push(rax); |
497 | 494 |
498 // Push the function to invoke on the stack. | 495 // Push the function to invoke on the stack. |
499 __ push(rdi); | 496 __ push(rdi); |
500 | 497 |
501 // Try to allocate the object without transitioning into C code. If any of the | 498 // Try to allocate the object without transitioning into C code. If any of the |
502 // preconditions is not met, the code bails out to the runtime call. | 499 // preconditions is not met, the code bails out to the runtime call. |
503 Label rt_call, allocated; | 500 Label rt_call, allocated; |
504 if (FLAG_inline_new) { | 501 if (FLAG_inline_new) { |
505 Label undo_allocation; | 502 Label undo_allocation; |
506 | 503 |
507 #ifdef ENABLE_DEBUGGER_SUPPORT | 504 #ifdef ENABLE_DEBUGGER_SUPPORT |
508 ExternalReference debug_step_in_fp = | 505 ExternalReference debug_step_in_fp = |
509 ExternalReference::debug_step_in_fp_address(); | 506 ExternalReference::debug_step_in_fp_address(); |
510 __ movq(kScratchRegister, debug_step_in_fp); | 507 __ movq(kScratchRegister, debug_step_in_fp); |
511 __ cmpq(Operand(kScratchRegister, 0), Immediate(0)); | 508 __ cmpq(Operand(kScratchRegister, 0), Immediate(0)); |
512 __ j(not_equal, &rt_call); | 509 __ j(not_equal, &rt_call); |
513 #endif | 510 #endif |
514 | 511 |
515 // Verified that the constructor is a JSFunction. | 512 // Verified that the constructor is a JSFunction. |
516 // Load the initial map and verify that it is in fact a map. | 513 // Load the initial map and verify that it is in fact a map. |
517 // rdi: constructor | 514 // rdi: constructor |
518 __ movq(rax, FieldOperand(rdi, JSFunction::kPrototypeOrInitialMapOffset)); | 515 __ movq(rax, FieldOperand(rdi, JSFunction::kPrototypeOrInitialMapOffset)); |
519 // Will both indicate a NULL and a Smi | 516 // Will both indicate a NULL and a Smi |
520 __ testl(rax, Immediate(kSmiTagMask)); | 517 __ JumpIfSmi(rax, &rt_call); |
521 __ j(zero, &rt_call); | |
522 // rdi: constructor | 518 // rdi: constructor |
523 // rax: initial map (if proven valid below) | 519 // rax: initial map (if proven valid below) |
524 __ CmpObjectType(rax, MAP_TYPE, rbx); | 520 __ CmpObjectType(rax, MAP_TYPE, rbx); |
525 __ j(not_equal, &rt_call); | 521 __ j(not_equal, &rt_call); |
526 | 522 |
527 // Check that the constructor is not constructing a JSFunction (see comments | 523 // Check that the constructor is not constructing a JSFunction (see comments |
528 // in Runtime_NewObject in runtime.cc). In which case the initial map's | 524 // in Runtime_NewObject in runtime.cc). In which case the initial map's |
529 // instance type would be JS_FUNCTION_TYPE. | 525 // instance type would be JS_FUNCTION_TYPE. |
530 // rdi: constructor | 526 // rdi: constructor |
531 // rax: initial map | 527 // rax: initial map |
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
661 __ movq(rbx, rax); // store result in rbx | 657 __ movq(rbx, rax); // store result in rbx |
662 | 658 |
663 // New object allocated. | 659 // New object allocated. |
664 // rbx: newly allocated object | 660 // rbx: newly allocated object |
665 __ bind(&allocated); | 661 __ bind(&allocated); |
666 // Retrieve the function from the stack. | 662 // Retrieve the function from the stack. |
667 __ pop(rdi); | 663 __ pop(rdi); |
668 | 664 |
669 // Retrieve smi-tagged arguments count from the stack. | 665 // Retrieve smi-tagged arguments count from the stack. |
670 __ movq(rax, Operand(rsp, 0)); | 666 __ movq(rax, Operand(rsp, 0)); |
671 __ shr(rax, Immediate(kSmiTagSize)); | 667 __ SmiToInteger32(rax, rax); |
672 | 668 |
673 // Push the allocated receiver to the stack. We need two copies | 669 // Push the allocated receiver to the stack. We need two copies |
674 // because we may have to return the original one and the calling | 670 // because we may have to return the original one and the calling |
675 // conventions dictate that the called function pops the receiver. | 671 // conventions dictate that the called function pops the receiver. |
676 __ push(rbx); | 672 __ push(rbx); |
677 __ push(rbx); | 673 __ push(rbx); |
678 | 674 |
679 // Setup pointer to last argument. | 675 // Setup pointer to last argument. |
680 __ lea(rbx, Operand(rbp, StandardFrameConstants::kCallerSPOffset)); | 676 __ lea(rbx, Operand(rbp, StandardFrameConstants::kCallerSPOffset)); |
681 | 677 |
(...skipping 12 matching lines...) Expand all Loading... | |
694 __ InvokeFunction(rdi, actual, CALL_FUNCTION); | 690 __ InvokeFunction(rdi, actual, CALL_FUNCTION); |
695 | 691 |
696 // Restore context from the frame. | 692 // Restore context from the frame. |
697 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | 693 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
698 | 694 |
699 // If the result is an object (in the ECMA sense), we should get rid | 695 // If the result is an object (in the ECMA sense), we should get rid |
700 // of the receiver and use the result; see ECMA-262 section 13.2.2-7 | 696 // of the receiver and use the result; see ECMA-262 section 13.2.2-7 |
701 // on page 74. | 697 // on page 74. |
702 Label use_receiver, exit; | 698 Label use_receiver, exit; |
703 // If the result is a smi, it is *not* an object in the ECMA sense. | 699 // If the result is a smi, it is *not* an object in the ECMA sense. |
704 __ testl(rax, Immediate(kSmiTagMask)); | 700 __ JumpIfSmi(rax, &use_receiver); |
705 __ j(zero, &use_receiver); | |
706 | 701 |
707 // If the type of the result (stored in its map) is less than | 702 // If the type of the result (stored in its map) is less than |
708 // FIRST_JS_OBJECT_TYPE, it is not an object in the ECMA sense. | 703 // FIRST_JS_OBJECT_TYPE, it is not an object in the ECMA sense. |
709 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rcx); | 704 __ CmpObjectType(rax, FIRST_JS_OBJECT_TYPE, rcx); |
710 __ j(above_equal, &exit); | 705 __ j(above_equal, &exit); |
711 | 706 |
712 // Throw away the result of the constructor invocation and use the | 707 // Throw away the result of the constructor invocation and use the |
713 // on-stack receiver as the result. | 708 // on-stack receiver as the result. |
714 __ bind(&use_receiver); | 709 __ bind(&use_receiver); |
715 __ movq(rax, Operand(rsp, 0)); | 710 __ movq(rax, Operand(rsp, 0)); |
716 | 711 |
717 // Restore the arguments count and leave the construct frame. | 712 // Restore the arguments count and leave the construct frame. |
718 __ bind(&exit); | 713 __ bind(&exit); |
719 __ movq(rbx, Operand(rsp, kPointerSize)); // get arguments count | 714 __ movq(rbx, Operand(rsp, kPointerSize)); // get arguments count |
720 __ LeaveConstructFrame(); | 715 __ LeaveConstructFrame(); |
721 | 716 |
722 // Remove caller arguments from the stack and return. | 717 // Remove caller arguments from the stack and return. |
723 ASSERT(kSmiTagSize == 1 && kSmiTag == 0); | 718 ASSERT(kSmiTagSize == 1 && kSmiTag == 0); |
719 // TODO(smi): Find a way to abstract indexing by a smi. | |
724 __ pop(rcx); | 720 __ pop(rcx); |
725 __ lea(rsp, Operand(rsp, rbx, times_4, 1 * kPointerSize)); // 1 ~ receiver | 721 // 1 * kPointerSize is offset of receiver. |
722 __ lea(rsp, Operand(rsp, rbx, times_half_pointer_size, 1 * kPointerSize)); | |
726 __ push(rcx); | 723 __ push(rcx); |
727 __ IncrementCounter(&Counters::constructed_objects, 1); | 724 __ IncrementCounter(&Counters::constructed_objects, 1); |
728 __ ret(0); | 725 __ ret(0); |
729 } | 726 } |
730 | 727 |
731 | 728 |
732 static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm, | 729 static void Generate_JSEntryTrampolineHelper(MacroAssembler* masm, |
733 bool is_construct) { | 730 bool is_construct) { |
734 // Expects five C++ function parameters. | 731 // Expects five C++ function parameters. |
735 // - Address entry (ignored) | 732 // - Address entry (ignored) |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
846 void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) { | 843 void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) { |
847 Generate_JSEntryTrampolineHelper(masm, false); | 844 Generate_JSEntryTrampolineHelper(masm, false); |
848 } | 845 } |
849 | 846 |
850 | 847 |
851 void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) { | 848 void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) { |
852 Generate_JSEntryTrampolineHelper(masm, true); | 849 Generate_JSEntryTrampolineHelper(masm, true); |
853 } | 850 } |
854 | 851 |
855 } } // namespace v8::internal | 852 } } // namespace v8::internal |
OLD | NEW |