Chromium Code Reviews| 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 |