| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 47 Isolate* isolate, | 47 Isolate* isolate, |
| 48 CodeStubInterfaceDescriptor* descriptor) { | 48 CodeStubInterfaceDescriptor* descriptor) { |
| 49 static Register registers[] = { ebx }; | 49 static Register registers[] = { ebx }; |
| 50 descriptor->register_param_count_ = 1; | 50 descriptor->register_param_count_ = 1; |
| 51 descriptor->register_params_ = registers; | 51 descriptor->register_params_ = registers; |
| 52 descriptor->deoptimization_handler_ = | 52 descriptor->deoptimization_handler_ = |
| 53 Runtime::FunctionForId(Runtime::kNewClosureFromStubFailure)->entry; | 53 Runtime::FunctionForId(Runtime::kNewClosureFromStubFailure)->entry; |
| 54 } | 54 } |
| 55 | 55 |
| 56 | 56 |
| 57 void FastNewContextStub::InitializeInterfaceDescriptor( |
| 58 Isolate* isolate, |
| 59 CodeStubInterfaceDescriptor* descriptor) { |
| 60 static Register registers[] = { edi }; |
| 61 descriptor->register_param_count_ = 1; |
| 62 descriptor->register_params_ = registers; |
| 63 descriptor->deoptimization_handler_ = NULL; |
| 64 } |
| 65 |
| 66 |
| 57 void ToNumberStub::InitializeInterfaceDescriptor( | 67 void ToNumberStub::InitializeInterfaceDescriptor( |
| 58 Isolate* isolate, | 68 Isolate* isolate, |
| 59 CodeStubInterfaceDescriptor* descriptor) { | 69 CodeStubInterfaceDescriptor* descriptor) { |
| 60 static Register registers[] = { eax }; | 70 static Register registers[] = { eax }; |
| 61 descriptor->register_param_count_ = 1; | 71 descriptor->register_param_count_ = 1; |
| 62 descriptor->register_params_ = registers; | 72 descriptor->register_params_ = registers; |
| 63 descriptor->deoptimization_handler_ = NULL; | 73 descriptor->deoptimization_handler_ = NULL; |
| 64 } | 74 } |
| 65 | 75 |
| 66 | 76 |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 184 } | 194 } |
| 185 | 195 |
| 186 | 196 |
| 187 static void InitializeArrayConstructorDescriptor( | 197 static void InitializeArrayConstructorDescriptor( |
| 188 Isolate* isolate, | 198 Isolate* isolate, |
| 189 CodeStubInterfaceDescriptor* descriptor, | 199 CodeStubInterfaceDescriptor* descriptor, |
| 190 int constant_stack_parameter_count) { | 200 int constant_stack_parameter_count) { |
| 191 // register state | 201 // register state |
| 192 // eax -- number of arguments | 202 // eax -- number of arguments |
| 193 // edi -- function | 203 // edi -- function |
| 194 // ebx -- type info cell with elements kind | 204 // ebx -- allocation site with elements kind |
| 195 static Register registers_variable_args[] = { edi, ebx, eax }; | 205 static Register registers_variable_args[] = { edi, ebx, eax }; |
| 196 static Register registers_no_args[] = { edi, ebx }; | 206 static Register registers_no_args[] = { edi, ebx }; |
| 197 | 207 |
| 198 if (constant_stack_parameter_count == 0) { | 208 if (constant_stack_parameter_count == 0) { |
| 199 descriptor->register_param_count_ = 2; | 209 descriptor->register_param_count_ = 2; |
| 200 descriptor->register_params_ = registers_no_args; | 210 descriptor->register_params_ = registers_no_args; |
| 201 } else { | 211 } else { |
| 202 // stack param count needs (constructor pointer, and single argument) | 212 // stack param count needs (constructor pointer, and single argument) |
| 203 descriptor->handler_arguments_mode_ = PASS_ARGUMENTS; | 213 descriptor->handler_arguments_mode_ = PASS_ARGUMENTS; |
| 204 descriptor->stack_parameter_count_ = eax; | 214 descriptor->stack_parameter_count_ = eax; |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 346 Isolate* isolate, | 356 Isolate* isolate, |
| 347 CodeStubInterfaceDescriptor* descriptor) { | 357 CodeStubInterfaceDescriptor* descriptor) { |
| 348 static Register registers[] = { ecx, edx, eax }; | 358 static Register registers[] = { ecx, edx, eax }; |
| 349 descriptor->register_param_count_ = 3; | 359 descriptor->register_param_count_ = 3; |
| 350 descriptor->register_params_ = registers; | 360 descriptor->register_params_ = registers; |
| 351 descriptor->deoptimization_handler_ = | 361 descriptor->deoptimization_handler_ = |
| 352 FUNCTION_ADDR(BinaryOpIC_MissWithAllocationSite); | 362 FUNCTION_ADDR(BinaryOpIC_MissWithAllocationSite); |
| 353 } | 363 } |
| 354 | 364 |
| 355 | 365 |
| 356 void NewStringAddStub::InitializeInterfaceDescriptor( | 366 void StringAddStub::InitializeInterfaceDescriptor( |
| 357 Isolate* isolate, | 367 Isolate* isolate, |
| 358 CodeStubInterfaceDescriptor* descriptor) { | 368 CodeStubInterfaceDescriptor* descriptor) { |
| 359 static Register registers[] = { edx, eax }; | 369 static Register registers[] = { edx, eax }; |
| 360 descriptor->register_param_count_ = 2; | 370 descriptor->register_param_count_ = 2; |
| 361 descriptor->register_params_ = registers; | 371 descriptor->register_params_ = registers; |
| 362 descriptor->deoptimization_handler_ = | 372 descriptor->deoptimization_handler_ = |
| 363 Runtime::FunctionForId(Runtime::kStringAdd)->entry; | 373 Runtime::FunctionForId(Runtime::kStringAdd)->entry; |
| 364 } | 374 } |
| 365 | 375 |
| 366 | 376 |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 434 __ push(descriptor->register_params_[i]); | 444 __ push(descriptor->register_params_[i]); |
| 435 } | 445 } |
| 436 ExternalReference miss = descriptor->miss_handler(); | 446 ExternalReference miss = descriptor->miss_handler(); |
| 437 __ CallExternalReference(miss, descriptor->register_param_count_); | 447 __ CallExternalReference(miss, descriptor->register_param_count_); |
| 438 } | 448 } |
| 439 | 449 |
| 440 __ ret(0); | 450 __ ret(0); |
| 441 } | 451 } |
| 442 | 452 |
| 443 | 453 |
| 444 void FastNewContextStub::Generate(MacroAssembler* masm) { | |
| 445 // Try to allocate the context in new space. | |
| 446 Label gc; | |
| 447 int length = slots_ + Context::MIN_CONTEXT_SLOTS; | |
| 448 __ Allocate((length * kPointerSize) + FixedArray::kHeaderSize, | |
| 449 eax, ebx, ecx, &gc, TAG_OBJECT); | |
| 450 | |
| 451 // Get the function from the stack. | |
| 452 __ mov(ecx, Operand(esp, 1 * kPointerSize)); | |
| 453 | |
| 454 // Set up the object header. | |
| 455 Factory* factory = masm->isolate()->factory(); | |
| 456 __ mov(FieldOperand(eax, HeapObject::kMapOffset), | |
| 457 factory->function_context_map()); | |
| 458 __ mov(FieldOperand(eax, Context::kLengthOffset), | |
| 459 Immediate(Smi::FromInt(length))); | |
| 460 | |
| 461 // Set up the fixed slots. | |
| 462 __ Set(ebx, Immediate(0)); // Set to NULL. | |
| 463 __ mov(Operand(eax, Context::SlotOffset(Context::CLOSURE_INDEX)), ecx); | |
| 464 __ mov(Operand(eax, Context::SlotOffset(Context::PREVIOUS_INDEX)), esi); | |
| 465 __ mov(Operand(eax, Context::SlotOffset(Context::EXTENSION_INDEX)), ebx); | |
| 466 | |
| 467 // Copy the global object from the previous context. | |
| 468 __ mov(ebx, Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX))); | |
| 469 __ mov(Operand(eax, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)), ebx); | |
| 470 | |
| 471 // Initialize the rest of the slots to undefined. | |
| 472 __ mov(ebx, factory->undefined_value()); | |
| 473 for (int i = Context::MIN_CONTEXT_SLOTS; i < length; i++) { | |
| 474 __ mov(Operand(eax, Context::SlotOffset(i)), ebx); | |
| 475 } | |
| 476 | |
| 477 // Return and remove the on-stack parameter. | |
| 478 __ mov(esi, eax); | |
| 479 __ ret(1 * kPointerSize); | |
| 480 | |
| 481 // Need to collect. Call into runtime system. | |
| 482 __ bind(&gc); | |
| 483 __ TailCallRuntime(Runtime::kNewFunctionContext, 1, 1); | |
| 484 } | |
| 485 | |
| 486 | |
| 487 void FastNewBlockContextStub::Generate(MacroAssembler* masm) { | 454 void FastNewBlockContextStub::Generate(MacroAssembler* masm) { |
| 488 // Stack layout on entry: | 455 // Stack layout on entry: |
| 489 // | 456 // |
| 490 // [esp + (1 * kPointerSize)]: function | 457 // [esp + (1 * kPointerSize)]: function |
| 491 // [esp + (2 * kPointerSize)]: serialized scope info | 458 // [esp + (2 * kPointerSize)]: serialized scope info |
| 492 | 459 |
| 493 // Try to allocate the context in new space. | 460 // Try to allocate the context in new space. |
| 494 Label gc; | 461 Label gc; |
| 495 int length = slots_ + Context::MIN_CONTEXT_SLOTS; | 462 int length = slots_ + Context::MIN_CONTEXT_SLOTS; |
| 496 __ Allocate(FixedArray::SizeFor(length), eax, ebx, ecx, &gc, TAG_OBJECT); | 463 __ Allocate(FixedArray::SizeFor(length), eax, ebx, ecx, &gc, TAG_OBJECT); |
| (...skipping 2873 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3370 if (!result_.is(eax)) { | 3337 if (!result_.is(eax)) { |
| 3371 __ mov(result_, eax); | 3338 __ mov(result_, eax); |
| 3372 } | 3339 } |
| 3373 call_helper.AfterCall(masm); | 3340 call_helper.AfterCall(masm); |
| 3374 __ jmp(&exit_); | 3341 __ jmp(&exit_); |
| 3375 | 3342 |
| 3376 __ Abort(kUnexpectedFallthroughFromCharFromCodeSlowCase); | 3343 __ Abort(kUnexpectedFallthroughFromCharFromCodeSlowCase); |
| 3377 } | 3344 } |
| 3378 | 3345 |
| 3379 | 3346 |
| 3380 void StringAddStub::Generate(MacroAssembler* masm) { | |
| 3381 Label call_runtime, call_builtin; | |
| 3382 Builtins::JavaScript builtin_id = Builtins::ADD; | |
| 3383 | |
| 3384 // Load the two arguments. | |
| 3385 __ mov(eax, Operand(esp, 2 * kPointerSize)); // First argument. | |
| 3386 __ mov(edx, Operand(esp, 1 * kPointerSize)); // Second argument. | |
| 3387 | |
| 3388 // Make sure that both arguments are strings if not known in advance. | |
| 3389 // Otherwise, at least one of the arguments is definitely a string, | |
| 3390 // and we convert the one that is not known to be a string. | |
| 3391 if ((flags_ & STRING_ADD_CHECK_BOTH) == STRING_ADD_CHECK_BOTH) { | |
| 3392 ASSERT((flags_ & STRING_ADD_CHECK_LEFT) == STRING_ADD_CHECK_LEFT); | |
| 3393 ASSERT((flags_ & STRING_ADD_CHECK_RIGHT) == STRING_ADD_CHECK_RIGHT); | |
| 3394 __ JumpIfSmi(eax, &call_runtime); | |
| 3395 __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, ebx); | |
| 3396 __ j(above_equal, &call_runtime); | |
| 3397 | |
| 3398 // First argument is a a string, test second. | |
| 3399 __ JumpIfSmi(edx, &call_runtime); | |
| 3400 __ CmpObjectType(edx, FIRST_NONSTRING_TYPE, ebx); | |
| 3401 __ j(above_equal, &call_runtime); | |
| 3402 } else if ((flags_ & STRING_ADD_CHECK_LEFT) == STRING_ADD_CHECK_LEFT) { | |
| 3403 ASSERT((flags_ & STRING_ADD_CHECK_RIGHT) == 0); | |
| 3404 GenerateConvertArgument(masm, 2 * kPointerSize, eax, ebx, ecx, edi, | |
| 3405 &call_builtin); | |
| 3406 builtin_id = Builtins::STRING_ADD_RIGHT; | |
| 3407 } else if ((flags_ & STRING_ADD_CHECK_RIGHT) == STRING_ADD_CHECK_RIGHT) { | |
| 3408 ASSERT((flags_ & STRING_ADD_CHECK_LEFT) == 0); | |
| 3409 GenerateConvertArgument(masm, 1 * kPointerSize, edx, ebx, ecx, edi, | |
| 3410 &call_builtin); | |
| 3411 builtin_id = Builtins::STRING_ADD_LEFT; | |
| 3412 } | |
| 3413 | |
| 3414 // Both arguments are strings. | |
| 3415 // eax: first string | |
| 3416 // edx: second string | |
| 3417 // Check if either of the strings are empty. In that case return the other. | |
| 3418 Label second_not_zero_length, both_not_zero_length; | |
| 3419 __ mov(ecx, FieldOperand(edx, String::kLengthOffset)); | |
| 3420 STATIC_ASSERT(kSmiTag == 0); | |
| 3421 __ test(ecx, ecx); | |
| 3422 __ j(not_zero, &second_not_zero_length, Label::kNear); | |
| 3423 // Second string is empty, result is first string which is already in eax. | |
| 3424 Counters* counters = masm->isolate()->counters(); | |
| 3425 __ IncrementCounter(counters->string_add_native(), 1); | |
| 3426 __ ret(2 * kPointerSize); | |
| 3427 __ bind(&second_not_zero_length); | |
| 3428 __ mov(ebx, FieldOperand(eax, String::kLengthOffset)); | |
| 3429 STATIC_ASSERT(kSmiTag == 0); | |
| 3430 __ test(ebx, ebx); | |
| 3431 __ j(not_zero, &both_not_zero_length, Label::kNear); | |
| 3432 // First string is empty, result is second string which is in edx. | |
| 3433 __ mov(eax, edx); | |
| 3434 __ IncrementCounter(counters->string_add_native(), 1); | |
| 3435 __ ret(2 * kPointerSize); | |
| 3436 | |
| 3437 // Both strings are non-empty. | |
| 3438 // eax: first string | |
| 3439 // ebx: length of first string as a smi | |
| 3440 // ecx: length of second string as a smi | |
| 3441 // edx: second string | |
| 3442 // Look at the length of the result of adding the two strings. | |
| 3443 Label string_add_flat_result, longer_than_two; | |
| 3444 __ bind(&both_not_zero_length); | |
| 3445 __ add(ebx, ecx); | |
| 3446 STATIC_ASSERT(Smi::kMaxValue == String::kMaxLength); | |
| 3447 // Handle exceptionally long strings in the runtime system. | |
| 3448 __ j(overflow, &call_runtime); | |
| 3449 // Use the string table when adding two one character strings, as it | |
| 3450 // helps later optimizations to return an internalized string here. | |
| 3451 __ cmp(ebx, Immediate(Smi::FromInt(2))); | |
| 3452 __ j(not_equal, &longer_than_two); | |
| 3453 | |
| 3454 // Check that both strings are non-external ASCII strings. | |
| 3455 __ JumpIfNotBothSequentialAsciiStrings(eax, edx, ebx, ecx, &call_runtime); | |
| 3456 | |
| 3457 // Get the two characters forming the new string. | |
| 3458 __ movzx_b(ebx, FieldOperand(eax, SeqOneByteString::kHeaderSize)); | |
| 3459 __ movzx_b(ecx, FieldOperand(edx, SeqOneByteString::kHeaderSize)); | |
| 3460 | |
| 3461 // Try to lookup two character string in string table. If it is not found | |
| 3462 // just allocate a new one. | |
| 3463 Label make_two_character_string, make_two_character_string_no_reload; | |
| 3464 StringHelper::GenerateTwoCharacterStringTableProbe( | |
| 3465 masm, ebx, ecx, eax, edx, edi, | |
| 3466 &make_two_character_string_no_reload, &make_two_character_string); | |
| 3467 __ IncrementCounter(counters->string_add_native(), 1); | |
| 3468 __ ret(2 * kPointerSize); | |
| 3469 | |
| 3470 // Allocate a two character string. | |
| 3471 __ bind(&make_two_character_string); | |
| 3472 // Reload the arguments. | |
| 3473 __ mov(eax, Operand(esp, 2 * kPointerSize)); // First argument. | |
| 3474 __ mov(edx, Operand(esp, 1 * kPointerSize)); // Second argument. | |
| 3475 // Get the two characters forming the new string. | |
| 3476 __ movzx_b(ebx, FieldOperand(eax, SeqOneByteString::kHeaderSize)); | |
| 3477 __ movzx_b(ecx, FieldOperand(edx, SeqOneByteString::kHeaderSize)); | |
| 3478 __ bind(&make_two_character_string_no_reload); | |
| 3479 __ IncrementCounter(counters->string_add_make_two_char(), 1); | |
| 3480 __ AllocateAsciiString(eax, 2, edi, edx, &call_runtime); | |
| 3481 // Pack both characters in ebx. | |
| 3482 __ shl(ecx, kBitsPerByte); | |
| 3483 __ or_(ebx, ecx); | |
| 3484 // Set the characters in the new string. | |
| 3485 __ mov_w(FieldOperand(eax, SeqOneByteString::kHeaderSize), ebx); | |
| 3486 __ IncrementCounter(counters->string_add_native(), 1); | |
| 3487 __ ret(2 * kPointerSize); | |
| 3488 | |
| 3489 __ bind(&longer_than_two); | |
| 3490 // Check if resulting string will be flat. | |
| 3491 __ cmp(ebx, Immediate(Smi::FromInt(ConsString::kMinLength))); | |
| 3492 __ j(below, &string_add_flat_result); | |
| 3493 | |
| 3494 // If result is not supposed to be flat allocate a cons string object. If both | |
| 3495 // strings are ASCII the result is an ASCII cons string. | |
| 3496 Label non_ascii, allocated, ascii_data; | |
| 3497 __ mov(edi, FieldOperand(eax, HeapObject::kMapOffset)); | |
| 3498 __ movzx_b(ecx, FieldOperand(edi, Map::kInstanceTypeOffset)); | |
| 3499 __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset)); | |
| 3500 __ movzx_b(edi, FieldOperand(edi, Map::kInstanceTypeOffset)); | |
| 3501 __ and_(ecx, edi); | |
| 3502 STATIC_ASSERT((kStringEncodingMask & kOneByteStringTag) != 0); | |
| 3503 STATIC_ASSERT((kStringEncodingMask & kTwoByteStringTag) == 0); | |
| 3504 __ test(ecx, Immediate(kStringEncodingMask)); | |
| 3505 __ j(zero, &non_ascii); | |
| 3506 __ bind(&ascii_data); | |
| 3507 // Allocate an ASCII cons string. | |
| 3508 __ AllocateAsciiConsString(ecx, edi, no_reg, &call_runtime); | |
| 3509 __ bind(&allocated); | |
| 3510 // Fill the fields of the cons string. | |
| 3511 __ AssertSmi(ebx); | |
| 3512 __ mov(FieldOperand(ecx, ConsString::kLengthOffset), ebx); | |
| 3513 __ mov(FieldOperand(ecx, ConsString::kHashFieldOffset), | |
| 3514 Immediate(String::kEmptyHashField)); | |
| 3515 | |
| 3516 Label skip_write_barrier, after_writing; | |
| 3517 ExternalReference high_promotion_mode = ExternalReference:: | |
| 3518 new_space_high_promotion_mode_active_address(masm->isolate()); | |
| 3519 __ test(Operand::StaticVariable(high_promotion_mode), Immediate(1)); | |
| 3520 __ j(zero, &skip_write_barrier); | |
| 3521 | |
| 3522 __ mov(FieldOperand(ecx, ConsString::kFirstOffset), eax); | |
| 3523 __ RecordWriteField(ecx, | |
| 3524 ConsString::kFirstOffset, | |
| 3525 eax, | |
| 3526 ebx, | |
| 3527 kDontSaveFPRegs); | |
| 3528 __ mov(FieldOperand(ecx, ConsString::kSecondOffset), edx); | |
| 3529 __ RecordWriteField(ecx, | |
| 3530 ConsString::kSecondOffset, | |
| 3531 edx, | |
| 3532 ebx, | |
| 3533 kDontSaveFPRegs); | |
| 3534 __ jmp(&after_writing); | |
| 3535 | |
| 3536 __ bind(&skip_write_barrier); | |
| 3537 __ mov(FieldOperand(ecx, ConsString::kFirstOffset), eax); | |
| 3538 __ mov(FieldOperand(ecx, ConsString::kSecondOffset), edx); | |
| 3539 | |
| 3540 __ bind(&after_writing); | |
| 3541 | |
| 3542 __ mov(eax, ecx); | |
| 3543 __ IncrementCounter(counters->string_add_native(), 1); | |
| 3544 __ ret(2 * kPointerSize); | |
| 3545 __ bind(&non_ascii); | |
| 3546 // At least one of the strings is two-byte. Check whether it happens | |
| 3547 // to contain only one byte characters. | |
| 3548 // ecx: first instance type AND second instance type. | |
| 3549 // edi: second instance type. | |
| 3550 __ test(ecx, Immediate(kOneByteDataHintMask)); | |
| 3551 __ j(not_zero, &ascii_data); | |
| 3552 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); | |
| 3553 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); | |
| 3554 __ xor_(edi, ecx); | |
| 3555 STATIC_ASSERT(kOneByteStringTag != 0 && kOneByteDataHintTag != 0); | |
| 3556 __ and_(edi, kOneByteStringTag | kOneByteDataHintTag); | |
| 3557 __ cmp(edi, kOneByteStringTag | kOneByteDataHintTag); | |
| 3558 __ j(equal, &ascii_data); | |
| 3559 // Allocate a two byte cons string. | |
| 3560 __ AllocateTwoByteConsString(ecx, edi, no_reg, &call_runtime); | |
| 3561 __ jmp(&allocated); | |
| 3562 | |
| 3563 // We cannot encounter sliced strings or cons strings here since: | |
| 3564 STATIC_ASSERT(SlicedString::kMinLength >= ConsString::kMinLength); | |
| 3565 // Handle creating a flat result from either external or sequential strings. | |
| 3566 // Locate the first characters' locations. | |
| 3567 // eax: first string | |
| 3568 // ebx: length of resulting flat string as a smi | |
| 3569 // edx: second string | |
| 3570 Label first_prepared, second_prepared; | |
| 3571 Label first_is_sequential, second_is_sequential; | |
| 3572 __ bind(&string_add_flat_result); | |
| 3573 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); | |
| 3574 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); | |
| 3575 // ecx: instance type of first string | |
| 3576 STATIC_ASSERT(kSeqStringTag == 0); | |
| 3577 __ test_b(ecx, kStringRepresentationMask); | |
| 3578 __ j(zero, &first_is_sequential, Label::kNear); | |
| 3579 // Rule out short external string and load string resource. | |
| 3580 STATIC_ASSERT(kShortExternalStringTag != 0); | |
| 3581 __ test_b(ecx, kShortExternalStringMask); | |
| 3582 __ j(not_zero, &call_runtime); | |
| 3583 __ mov(eax, FieldOperand(eax, ExternalString::kResourceDataOffset)); | |
| 3584 STATIC_ASSERT(SeqOneByteString::kHeaderSize == SeqTwoByteString::kHeaderSize); | |
| 3585 __ jmp(&first_prepared, Label::kNear); | |
| 3586 __ bind(&first_is_sequential); | |
| 3587 __ add(eax, Immediate(SeqOneByteString::kHeaderSize - kHeapObjectTag)); | |
| 3588 __ bind(&first_prepared); | |
| 3589 | |
| 3590 __ mov(edi, FieldOperand(edx, HeapObject::kMapOffset)); | |
| 3591 __ movzx_b(edi, FieldOperand(edi, Map::kInstanceTypeOffset)); | |
| 3592 // Check whether both strings have same encoding. | |
| 3593 // edi: instance type of second string | |
| 3594 __ xor_(ecx, edi); | |
| 3595 __ test_b(ecx, kStringEncodingMask); | |
| 3596 __ j(not_zero, &call_runtime); | |
| 3597 STATIC_ASSERT(kSeqStringTag == 0); | |
| 3598 __ test_b(edi, kStringRepresentationMask); | |
| 3599 __ j(zero, &second_is_sequential, Label::kNear); | |
| 3600 // Rule out short external string and load string resource. | |
| 3601 STATIC_ASSERT(kShortExternalStringTag != 0); | |
| 3602 __ test_b(edi, kShortExternalStringMask); | |
| 3603 __ j(not_zero, &call_runtime); | |
| 3604 __ mov(edx, FieldOperand(edx, ExternalString::kResourceDataOffset)); | |
| 3605 STATIC_ASSERT(SeqOneByteString::kHeaderSize == SeqTwoByteString::kHeaderSize); | |
| 3606 __ jmp(&second_prepared, Label::kNear); | |
| 3607 __ bind(&second_is_sequential); | |
| 3608 __ add(edx, Immediate(SeqOneByteString::kHeaderSize - kHeapObjectTag)); | |
| 3609 __ bind(&second_prepared); | |
| 3610 | |
| 3611 // Push the addresses of both strings' first characters onto the stack. | |
| 3612 __ push(edx); | |
| 3613 __ push(eax); | |
| 3614 | |
| 3615 Label non_ascii_string_add_flat_result, call_runtime_drop_two; | |
| 3616 // edi: instance type of second string | |
| 3617 // First string and second string have the same encoding. | |
| 3618 STATIC_ASSERT(kTwoByteStringTag == 0); | |
| 3619 __ test_b(edi, kStringEncodingMask); | |
| 3620 __ j(zero, &non_ascii_string_add_flat_result); | |
| 3621 | |
| 3622 // Both strings are ASCII strings. | |
| 3623 // ebx: length of resulting flat string as a smi | |
| 3624 __ SmiUntag(ebx); | |
| 3625 __ AllocateAsciiString(eax, ebx, ecx, edx, edi, &call_runtime_drop_two); | |
| 3626 // eax: result string | |
| 3627 __ mov(ecx, eax); | |
| 3628 // Locate first character of result. | |
| 3629 __ add(ecx, Immediate(SeqOneByteString::kHeaderSize - kHeapObjectTag)); | |
| 3630 // Load first argument's length and first character location. Account for | |
| 3631 // values currently on the stack when fetching arguments from it. | |
| 3632 __ mov(edx, Operand(esp, 4 * kPointerSize)); | |
| 3633 __ mov(edi, FieldOperand(edx, String::kLengthOffset)); | |
| 3634 __ SmiUntag(edi); | |
| 3635 __ pop(edx); | |
| 3636 // eax: result string | |
| 3637 // ecx: first character of result | |
| 3638 // edx: first char of first argument | |
| 3639 // edi: length of first argument | |
| 3640 StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true); | |
| 3641 // Load second argument's length and first character location. Account for | |
| 3642 // values currently on the stack when fetching arguments from it. | |
| 3643 __ mov(edx, Operand(esp, 2 * kPointerSize)); | |
| 3644 __ mov(edi, FieldOperand(edx, String::kLengthOffset)); | |
| 3645 __ SmiUntag(edi); | |
| 3646 __ pop(edx); | |
| 3647 // eax: result string | |
| 3648 // ecx: next character of result | |
| 3649 // edx: first char of second argument | |
| 3650 // edi: length of second argument | |
| 3651 StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true); | |
| 3652 __ IncrementCounter(counters->string_add_native(), 1); | |
| 3653 __ ret(2 * kPointerSize); | |
| 3654 | |
| 3655 // Handle creating a flat two byte result. | |
| 3656 // eax: first string - known to be two byte | |
| 3657 // ebx: length of resulting flat string as a smi | |
| 3658 // edx: second string | |
| 3659 __ bind(&non_ascii_string_add_flat_result); | |
| 3660 // Both strings are two byte strings. | |
| 3661 __ SmiUntag(ebx); | |
| 3662 __ AllocateTwoByteString(eax, ebx, ecx, edx, edi, &call_runtime_drop_two); | |
| 3663 // eax: result string | |
| 3664 __ mov(ecx, eax); | |
| 3665 // Locate first character of result. | |
| 3666 __ add(ecx, Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); | |
| 3667 // Load second argument's length and first character location. Account for | |
| 3668 // values currently on the stack when fetching arguments from it. | |
| 3669 __ mov(edx, Operand(esp, 4 * kPointerSize)); | |
| 3670 __ mov(edi, FieldOperand(edx, String::kLengthOffset)); | |
| 3671 __ SmiUntag(edi); | |
| 3672 __ pop(edx); | |
| 3673 // eax: result string | |
| 3674 // ecx: first character of result | |
| 3675 // edx: first char of first argument | |
| 3676 // edi: length of first argument | |
| 3677 StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false); | |
| 3678 // Load second argument's length and first character location. Account for | |
| 3679 // values currently on the stack when fetching arguments from it. | |
| 3680 __ mov(edx, Operand(esp, 2 * kPointerSize)); | |
| 3681 __ mov(edi, FieldOperand(edx, String::kLengthOffset)); | |
| 3682 __ SmiUntag(edi); | |
| 3683 __ pop(edx); | |
| 3684 // eax: result string | |
| 3685 // ecx: next character of result | |
| 3686 // edx: first char of second argument | |
| 3687 // edi: length of second argument | |
| 3688 StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false); | |
| 3689 __ IncrementCounter(counters->string_add_native(), 1); | |
| 3690 __ ret(2 * kPointerSize); | |
| 3691 | |
| 3692 // Recover stack pointer before jumping to runtime. | |
| 3693 __ bind(&call_runtime_drop_two); | |
| 3694 __ Drop(2); | |
| 3695 // Just jump to runtime to add the two strings. | |
| 3696 __ bind(&call_runtime); | |
| 3697 __ TailCallRuntime(Runtime::kStringAdd, 2, 1); | |
| 3698 | |
| 3699 if (call_builtin.is_linked()) { | |
| 3700 __ bind(&call_builtin); | |
| 3701 __ InvokeBuiltin(builtin_id, JUMP_FUNCTION); | |
| 3702 } | |
| 3703 } | |
| 3704 | |
| 3705 | |
| 3706 void StringAddStub::GenerateRegisterArgsPush(MacroAssembler* masm) { | |
| 3707 __ push(eax); | |
| 3708 __ push(edx); | |
| 3709 } | |
| 3710 | |
| 3711 | |
| 3712 void StringAddStub::GenerateRegisterArgsPop(MacroAssembler* masm, | |
| 3713 Register temp) { | |
| 3714 __ pop(temp); | |
| 3715 __ pop(edx); | |
| 3716 __ pop(eax); | |
| 3717 __ push(temp); | |
| 3718 } | |
| 3719 | |
| 3720 | |
| 3721 void StringAddStub::GenerateConvertArgument(MacroAssembler* masm, | |
| 3722 int stack_offset, | |
| 3723 Register arg, | |
| 3724 Register scratch1, | |
| 3725 Register scratch2, | |
| 3726 Register scratch3, | |
| 3727 Label* slow) { | |
| 3728 // First check if the argument is already a string. | |
| 3729 Label not_string, done; | |
| 3730 __ JumpIfSmi(arg, ¬_string); | |
| 3731 __ CmpObjectType(arg, FIRST_NONSTRING_TYPE, scratch1); | |
| 3732 __ j(below, &done); | |
| 3733 | |
| 3734 // Check the number to string cache. | |
| 3735 __ bind(¬_string); | |
| 3736 // Puts the cached result into scratch1. | |
| 3737 __ LookupNumberStringCache(arg, scratch1, scratch2, scratch3, slow); | |
| 3738 __ mov(arg, scratch1); | |
| 3739 __ mov(Operand(esp, stack_offset), arg); | |
| 3740 __ bind(&done); | |
| 3741 } | |
| 3742 | |
| 3743 | |
| 3744 void StringHelper::GenerateCopyCharacters(MacroAssembler* masm, | |
| 3745 Register dest, | |
| 3746 Register src, | |
| 3747 Register count, | |
| 3748 Register scratch, | |
| 3749 bool ascii) { | |
| 3750 Label loop; | |
| 3751 __ bind(&loop); | |
| 3752 // This loop just copies one character at a time, as it is only used for very | |
| 3753 // short strings. | |
| 3754 if (ascii) { | |
| 3755 __ mov_b(scratch, Operand(src, 0)); | |
| 3756 __ mov_b(Operand(dest, 0), scratch); | |
| 3757 __ add(src, Immediate(1)); | |
| 3758 __ add(dest, Immediate(1)); | |
| 3759 } else { | |
| 3760 __ mov_w(scratch, Operand(src, 0)); | |
| 3761 __ mov_w(Operand(dest, 0), scratch); | |
| 3762 __ add(src, Immediate(2)); | |
| 3763 __ add(dest, Immediate(2)); | |
| 3764 } | |
| 3765 __ sub(count, Immediate(1)); | |
| 3766 __ j(not_zero, &loop); | |
| 3767 } | |
| 3768 | |
| 3769 | |
| 3770 void StringHelper::GenerateCopyCharactersREP(MacroAssembler* masm, | 3347 void StringHelper::GenerateCopyCharactersREP(MacroAssembler* masm, |
| 3771 Register dest, | 3348 Register dest, |
| 3772 Register src, | 3349 Register src, |
| 3773 Register count, | 3350 Register count, |
| 3774 Register scratch, | 3351 Register scratch, |
| 3775 bool ascii) { | 3352 bool ascii) { |
| 3776 // Copy characters using rep movs of doublewords. | 3353 // Copy characters using rep movs of doublewords. |
| 3777 // The destination is aligned on a 4 byte boundary because we are | 3354 // The destination is aligned on a 4 byte boundary because we are |
| 3778 // copying to the beginning of a newly allocated string. | 3355 // copying to the beginning of a newly allocated string. |
| 3779 ASSERT(dest.is(edi)); // rep movs destination | 3356 ASSERT(dest.is(edi)); // rep movs destination |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3820 __ mov_b(Operand(dest, 0), scratch); | 3397 __ mov_b(Operand(dest, 0), scratch); |
| 3821 __ add(src, Immediate(1)); | 3398 __ add(src, Immediate(1)); |
| 3822 __ add(dest, Immediate(1)); | 3399 __ add(dest, Immediate(1)); |
| 3823 __ sub(count, Immediate(1)); | 3400 __ sub(count, Immediate(1)); |
| 3824 __ j(not_zero, &loop); | 3401 __ j(not_zero, &loop); |
| 3825 | 3402 |
| 3826 __ bind(&done); | 3403 __ bind(&done); |
| 3827 } | 3404 } |
| 3828 | 3405 |
| 3829 | 3406 |
| 3830 void StringHelper::GenerateTwoCharacterStringTableProbe(MacroAssembler* masm, | |
| 3831 Register c1, | |
| 3832 Register c2, | |
| 3833 Register scratch1, | |
| 3834 Register scratch2, | |
| 3835 Register scratch3, | |
| 3836 Label* not_probed, | |
| 3837 Label* not_found) { | |
| 3838 // Register scratch3 is the general scratch register in this function. | |
| 3839 Register scratch = scratch3; | |
| 3840 | |
| 3841 // Make sure that both characters are not digits as such strings has a | |
| 3842 // different hash algorithm. Don't try to look for these in the string table. | |
| 3843 Label not_array_index; | |
| 3844 __ mov(scratch, c1); | |
| 3845 __ sub(scratch, Immediate(static_cast<int>('0'))); | |
| 3846 __ cmp(scratch, Immediate(static_cast<int>('9' - '0'))); | |
| 3847 __ j(above, ¬_array_index, Label::kNear); | |
| 3848 __ mov(scratch, c2); | |
| 3849 __ sub(scratch, Immediate(static_cast<int>('0'))); | |
| 3850 __ cmp(scratch, Immediate(static_cast<int>('9' - '0'))); | |
| 3851 __ j(below_equal, not_probed); | |
| 3852 | |
| 3853 __ bind(¬_array_index); | |
| 3854 // Calculate the two character string hash. | |
| 3855 Register hash = scratch1; | |
| 3856 GenerateHashInit(masm, hash, c1, scratch); | |
| 3857 GenerateHashAddCharacter(masm, hash, c2, scratch); | |
| 3858 GenerateHashGetHash(masm, hash, scratch); | |
| 3859 | |
| 3860 // Collect the two characters in a register. | |
| 3861 Register chars = c1; | |
| 3862 __ shl(c2, kBitsPerByte); | |
| 3863 __ or_(chars, c2); | |
| 3864 | |
| 3865 // chars: two character string, char 1 in byte 0 and char 2 in byte 1. | |
| 3866 // hash: hash of two character string. | |
| 3867 | |
| 3868 // Load the string table. | |
| 3869 Register string_table = c2; | |
| 3870 __ LoadRoot(string_table, Heap::kStringTableRootIndex); | |
| 3871 | |
| 3872 // Calculate capacity mask from the string table capacity. | |
| 3873 Register mask = scratch2; | |
| 3874 __ mov(mask, FieldOperand(string_table, StringTable::kCapacityOffset)); | |
| 3875 __ SmiUntag(mask); | |
| 3876 __ sub(mask, Immediate(1)); | |
| 3877 | |
| 3878 // Registers | |
| 3879 // chars: two character string, char 1 in byte 0 and char 2 in byte 1. | |
| 3880 // hash: hash of two character string | |
| 3881 // string_table: string table | |
| 3882 // mask: capacity mask | |
| 3883 // scratch: - | |
| 3884 | |
| 3885 // Perform a number of probes in the string table. | |
| 3886 static const int kProbes = 4; | |
| 3887 Label found_in_string_table; | |
| 3888 Label next_probe[kProbes], next_probe_pop_mask[kProbes]; | |
| 3889 Register candidate = scratch; // Scratch register contains candidate. | |
| 3890 for (int i = 0; i < kProbes; i++) { | |
| 3891 // Calculate entry in string table. | |
| 3892 __ mov(scratch, hash); | |
| 3893 if (i > 0) { | |
| 3894 __ add(scratch, Immediate(StringTable::GetProbeOffset(i))); | |
| 3895 } | |
| 3896 __ and_(scratch, mask); | |
| 3897 | |
| 3898 // Load the entry from the string table. | |
| 3899 STATIC_ASSERT(StringTable::kEntrySize == 1); | |
| 3900 __ mov(candidate, | |
| 3901 FieldOperand(string_table, | |
| 3902 scratch, | |
| 3903 times_pointer_size, | |
| 3904 StringTable::kElementsStartOffset)); | |
| 3905 | |
| 3906 // If entry is undefined no string with this hash can be found. | |
| 3907 Factory* factory = masm->isolate()->factory(); | |
| 3908 __ cmp(candidate, factory->undefined_value()); | |
| 3909 __ j(equal, not_found); | |
| 3910 __ cmp(candidate, factory->the_hole_value()); | |
| 3911 __ j(equal, &next_probe[i]); | |
| 3912 | |
| 3913 // If length is not 2 the string is not a candidate. | |
| 3914 __ cmp(FieldOperand(candidate, String::kLengthOffset), | |
| 3915 Immediate(Smi::FromInt(2))); | |
| 3916 __ j(not_equal, &next_probe[i]); | |
| 3917 | |
| 3918 // As we are out of registers save the mask on the stack and use that | |
| 3919 // register as a temporary. | |
| 3920 __ push(mask); | |
| 3921 Register temp = mask; | |
| 3922 | |
| 3923 // Check that the candidate is a non-external ASCII string. | |
| 3924 __ mov(temp, FieldOperand(candidate, HeapObject::kMapOffset)); | |
| 3925 __ movzx_b(temp, FieldOperand(temp, Map::kInstanceTypeOffset)); | |
| 3926 __ JumpIfInstanceTypeIsNotSequentialAscii( | |
| 3927 temp, temp, &next_probe_pop_mask[i]); | |
| 3928 | |
| 3929 // Check if the two characters match. | |
| 3930 __ mov(temp, FieldOperand(candidate, SeqOneByteString::kHeaderSize)); | |
| 3931 __ and_(temp, 0x0000ffff); | |
| 3932 __ cmp(chars, temp); | |
| 3933 __ j(equal, &found_in_string_table); | |
| 3934 __ bind(&next_probe_pop_mask[i]); | |
| 3935 __ pop(mask); | |
| 3936 __ bind(&next_probe[i]); | |
| 3937 } | |
| 3938 | |
| 3939 // No matching 2 character string found by probing. | |
| 3940 __ jmp(not_found); | |
| 3941 | |
| 3942 // Scratch register contains result when we fall through to here. | |
| 3943 Register result = candidate; | |
| 3944 __ bind(&found_in_string_table); | |
| 3945 __ pop(mask); // Pop saved mask from the stack. | |
| 3946 if (!result.is(eax)) { | |
| 3947 __ mov(eax, result); | |
| 3948 } | |
| 3949 } | |
| 3950 | |
| 3951 | |
| 3952 void StringHelper::GenerateHashInit(MacroAssembler* masm, | 3407 void StringHelper::GenerateHashInit(MacroAssembler* masm, |
| 3953 Register hash, | 3408 Register hash, |
| 3954 Register character, | 3409 Register character, |
| 3955 Register scratch) { | 3410 Register scratch) { |
| 3956 // hash = (seed + character) + ((seed + character) << 10); | 3411 // hash = (seed + character) + ((seed + character) << 10); |
| 3957 if (Serializer::enabled()) { | 3412 if (Serializer::enabled()) { |
| 3958 __ LoadRoot(scratch, Heap::kHashSeedRootIndex); | 3413 __ LoadRoot(scratch, Heap::kHashSeedRootIndex); |
| 3959 __ SmiUntag(scratch); | 3414 __ SmiUntag(scratch); |
| 3960 __ add(scratch, character); | 3415 __ add(scratch, character); |
| 3961 __ mov(hash, scratch); | 3416 __ mov(hash, scratch); |
| (...skipping 444 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4406 __ push(ecx); | 3861 __ push(ecx); |
| 4407 GenerateCompareFlatAsciiStrings(masm, edx, eax, ecx, ebx, edi); | 3862 GenerateCompareFlatAsciiStrings(masm, edx, eax, ecx, ebx, edi); |
| 4408 | 3863 |
| 4409 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) | 3864 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) |
| 4410 // tagged as a small integer. | 3865 // tagged as a small integer. |
| 4411 __ bind(&runtime); | 3866 __ bind(&runtime); |
| 4412 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); | 3867 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); |
| 4413 } | 3868 } |
| 4414 | 3869 |
| 4415 | 3870 |
| 3871 void ArrayPushStub::Generate(MacroAssembler* masm) { |
| 3872 int argc = arguments_count(); |
| 3873 |
| 3874 if (argc == 0) { |
| 3875 // Noop, return the length. |
| 3876 __ mov(eax, FieldOperand(edx, JSArray::kLengthOffset)); |
| 3877 __ ret((argc + 1) * kPointerSize); |
| 3878 return; |
| 3879 } |
| 3880 |
| 3881 Isolate* isolate = masm->isolate(); |
| 3882 |
| 3883 if (argc != 1) { |
| 3884 __ TailCallExternalReference( |
| 3885 ExternalReference(Builtins::c_ArrayPush, isolate), argc + 1, 1); |
| 3886 return; |
| 3887 } |
| 3888 |
| 3889 Label call_builtin, attempt_to_grow_elements, with_write_barrier; |
| 3890 |
| 3891 // Get the elements array of the object. |
| 3892 __ mov(edi, FieldOperand(edx, JSArray::kElementsOffset)); |
| 3893 |
| 3894 if (IsFastSmiOrObjectElementsKind(elements_kind())) { |
| 3895 // Check that the elements are in fast mode and writable. |
| 3896 __ cmp(FieldOperand(edi, HeapObject::kMapOffset), |
| 3897 isolate->factory()->fixed_array_map()); |
| 3898 __ j(not_equal, &call_builtin); |
| 3899 } |
| 3900 |
| 3901 // Get the array's length into eax and calculate new length. |
| 3902 __ mov(eax, FieldOperand(edx, JSArray::kLengthOffset)); |
| 3903 STATIC_ASSERT(kSmiTagSize == 1); |
| 3904 STATIC_ASSERT(kSmiTag == 0); |
| 3905 __ add(eax, Immediate(Smi::FromInt(argc))); |
| 3906 |
| 3907 // Get the elements' length into ecx. |
| 3908 __ mov(ecx, FieldOperand(edi, FixedArray::kLengthOffset)); |
| 3909 |
| 3910 // Check if we could survive without allocation. |
| 3911 __ cmp(eax, ecx); |
| 3912 |
| 3913 if (IsFastSmiOrObjectElementsKind(elements_kind())) { |
| 3914 __ j(greater, &attempt_to_grow_elements); |
| 3915 |
| 3916 // Check if value is a smi. |
| 3917 __ mov(ecx, Operand(esp, argc * kPointerSize)); |
| 3918 __ JumpIfNotSmi(ecx, &with_write_barrier); |
| 3919 |
| 3920 // Store the value. |
| 3921 __ mov(FieldOperand(edi, eax, times_half_pointer_size, |
| 3922 FixedArray::kHeaderSize - argc * kPointerSize), |
| 3923 ecx); |
| 3924 } else { |
| 3925 __ j(greater, &call_builtin); |
| 3926 |
| 3927 __ mov(ecx, Operand(esp, argc * kPointerSize)); |
| 3928 __ StoreNumberToDoubleElements( |
| 3929 ecx, edi, eax, ecx, xmm0, &call_builtin, true, argc * kDoubleSize); |
| 3930 } |
| 3931 |
| 3932 // Save new length. |
| 3933 __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax); |
| 3934 __ ret((argc + 1) * kPointerSize); |
| 3935 |
| 3936 if (IsFastDoubleElementsKind(elements_kind())) { |
| 3937 __ bind(&call_builtin); |
| 3938 __ TailCallExternalReference( |
| 3939 ExternalReference(Builtins::c_ArrayPush, isolate), argc + 1, 1); |
| 3940 return; |
| 3941 } |
| 3942 |
| 3943 __ bind(&with_write_barrier); |
| 3944 |
| 3945 if (IsFastSmiElementsKind(elements_kind())) { |
| 3946 if (FLAG_trace_elements_transitions) __ jmp(&call_builtin); |
| 3947 |
| 3948 __ cmp(FieldOperand(ecx, HeapObject::kMapOffset), |
| 3949 isolate->factory()->heap_number_map()); |
| 3950 __ j(equal, &call_builtin); |
| 3951 |
| 3952 ElementsKind target_kind = IsHoleyElementsKind(elements_kind()) |
| 3953 ? FAST_HOLEY_ELEMENTS : FAST_ELEMENTS; |
| 3954 __ mov(ebx, ContextOperand(esi, Context::GLOBAL_OBJECT_INDEX)); |
| 3955 __ mov(ebx, FieldOperand(ebx, GlobalObject::kNativeContextOffset)); |
| 3956 __ mov(ebx, ContextOperand(ebx, Context::JS_ARRAY_MAPS_INDEX)); |
| 3957 const int header_size = FixedArrayBase::kHeaderSize; |
| 3958 // Verify that the object can be transitioned in place. |
| 3959 const int origin_offset = header_size + elements_kind() * kPointerSize; |
| 3960 __ mov(edi, FieldOperand(ebx, origin_offset)); |
| 3961 __ cmp(edi, FieldOperand(edx, HeapObject::kMapOffset)); |
| 3962 __ j(not_equal, &call_builtin); |
| 3963 |
| 3964 const int target_offset = header_size + target_kind * kPointerSize; |
| 3965 __ mov(ebx, FieldOperand(ebx, target_offset)); |
| 3966 ElementsTransitionGenerator::GenerateMapChangeElementsTransition( |
| 3967 masm, DONT_TRACK_ALLOCATION_SITE, NULL); |
| 3968 // Restore edi used as a scratch register for the write barrier used while |
| 3969 // setting the map. |
| 3970 __ mov(edi, FieldOperand(edx, JSArray::kElementsOffset)); |
| 3971 } |
| 3972 |
| 3973 // Save new length. |
| 3974 __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax); |
| 3975 |
| 3976 // Store the value. |
| 3977 __ lea(edx, FieldOperand(edi, eax, times_half_pointer_size, |
| 3978 FixedArray::kHeaderSize - argc * kPointerSize)); |
| 3979 __ mov(Operand(edx, 0), ecx); |
| 3980 |
| 3981 __ RecordWrite(edi, edx, ecx, kDontSaveFPRegs, EMIT_REMEMBERED_SET, |
| 3982 OMIT_SMI_CHECK); |
| 3983 |
| 3984 __ ret((argc + 1) * kPointerSize); |
| 3985 |
| 3986 __ bind(&attempt_to_grow_elements); |
| 3987 if (!FLAG_inline_new) { |
| 3988 __ bind(&call_builtin); |
| 3989 __ TailCallExternalReference( |
| 3990 ExternalReference(Builtins::c_ArrayPush, isolate), argc + 1, 1); |
| 3991 return; |
| 3992 } |
| 3993 |
| 3994 __ mov(ebx, Operand(esp, argc * kPointerSize)); |
| 3995 // Growing elements that are SMI-only requires special handling in case the |
| 3996 // new element is non-Smi. For now, delegate to the builtin. |
| 3997 if (IsFastSmiElementsKind(elements_kind())) { |
| 3998 __ JumpIfNotSmi(ebx, &call_builtin); |
| 3999 } |
| 4000 |
| 4001 // We could be lucky and the elements array could be at the top of new-space. |
| 4002 // In this case we can just grow it in place by moving the allocation pointer |
| 4003 // up. |
| 4004 ExternalReference new_space_allocation_top = |
| 4005 ExternalReference::new_space_allocation_top_address(isolate); |
| 4006 ExternalReference new_space_allocation_limit = |
| 4007 ExternalReference::new_space_allocation_limit_address(isolate); |
| 4008 |
| 4009 const int kAllocationDelta = 4; |
| 4010 ASSERT(kAllocationDelta >= argc); |
| 4011 // Load top. |
| 4012 __ mov(ecx, Operand::StaticVariable(new_space_allocation_top)); |
| 4013 |
| 4014 // Check if it's the end of elements. |
| 4015 __ lea(edx, FieldOperand(edi, eax, times_half_pointer_size, |
| 4016 FixedArray::kHeaderSize - argc * kPointerSize)); |
| 4017 __ cmp(edx, ecx); |
| 4018 __ j(not_equal, &call_builtin); |
| 4019 __ add(ecx, Immediate(kAllocationDelta * kPointerSize)); |
| 4020 __ cmp(ecx, Operand::StaticVariable(new_space_allocation_limit)); |
| 4021 __ j(above, &call_builtin); |
| 4022 |
| 4023 // We fit and could grow elements. |
| 4024 __ mov(Operand::StaticVariable(new_space_allocation_top), ecx); |
| 4025 |
| 4026 // Push the argument... |
| 4027 __ mov(Operand(edx, 0), ebx); |
| 4028 // ... and fill the rest with holes. |
| 4029 for (int i = 1; i < kAllocationDelta; i++) { |
| 4030 __ mov(Operand(edx, i * kPointerSize), |
| 4031 isolate->factory()->the_hole_value()); |
| 4032 } |
| 4033 |
| 4034 if (IsFastObjectElementsKind(elements_kind())) { |
| 4035 // We know the elements array is in new space so we don't need the |
| 4036 // remembered set, but we just pushed a value onto it so we may have to tell |
| 4037 // the incremental marker to rescan the object that we just grew. We don't |
| 4038 // need to worry about the holes because they are in old space and already |
| 4039 // marked black. |
| 4040 __ RecordWrite(edi, edx, ebx, kDontSaveFPRegs, OMIT_REMEMBERED_SET); |
| 4041 } |
| 4042 |
| 4043 // Restore receiver to edx as finish sequence assumes it's here. |
| 4044 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); |
| 4045 |
| 4046 // Increment element's and array's sizes. |
| 4047 __ add(FieldOperand(edi, FixedArray::kLengthOffset), |
| 4048 Immediate(Smi::FromInt(kAllocationDelta))); |
| 4049 |
| 4050 // NOTE: This only happen in new-space, where we don't care about the |
| 4051 // black-byte-count on pages. Otherwise we should update that too if the |
| 4052 // object is black. |
| 4053 |
| 4054 __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax); |
| 4055 __ ret((argc + 1) * kPointerSize); |
| 4056 |
| 4057 __ bind(&call_builtin); |
| 4058 __ TailCallExternalReference( |
| 4059 ExternalReference(Builtins::c_ArrayPush, isolate), argc + 1, 1); |
| 4060 } |
| 4061 |
| 4062 |
| 4416 void BinaryOpICWithAllocationSiteStub::Generate(MacroAssembler* masm) { | 4063 void BinaryOpICWithAllocationSiteStub::Generate(MacroAssembler* masm) { |
| 4417 // ----------- S t a t e ------------- | 4064 // ----------- S t a t e ------------- |
| 4418 // -- edx : left | 4065 // -- edx : left |
| 4419 // -- eax : right | 4066 // -- eax : right |
| 4420 // -- esp[0] : return address | 4067 // -- esp[0] : return address |
| 4421 // ----------------------------------- | 4068 // ----------------------------------- |
| 4422 Isolate* isolate = masm->isolate(); | 4069 Isolate* isolate = masm->isolate(); |
| 4423 | 4070 |
| 4424 // Load ecx with the allocation site. We stick an undefined dummy value here | 4071 // Load ecx with the allocation site. We stick an undefined dummy value here |
| 4425 // and replace it with the real allocation site later when we instantiate this | 4072 // and replace it with the real allocation site later when we instantiate this |
| (...skipping 998 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5424 // If we reached this point there is a problem. | 5071 // If we reached this point there is a problem. |
| 5425 __ Abort(kUnexpectedElementsKindInArrayConstructor); | 5072 __ Abort(kUnexpectedElementsKindInArrayConstructor); |
| 5426 } else { | 5073 } else { |
| 5427 UNREACHABLE(); | 5074 UNREACHABLE(); |
| 5428 } | 5075 } |
| 5429 } | 5076 } |
| 5430 | 5077 |
| 5431 | 5078 |
| 5432 static void CreateArrayDispatchOneArgument(MacroAssembler* masm, | 5079 static void CreateArrayDispatchOneArgument(MacroAssembler* masm, |
| 5433 AllocationSiteOverrideMode mode) { | 5080 AllocationSiteOverrideMode mode) { |
| 5434 // ebx - type info cell (if mode != DISABLE_ALLOCATION_SITES) | 5081 // ebx - allocation site (if mode != DISABLE_ALLOCATION_SITES) |
| 5435 // edx - kind (if mode != DISABLE_ALLOCATION_SITES) | 5082 // edx - kind (if mode != DISABLE_ALLOCATION_SITES) |
| 5436 // eax - number of arguments | 5083 // eax - number of arguments |
| 5437 // edi - constructor? | 5084 // edi - constructor? |
| 5438 // esp[0] - return address | 5085 // esp[0] - return address |
| 5439 // esp[4] - last argument | 5086 // esp[4] - last argument |
| 5440 Label normal_sequence; | 5087 Label normal_sequence; |
| 5441 if (mode == DONT_OVERRIDE) { | 5088 if (mode == DONT_OVERRIDE) { |
| 5442 ASSERT(FAST_SMI_ELEMENTS == 0); | 5089 ASSERT(FAST_SMI_ELEMENTS == 0); |
| 5443 ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1); | 5090 ASSERT(FAST_HOLEY_SMI_ELEMENTS == 1); |
| 5444 ASSERT(FAST_ELEMENTS == 2); | 5091 ASSERT(FAST_ELEMENTS == 2); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 5465 __ TailCallStub(&stub_holey); | 5112 __ TailCallStub(&stub_holey); |
| 5466 | 5113 |
| 5467 __ bind(&normal_sequence); | 5114 __ bind(&normal_sequence); |
| 5468 ArraySingleArgumentConstructorStub stub(initial, | 5115 ArraySingleArgumentConstructorStub stub(initial, |
| 5469 DISABLE_ALLOCATION_SITES); | 5116 DISABLE_ALLOCATION_SITES); |
| 5470 __ TailCallStub(&stub); | 5117 __ TailCallStub(&stub); |
| 5471 } else if (mode == DONT_OVERRIDE) { | 5118 } else if (mode == DONT_OVERRIDE) { |
| 5472 // We are going to create a holey array, but our kind is non-holey. | 5119 // We are going to create a holey array, but our kind is non-holey. |
| 5473 // Fix kind and retry. | 5120 // Fix kind and retry. |
| 5474 __ inc(edx); | 5121 __ inc(edx); |
| 5475 __ mov(ecx, FieldOperand(ebx, Cell::kValueOffset)); | 5122 |
| 5476 if (FLAG_debug_code) { | 5123 if (FLAG_debug_code) { |
| 5477 Handle<Map> allocation_site_map = | 5124 Handle<Map> allocation_site_map = |
| 5478 masm->isolate()->factory()->allocation_site_map(); | 5125 masm->isolate()->factory()->allocation_site_map(); |
| 5479 __ cmp(FieldOperand(ecx, 0), Immediate(allocation_site_map)); | 5126 __ cmp(FieldOperand(ebx, 0), Immediate(allocation_site_map)); |
| 5480 __ Assert(equal, kExpectedAllocationSiteInCell); | 5127 __ Assert(equal, kExpectedAllocationSite); |
| 5481 } | 5128 } |
| 5482 | 5129 |
| 5483 // Save the resulting elements kind in type info. We can't just store r3 | 5130 // Save the resulting elements kind in type info. We can't just store r3 |
| 5484 // in the AllocationSite::transition_info field because elements kind is | 5131 // in the AllocationSite::transition_info field because elements kind is |
| 5485 // restricted to a portion of the field...upper bits need to be left alone. | 5132 // restricted to a portion of the field...upper bits need to be left alone. |
| 5486 STATIC_ASSERT(AllocationSite::ElementsKindBits::kShift == 0); | 5133 STATIC_ASSERT(AllocationSite::ElementsKindBits::kShift == 0); |
| 5487 __ add(FieldOperand(ecx, AllocationSite::kTransitionInfoOffset), | 5134 __ add(FieldOperand(ebx, AllocationSite::kTransitionInfoOffset), |
| 5488 Immediate(Smi::FromInt(kFastElementsKindPackedToHoley))); | 5135 Immediate(Smi::FromInt(kFastElementsKindPackedToHoley))); |
| 5489 | 5136 |
| 5490 __ bind(&normal_sequence); | 5137 __ bind(&normal_sequence); |
| 5491 int last_index = GetSequenceIndexFromFastElementsKind( | 5138 int last_index = GetSequenceIndexFromFastElementsKind( |
| 5492 TERMINAL_FAST_ELEMENTS_KIND); | 5139 TERMINAL_FAST_ELEMENTS_KIND); |
| 5493 for (int i = 0; i <= last_index; ++i) { | 5140 for (int i = 0; i <= last_index; ++i) { |
| 5494 Label next; | 5141 Label next; |
| 5495 ElementsKind kind = GetFastElementsKindFromSequenceIndex(i); | 5142 ElementsKind kind = GetFastElementsKindFromSequenceIndex(i); |
| 5496 __ cmp(edx, kind); | 5143 __ cmp(edx, kind); |
| 5497 __ j(not_equal, &next); | 5144 __ j(not_equal, &next); |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5609 __ cmp(FieldOperand(ebx, 0), Immediate(cell_map)); | 5256 __ cmp(FieldOperand(ebx, 0), Immediate(cell_map)); |
| 5610 __ Assert(equal, kExpectedPropertyCellInRegisterEbx); | 5257 __ Assert(equal, kExpectedPropertyCellInRegisterEbx); |
| 5611 __ bind(&okay_here); | 5258 __ bind(&okay_here); |
| 5612 } | 5259 } |
| 5613 | 5260 |
| 5614 Label no_info; | 5261 Label no_info; |
| 5615 // If the type cell is undefined, or contains anything other than an | 5262 // If the type cell is undefined, or contains anything other than an |
| 5616 // AllocationSite, call an array constructor that doesn't use AllocationSites. | 5263 // AllocationSite, call an array constructor that doesn't use AllocationSites. |
| 5617 __ cmp(ebx, Immediate(undefined_sentinel)); | 5264 __ cmp(ebx, Immediate(undefined_sentinel)); |
| 5618 __ j(equal, &no_info); | 5265 __ j(equal, &no_info); |
| 5619 __ mov(edx, FieldOperand(ebx, Cell::kValueOffset)); | 5266 __ mov(ebx, FieldOperand(ebx, Cell::kValueOffset)); |
| 5620 __ cmp(FieldOperand(edx, 0), Immediate( | 5267 __ cmp(FieldOperand(ebx, 0), Immediate( |
| 5621 masm->isolate()->factory()->allocation_site_map())); | 5268 masm->isolate()->factory()->allocation_site_map())); |
| 5622 __ j(not_equal, &no_info); | 5269 __ j(not_equal, &no_info); |
| 5623 | 5270 |
| 5624 // Only look at the lower 16 bits of the transition info. | 5271 // Only look at the lower 16 bits of the transition info. |
| 5625 __ mov(edx, FieldOperand(edx, AllocationSite::kTransitionInfoOffset)); | 5272 __ mov(edx, FieldOperand(ebx, AllocationSite::kTransitionInfoOffset)); |
| 5626 __ SmiUntag(edx); | 5273 __ SmiUntag(edx); |
| 5627 STATIC_ASSERT(AllocationSite::ElementsKindBits::kShift == 0); | 5274 STATIC_ASSERT(AllocationSite::ElementsKindBits::kShift == 0); |
| 5628 __ and_(edx, Immediate(AllocationSite::ElementsKindBits::kMask)); | 5275 __ and_(edx, Immediate(AllocationSite::ElementsKindBits::kMask)); |
| 5629 GenerateDispatchToArrayStub(masm, DONT_OVERRIDE); | 5276 GenerateDispatchToArrayStub(masm, DONT_OVERRIDE); |
| 5630 | 5277 |
| 5631 __ bind(&no_info); | 5278 __ bind(&no_info); |
| 5632 GenerateDispatchToArrayStub(masm, DISABLE_ALLOCATION_SITES); | 5279 GenerateDispatchToArrayStub(masm, DISABLE_ALLOCATION_SITES); |
| 5633 } | 5280 } |
| 5634 | 5281 |
| 5635 | 5282 |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5719 __ bind(&fast_elements_case); | 5366 __ bind(&fast_elements_case); |
| 5720 GenerateCase(masm, FAST_ELEMENTS); | 5367 GenerateCase(masm, FAST_ELEMENTS); |
| 5721 } | 5368 } |
| 5722 | 5369 |
| 5723 | 5370 |
| 5724 #undef __ | 5371 #undef __ |
| 5725 | 5372 |
| 5726 } } // namespace v8::internal | 5373 } } // namespace v8::internal |
| 5727 | 5374 |
| 5728 #endif // V8_TARGET_ARCH_IA32 | 5375 #endif // V8_TARGET_ARCH_IA32 |
| OLD | NEW |