OLD | NEW |
---|---|
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 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 3213 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3224 | 3224 |
3225 __ movl(rax, FieldOperand(rax, String::kHashFieldOffset)); | 3225 __ movl(rax, FieldOperand(rax, String::kHashFieldOffset)); |
3226 ASSERT(String::kHashShift >= kSmiTagSize); | 3226 ASSERT(String::kHashShift >= kSmiTagSize); |
3227 __ IndexFromHash(rax, rax); | 3227 __ IndexFromHash(rax, rax); |
3228 | 3228 |
3229 context()->Plug(rax); | 3229 context()->Plug(rax); |
3230 } | 3230 } |
3231 | 3231 |
3232 | 3232 |
3233 void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList<Expression*>* args) { | 3233 void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList<Expression*>* args) { |
3234 context()->Plug(Heap::kUndefinedValueRootIndex); | 3234 Label bailout, return_result, done, one_char_separator, long_separator, |
3235 non_trivial_array, not_size_one_array, loop, | |
3236 loop_1, loop_1_condition, loop_2, loop_2_entry, loop_3, loop_3_entry; | |
3237 ASSERT(args->length() == 2); | |
3238 // We will leave the separator on the stack until the end of the function. | |
3239 VisitForStackValue(args->at(1)); | |
3240 // Load this to rax (= array) | |
3241 VisitForAccumulatorValue(args->at(0)); | |
3242 // All aliases of the same register have disjoint lifetimes. | |
3243 Register array = rax; | |
3244 Register elements = no_reg; // Will be rax. | |
3245 | |
3246 Register index = rdx; | |
3247 | |
3248 Register string_length = rcx; | |
3249 | |
3250 Register string = rsi; | |
3251 | |
3252 Register scratch = rbx; | |
3253 | |
3254 Register array_length = rdi; | |
3255 Register result_pos = no_reg; // Will be rdi. | |
3256 | |
3257 Operand separator_operand = Operand(rsp, 2 * kPointerSize); | |
3258 Operand result_operand = Operand(rsp, 1 * kPointerSize); | |
3259 Operand array_length_operand = Operand(rsp, 0 * kPointerSize); | |
3260 // Separator operand is already pushed. Make room for the two | |
3261 // other stack fields, and clear the direction flag in anticipation | |
3262 // of calling CopyBytes. | |
3263 __ subq(rsp, Immediate(2 * kPointerSize)); | |
3264 __ cld(); | |
3265 // Check that the array is a JSArray | |
3266 __ JumpIfSmi(array, &bailout); | |
3267 __ CmpObjectType(array, JS_ARRAY_TYPE, scratch); | |
3268 __ j(not_equal, &bailout); | |
3269 | |
3270 // Check that the array has fast elements. | |
3271 __ testb(FieldOperand(scratch, Map::kBitField2Offset), | |
3272 Immediate(1 << Map::kHasFastElements)); | |
3273 __ j(zero, &bailout); | |
3274 | |
3275 // Array has fast elements, so its length must be a smi. | |
3276 // If the array has length zero, return the empty string. | |
3277 __ movq(array_length, FieldOperand(array, JSArray::kLengthOffset)); | |
3278 __ SmiCompare(array_length, Smi::FromInt(0)); | |
3279 __ j(not_zero, &non_trivial_array); | |
3280 __ LoadRoot(rax, Heap::kEmptyStringRootIndex); | |
3281 __ jmp(&return_result); | |
3282 | |
3283 // Save the array length on the stack. | |
3284 __ bind(&non_trivial_array); | |
3285 __ SmiToInteger32(array_length, array_length); | |
3286 __ movl(array_length_operand, array_length); | |
3287 | |
3288 // Save the FixedArray containing array's elements. | |
3289 // End of array's live range. | |
3290 elements = array; | |
3291 __ movq(elements, FieldOperand(array, JSArray::kElementsOffset)); | |
3292 array = no_reg; | |
3293 | |
3294 | |
3295 // Check that all array elements are sequential ASCII strings, and | |
3296 // accumulate the sum of their lengths, as a smi-encoded value. | |
3297 __ Set(index, 0); | |
3298 __ Set(string_length, 0); | |
3299 // Loop condition: while (index < array_length). | |
3300 // Live loop registers: index(int32), array_length(int32), string(String*), | |
3301 // scratch, string_length(int32), elements(FixedArray*). | |
3302 if (FLAG_debug_code) { | |
3303 __ cmpq(index, array_length); | |
3304 __ Assert(below, "No empty arrays here in EmitFastAsciiArrayJoin"); | |
3305 } | |
3306 __ bind(&loop); | |
3307 __ movq(string, FieldOperand(elements, | |
3308 index, | |
3309 times_pointer_size, | |
3310 FixedArray::kHeaderSize)); | |
3311 __ JumpIfSmi(string, &bailout); | |
3312 __ movq(scratch, FieldOperand(string, HeapObject::kMapOffset)); | |
3313 __ movzxbl(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); | |
3314 __ andb(scratch, Immediate( | |
3315 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask)); | |
3316 __ cmpb(scratch, Immediate(kStringTag | kAsciiStringTag | kSeqStringTag)); | |
3317 __ j(not_equal, &bailout); | |
3318 __ AddSmiField(string_length, | |
3319 FieldOperand(string, SeqAsciiString::kLengthOffset)); | |
3320 __ j(overflow, &bailout); | |
3321 __ incl(index); | |
3322 __ cmpl(index, array_length); | |
3323 __ j(less, &loop); | |
3324 | |
3325 // Live registers: | |
3326 // string_length: Sum of string lengths. | |
3327 // elements: FixedArray of strings. | |
3328 // index: Array length. | |
3329 // array_length: Array length. | |
3330 | |
3331 // If array_length is 1, return elements[0], a string. | |
3332 __ cmpl(array_length, Immediate(1)); | |
3333 __ j(not_equal, ¬_size_one_array); | |
3334 __ movq(rax, FieldOperand(elements, FixedArray::kHeaderSize)); | |
3335 __ jmp(&return_result); | |
3336 | |
3337 __ bind(¬_size_one_array); | |
3338 | |
3339 // End of array_length live range. | |
3340 result_pos = array_length; | |
3341 array_length = no_reg; | |
3342 | |
3343 // Live registers: | |
3344 // string_length: Sum of string lengths. | |
3345 // elements: FixedArray of strings. | |
3346 // index: Array length. | |
3347 | |
3348 // Check that the separator is a flat ASCII string. | |
William Hesse
2011/03/24 12:02:21
sequential ASCII string?
Lasse Reichstein
2011/03/24 12:14:08
Done.
| |
3349 __ movq(string, separator_operand); | |
3350 __ JumpIfSmi(string, &bailout); | |
3351 __ movq(scratch, FieldOperand(string, HeapObject::kMapOffset)); | |
3352 __ movzxbl(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); | |
3353 __ andb(scratch, Immediate( | |
3354 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask)); | |
3355 __ cmpb(scratch, Immediate(ASCII_STRING_TYPE)); | |
William Hesse
2011/03/24 12:02:21
Why don't we use ASCII_STRING_TYPE above? And why
Lasse Reichstein
2011/03/24 12:14:08
No idea. I'll just make it use the or-of-three-thi
| |
3356 __ j(not_equal, &bailout); | |
3357 | |
3358 // Live registers: | |
3359 // string_length: Sum of string lengths. | |
3360 // elements: FixedArray of strings. | |
3361 // index: Array length. | |
3362 // string: Separator string. | |
3363 | |
3364 // Add (separator length times (array_length - 1)) to string_length. | |
3365 __ SmiToInteger32(scratch, | |
3366 FieldOperand(string, SeqAsciiString::kLengthOffset)); | |
3367 __ decl(index); | |
3368 __ imull(scratch, index); | |
3369 __ j(overflow, &bailout); | |
3370 __ addl(string_length, scratch); | |
3371 __ j(overflow, &bailout); | |
3372 | |
3373 // Live registers and stack values: | |
3374 // string_length: Total length of result string. | |
3375 // elements: FixedArray of strings. | |
3376 __ AllocateAsciiString(result_pos, string_length, scratch, | |
3377 index, string, &bailout); | |
3378 __ movq(result_operand, result_pos); | |
3379 __ lea(result_pos, FieldOperand(result_pos, SeqAsciiString::kHeaderSize)); | |
3380 | |
3381 __ movq(string, separator_operand); | |
3382 __ SmiCompare(FieldOperand(string, SeqAsciiString::kLengthOffset), | |
3383 Smi::FromInt(1)); | |
3384 __ j(equal, &one_char_separator); | |
3385 __ j(greater, &long_separator); | |
3386 | |
3387 | |
3388 // Empty separator case: | |
3389 __ Set(index, 0); | |
3390 __ movl(scratch, array_length_operand); | |
3391 __ jmp(&loop_1_condition); | |
3392 // Loop condition: while (index < array_length). | |
3393 __ bind(&loop_1); | |
3394 // Each iteration of the loop concatenates one string to the result. | |
3395 // Live values in registers: | |
3396 // index: which element of the elements array we are adding to the result. | |
3397 // result_pos: the position to which we are currently copying characters. | |
3398 // elements: the FixedArray of strings we are joining. | |
3399 // scratch: array length. | |
3400 | |
3401 // Get string = array[index]. | |
3402 __ movq(string, FieldOperand(elements, index, | |
3403 times_pointer_size, | |
3404 FixedArray::kHeaderSize)); | |
3405 __ SmiToInteger32(string_length, | |
3406 FieldOperand(string, String::kLengthOffset)); | |
3407 __ lea(string, | |
3408 FieldOperand(string, SeqAsciiString::kHeaderSize)); | |
3409 __ CopyBytes(result_pos, string, string_length); | |
3410 __ incl(index); | |
3411 __ bind(&loop_1_condition); | |
3412 __ cmpl(index, scratch); | |
3413 __ j(less, &loop_1); // Loop while (index < array_length). | |
3414 __ jmp(&done); | |
3415 | |
3416 // Generic bailout code used from several places. | |
3417 __ bind(&bailout); | |
3418 __ LoadRoot(rax, Heap::kUndefinedValueRootIndex); | |
3419 __ jmp(&return_result); | |
3420 | |
3421 | |
3422 // One-character separator case | |
3423 __ bind(&one_char_separator); | |
3424 // Get the separator ascii character value. | |
3425 // Register "string" holds the separator. | |
3426 __ movzxbl(scratch, FieldOperand(string, SeqAsciiString::kHeaderSize)); | |
3427 __ Set(index, 0); | |
3428 // Jump into the loop after the code that copies the separator, so the first | |
3429 // element is not preceded by a separator | |
3430 __ jmp(&loop_2_entry); | |
3431 // Loop condition: while (index < length). | |
3432 __ bind(&loop_2); | |
3433 // Each iteration of the loop concatenates one string to the result. | |
3434 // Live values in registers: | |
3435 // elements: The FixedArray of strings we are joining. | |
3436 // index: which element of the elements array we are adding to the result. | |
3437 // result_pos: the position to which we are currently copying characters. | |
3438 // scratch: Separator character. | |
3439 | |
3440 // Copy the separator character to the result. | |
3441 __ movb(Operand(result_pos, 0), scratch); | |
3442 __ incq(result_pos); | |
3443 | |
3444 __ bind(&loop_2_entry); | |
3445 // Get string = array[index]. | |
3446 __ movq(string, FieldOperand(elements, index, | |
3447 times_pointer_size, | |
3448 FixedArray::kHeaderSize)); | |
3449 __ SmiToInteger32(string_length, | |
3450 FieldOperand(string, String::kLengthOffset)); | |
3451 __ lea(string, | |
3452 FieldOperand(string, SeqAsciiString::kHeaderSize)); | |
3453 __ CopyBytes(result_pos, string, string_length); | |
3454 __ incl(index); | |
3455 __ cmpl(index, array_length_operand); | |
3456 __ j(less, &loop_2); // End while (index < length). | |
3457 __ jmp(&done); | |
3458 | |
3459 | |
3460 // Long separator case (separator is more than one character). | |
3461 __ bind(&long_separator); | |
3462 | |
3463 // Make elements point to end of elements array, and index | |
3464 // count from -array_length to zero, so we don't need to maintain | |
3465 // a loop limit. | |
William Hesse
2011/03/24 12:02:21
You should try this change on ia32, to see if it m
Lasse Reichstein
2011/03/24 12:14:08
Good idea for another CL.
| |
3466 __ movl(index, array_length_operand); | |
3467 __ lea(elements, FieldOperand(elements, index, times_pointer_size, | |
3468 FixedArray::kHeaderSize)); | |
3469 __ neg(index); | |
3470 | |
3471 // Replace separator string with pointer to its first character, and | |
3472 // make scratch be its length. | |
3473 __ movq(string, separator_operand); | |
3474 __ SmiToInteger32(scratch, | |
3475 FieldOperand(string, String::kLengthOffset)); | |
3476 __ lea(string, | |
3477 FieldOperand(string, SeqAsciiString::kHeaderSize)); | |
3478 __ movq(separator_operand, string); | |
3479 | |
3480 // Jump into the loop after the code that copies the separator, so the first | |
3481 // element is not preceded by a separator | |
3482 __ jmp(&loop_3_entry); | |
3483 // Loop condition: while (index < length). | |
3484 __ bind(&loop_3); | |
3485 // Each iteration of the loop concatenates one string to the result. | |
3486 // Live values in registers: | |
3487 // index: which element of the elements array we are adding to the result. | |
3488 // result_pos: the position to which we are currently copying characters. | |
3489 // scratch: Separator length. | |
3490 // rsp[0x10] (separator_operand): Address of first char of separator. | |
William Hesse
2011/03/24 12:02:21
why not separator_operand (rsp[0x10])?
Lasse Reichstein
2011/03/24 12:14:08
That's better, thanks.
| |
3491 | |
3492 // Copy the separator to the result. | |
3493 __ movq(string, separator_operand); | |
3494 __ movl(string_length, scratch); | |
3495 __ CopyBytes(result_pos, string, string_length, 2); | |
3496 | |
3497 __ bind(&loop_3_entry); | |
3498 // Get string = array[index]. | |
3499 __ movq(string, Operand(elements, index, times_pointer_size, 0)); | |
3500 __ SmiToInteger32(string_length, | |
3501 FieldOperand(string, String::kLengthOffset)); | |
3502 __ lea(string, | |
3503 FieldOperand(string, SeqAsciiString::kHeaderSize)); | |
3504 __ CopyBytes(result_pos, string, string_length); | |
3505 __ addq(index, Immediate(1)); | |
3506 __ j(less, &loop_3); // Loop while (index < 0). | |
William Hesse
2011/03/24 12:02:21
I think if you use not_equal for the condition, yo
Lasse Reichstein
2011/03/24 12:14:08
Done.
| |
3507 | |
3508 __ bind(&done); | |
3509 __ movq(rax, result_operand); | |
3510 | |
3511 __ bind(&return_result); | |
3512 // Drop temp values from the stack, and restore context register. | |
3513 __ addq(rsp, Immediate(3 * kPointerSize)); | |
3514 __ movq(rsi, Operand(rbp, StandardFrameConstants::kContextOffset)); | |
3515 context()->Plug(rax); | |
3235 } | 3516 } |
3236 | 3517 |
3237 | 3518 |
3238 void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) { | 3519 void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) { |
3239 Handle<String> name = expr->name(); | 3520 Handle<String> name = expr->name(); |
3240 if (name->length() > 0 && name->Get(0) == '_') { | 3521 if (name->length() > 0 && name->Get(0) == '_') { |
3241 Comment cmnt(masm_, "[ InlineRuntimeCall"); | 3522 Comment cmnt(masm_, "[ InlineRuntimeCall"); |
3242 EmitInlineRuntimeCall(expr); | 3523 EmitInlineRuntimeCall(expr); |
3243 return; | 3524 return; |
3244 } | 3525 } |
(...skipping 753 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3998 __ ret(0); | 4279 __ ret(0); |
3999 } | 4280 } |
4000 | 4281 |
4001 | 4282 |
4002 #undef __ | 4283 #undef __ |
4003 | 4284 |
4004 | 4285 |
4005 } } // namespace v8::internal | 4286 } } // namespace v8::internal |
4006 | 4287 |
4007 #endif // V8_TARGET_ARCH_X64 | 4288 #endif // V8_TARGET_ARCH_X64 |
OLD | NEW |