OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/v8.h" | 5 #include "src/v8.h" |
6 | 6 |
7 #if V8_TARGET_ARCH_X87 | 7 #if V8_TARGET_ARCH_X87 |
8 | 8 |
9 #include "src/code-factory.h" | 9 #include "src/code-factory.h" |
10 #include "src/codegen.h" | 10 #include "src/codegen.h" |
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
131 if (create_memento) { | 131 if (create_memento) { |
132 __ jmp(count_incremented); | 132 __ jmp(count_incremented); |
133 } else { | 133 } else { |
134 __ jmp(allocated); | 134 __ jmp(allocated); |
135 } | 135 } |
136 } | 136 } |
137 | 137 |
138 | 138 |
139 static void Generate_JSConstructStubHelper(MacroAssembler* masm, | 139 static void Generate_JSConstructStubHelper(MacroAssembler* masm, |
140 bool is_api_function, | 140 bool is_api_function, |
| 141 bool use_new_target, |
141 bool create_memento) { | 142 bool create_memento) { |
142 // ----------- S t a t e ------------- | 143 // ----------- S t a t e ------------- |
143 // -- eax: number of arguments | 144 // -- eax: number of arguments |
144 // -- edi: constructor function | 145 // -- edi: constructor function |
145 // -- ebx: allocation site or undefined | 146 // -- ebx: allocation site or undefined |
146 // -- edx: original constructor | 147 // -- edx: original constructor |
147 // ----------------------------------- | 148 // ----------------------------------- |
148 | 149 |
149 // Should never create mementos for api functions. | 150 // Should never create mementos for api functions. |
150 DCHECK(!is_api_function || !create_memento); | 151 DCHECK(!is_api_function || !create_memento); |
151 | 152 |
152 // Enter a construct frame. | 153 // Enter a construct frame. |
153 { | 154 { |
154 FrameScope scope(masm, StackFrame::CONSTRUCT); | 155 FrameScope scope(masm, StackFrame::CONSTRUCT); |
155 | 156 |
156 if (create_memento) { | 157 if (create_memento) { |
157 __ AssertUndefinedOrAllocationSite(ebx); | 158 __ AssertUndefinedOrAllocationSite(ebx); |
158 __ push(ebx); | 159 __ push(ebx); |
159 } | 160 } |
160 | 161 |
161 // Store a smi-tagged arguments count on the stack. | 162 // Preserve the incoming parameters on the stack. |
162 __ SmiTag(eax); | 163 __ SmiTag(eax); |
163 __ push(eax); | 164 __ push(eax); |
164 | |
165 // Push the function to invoke on the stack. | |
166 __ push(edi); | 165 __ push(edi); |
| 166 if (use_new_target) { |
| 167 __ push(edx); |
| 168 } |
167 | 169 |
168 __ cmp(edx, edi); | 170 __ cmp(edx, edi); |
169 Label normal_new; | 171 Label normal_new; |
170 Label count_incremented; | 172 Label count_incremented; |
171 Label allocated; | 173 Label allocated; |
172 __ j(equal, &normal_new); | 174 __ j(equal, &normal_new); |
173 | 175 |
174 // Original constructor and function are different. | 176 // Original constructor and function are different. |
175 Generate_Runtime_NewObject(masm, create_memento, edx, &count_incremented, | 177 Generate_Runtime_NewObject(masm, create_memento, edx, &count_incremented, |
176 &allocated); | 178 &allocated); |
(...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
392 | 394 |
393 // Allocate the new receiver object using the runtime call. | 395 // Allocate the new receiver object using the runtime call. |
394 __ bind(&rt_call); | 396 __ bind(&rt_call); |
395 Generate_Runtime_NewObject(masm, create_memento, edi, &count_incremented, | 397 Generate_Runtime_NewObject(masm, create_memento, edi, &count_incremented, |
396 &allocated); | 398 &allocated); |
397 // New object allocated. | 399 // New object allocated. |
398 // ebx: newly allocated object | 400 // ebx: newly allocated object |
399 __ bind(&allocated); | 401 __ bind(&allocated); |
400 | 402 |
401 if (create_memento) { | 403 if (create_memento) { |
402 __ mov(ecx, Operand(esp, kPointerSize * 2)); | 404 int offset = (use_new_target ? 3 : 2) * kPointerSize; |
| 405 __ mov(ecx, Operand(esp, offset)); |
403 __ cmp(ecx, masm->isolate()->factory()->undefined_value()); | 406 __ cmp(ecx, masm->isolate()->factory()->undefined_value()); |
404 __ j(equal, &count_incremented); | 407 __ j(equal, &count_incremented); |
405 // ecx is an AllocationSite. We are creating a memento from it, so we | 408 // ecx is an AllocationSite. We are creating a memento from it, so we |
406 // need to increment the memento create count. | 409 // need to increment the memento create count. |
407 __ add(FieldOperand(ecx, AllocationSite::kPretenureCreateCountOffset), | 410 __ add(FieldOperand(ecx, AllocationSite::kPretenureCreateCountOffset), |
408 Immediate(Smi::FromInt(1))); | 411 Immediate(Smi::FromInt(1))); |
409 __ bind(&count_incremented); | 412 __ bind(&count_incremented); |
410 } | 413 } |
411 | 414 |
412 // Retrieve the function from the stack. | 415 // Restore the parameters. |
413 __ pop(edi); | 416 if (use_new_target) { |
| 417 __ pop(edx); // new.target |
| 418 } |
| 419 __ pop(edi); // Constructor function. |
414 | 420 |
415 // Retrieve smi-tagged arguments count from the stack. | 421 // Retrieve smi-tagged arguments count from the stack. |
416 __ mov(eax, Operand(esp, 0)); | 422 __ mov(eax, Operand(esp, 0)); |
417 __ SmiUntag(eax); | 423 __ SmiUntag(eax); |
418 | 424 |
| 425 // Push new.target onto the construct frame. This is stored just below the |
| 426 // receiver on the stack. |
| 427 if (use_new_target) { |
| 428 __ push(edx); |
| 429 } |
| 430 |
419 // Push the allocated receiver to the stack. We need two copies | 431 // Push the allocated receiver to the stack. We need two copies |
420 // because we may have to return the original one and the calling | 432 // because we may have to return the original one and the calling |
421 // conventions dictate that the called function pops the receiver. | 433 // conventions dictate that the called function pops the receiver. |
422 __ push(ebx); | 434 __ push(ebx); |
423 __ push(ebx); | 435 __ push(ebx); |
424 | 436 |
425 // Set up pointer to last argument. | 437 // Set up pointer to last argument. |
426 __ lea(ebx, Operand(ebp, StandardFrameConstants::kCallerSPOffset)); | 438 __ lea(ebx, Operand(ebp, StandardFrameConstants::kCallerSPOffset)); |
427 | 439 |
428 // Copy arguments and receiver to the expression stack. | 440 // Copy arguments and receiver to the expression stack. |
(...skipping 12 matching lines...) Expand all Loading... |
441 Handle<Code> code = | 453 Handle<Code> code = |
442 masm->isolate()->builtins()->HandleApiCallConstruct(); | 454 masm->isolate()->builtins()->HandleApiCallConstruct(); |
443 __ call(code, RelocInfo::CODE_TARGET); | 455 __ call(code, RelocInfo::CODE_TARGET); |
444 } else { | 456 } else { |
445 ParameterCount actual(eax); | 457 ParameterCount actual(eax); |
446 __ InvokeFunction(edi, actual, CALL_FUNCTION, | 458 __ InvokeFunction(edi, actual, CALL_FUNCTION, |
447 NullCallWrapper()); | 459 NullCallWrapper()); |
448 } | 460 } |
449 | 461 |
450 // Store offset of return address for deoptimizer. | 462 // Store offset of return address for deoptimizer. |
451 if (!is_api_function) { | 463 // TODO(arv): Remove the "!use_new_target" before supporting optimization |
| 464 // of functions that reference new.target |
| 465 if (!is_api_function && !use_new_target) { |
452 masm->isolate()->heap()->SetConstructStubDeoptPCOffset(masm->pc_offset()); | 466 masm->isolate()->heap()->SetConstructStubDeoptPCOffset(masm->pc_offset()); |
453 } | 467 } |
454 | 468 |
455 // Restore context from the frame. | 469 // Restore context from the frame. |
456 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 470 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
457 | 471 |
458 // If the result is an object (in the ECMA sense), we should get rid | 472 // If the result is an object (in the ECMA sense), we should get rid |
459 // of the receiver and use the result; see ECMA-262 section 13.2.2-7 | 473 // of the receiver and use the result; see ECMA-262 section 13.2.2-7 |
460 // on page 74. | 474 // on page 74. |
461 Label use_receiver, exit; | 475 Label use_receiver, exit; |
462 | 476 |
463 // If the result is a smi, it is *not* an object in the ECMA sense. | 477 // If the result is a smi, it is *not* an object in the ECMA sense. |
464 __ JumpIfSmi(eax, &use_receiver); | 478 __ JumpIfSmi(eax, &use_receiver); |
465 | 479 |
466 // If the type of the result (stored in its map) is less than | 480 // If the type of the result (stored in its map) is less than |
467 // FIRST_SPEC_OBJECT_TYPE, it is not an object in the ECMA sense. | 481 // FIRST_SPEC_OBJECT_TYPE, it is not an object in the ECMA sense. |
468 __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx); | 482 __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx); |
469 __ j(above_equal, &exit); | 483 __ j(above_equal, &exit); |
470 | 484 |
471 // Throw away the result of the constructor invocation and use the | 485 // Throw away the result of the constructor invocation and use the |
472 // on-stack receiver as the result. | 486 // on-stack receiver as the result. |
473 __ bind(&use_receiver); | 487 __ bind(&use_receiver); |
474 __ mov(eax, Operand(esp, 0)); | 488 __ mov(eax, Operand(esp, 0)); |
475 | 489 |
476 // Restore the arguments count and leave the construct frame. | 490 // Restore the arguments count and leave the construct frame. The arguments |
| 491 // count is stored below the reciever and the new.target. |
477 __ bind(&exit); | 492 __ bind(&exit); |
478 __ mov(ebx, Operand(esp, kPointerSize)); // Get arguments count. | 493 int offset = (use_new_target ? 2 : 1) * kPointerSize; |
| 494 __ mov(ebx, Operand(esp, offset)); |
479 | 495 |
480 // Leave construct frame. | 496 // Leave construct frame. |
481 } | 497 } |
482 | 498 |
483 // Remove caller arguments from the stack and return. | 499 // Remove caller arguments from the stack and return. |
484 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0); | 500 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0); |
485 __ pop(ecx); | 501 __ pop(ecx); |
486 __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver | 502 __ lea(esp, Operand(esp, ebx, times_2, 1 * kPointerSize)); // 1 ~ receiver |
487 __ push(ecx); | 503 __ push(ecx); |
488 __ IncrementCounter(masm->isolate()->counters()->constructed_objects(), 1); | 504 __ IncrementCounter(masm->isolate()->counters()->constructed_objects(), 1); |
489 __ ret(0); | 505 __ ret(0); |
490 } | 506 } |
491 | 507 |
492 | 508 |
493 void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { | 509 void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { |
494 Generate_JSConstructStubHelper(masm, false, FLAG_pretenuring_call_new); | 510 Generate_JSConstructStubHelper(masm, false, false, FLAG_pretenuring_call_new); |
495 } | 511 } |
496 | 512 |
497 | 513 |
498 void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) { | 514 void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) { |
499 Generate_JSConstructStubHelper(masm, true, false); | 515 Generate_JSConstructStubHelper(masm, true, false, false); |
500 } | 516 } |
501 | 517 |
502 | 518 |
| 519 void Builtins::Generate_JSConstructStubNewTarget(MacroAssembler* masm) { |
| 520 Generate_JSConstructStubHelper(masm, false, true, FLAG_pretenuring_call_new); |
| 521 } |
| 522 |
| 523 |
503 void Builtins::Generate_JSConstructStubForDerived(MacroAssembler* masm) { | 524 void Builtins::Generate_JSConstructStubForDerived(MacroAssembler* masm) { |
504 // ----------- S t a t e ------------- | 525 // ----------- S t a t e ------------- |
505 // -- eax: number of arguments | 526 // -- eax: number of arguments |
506 // -- edi: constructor function | 527 // -- edi: constructor function |
507 // -- ebx: allocation site or undefined | 528 // -- ebx: allocation site or undefined |
508 // -- edx: original constructor | 529 // -- edx: original constructor |
509 // ----------------------------------- | 530 // ----------------------------------- |
510 | 531 |
511 // TODO(dslomov): support pretenuring | 532 // TODO(dslomov): support pretenuring |
512 CHECK(!FLAG_pretenuring_call_new); | 533 CHECK(!FLAG_pretenuring_call_new); |
(...skipping 1203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1716 | 1737 |
1717 __ bind(&ok); | 1738 __ bind(&ok); |
1718 __ ret(0); | 1739 __ ret(0); |
1719 } | 1740 } |
1720 | 1741 |
1721 #undef __ | 1742 #undef __ |
1722 } // namespace internal | 1743 } // namespace internal |
1723 } // namespace v8 | 1744 } // namespace v8 |
1724 | 1745 |
1725 #endif // V8_TARGET_ARCH_X87 | 1746 #endif // V8_TARGET_ARCH_X87 |
OLD | NEW |