| 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 749 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 760 VisitForStackValue(stmt->tag()); | 760 VisitForStackValue(stmt->tag()); |
| 761 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS); | 761 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS); |
| 762 | 762 |
| 763 ZoneList<CaseClause*>* clauses = stmt->cases(); | 763 ZoneList<CaseClause*>* clauses = stmt->cases(); |
| 764 CaseClause* default_clause = NULL; // Can occur anywhere in the list. | 764 CaseClause* default_clause = NULL; // Can occur anywhere in the list. |
| 765 | 765 |
| 766 Label next_test; // Recycled for each test. | 766 Label next_test; // Recycled for each test. |
| 767 // Compile all the tests with branches to their bodies. | 767 // Compile all the tests with branches to their bodies. |
| 768 for (int i = 0; i < clauses->length(); i++) { | 768 for (int i = 0; i < clauses->length(); i++) { |
| 769 CaseClause* clause = clauses->at(i); | 769 CaseClause* clause = clauses->at(i); |
| 770 clause->body_target()->entry_label()->Unuse(); |
| 771 |
| 770 // The default is not a test, but remember it as final fall through. | 772 // The default is not a test, but remember it as final fall through. |
| 771 if (clause->is_default()) { | 773 if (clause->is_default()) { |
| 772 default_clause = clause; | 774 default_clause = clause; |
| 773 continue; | 775 continue; |
| 774 } | 776 } |
| 775 | 777 |
| 776 Comment cmnt(masm_, "[ Case comparison"); | 778 Comment cmnt(masm_, "[ Case comparison"); |
| 777 __ bind(&next_test); | 779 __ bind(&next_test); |
| 778 next_test.Unuse(); | 780 next_test.Unuse(); |
| 779 | 781 |
| (...skipping 1571 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2351 Property* prop = fun->AsProperty(); | 2353 Property* prop = fun->AsProperty(); |
| 2352 Literal* key = prop->key()->AsLiteral(); | 2354 Literal* key = prop->key()->AsLiteral(); |
| 2353 if (key != NULL && key->handle()->IsSymbol()) { | 2355 if (key != NULL && key->handle()->IsSymbol()) { |
| 2354 // Call to a named property, use call IC. | 2356 // Call to a named property, use call IC. |
| 2355 VisitForStackValue(prop->obj()); | 2357 VisitForStackValue(prop->obj()); |
| 2356 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET); | 2358 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET); |
| 2357 } else { | 2359 } else { |
| 2358 // Call to a keyed property. | 2360 // Call to a keyed property. |
| 2359 // For a synthetic property use keyed load IC followed by function call, | 2361 // For a synthetic property use keyed load IC followed by function call, |
| 2360 // for a regular property use keyed EmitCallIC. | 2362 // for a regular property use keyed EmitCallIC. |
| 2361 { PreservePositionScope scope(masm()->positions_recorder()); | |
| 2362 VisitForStackValue(prop->obj()); | |
| 2363 } | |
| 2364 if (prop->is_synthetic()) { | 2363 if (prop->is_synthetic()) { |
| 2365 { PreservePositionScope scope(masm()->positions_recorder()); | 2364 // Do not visit the object and key subexpressions (they are shared |
| 2366 VisitForAccumulatorValue(prop->key()); | 2365 // by all occurrences of the same rewritten parameter). |
| 2367 } | 2366 ASSERT(prop->obj()->AsVariableProxy() != NULL); |
| 2367 ASSERT(prop->obj()->AsVariableProxy()->var()->AsSlot() != NULL); |
| 2368 Slot* slot = prop->obj()->AsVariableProxy()->var()->AsSlot(); |
| 2369 MemOperand operand = EmitSlotSearch(slot, edx); |
| 2370 __ mov(edx, operand); |
| 2371 |
| 2372 ASSERT(prop->key()->AsLiteral() != NULL); |
| 2373 ASSERT(prop->key()->AsLiteral()->handle()->IsSmi()); |
| 2374 __ mov(eax, prop->key()->AsLiteral()->handle()); |
| 2375 |
| 2368 // Record source code position for IC call. | 2376 // Record source code position for IC call. |
| 2369 SetSourcePosition(prop->position()); | 2377 SetSourcePosition(prop->position()); |
| 2370 __ pop(edx); // We do not need to keep the receiver. | |
| 2371 | 2378 |
| 2372 Handle<Code> ic(isolate()->builtins()->builtin( | 2379 Handle<Code> ic(isolate()->builtins()->builtin( |
| 2373 Builtins::KeyedLoadIC_Initialize)); | 2380 Builtins::KeyedLoadIC_Initialize)); |
| 2374 EmitCallIC(ic, RelocInfo::CODE_TARGET); | 2381 EmitCallIC(ic, RelocInfo::CODE_TARGET); |
| 2375 // Push result (function). | 2382 // Push result (function). |
| 2376 __ push(eax); | 2383 __ push(eax); |
| 2377 // Push Global receiver. | 2384 // Push Global receiver. |
| 2378 __ mov(ecx, GlobalObjectOperand()); | 2385 __ mov(ecx, GlobalObjectOperand()); |
| 2379 __ push(FieldOperand(ecx, GlobalObject::kGlobalReceiverOffset)); | 2386 __ push(FieldOperand(ecx, GlobalObject::kGlobalReceiverOffset)); |
| 2380 EmitCallWithStub(expr); | 2387 EmitCallWithStub(expr); |
| 2381 } else { | 2388 } else { |
| 2389 { PreservePositionScope scope(masm()->positions_recorder()); |
| 2390 VisitForStackValue(prop->obj()); |
| 2391 } |
| 2382 EmitKeyedCallWithIC(expr, prop->key(), RelocInfo::CODE_TARGET); | 2392 EmitKeyedCallWithIC(expr, prop->key(), RelocInfo::CODE_TARGET); |
| 2383 } | 2393 } |
| 2384 } | 2394 } |
| 2385 } else { | 2395 } else { |
| 2386 // Call to some other expression. If the expression is an anonymous | 2396 // Call to some other expression. If the expression is an anonymous |
| 2387 // function literal not called in a loop, mark it as one that should | 2397 // function literal not called in a loop, mark it as one that should |
| 2388 // also use the full code generator. | 2398 // also use the full code generator. |
| 2389 FunctionLiteral* lit = fun->AsFunctionLiteral(); | 2399 FunctionLiteral* lit = fun->AsFunctionLiteral(); |
| 2390 if (lit != NULL && | 2400 if (lit != NULL && |
| 2391 lit->name()->Equals(isolate()->heap()->empty_string()) && | 2401 lit->name()->Equals(isolate()->heap()->empty_string()) && |
| (...skipping 974 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3366 } | 3376 } |
| 3367 | 3377 |
| 3368 __ mov(eax, FieldOperand(eax, String::kHashFieldOffset)); | 3378 __ mov(eax, FieldOperand(eax, String::kHashFieldOffset)); |
| 3369 __ IndexFromHash(eax, eax); | 3379 __ IndexFromHash(eax, eax); |
| 3370 | 3380 |
| 3371 context()->Plug(eax); | 3381 context()->Plug(eax); |
| 3372 } | 3382 } |
| 3373 | 3383 |
| 3374 | 3384 |
| 3375 void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList<Expression*>* args) { | 3385 void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList<Expression*>* args) { |
| 3376 Label bailout; | 3386 Label bailout, done, one_char_separator, long_separator, |
| 3377 Label done; | 3387 non_trivial_array, not_size_one_array, loop, loop_condition, |
| 3388 loop_1, loop_1_condition, loop_2, loop_2_entry, loop_3, loop_3_entry; |
| 3378 | 3389 |
| 3379 ASSERT(args->length() == 2); | 3390 ASSERT(args->length() == 2); |
| 3380 // We will leave the separator on the stack until the end of the function. | 3391 // We will leave the separator on the stack until the end of the function. |
| 3381 VisitForStackValue(args->at(1)); | 3392 VisitForStackValue(args->at(1)); |
| 3382 // Load this to eax (= array) | 3393 // Load this to eax (= array) |
| 3383 VisitForAccumulatorValue(args->at(0)); | 3394 VisitForAccumulatorValue(args->at(0)); |
| 3384 | |
| 3385 // All aliases of the same register have disjoint lifetimes. | 3395 // All aliases of the same register have disjoint lifetimes. |
| 3386 Register array = eax; | 3396 Register array = eax; |
| 3387 Register result_pos = no_reg; | 3397 Register elements = no_reg; // Will be eax. |
| 3388 | 3398 |
| 3389 Register index = edi; | 3399 Register index = edx; |
| 3390 | 3400 |
| 3391 Register current_string_length = ecx; // Will be ecx when live. | 3401 Register string_length = ecx; |
| 3392 | 3402 |
| 3393 Register current_string = edx; | 3403 Register string = esi; |
| 3394 | 3404 |
| 3395 Register scratch = ebx; | 3405 Register scratch = ebx; |
| 3396 | 3406 |
| 3397 Register scratch_2 = esi; | 3407 Register array_length = edi; |
| 3398 Register new_padding_chars = scratch_2; | 3408 Register result_pos = no_reg; // Will be edi. |
| 3399 | 3409 |
| 3400 Operand separator = Operand(esp, 4 * kPointerSize); // Already pushed. | 3410 // Separator operand is already pushed. |
| 3401 Operand elements = Operand(esp, 3 * kPointerSize); | 3411 Operand separator_operand = Operand(esp, 2 * kPointerSize); |
| 3402 Operand result = Operand(esp, 2 * kPointerSize); | 3412 Operand result_operand = Operand(esp, 1 * kPointerSize); |
| 3403 Operand padding_chars = Operand(esp, 1 * kPointerSize); | 3413 Operand array_length_operand = Operand(esp, 0); |
| 3404 Operand array_length = Operand(esp, 0); | 3414 __ sub(Operand(esp), Immediate(2 * kPointerSize)); |
| 3405 __ sub(Operand(esp), Immediate(4 * kPointerSize)); | 3415 __ cld(); |
| 3406 | 3416 // Check that the array is a JSArray |
| 3407 | |
| 3408 // Check that eax is a JSArray | |
| 3409 __ test(array, Immediate(kSmiTagMask)); | 3417 __ test(array, Immediate(kSmiTagMask)); |
| 3410 __ j(zero, &bailout); | 3418 __ j(zero, &bailout); |
| 3411 __ CmpObjectType(array, JS_ARRAY_TYPE, scratch); | 3419 __ CmpObjectType(array, JS_ARRAY_TYPE, scratch); |
| 3412 __ j(not_equal, &bailout); | 3420 __ j(not_equal, &bailout); |
| 3413 | 3421 |
| 3414 // Check that the array has fast elements. | 3422 // Check that the array has fast elements. |
| 3415 __ test_b(FieldOperand(scratch, Map::kBitField2Offset), | 3423 __ test_b(FieldOperand(scratch, Map::kBitField2Offset), |
| 3416 1 << Map::kHasFastElements); | 3424 1 << Map::kHasFastElements); |
| 3417 __ j(zero, &bailout); | 3425 __ j(zero, &bailout); |
| 3418 | 3426 |
| 3419 // If the array is empty, return the empty string. | 3427 // If the array has length zero, return the empty string. |
| 3420 __ mov(scratch, FieldOperand(array, JSArray::kLengthOffset)); | 3428 __ mov(array_length, FieldOperand(array, JSArray::kLengthOffset)); |
| 3421 __ sar(scratch, 1); | 3429 __ sar(array_length, 1); |
| 3422 Label non_trivial; | 3430 __ j(not_zero, &non_trivial_array); |
| 3423 __ j(not_zero, &non_trivial); | 3431 __ mov(result_operand, FACTORY->empty_string()); |
| 3424 __ mov(result, isolate()->factory()->empty_string()); | 3432 __ jmp(&done); |
| 3425 __ jmp(&done); | 3433 |
| 3426 | 3434 // Save the array length. |
| 3427 __ bind(&non_trivial); | 3435 __ bind(&non_trivial_array); |
| 3428 __ mov(array_length, scratch); | 3436 __ mov(array_length_operand, array_length); |
| 3429 | 3437 |
| 3430 __ mov(scratch, FieldOperand(array, JSArray::kElementsOffset)); | 3438 // Save the FixedArray containing array's elements. |
| 3431 __ mov(elements, scratch); | |
| 3432 | |
| 3433 // End of array's live range. | 3439 // End of array's live range. |
| 3434 result_pos = array; | 3440 elements = array; |
| 3441 __ mov(elements, FieldOperand(array, JSArray::kElementsOffset)); |
| 3435 array = no_reg; | 3442 array = no_reg; |
| 3436 | 3443 |
| 3437 | 3444 |
| 3438 // Check that the separator is a flat ascii string. | 3445 // Check that all array elements are sequential ASCII strings, and |
| 3439 __ mov(current_string, separator); | 3446 // accumulate the sum of their lengths, as a smi-encoded value. |
| 3440 __ test(current_string, Immediate(kSmiTagMask)); | 3447 __ Set(index, Immediate(0)); |
| 3448 __ Set(string_length, Immediate(0)); |
| 3449 // Loop condition: while (index < length). |
| 3450 // Live loop registers: index, array_length, string, |
| 3451 // scratch, string_length, elements. |
| 3452 __ jmp(&loop_condition); |
| 3453 __ bind(&loop); |
| 3454 __ cmp(index, Operand(array_length)); |
| 3455 __ j(greater_equal, &done); |
| 3456 |
| 3457 __ mov(string, FieldOperand(elements, index, |
| 3458 times_pointer_size, |
| 3459 FixedArray::kHeaderSize)); |
| 3460 __ test(string, Immediate(kSmiTagMask)); |
| 3441 __ j(zero, &bailout); | 3461 __ j(zero, &bailout); |
| 3442 __ mov(scratch, FieldOperand(current_string, HeapObject::kMapOffset)); | 3462 __ mov(scratch, FieldOperand(string, HeapObject::kMapOffset)); |
| 3443 __ mov_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); | 3463 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); |
| 3444 __ and_(scratch, Immediate( | 3464 __ and_(scratch, Immediate( |
| 3445 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask)); | 3465 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask)); |
| 3446 __ cmp(scratch, kStringTag | kAsciiStringTag | kSeqStringTag); | 3466 __ cmp(scratch, kStringTag | kAsciiStringTag | kSeqStringTag); |
| 3447 __ j(not_equal, &bailout); | 3467 __ j(not_equal, &bailout); |
| 3448 // If the separator is the empty string, replace it with NULL. | 3468 __ add(string_length, |
| 3449 // The test for NULL is quicker than the empty string test, in a loop. | 3469 FieldOperand(string, SeqAsciiString::kLengthOffset)); |
| 3450 __ cmp(FieldOperand(current_string, SeqAsciiString::kLengthOffset), | 3470 __ j(overflow, &bailout); |
| 3451 Immediate(0)); | 3471 __ add(Operand(index), Immediate(1)); |
| 3452 Label separator_checked; | 3472 __ bind(&loop_condition); |
| 3453 __ j(not_zero, &separator_checked); | 3473 __ cmp(index, Operand(array_length)); |
| 3454 __ mov(separator, Immediate(0)); | 3474 __ j(less, &loop); |
| 3455 __ bind(&separator_checked); | 3475 |
| 3456 | 3476 // If array_length is 1, return elements[0], a string. |
| 3457 // Check that elements[0] is a flat ascii string, and copy it in new space. | 3477 __ cmp(array_length, 1); |
| 3458 __ mov(scratch, elements); | 3478 __ j(not_equal, ¬_size_one_array); |
| 3459 __ mov(current_string, FieldOperand(scratch, FixedArray::kHeaderSize)); | 3479 __ mov(scratch, FieldOperand(elements, FixedArray::kHeaderSize)); |
| 3460 __ test(current_string, Immediate(kSmiTagMask)); | 3480 __ mov(result_operand, scratch); |
| 3481 __ jmp(&done); |
| 3482 |
| 3483 __ bind(¬_size_one_array); |
| 3484 |
| 3485 // End of array_length live range. |
| 3486 result_pos = array_length; |
| 3487 array_length = no_reg; |
| 3488 |
| 3489 // Live registers: |
| 3490 // string_length: Sum of string lengths, as a smi. |
| 3491 // elements: FixedArray of strings. |
| 3492 |
| 3493 // Check that the separator is a flat ASCII string. |
| 3494 __ mov(string, separator_operand); |
| 3495 __ test(string, Immediate(kSmiTagMask)); |
| 3461 __ j(zero, &bailout); | 3496 __ j(zero, &bailout); |
| 3462 __ mov(scratch, FieldOperand(current_string, HeapObject::kMapOffset)); | 3497 __ mov(scratch, FieldOperand(string, HeapObject::kMapOffset)); |
| 3463 __ mov_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); | 3498 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); |
| 3464 __ and_(scratch, Immediate( | 3499 __ and_(scratch, Immediate( |
| 3465 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask)); | 3500 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask)); |
| 3466 __ cmp(scratch, kStringTag | kAsciiStringTag | kSeqStringTag); | 3501 __ cmp(scratch, kStringTag | kAsciiStringTag | kSeqStringTag); |
| 3467 __ j(not_equal, &bailout); | 3502 __ j(not_equal, &bailout); |
| 3468 | 3503 |
| 3469 // Allocate space to copy it. Round up the size to the alignment granularity. | 3504 // Add (separator length times array_length) - separator length |
| 3470 __ mov(current_string_length, | 3505 // to string_length. |
| 3471 FieldOperand(current_string, String::kLengthOffset)); | 3506 __ mov(scratch, separator_operand); |
| 3472 __ shr(current_string_length, 1); | 3507 __ mov(scratch, FieldOperand(scratch, SeqAsciiString::kLengthOffset)); |
| 3473 | 3508 __ sub(string_length, Operand(scratch)); // May be negative, temporarily. |
| 3509 __ imul(scratch, array_length_operand); |
| 3510 __ j(overflow, &bailout); |
| 3511 __ add(string_length, Operand(scratch)); |
| 3512 __ j(overflow, &bailout); |
| 3513 |
| 3514 __ shr(string_length, 1); |
| 3474 // Live registers and stack values: | 3515 // Live registers and stack values: |
| 3475 // current_string_length: length of elements[0]. | 3516 // string_length |
| 3476 | 3517 // elements |
| 3477 // New string result in new space = elements[0] | 3518 __ AllocateAsciiString(result_pos, string_length, scratch, |
| 3478 __ AllocateAsciiString(result_pos, current_string_length, scratch_2, | 3519 index, string, &bailout); |
| 3479 index, no_reg, &bailout); | 3520 __ mov(result_operand, result_pos); |
| 3480 __ mov(result, result_pos); | 3521 __ lea(result_pos, FieldOperand(result_pos, SeqAsciiString::kHeaderSize)); |
| 3481 | 3522 |
| 3482 // Adjust current_string_length to include padding bytes at end of string. | 3523 |
| 3483 // Keep track of the number of padding bytes. | 3524 __ mov(string, separator_operand); |
| 3484 __ mov(new_padding_chars, current_string_length); | 3525 __ cmp(FieldOperand(string, SeqAsciiString::kLengthOffset), |
| 3485 __ add(Operand(current_string_length), Immediate(kObjectAlignmentMask)); | 3526 Immediate(Smi::FromInt(1))); |
| 3486 __ and_(Operand(current_string_length), Immediate(~kObjectAlignmentMask)); | 3527 __ j(equal, &one_char_separator); |
| 3487 __ sub(new_padding_chars, Operand(current_string_length)); | 3528 __ j(greater, &long_separator); |
| 3488 __ neg(new_padding_chars); | 3529 |
| 3489 __ mov(padding_chars, new_padding_chars); | 3530 |
| 3490 | 3531 // Empty separator case |
| 3491 Label copy_loop_1_done; | 3532 __ mov(index, Immediate(0)); |
| 3492 Label copy_loop_1; | 3533 __ jmp(&loop_1_condition); |
| 3493 __ test(current_string_length, Operand(current_string_length)); | 3534 // Loop condition: while (index < length). |
| 3494 __ j(zero, ©_loop_1_done); | 3535 __ bind(&loop_1); |
| 3495 __ bind(©_loop_1); | 3536 // Each iteration of the loop concatenates one string to the result. |
| 3496 __ sub(Operand(current_string_length), Immediate(kPointerSize)); | 3537 // Live values in registers: |
| 3497 __ mov(scratch, FieldOperand(current_string, current_string_length, | 3538 // index: which element of the elements array we are adding to the result. |
| 3498 times_1, SeqAsciiString::kHeaderSize)); | 3539 // result_pos: the position to which we are currently copying characters. |
| 3499 __ mov(FieldOperand(result_pos, current_string_length, | 3540 // elements: the FixedArray of strings we are joining. |
| 3500 times_1, SeqAsciiString::kHeaderSize), | 3541 |
| 3501 scratch); | 3542 // Get string = array[index]. |
| 3502 __ j(not_zero, ©_loop_1); | 3543 __ mov(string, FieldOperand(elements, index, |
| 3503 __ bind(©_loop_1_done); | 3544 times_pointer_size, |
| 3504 | 3545 FixedArray::kHeaderSize)); |
| 3505 __ mov(index, Immediate(1)); | 3546 __ mov(string_length, |
| 3506 // Loop condition: while (index < length). | 3547 FieldOperand(string, String::kLengthOffset)); |
| 3507 Label loop; | 3548 __ shr(string_length, 1); |
| 3508 __ bind(&loop); | 3549 __ lea(string, |
| 3509 __ cmp(index, array_length); | 3550 FieldOperand(string, SeqAsciiString::kHeaderSize)); |
| 3510 __ j(greater_equal, &done); | 3551 __ CopyBytes(string, result_pos, string_length, scratch); |
| 3511 | 3552 __ add(Operand(index), Immediate(1)); |
| 3512 // If the separator is the empty string, signalled by NULL, skip it. | 3553 __ bind(&loop_1_condition); |
| 3513 Label separator_done; | 3554 __ cmp(index, array_length_operand); |
| 3514 __ mov(current_string, separator); | 3555 __ j(less, &loop_1); // End while (index < length). |
| 3515 __ test(current_string, Operand(current_string)); | 3556 __ jmp(&done); |
| 3516 __ j(zero, &separator_done); | 3557 |
| 3517 | 3558 |
| 3518 // Append separator to result. It is known to be a flat ascii string. | 3559 |
| 3519 __ AppendStringToTopOfNewSpace(current_string, current_string_length, | 3560 // One-character separator case |
| 3520 result_pos, scratch, scratch_2, result, | 3561 __ bind(&one_char_separator); |
| 3521 padding_chars, &bailout); | 3562 // Replace separator with its ascii character value. |
| 3522 __ bind(&separator_done); | 3563 __ mov_b(scratch, FieldOperand(string, SeqAsciiString::kHeaderSize)); |
| 3523 | 3564 __ mov_b(separator_operand, scratch); |
| 3524 // Add next element of array to the end of the result. | 3565 |
| 3525 // Get current_string = array[index]. | 3566 __ Set(index, Immediate(0)); |
| 3526 __ mov(scratch, elements); | 3567 // Jump into the loop after the code that copies the separator, so the first |
| 3527 __ mov(current_string, FieldOperand(scratch, index, | 3568 // element is not preceded by a separator |
| 3528 times_pointer_size, | 3569 __ jmp(&loop_2_entry); |
| 3529 FixedArray::kHeaderSize)); | 3570 // Loop condition: while (index < length). |
| 3530 // If current != flat ascii string drop result, return undefined. | 3571 __ bind(&loop_2); |
| 3531 __ test(current_string, Immediate(kSmiTagMask)); | 3572 // Each iteration of the loop concatenates one string to the result. |
| 3532 __ j(zero, &bailout); | 3573 // Live values in registers: |
| 3533 __ mov(scratch, FieldOperand(current_string, HeapObject::kMapOffset)); | 3574 // index: which element of the elements array we are adding to the result. |
| 3534 __ mov_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); | 3575 // result_pos: the position to which we are currently copying characters. |
| 3535 __ and_(scratch, Immediate( | 3576 |
| 3536 kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask)); | 3577 // Copy the separator character to the result. |
| 3537 __ cmp(scratch, kStringTag | kAsciiStringTag | kSeqStringTag); | 3578 __ mov_b(scratch, separator_operand); |
| 3538 __ j(not_equal, &bailout); | 3579 __ mov_b(Operand(result_pos, 0), scratch); |
| 3539 | 3580 __ inc(result_pos); |
| 3540 // Append current to the result. | 3581 |
| 3541 __ AppendStringToTopOfNewSpace(current_string, current_string_length, | 3582 __ bind(&loop_2_entry); |
| 3542 result_pos, scratch, scratch_2, result, | 3583 // Get string = array[index]. |
| 3543 padding_chars, &bailout); | 3584 __ mov(string, FieldOperand(elements, index, |
| 3544 __ add(Operand(index), Immediate(1)); | 3585 times_pointer_size, |
| 3545 __ jmp(&loop); // End while (index < length). | 3586 FixedArray::kHeaderSize)); |
| 3587 __ mov(string_length, |
| 3588 FieldOperand(string, String::kLengthOffset)); |
| 3589 __ shr(string_length, 1); |
| 3590 __ lea(string, |
| 3591 FieldOperand(string, SeqAsciiString::kHeaderSize)); |
| 3592 __ CopyBytes(string, result_pos, string_length, scratch); |
| 3593 __ add(Operand(index), Immediate(1)); |
| 3594 |
| 3595 __ cmp(index, array_length_operand); |
| 3596 __ j(less, &loop_2); // End while (index < length). |
| 3597 __ jmp(&done); |
| 3598 |
| 3599 |
| 3600 // Long separator case (separator is more than one character). |
| 3601 __ bind(&long_separator); |
| 3602 |
| 3603 __ Set(index, Immediate(0)); |
| 3604 // Jump into the loop after the code that copies the separator, so the first |
| 3605 // element is not preceded by a separator |
| 3606 __ jmp(&loop_3_entry); |
| 3607 // Loop condition: while (index < length). |
| 3608 __ bind(&loop_3); |
| 3609 // Each iteration of the loop concatenates one string to the result. |
| 3610 // Live values in registers: |
| 3611 // index: which element of the elements array we are adding to the result. |
| 3612 // result_pos: the position to which we are currently copying characters. |
| 3613 |
| 3614 // Copy the separator to the result. |
| 3615 __ mov(string, separator_operand); |
| 3616 __ mov(string_length, |
| 3617 FieldOperand(string, String::kLengthOffset)); |
| 3618 __ shr(string_length, 1); |
| 3619 __ lea(string, |
| 3620 FieldOperand(string, SeqAsciiString::kHeaderSize)); |
| 3621 __ CopyBytes(string, result_pos, string_length, scratch); |
| 3622 |
| 3623 __ bind(&loop_3_entry); |
| 3624 // Get string = array[index]. |
| 3625 __ mov(string, FieldOperand(elements, index, |
| 3626 times_pointer_size, |
| 3627 FixedArray::kHeaderSize)); |
| 3628 __ mov(string_length, |
| 3629 FieldOperand(string, String::kLengthOffset)); |
| 3630 __ shr(string_length, 1); |
| 3631 __ lea(string, |
| 3632 FieldOperand(string, SeqAsciiString::kHeaderSize)); |
| 3633 __ CopyBytes(string, result_pos, string_length, scratch); |
| 3634 __ add(Operand(index), Immediate(1)); |
| 3635 |
| 3636 __ cmp(index, array_length_operand); |
| 3637 __ j(less, &loop_3); // End while (index < length). |
| 3638 __ jmp(&done); |
| 3639 |
| 3546 | 3640 |
| 3547 __ bind(&bailout); | 3641 __ bind(&bailout); |
| 3548 __ mov(result, isolate()->factory()->undefined_value()); | 3642 __ mov(result_operand, FACTORY->undefined_value()); |
| 3549 __ bind(&done); | 3643 __ bind(&done); |
| 3550 __ mov(eax, result); | 3644 __ mov(eax, result_operand); |
| 3551 // Drop temp values from the stack, and restore context register. | 3645 // Drop temp values from the stack, and restore context register. |
| 3552 __ add(Operand(esp), Immediate(5 * kPointerSize)); | 3646 __ add(Operand(esp), Immediate(3 * kPointerSize)); |
| 3553 | 3647 |
| 3554 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 3648 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
| 3555 context()->Plug(eax); | 3649 context()->Plug(eax); |
| 3556 } | 3650 } |
| 3557 | 3651 |
| 3558 | 3652 |
| 3559 void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) { | 3653 void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) { |
| 3560 Handle<String> name = expr->name(); | 3654 Handle<String> name = expr->name(); |
| 3561 if (name->length() > 0 && name->Get(0) == '_') { | 3655 if (name->length() > 0 && name->Get(0) == '_') { |
| 3562 Comment cmnt(masm_, "[ InlineRuntimeCall"); | 3656 Comment cmnt(masm_, "[ InlineRuntimeCall"); |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3613 var->AsSlot()->type() != Slot::LOOKUP) { | 3707 var->AsSlot()->type() != Slot::LOOKUP) { |
| 3614 // Result of deleting non-global, non-dynamic variables is false. | 3708 // Result of deleting non-global, non-dynamic variables is false. |
| 3615 // The subexpression does not have side effects. | 3709 // The subexpression does not have side effects. |
| 3616 context()->Plug(false); | 3710 context()->Plug(false); |
| 3617 } else { | 3711 } else { |
| 3618 // Property or variable reference. Call the delete builtin with | 3712 // Property or variable reference. Call the delete builtin with |
| 3619 // object and property name as arguments. | 3713 // object and property name as arguments. |
| 3620 if (prop != NULL) { | 3714 if (prop != NULL) { |
| 3621 VisitForStackValue(prop->obj()); | 3715 VisitForStackValue(prop->obj()); |
| 3622 VisitForStackValue(prop->key()); | 3716 VisitForStackValue(prop->key()); |
| 3717 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); |
| 3623 } else if (var->is_global()) { | 3718 } else if (var->is_global()) { |
| 3624 __ push(GlobalObjectOperand()); | 3719 __ push(GlobalObjectOperand()); |
| 3625 __ push(Immediate(var->name())); | 3720 __ push(Immediate(var->name())); |
| 3721 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); |
| 3626 } else { | 3722 } else { |
| 3627 // Non-global variable. Call the runtime to look up the context | 3723 // Non-global variable. Call the runtime to delete from the |
| 3628 // where the variable was introduced. | 3724 // context where the variable was introduced. |
| 3629 __ push(context_register()); | 3725 __ push(context_register()); |
| 3630 __ push(Immediate(var->name())); | 3726 __ push(Immediate(var->name())); |
| 3631 __ CallRuntime(Runtime::kLookupContext, 2); | 3727 __ CallRuntime(Runtime::kDeleteContextSlot, 2); |
| 3632 __ push(eax); | |
| 3633 __ push(Immediate(var->name())); | |
| 3634 } | 3728 } |
| 3635 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); | |
| 3636 context()->Plug(eax); | 3729 context()->Plug(eax); |
| 3637 } | 3730 } |
| 3638 break; | 3731 break; |
| 3639 } | 3732 } |
| 3640 | 3733 |
| 3641 case Token::VOID: { | 3734 case Token::VOID: { |
| 3642 Comment cmnt(masm_, "[ UnaryOperation (VOID)"); | 3735 Comment cmnt(masm_, "[ UnaryOperation (VOID)"); |
| 3643 VisitForEffect(expr->expression()); | 3736 VisitForEffect(expr->expression()); |
| 3644 context()->Plug(isolate()->factory()->undefined_value()); | 3737 context()->Plug(isolate()->factory()->undefined_value()); |
| 3645 break; | 3738 break; |
| (...skipping 653 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4299 // And return. | 4392 // And return. |
| 4300 __ ret(0); | 4393 __ ret(0); |
| 4301 } | 4394 } |
| 4302 | 4395 |
| 4303 | 4396 |
| 4304 #undef __ | 4397 #undef __ |
| 4305 | 4398 |
| 4306 } } // namespace v8::internal | 4399 } } // namespace v8::internal |
| 4307 | 4400 |
| 4308 #endif // V8_TARGET_ARCH_IA32 | 4401 #endif // V8_TARGET_ARCH_IA32 |
| OLD | NEW |