| 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 2229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2240 | 2240 |
| 2241 // The displacement is used for skipping the frame pointer on the | 2241 // The displacement is used for skipping the frame pointer on the |
| 2242 // stack. It is the offset of the last parameter (if any) relative | 2242 // stack. It is the offset of the last parameter (if any) relative |
| 2243 // to the frame pointer. | 2243 // to the frame pointer. |
| 2244 static const int kDisplacement = 1 * kPointerSize; | 2244 static const int kDisplacement = 1 * kPointerSize; |
| 2245 | 2245 |
| 2246 // Check that the key is a smi. | 2246 // Check that the key is a smi. |
| 2247 Label slow; | 2247 Label slow; |
| 2248 __ JumpIfNotSmi(rdx, &slow); | 2248 __ JumpIfNotSmi(rdx, &slow); |
| 2249 | 2249 |
| 2250 // Check if the calling frame is an arguments adaptor frame. | 2250 // Check if the calling frame is an arguments adaptor frame. We look at the |
| 2251 // context offset, and if the frame is not a regular one, then we find a |
| 2252 // Smi instead of the context. We can't use SmiCompare here, because that |
| 2253 // only works for comparing two smis. |
| 2251 Label adaptor; | 2254 Label adaptor; |
| 2252 __ movq(rbx, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); | 2255 __ movq(rbx, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); |
| 2253 __ SmiCompare(Operand(rbx, StandardFrameConstants::kContextOffset), | 2256 __ Cmp(Operand(rbx, StandardFrameConstants::kContextOffset), |
| 2254 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); | 2257 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); |
| 2255 __ j(equal, &adaptor); | 2258 __ j(equal, &adaptor); |
| 2256 | 2259 |
| 2257 // Check index against formal parameters count limit passed in | 2260 // Check index against formal parameters count limit passed in |
| 2258 // through register rax. Use unsigned comparison to get negative | 2261 // through register rax. Use unsigned comparison to get negative |
| 2259 // check for free. | 2262 // check for free. |
| 2260 __ cmpq(rdx, rax); | 2263 __ cmpq(rdx, rax); |
| 2261 __ j(above_equal, &slow); | 2264 __ j(above_equal, &slow); |
| 2262 | 2265 |
| 2263 // Read the argument from the stack and return it. | 2266 // Read the argument from the stack and return it. |
| 2264 SmiIndex index = masm->SmiToIndex(rax, rax, kPointerSizeLog2); | 2267 SmiIndex index = masm->SmiToIndex(rax, rax, kPointerSizeLog2); |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2299 // rsp[24] : function | 2302 // rsp[24] : function |
| 2300 | 2303 |
| 2301 // The displacement is used for skipping the return address and the | 2304 // The displacement is used for skipping the return address and the |
| 2302 // frame pointer on the stack. It is the offset of the last | 2305 // frame pointer on the stack. It is the offset of the last |
| 2303 // parameter (if any) relative to the frame pointer. | 2306 // parameter (if any) relative to the frame pointer. |
| 2304 static const int kDisplacement = 2 * kPointerSize; | 2307 static const int kDisplacement = 2 * kPointerSize; |
| 2305 | 2308 |
| 2306 // Check if the calling frame is an arguments adaptor frame. | 2309 // Check if the calling frame is an arguments adaptor frame. |
| 2307 Label adaptor_frame, try_allocate, runtime; | 2310 Label adaptor_frame, try_allocate, runtime; |
| 2308 __ movq(rdx, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); | 2311 __ movq(rdx, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); |
| 2309 __ SmiCompare(Operand(rdx, StandardFrameConstants::kContextOffset), | 2312 __ Cmp(Operand(rdx, StandardFrameConstants::kContextOffset), |
| 2310 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); | 2313 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); |
| 2311 __ j(equal, &adaptor_frame); | 2314 __ j(equal, &adaptor_frame); |
| 2312 | 2315 |
| 2313 // Get the length from the frame. | 2316 // Get the length from the frame. |
| 2314 __ SmiToInteger32(rcx, Operand(rsp, 1 * kPointerSize)); | 2317 __ SmiToInteger32(rcx, Operand(rsp, 1 * kPointerSize)); |
| 2315 __ jmp(&try_allocate); | 2318 __ jmp(&try_allocate); |
| 2316 | 2319 |
| 2317 // Patch the arguments.length and the parameters pointer. | 2320 // Patch the arguments.length and the parameters pointer. |
| 2318 __ bind(&adaptor_frame); | 2321 __ bind(&adaptor_frame); |
| 2319 __ SmiToInteger32(rcx, | 2322 __ SmiToInteger32(rcx, |
| 2320 Operand(rdx, | 2323 Operand(rdx, |
| (...skipping 1847 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4168 __ movq(r8, FieldOperand(rax, HeapObject::kMapOffset)); | 4171 __ movq(r8, FieldOperand(rax, HeapObject::kMapOffset)); |
| 4169 __ movq(r9, FieldOperand(rdx, HeapObject::kMapOffset)); | 4172 __ movq(r9, FieldOperand(rdx, HeapObject::kMapOffset)); |
| 4170 } | 4173 } |
| 4171 // Get the instance types of the two strings as they will be needed soon. | 4174 // Get the instance types of the two strings as they will be needed soon. |
| 4172 __ movzxbl(r8, FieldOperand(r8, Map::kInstanceTypeOffset)); | 4175 __ movzxbl(r8, FieldOperand(r8, Map::kInstanceTypeOffset)); |
| 4173 __ movzxbl(r9, FieldOperand(r9, Map::kInstanceTypeOffset)); | 4176 __ movzxbl(r9, FieldOperand(r9, Map::kInstanceTypeOffset)); |
| 4174 | 4177 |
| 4175 // Look at the length of the result of adding the two strings. | 4178 // Look at the length of the result of adding the two strings. |
| 4176 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue / 2); | 4179 STATIC_ASSERT(String::kMaxLength <= Smi::kMaxValue / 2); |
| 4177 __ SmiAdd(rbx, rbx, rcx); | 4180 __ SmiAdd(rbx, rbx, rcx); |
| 4178 // Use the runtime system when adding two one character strings, as it | 4181 // Use the symbol table when adding two one character strings, as it |
| 4179 // contains optimizations for this specific case using the symbol table. | 4182 // helps later optimizations to return a symbol here. |
| 4180 __ SmiCompare(rbx, Smi::FromInt(2)); | 4183 __ SmiCompare(rbx, Smi::FromInt(2)); |
| 4181 __ j(not_equal, &longer_than_two); | 4184 __ j(not_equal, &longer_than_two); |
| 4182 | 4185 |
| 4183 // Check that both strings are non-external ascii strings. | 4186 // Check that both strings are non-external ascii strings. |
| 4184 __ JumpIfBothInstanceTypesAreNotSequentialAscii(r8, r9, rbx, rcx, | 4187 __ JumpIfBothInstanceTypesAreNotSequentialAscii(r8, r9, rbx, rcx, |
| 4185 &string_add_runtime); | 4188 &string_add_runtime); |
| 4186 | 4189 |
| 4187 // Get the two characters forming the sub string. | 4190 // Get the two characters forming the sub string. |
| 4188 __ movzxbq(rbx, FieldOperand(rax, SeqAsciiString::kHeaderSize)); | 4191 __ movzxbq(rbx, FieldOperand(rax, SeqAsciiString::kHeaderSize)); |
| 4189 __ movzxbq(rcx, FieldOperand(rdx, SeqAsciiString::kHeaderSize)); | 4192 __ movzxbq(rcx, FieldOperand(rdx, SeqAsciiString::kHeaderSize)); |
| (...skipping 331 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4521 // Load the symbol table. | 4524 // Load the symbol table. |
| 4522 Register symbol_table = c2; | 4525 Register symbol_table = c2; |
| 4523 __ LoadRoot(symbol_table, Heap::kSymbolTableRootIndex); | 4526 __ LoadRoot(symbol_table, Heap::kSymbolTableRootIndex); |
| 4524 | 4527 |
| 4525 // Calculate capacity mask from the symbol table capacity. | 4528 // Calculate capacity mask from the symbol table capacity. |
| 4526 Register mask = scratch2; | 4529 Register mask = scratch2; |
| 4527 __ SmiToInteger32(mask, | 4530 __ SmiToInteger32(mask, |
| 4528 FieldOperand(symbol_table, SymbolTable::kCapacityOffset)); | 4531 FieldOperand(symbol_table, SymbolTable::kCapacityOffset)); |
| 4529 __ decl(mask); | 4532 __ decl(mask); |
| 4530 | 4533 |
| 4531 Register undefined = scratch4; | 4534 Register map = scratch4; |
| 4532 __ LoadRoot(undefined, Heap::kUndefinedValueRootIndex); | |
| 4533 | 4535 |
| 4534 // Registers | 4536 // Registers |
| 4535 // chars: two character string, char 1 in byte 0 and char 2 in byte 1. | 4537 // chars: two character string, char 1 in byte 0 and char 2 in byte 1. |
| 4536 // hash: hash of two character string (32-bit int) | 4538 // hash: hash of two character string (32-bit int) |
| 4537 // symbol_table: symbol table | 4539 // symbol_table: symbol table |
| 4538 // mask: capacity mask (32-bit int) | 4540 // mask: capacity mask (32-bit int) |
| 4539 // undefined: undefined value | 4541 // map: - |
| 4540 // scratch: - | 4542 // scratch: - |
| 4541 | 4543 |
| 4542 // Perform a number of probes in the symbol table. | 4544 // Perform a number of probes in the symbol table. |
| 4543 static const int kProbes = 4; | 4545 static const int kProbes = 4; |
| 4544 Label found_in_symbol_table; | 4546 Label found_in_symbol_table; |
| 4545 Label next_probe[kProbes]; | 4547 Label next_probe[kProbes]; |
| 4546 for (int i = 0; i < kProbes; i++) { | 4548 for (int i = 0; i < kProbes; i++) { |
| 4547 // Calculate entry in symbol table. | 4549 // Calculate entry in symbol table. |
| 4548 __ movl(scratch, hash); | 4550 __ movl(scratch, hash); |
| 4549 if (i > 0) { | 4551 if (i > 0) { |
| 4550 __ addl(scratch, Immediate(SymbolTable::GetProbeOffset(i))); | 4552 __ addl(scratch, Immediate(SymbolTable::GetProbeOffset(i))); |
| 4551 } | 4553 } |
| 4552 __ andl(scratch, mask); | 4554 __ andl(scratch, mask); |
| 4553 | 4555 |
| 4554 // Load the entry from the symble table. | 4556 // Load the entry from the symbol table. |
| 4555 Register candidate = scratch; // Scratch register contains candidate. | 4557 Register candidate = scratch; // Scratch register contains candidate. |
| 4556 STATIC_ASSERT(SymbolTable::kEntrySize == 1); | 4558 STATIC_ASSERT(SymbolTable::kEntrySize == 1); |
| 4557 __ movq(candidate, | 4559 __ movq(candidate, |
| 4558 FieldOperand(symbol_table, | 4560 FieldOperand(symbol_table, |
| 4559 scratch, | 4561 scratch, |
| 4560 times_pointer_size, | 4562 times_pointer_size, |
| 4561 SymbolTable::kElementsStartOffset)); | 4563 SymbolTable::kElementsStartOffset)); |
| 4562 | 4564 |
| 4563 // If entry is undefined no string with this hash can be found. | 4565 // If entry is undefined no string with this hash can be found. |
| 4564 __ cmpq(candidate, undefined); | 4566 NearLabel is_string; |
| 4567 __ CmpObjectType(candidate, ODDBALL_TYPE, map); |
| 4568 __ j(not_equal, &is_string); |
| 4569 |
| 4570 __ CompareRoot(candidate, Heap::kUndefinedValueRootIndex); |
| 4565 __ j(equal, not_found); | 4571 __ j(equal, not_found); |
| 4572 // Must be null (deleted entry). |
| 4573 __ jmp(&next_probe[i]); |
| 4574 |
| 4575 __ bind(&is_string); |
| 4566 | 4576 |
| 4567 // If length is not 2 the string is not a candidate. | 4577 // If length is not 2 the string is not a candidate. |
| 4568 __ SmiCompare(FieldOperand(candidate, String::kLengthOffset), | 4578 __ SmiCompare(FieldOperand(candidate, String::kLengthOffset), |
| 4569 Smi::FromInt(2)); | 4579 Smi::FromInt(2)); |
| 4570 __ j(not_equal, &next_probe[i]); | 4580 __ j(not_equal, &next_probe[i]); |
| 4571 | 4581 |
| 4572 // We use kScratchRegister as a temporary register in assumption that | 4582 // We use kScratchRegister as a temporary register in assumption that |
| 4573 // JumpIfInstanceTypeIsNotSequentialAscii does not use it implicitly | 4583 // JumpIfInstanceTypeIsNotSequentialAscii does not use it implicitly |
| 4574 Register temp = kScratchRegister; | 4584 Register temp = kScratchRegister; |
| 4575 | 4585 |
| 4576 // Check that the candidate is a non-external ascii string. | 4586 // Check that the candidate is a non-external ascii string. |
| 4577 __ movq(temp, FieldOperand(candidate, HeapObject::kMapOffset)); | 4587 __ movzxbl(temp, FieldOperand(map, Map::kInstanceTypeOffset)); |
| 4578 __ movzxbl(temp, FieldOperand(temp, Map::kInstanceTypeOffset)); | |
| 4579 __ JumpIfInstanceTypeIsNotSequentialAscii( | 4588 __ JumpIfInstanceTypeIsNotSequentialAscii( |
| 4580 temp, temp, &next_probe[i]); | 4589 temp, temp, &next_probe[i]); |
| 4581 | 4590 |
| 4582 // Check if the two characters match. | 4591 // Check if the two characters match. |
| 4583 __ movl(temp, FieldOperand(candidate, SeqAsciiString::kHeaderSize)); | 4592 __ movl(temp, FieldOperand(candidate, SeqAsciiString::kHeaderSize)); |
| 4584 __ andl(temp, Immediate(0x0000ffff)); | 4593 __ andl(temp, Immediate(0x0000ffff)); |
| 4585 __ cmpl(chars, temp); | 4594 __ cmpl(chars, temp); |
| 4586 __ j(equal, &found_in_symbol_table); | 4595 __ j(equal, &found_in_symbol_table); |
| 4587 __ bind(&next_probe[i]); | 4596 __ bind(&next_probe[i]); |
| 4588 } | 4597 } |
| (...skipping 331 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4920 __ push(rcx); | 4929 __ push(rcx); |
| 4921 GenerateCompareFlatAsciiStrings(masm, rdx, rax, rcx, rbx, rdi, r8); | 4930 GenerateCompareFlatAsciiStrings(masm, rdx, rax, rcx, rbx, rdi, r8); |
| 4922 | 4931 |
| 4923 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) | 4932 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) |
| 4924 // tagged as a small integer. | 4933 // tagged as a small integer. |
| 4925 __ bind(&runtime); | 4934 __ bind(&runtime); |
| 4926 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); | 4935 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); |
| 4927 } | 4936 } |
| 4928 | 4937 |
| 4929 | 4938 |
| 4930 void StringCharAtStub::Generate(MacroAssembler* masm) { | |
| 4931 // Expects two arguments (object, index) on the stack: | |
| 4932 | |
| 4933 // Stack frame on entry. | |
| 4934 // rsp[0]: return address | |
| 4935 // rsp[8]: index | |
| 4936 // rsp[16]: object | |
| 4937 | |
| 4938 Register object = rbx; | |
| 4939 Register index = rax; | |
| 4940 Register scratch1 = rcx; | |
| 4941 Register scratch2 = rdx; | |
| 4942 Register result = rax; | |
| 4943 | |
| 4944 __ pop(scratch1); // Return address. | |
| 4945 __ pop(index); | |
| 4946 __ pop(object); | |
| 4947 __ push(scratch1); | |
| 4948 | |
| 4949 Label need_conversion; | |
| 4950 Label index_out_of_range; | |
| 4951 Label done; | |
| 4952 StringCharAtGenerator generator(object, | |
| 4953 index, | |
| 4954 scratch1, | |
| 4955 scratch2, | |
| 4956 result, | |
| 4957 &need_conversion, | |
| 4958 &need_conversion, | |
| 4959 &index_out_of_range, | |
| 4960 STRING_INDEX_IS_NUMBER); | |
| 4961 generator.GenerateFast(masm); | |
| 4962 __ jmp(&done); | |
| 4963 | |
| 4964 __ bind(&index_out_of_range); | |
| 4965 // When the index is out of range, the spec requires us to return | |
| 4966 // the empty string. | |
| 4967 __ LoadRoot(result, Heap::kEmptyStringRootIndex); | |
| 4968 __ jmp(&done); | |
| 4969 | |
| 4970 __ bind(&need_conversion); | |
| 4971 // Move smi zero into the result register, which will trigger | |
| 4972 // conversion. | |
| 4973 __ Move(result, Smi::FromInt(0)); | |
| 4974 __ jmp(&done); | |
| 4975 | |
| 4976 StubRuntimeCallHelper call_helper; | |
| 4977 generator.GenerateSlow(masm, call_helper); | |
| 4978 | |
| 4979 __ bind(&done); | |
| 4980 __ ret(0); | |
| 4981 } | |
| 4982 | |
| 4983 | |
| 4984 void ICCompareStub::GenerateSmis(MacroAssembler* masm) { | 4939 void ICCompareStub::GenerateSmis(MacroAssembler* masm) { |
| 4985 ASSERT(state_ == CompareIC::SMIS); | 4940 ASSERT(state_ == CompareIC::SMIS); |
| 4986 NearLabel miss; | 4941 NearLabel miss; |
| 4987 __ JumpIfNotBothSmi(rdx, rax, &miss); | 4942 __ JumpIfNotBothSmi(rdx, rax, &miss); |
| 4988 | 4943 |
| 4989 if (GetCondition() == equal) { | 4944 if (GetCondition() == equal) { |
| 4990 // For equality we do not care about the sign of the result. | 4945 // For equality we do not care about the sign of the result. |
| 4991 __ subq(rax, rdx); | 4946 __ subq(rax, rdx); |
| 4992 } else { | 4947 } else { |
| 4993 NearLabel done; | 4948 NearLabel done; |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5096 // Do a tail call to the rewritten stub. | 5051 // Do a tail call to the rewritten stub. |
| 5097 __ jmp(rdi); | 5052 __ jmp(rdi); |
| 5098 } | 5053 } |
| 5099 | 5054 |
| 5100 | 5055 |
| 5101 #undef __ | 5056 #undef __ |
| 5102 | 5057 |
| 5103 } } // namespace v8::internal | 5058 } } // namespace v8::internal |
| 5104 | 5059 |
| 5105 #endif // V8_TARGET_ARCH_X64 | 5060 #endif // V8_TARGET_ARCH_X64 |
| OLD | NEW |