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 #if V8_TARGET_ARCH_X64 | 5 #if V8_TARGET_ARCH_X64 |
6 | 6 |
7 #include "src/ast/scopes.h" | 7 #include "src/ast/scopes.h" |
8 #include "src/code-factory.h" | 8 #include "src/code-factory.h" |
9 #include "src/code-stubs.h" | 9 #include "src/code-stubs.h" |
10 #include "src/codegen.h" | 10 #include "src/codegen.h" |
(...skipping 3290 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3301 void FullCodeGenerator::EmitGetSuperConstructor(CallRuntime* expr) { | 3301 void FullCodeGenerator::EmitGetSuperConstructor(CallRuntime* expr) { |
3302 ZoneList<Expression*>* args = expr->arguments(); | 3302 ZoneList<Expression*>* args = expr->arguments(); |
3303 DCHECK_EQ(1, args->length()); | 3303 DCHECK_EQ(1, args->length()); |
3304 VisitForAccumulatorValue(args->at(0)); | 3304 VisitForAccumulatorValue(args->at(0)); |
3305 __ AssertFunction(rax); | 3305 __ AssertFunction(rax); |
3306 __ movp(rax, FieldOperand(rax, HeapObject::kMapOffset)); | 3306 __ movp(rax, FieldOperand(rax, HeapObject::kMapOffset)); |
3307 __ movp(rax, FieldOperand(rax, Map::kPrototypeOffset)); | 3307 __ movp(rax, FieldOperand(rax, Map::kPrototypeOffset)); |
3308 context()->Plug(rax); | 3308 context()->Plug(rax); |
3309 } | 3309 } |
3310 | 3310 |
| 3311 |
| 3312 void FullCodeGenerator::EmitFastOneByteArrayJoin(CallRuntime* expr) { |
| 3313 Label bailout, return_result, done, one_char_separator, long_separator, |
| 3314 non_trivial_array, not_size_one_array, loop, |
| 3315 loop_1, loop_1_condition, loop_2, loop_2_entry, loop_3, loop_3_entry; |
| 3316 ZoneList<Expression*>* args = expr->arguments(); |
| 3317 DCHECK(args->length() == 2); |
| 3318 // We will leave the separator on the stack until the end of the function. |
| 3319 VisitForStackValue(args->at(1)); |
| 3320 // Load this to rax (= array) |
| 3321 VisitForAccumulatorValue(args->at(0)); |
| 3322 // All aliases of the same register have disjoint lifetimes. |
| 3323 Register array = rax; |
| 3324 Register elements = no_reg; // Will be rax. |
| 3325 |
| 3326 Register index = rdx; |
| 3327 |
| 3328 Register string_length = rcx; |
| 3329 |
| 3330 Register string = rsi; |
| 3331 |
| 3332 Register scratch = rbx; |
| 3333 |
| 3334 Register array_length = rdi; |
| 3335 Register result_pos = no_reg; // Will be rdi. |
| 3336 |
| 3337 Operand separator_operand = Operand(rsp, 2 * kPointerSize); |
| 3338 Operand result_operand = Operand(rsp, 1 * kPointerSize); |
| 3339 Operand array_length_operand = Operand(rsp, 0 * kPointerSize); |
| 3340 // Separator operand is already pushed. Make room for the two |
| 3341 // other stack fields, and clear the direction flag in anticipation |
| 3342 // of calling CopyBytes. |
| 3343 __ subp(rsp, Immediate(2 * kPointerSize)); |
| 3344 __ cld(); |
| 3345 // Check that the array is a JSArray |
| 3346 __ JumpIfSmi(array, &bailout); |
| 3347 __ CmpObjectType(array, JS_ARRAY_TYPE, scratch); |
| 3348 __ j(not_equal, &bailout); |
| 3349 |
| 3350 // Check that the array has fast elements. |
| 3351 __ CheckFastElements(scratch, &bailout); |
| 3352 |
| 3353 // Array has fast elements, so its length must be a smi. |
| 3354 // If the array has length zero, return the empty string. |
| 3355 __ movp(array_length, FieldOperand(array, JSArray::kLengthOffset)); |
| 3356 __ SmiCompare(array_length, Smi::FromInt(0)); |
| 3357 __ j(not_zero, &non_trivial_array); |
| 3358 __ LoadRoot(rax, Heap::kempty_stringRootIndex); |
| 3359 __ jmp(&return_result); |
| 3360 |
| 3361 // Save the array length on the stack. |
| 3362 __ bind(&non_trivial_array); |
| 3363 __ SmiToInteger32(array_length, array_length); |
| 3364 __ movl(array_length_operand, array_length); |
| 3365 |
| 3366 // Save the FixedArray containing array's elements. |
| 3367 // End of array's live range. |
| 3368 elements = array; |
| 3369 __ movp(elements, FieldOperand(array, JSArray::kElementsOffset)); |
| 3370 array = no_reg; |
| 3371 |
| 3372 |
| 3373 // Check that all array elements are sequential one-byte strings, and |
| 3374 // accumulate the sum of their lengths, as a smi-encoded value. |
| 3375 __ Set(index, 0); |
| 3376 __ Set(string_length, 0); |
| 3377 // Loop condition: while (index < array_length). |
| 3378 // Live loop registers: index(int32), array_length(int32), string(String*), |
| 3379 // scratch, string_length(int32), elements(FixedArray*). |
| 3380 if (generate_debug_code_) { |
| 3381 __ cmpp(index, array_length); |
| 3382 __ Assert(below, kNoEmptyArraysHereInEmitFastOneByteArrayJoin); |
| 3383 } |
| 3384 __ bind(&loop); |
| 3385 __ movp(string, FieldOperand(elements, |
| 3386 index, |
| 3387 times_pointer_size, |
| 3388 FixedArray::kHeaderSize)); |
| 3389 __ JumpIfSmi(string, &bailout); |
| 3390 __ movp(scratch, FieldOperand(string, HeapObject::kMapOffset)); |
| 3391 __ movzxbl(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); |
| 3392 __ andb(scratch, Immediate( |
| 3393 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask)); |
| 3394 __ cmpb(scratch, Immediate(kStringTag | kOneByteStringTag | kSeqStringTag)); |
| 3395 __ j(not_equal, &bailout); |
| 3396 __ AddSmiField(string_length, |
| 3397 FieldOperand(string, SeqOneByteString::kLengthOffset)); |
| 3398 __ j(overflow, &bailout); |
| 3399 __ incl(index); |
| 3400 __ cmpl(index, array_length); |
| 3401 __ j(less, &loop); |
| 3402 |
| 3403 // Live registers: |
| 3404 // string_length: Sum of string lengths. |
| 3405 // elements: FixedArray of strings. |
| 3406 // index: Array length. |
| 3407 // array_length: Array length. |
| 3408 |
| 3409 // If array_length is 1, return elements[0], a string. |
| 3410 __ cmpl(array_length, Immediate(1)); |
| 3411 __ j(not_equal, ¬_size_one_array); |
| 3412 __ movp(rax, FieldOperand(elements, FixedArray::kHeaderSize)); |
| 3413 __ jmp(&return_result); |
| 3414 |
| 3415 __ bind(¬_size_one_array); |
| 3416 |
| 3417 // End of array_length live range. |
| 3418 result_pos = array_length; |
| 3419 array_length = no_reg; |
| 3420 |
| 3421 // Live registers: |
| 3422 // string_length: Sum of string lengths. |
| 3423 // elements: FixedArray of strings. |
| 3424 // index: Array length. |
| 3425 |
| 3426 // Check that the separator is a sequential one-byte string. |
| 3427 __ movp(string, separator_operand); |
| 3428 __ JumpIfSmi(string, &bailout); |
| 3429 __ movp(scratch, FieldOperand(string, HeapObject::kMapOffset)); |
| 3430 __ movzxbl(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); |
| 3431 __ andb(scratch, Immediate( |
| 3432 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask)); |
| 3433 __ cmpb(scratch, Immediate(kStringTag | kOneByteStringTag | kSeqStringTag)); |
| 3434 __ j(not_equal, &bailout); |
| 3435 |
| 3436 // Live registers: |
| 3437 // string_length: Sum of string lengths. |
| 3438 // elements: FixedArray of strings. |
| 3439 // index: Array length. |
| 3440 // string: Separator string. |
| 3441 |
| 3442 // Add (separator length times (array_length - 1)) to string_length. |
| 3443 __ SmiToInteger32(scratch, |
| 3444 FieldOperand(string, SeqOneByteString::kLengthOffset)); |
| 3445 __ decl(index); |
| 3446 __ imull(scratch, index); |
| 3447 __ j(overflow, &bailout); |
| 3448 __ addl(string_length, scratch); |
| 3449 __ j(overflow, &bailout); |
| 3450 __ jmp(&bailout); |
| 3451 |
| 3452 // Bailout for large object allocations. |
| 3453 __ cmpl(string_length, Immediate(Page::kMaxRegularHeapObjectSize)); |
| 3454 __ j(greater, &bailout); |
| 3455 |
| 3456 // Live registers and stack values: |
| 3457 // string_length: Total length of result string. |
| 3458 // elements: FixedArray of strings. |
| 3459 __ AllocateOneByteString(result_pos, string_length, scratch, index, string, |
| 3460 &bailout); |
| 3461 __ movp(result_operand, result_pos); |
| 3462 __ leap(result_pos, FieldOperand(result_pos, SeqOneByteString::kHeaderSize)); |
| 3463 |
| 3464 __ movp(string, separator_operand); |
| 3465 __ SmiCompare(FieldOperand(string, SeqOneByteString::kLengthOffset), |
| 3466 Smi::FromInt(1)); |
| 3467 __ j(equal, &one_char_separator); |
| 3468 __ j(greater, &long_separator); |
| 3469 |
| 3470 |
| 3471 // Empty separator case: |
| 3472 __ Set(index, 0); |
| 3473 __ movl(scratch, array_length_operand); |
| 3474 __ jmp(&loop_1_condition); |
| 3475 // Loop condition: while (index < array_length). |
| 3476 __ bind(&loop_1); |
| 3477 // Each iteration of the loop concatenates one string to the result. |
| 3478 // Live values in registers: |
| 3479 // index: which element of the elements array we are adding to the result. |
| 3480 // result_pos: the position to which we are currently copying characters. |
| 3481 // elements: the FixedArray of strings we are joining. |
| 3482 // scratch: array length. |
| 3483 |
| 3484 // Get string = array[index]. |
| 3485 __ movp(string, FieldOperand(elements, index, |
| 3486 times_pointer_size, |
| 3487 FixedArray::kHeaderSize)); |
| 3488 __ SmiToInteger32(string_length, |
| 3489 FieldOperand(string, String::kLengthOffset)); |
| 3490 __ leap(string, |
| 3491 FieldOperand(string, SeqOneByteString::kHeaderSize)); |
| 3492 __ CopyBytes(result_pos, string, string_length); |
| 3493 __ incl(index); |
| 3494 __ bind(&loop_1_condition); |
| 3495 __ cmpl(index, scratch); |
| 3496 __ j(less, &loop_1); // Loop while (index < array_length). |
| 3497 __ jmp(&done); |
| 3498 |
| 3499 // Generic bailout code used from several places. |
| 3500 __ bind(&bailout); |
| 3501 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); |
| 3502 __ jmp(&return_result); |
| 3503 |
| 3504 |
| 3505 // One-character separator case |
| 3506 __ bind(&one_char_separator); |
| 3507 // Get the separator one-byte character value. |
| 3508 // Register "string" holds the separator. |
| 3509 __ movzxbl(scratch, FieldOperand(string, SeqOneByteString::kHeaderSize)); |
| 3510 __ Set(index, 0); |
| 3511 // Jump into the loop after the code that copies the separator, so the first |
| 3512 // element is not preceded by a separator |
| 3513 __ jmp(&loop_2_entry); |
| 3514 // Loop condition: while (index < length). |
| 3515 __ bind(&loop_2); |
| 3516 // Each iteration of the loop concatenates one string to the result. |
| 3517 // Live values in registers: |
| 3518 // elements: The FixedArray of strings we are joining. |
| 3519 // index: which element of the elements array we are adding to the result. |
| 3520 // result_pos: the position to which we are currently copying characters. |
| 3521 // scratch: Separator character. |
| 3522 |
| 3523 // Copy the separator character to the result. |
| 3524 __ movb(Operand(result_pos, 0), scratch); |
| 3525 __ incp(result_pos); |
| 3526 |
| 3527 __ bind(&loop_2_entry); |
| 3528 // Get string = array[index]. |
| 3529 __ movp(string, FieldOperand(elements, index, |
| 3530 times_pointer_size, |
| 3531 FixedArray::kHeaderSize)); |
| 3532 __ SmiToInteger32(string_length, |
| 3533 FieldOperand(string, String::kLengthOffset)); |
| 3534 __ leap(string, |
| 3535 FieldOperand(string, SeqOneByteString::kHeaderSize)); |
| 3536 __ CopyBytes(result_pos, string, string_length); |
| 3537 __ incl(index); |
| 3538 __ cmpl(index, array_length_operand); |
| 3539 __ j(less, &loop_2); // End while (index < length). |
| 3540 __ jmp(&done); |
| 3541 |
| 3542 |
| 3543 // Long separator case (separator is more than one character). |
| 3544 __ bind(&long_separator); |
| 3545 |
| 3546 // Make elements point to end of elements array, and index |
| 3547 // count from -array_length to zero, so we don't need to maintain |
| 3548 // a loop limit. |
| 3549 __ movl(index, array_length_operand); |
| 3550 __ leap(elements, FieldOperand(elements, index, times_pointer_size, |
| 3551 FixedArray::kHeaderSize)); |
| 3552 __ negq(index); |
| 3553 |
| 3554 // Replace separator string with pointer to its first character, and |
| 3555 // make scratch be its length. |
| 3556 __ movp(string, separator_operand); |
| 3557 __ SmiToInteger32(scratch, |
| 3558 FieldOperand(string, String::kLengthOffset)); |
| 3559 __ leap(string, |
| 3560 FieldOperand(string, SeqOneByteString::kHeaderSize)); |
| 3561 __ movp(separator_operand, string); |
| 3562 |
| 3563 // Jump into the loop after the code that copies the separator, so the first |
| 3564 // element is not preceded by a separator |
| 3565 __ jmp(&loop_3_entry); |
| 3566 // Loop condition: while (index < length). |
| 3567 __ bind(&loop_3); |
| 3568 // Each iteration of the loop concatenates one string to the result. |
| 3569 // Live values in registers: |
| 3570 // index: which element of the elements array we are adding to the result. |
| 3571 // result_pos: the position to which we are currently copying characters. |
| 3572 // scratch: Separator length. |
| 3573 // separator_operand (rsp[0x10]): Address of first char of separator. |
| 3574 |
| 3575 // Copy the separator to the result. |
| 3576 __ movp(string, separator_operand); |
| 3577 __ movl(string_length, scratch); |
| 3578 __ CopyBytes(result_pos, string, string_length, 2); |
| 3579 |
| 3580 __ bind(&loop_3_entry); |
| 3581 // Get string = array[index]. |
| 3582 __ movp(string, Operand(elements, index, times_pointer_size, 0)); |
| 3583 __ SmiToInteger32(string_length, |
| 3584 FieldOperand(string, String::kLengthOffset)); |
| 3585 __ leap(string, |
| 3586 FieldOperand(string, SeqOneByteString::kHeaderSize)); |
| 3587 __ CopyBytes(result_pos, string, string_length); |
| 3588 __ incq(index); |
| 3589 __ j(not_equal, &loop_3); // Loop while (index < 0). |
| 3590 |
| 3591 __ bind(&done); |
| 3592 __ movp(rax, result_operand); |
| 3593 |
| 3594 __ bind(&return_result); |
| 3595 // Drop temp values from the stack, and restore context register. |
| 3596 __ addp(rsp, Immediate(3 * kPointerSize)); |
| 3597 __ movp(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); |
| 3598 context()->Plug(rax); |
| 3599 } |
| 3600 |
3311 | 3601 |
3312 void FullCodeGenerator::EmitDebugIsActive(CallRuntime* expr) { | 3602 void FullCodeGenerator::EmitDebugIsActive(CallRuntime* expr) { |
3313 DCHECK(expr->arguments()->length() == 0); | 3603 DCHECK(expr->arguments()->length() == 0); |
3314 ExternalReference debug_is_active = | 3604 ExternalReference debug_is_active = |
3315 ExternalReference::debug_is_active_address(isolate()); | 3605 ExternalReference::debug_is_active_address(isolate()); |
3316 __ Move(kScratchRegister, debug_is_active); | 3606 __ Move(kScratchRegister, debug_is_active); |
3317 __ movzxbp(rax, Operand(kScratchRegister, 0)); | 3607 __ movzxbp(rax, Operand(kScratchRegister, 0)); |
3318 __ Integer32ToSmi(rax, rax); | 3608 __ Integer32ToSmi(rax, rax); |
3319 context()->Plug(rax); | 3609 context()->Plug(rax); |
3320 } | 3610 } |
(...skipping 837 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4158 DCHECK_EQ(isolate->builtins()->OsrAfterStackCheck()->entry(), | 4448 DCHECK_EQ(isolate->builtins()->OsrAfterStackCheck()->entry(), |
4159 Assembler::target_address_at(call_target_address, | 4449 Assembler::target_address_at(call_target_address, |
4160 unoptimized_code)); | 4450 unoptimized_code)); |
4161 return OSR_AFTER_STACK_CHECK; | 4451 return OSR_AFTER_STACK_CHECK; |
4162 } | 4452 } |
4163 | 4453 |
4164 } // namespace internal | 4454 } // namespace internal |
4165 } // namespace v8 | 4455 } // namespace v8 |
4166 | 4456 |
4167 #endif // V8_TARGET_ARCH_X64 | 4457 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |