Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(156)

Side by Side Diff: src/x64/full-codegen-x64.cc

Issue 6729016: Implemented FastAsciiStringJoin in X64 full codegen. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 9 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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, &not_size_one_array);
3334 __ movq(rax, FieldOperand(elements, FixedArray::kHeaderSize));
3335 __ jmp(&return_result);
3336
3337 __ bind(&not_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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698