| OLD | NEW |
| 1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 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 2330 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2341 operand->ToRegister(); | 2341 operand->ToRegister(); |
| 2342 frame_->Spill(operand->reg()); | 2342 frame_->Spill(operand->reg()); |
| 2343 DeferredCode* deferred = | 2343 DeferredCode* deferred = |
| 2344 new DeferredInlineSmiOperation(op, | 2344 new DeferredInlineSmiOperation(op, |
| 2345 operand->reg(), | 2345 operand->reg(), |
| 2346 operand->reg(), | 2346 operand->reg(), |
| 2347 operand->type_info(), | 2347 operand->type_info(), |
| 2348 smi_value, | 2348 smi_value, |
| 2349 overwrite_mode); | 2349 overwrite_mode); |
| 2350 // Check for negative or non-Smi left hand side. | 2350 // Check for negative or non-Smi left hand side. |
| 2351 __ test(operand->reg(), Immediate(kSmiTagMask | kSmiSignMask)); | 2351 __ test(operand->reg(), Immediate(kSmiTagMask | 0x80000000)); |
| 2352 deferred->Branch(not_zero); | 2352 deferred->Branch(not_zero); |
| 2353 if (int_value < 0) int_value = -int_value; | 2353 if (int_value < 0) int_value = -int_value; |
| 2354 if (int_value == 1) { | 2354 if (int_value == 1) { |
| 2355 __ mov(operand->reg(), Immediate(Smi::FromInt(0))); | 2355 __ mov(operand->reg(), Immediate(Smi::FromInt(0))); |
| 2356 } else { | 2356 } else { |
| 2357 __ and_(operand->reg(), (int_value << kSmiTagSize) - 1); | 2357 __ and_(operand->reg(), (int_value << kSmiTagSize) - 1); |
| 2358 } | 2358 } |
| 2359 deferred->BindExit(); | 2359 deferred->BindExit(); |
| 2360 answer = *operand; | 2360 answer = *operand; |
| 2361 break; | 2361 break; |
| (...skipping 3532 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5894 frame_->Push(Factory::undefined_value()); | 5894 frame_->Push(Factory::undefined_value()); |
| 5895 } | 5895 } |
| 5896 | 5896 |
| 5897 | 5897 |
| 5898 void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) { | 5898 void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) { |
| 5899 ASSERT(args->length() == 1); | 5899 ASSERT(args->length() == 1); |
| 5900 Load(args->at(0)); | 5900 Load(args->at(0)); |
| 5901 Result value = frame_->Pop(); | 5901 Result value = frame_->Pop(); |
| 5902 value.ToRegister(); | 5902 value.ToRegister(); |
| 5903 ASSERT(value.is_valid()); | 5903 ASSERT(value.is_valid()); |
| 5904 __ test(value.reg(), Immediate(kSmiTagMask | kSmiSignMask)); | 5904 __ test(value.reg(), Immediate(kSmiTagMask | 0x80000000)); |
| 5905 value.Unuse(); | 5905 value.Unuse(); |
| 5906 destination()->Split(zero); | 5906 destination()->Split(zero); |
| 5907 } | 5907 } |
| 5908 | 5908 |
| 5909 | 5909 |
| 5910 // This generates code that performs a charCodeAt() call or returns | 5910 // This generates code that performs a charCodeAt() call or returns |
| 5911 // undefined in order to trigger the slow case, Runtime_StringCharCodeAt. | 5911 // undefined in order to trigger the slow case, Runtime_StringCharCodeAt. |
| 5912 // It can handle flat, 8 and 16 bit characters and cons strings where the | 5912 // It can handle flat, 8 and 16 bit characters and cons strings where the |
| 5913 // answer is found in the left hand branch of the cons. The slow case will | 5913 // answer is found in the left hand branch of the cons. The slow case will |
| 5914 // flatten the string, which will ensure that the answer is in the left hand | 5914 // flatten the string, which will ensure that the answer is in the left hand |
| 5915 // side the next time around. | 5915 // side the next time around. |
| 5916 void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) { | 5916 void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) { |
| 5917 Comment(masm_, "[ GenerateFastCharCodeAt"); | 5917 Comment(masm_, "[ GenerateFastCharCodeAt"); |
| 5918 ASSERT(args->length() == 2); | 5918 ASSERT(args->length() == 2); |
| 5919 | 5919 |
| 5920 Label slow_case; |
| 5921 Label end; |
| 5922 Label not_a_flat_string; |
| 5923 Label try_again_with_new_string; |
| 5924 Label ascii_string; |
| 5925 Label got_char_code; |
| 5926 |
| 5920 Load(args->at(0)); | 5927 Load(args->at(0)); |
| 5921 Load(args->at(1)); | 5928 Load(args->at(1)); |
| 5922 Result index = frame_->Pop(); | 5929 Result index = frame_->Pop(); |
| 5923 Result object = frame_->Pop(); | 5930 Result object = frame_->Pop(); |
| 5924 | 5931 |
| 5932 // Get register ecx to use as shift amount later. |
| 5933 Result shift_amount; |
| 5934 if (object.is_register() && object.reg().is(ecx)) { |
| 5935 Result fresh = allocator_->Allocate(); |
| 5936 shift_amount = object; |
| 5937 object = fresh; |
| 5938 __ mov(object.reg(), ecx); |
| 5939 } |
| 5940 if (index.is_register() && index.reg().is(ecx)) { |
| 5941 Result fresh = allocator_->Allocate(); |
| 5942 shift_amount = index; |
| 5943 index = fresh; |
| 5944 __ mov(index.reg(), ecx); |
| 5945 } |
| 5946 // There could be references to ecx in the frame. Allocating will |
| 5947 // spill them, otherwise spill explicitly. |
| 5948 if (shift_amount.is_valid()) { |
| 5949 frame_->Spill(ecx); |
| 5950 } else { |
| 5951 shift_amount = allocator()->Allocate(ecx); |
| 5952 } |
| 5953 ASSERT(shift_amount.is_register()); |
| 5954 ASSERT(shift_amount.reg().is(ecx)); |
| 5955 ASSERT(allocator_->count(ecx) == 1); |
| 5956 |
| 5925 // We will mutate the index register and possibly the object register. | 5957 // We will mutate the index register and possibly the object register. |
| 5926 // The case where they are somehow the same register is handled | 5958 // The case where they are somehow the same register is handled |
| 5927 // because we only mutate them in the case where the receiver is a | 5959 // because we only mutate them in the case where the receiver is a |
| 5928 // heap object and the index is not. | 5960 // heap object and the index is not. |
| 5929 object.ToRegister(); | 5961 object.ToRegister(); |
| 5930 index.ToRegister(); | 5962 index.ToRegister(); |
| 5931 frame_->Spill(object.reg()); | 5963 frame_->Spill(object.reg()); |
| 5932 frame_->Spill(index.reg()); | 5964 frame_->Spill(index.reg()); |
| 5933 | 5965 |
| 5934 // We need two extra registers. | 5966 // We need a single extra temporary register. |
| 5935 Result result = allocator()->Allocate(); | 5967 Result temp = allocator()->Allocate(); |
| 5936 ASSERT(result.is_valid()); | 5968 ASSERT(temp.is_valid()); |
| 5937 Result scratch = allocator()->Allocate(); | |
| 5938 ASSERT(scratch.is_valid()); | |
| 5939 | 5969 |
| 5940 // There is no virtual frame effect from here up to the final result | 5970 // There is no virtual frame effect from here up to the final result |
| 5941 // push. | 5971 // push. |
| 5942 Label slow_case; | 5972 |
| 5943 Label exit; | 5973 // If the receiver is a smi trigger the slow case. |
| 5944 StringHelper::GenerateFastCharCodeAt(masm_, | 5974 ASSERT(kSmiTag == 0); |
| 5945 object.reg(), | 5975 __ test(object.reg(), Immediate(kSmiTagMask)); |
| 5946 index.reg(), | 5976 __ j(zero, &slow_case); |
| 5947 scratch.reg(), | 5977 |
| 5948 result.reg(), | 5978 // If the index is negative or non-smi trigger the slow case. |
| 5949 &slow_case, | 5979 ASSERT(kSmiTag == 0); |
| 5950 &slow_case, | 5980 __ test(index.reg(), Immediate(kSmiTagMask | 0x80000000)); |
| 5951 &slow_case); | 5981 __ j(not_zero, &slow_case); |
| 5952 __ jmp(&exit); | 5982 // Untag the index. |
| 5983 __ SmiUntag(index.reg()); |
| 5984 |
| 5985 __ bind(&try_again_with_new_string); |
| 5986 // Fetch the instance type of the receiver into ecx. |
| 5987 __ mov(ecx, FieldOperand(object.reg(), HeapObject::kMapOffset)); |
| 5988 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); |
| 5989 // If the receiver is not a string trigger the slow case. |
| 5990 __ test(ecx, Immediate(kIsNotStringMask)); |
| 5991 __ j(not_zero, &slow_case); |
| 5992 |
| 5993 // Fetch the length field into the temporary register. |
| 5994 __ mov(temp.reg(), FieldOperand(object.reg(), String::kLengthOffset)); |
| 5995 // Check for index out of range. |
| 5996 __ cmp(index.reg(), Operand(temp.reg())); |
| 5997 __ j(greater_equal, &slow_case); |
| 5998 // Reload the instance type (into the temp register this time).. |
| 5999 __ mov(temp.reg(), FieldOperand(object.reg(), HeapObject::kMapOffset)); |
| 6000 __ movzx_b(temp.reg(), FieldOperand(temp.reg(), Map::kInstanceTypeOffset)); |
| 6001 |
| 6002 // We need special handling for non-flat strings. |
| 6003 ASSERT(kSeqStringTag == 0); |
| 6004 __ test(temp.reg(), Immediate(kStringRepresentationMask)); |
| 6005 __ j(not_zero, ¬_a_flat_string); |
| 6006 // Check for 1-byte or 2-byte string. |
| 6007 __ test(temp.reg(), Immediate(kStringEncodingMask)); |
| 6008 __ j(not_zero, &ascii_string); |
| 6009 |
| 6010 // 2-byte string. |
| 6011 // Load the 2-byte character code into the temp register. |
| 6012 __ movzx_w(temp.reg(), FieldOperand(object.reg(), |
| 6013 index.reg(), |
| 6014 times_2, |
| 6015 SeqTwoByteString::kHeaderSize)); |
| 6016 __ jmp(&got_char_code); |
| 6017 |
| 6018 // ASCII string. |
| 6019 __ bind(&ascii_string); |
| 6020 // Load the byte into the temp register. |
| 6021 __ movzx_b(temp.reg(), FieldOperand(object.reg(), |
| 6022 index.reg(), |
| 6023 times_1, |
| 6024 SeqAsciiString::kHeaderSize)); |
| 6025 __ bind(&got_char_code); |
| 6026 __ SmiTag(temp.reg()); |
| 6027 __ jmp(&end); |
| 6028 |
| 6029 // Handle non-flat strings. |
| 6030 __ bind(¬_a_flat_string); |
| 6031 __ and_(temp.reg(), kStringRepresentationMask); |
| 6032 __ cmp(temp.reg(), kConsStringTag); |
| 6033 __ j(not_equal, &slow_case); |
| 6034 |
| 6035 // ConsString. |
| 6036 // Check that the right hand side is the empty string (ie if this is really a |
| 6037 // flat string in a cons string). If that is not the case we would rather go |
| 6038 // to the runtime system now, to flatten the string. |
| 6039 __ mov(temp.reg(), FieldOperand(object.reg(), ConsString::kSecondOffset)); |
| 6040 __ cmp(Operand(temp.reg()), Factory::empty_string()); |
| 6041 __ j(not_equal, &slow_case); |
| 6042 // Get the first of the two strings. |
| 6043 __ mov(object.reg(), FieldOperand(object.reg(), ConsString::kFirstOffset)); |
| 6044 __ jmp(&try_again_with_new_string); |
| 5953 | 6045 |
| 5954 __ bind(&slow_case); | 6046 __ bind(&slow_case); |
| 5955 // Move the undefined value into the result register, which will | 6047 // Move the undefined value into the result register, which will |
| 5956 // trigger the slow case. | 6048 // trigger the slow case. |
| 5957 __ Set(result.reg(), Immediate(Factory::undefined_value())); | 6049 __ Set(temp.reg(), Immediate(Factory::undefined_value())); |
| 5958 | 6050 |
| 5959 __ bind(&exit); | 6051 __ bind(&end); |
| 5960 frame_->Push(&result); | 6052 frame_->Push(&temp); |
| 5961 } | 6053 } |
| 5962 | 6054 |
| 5963 | 6055 |
| 5964 void CodeGenerator::GenerateCharFromCode(ZoneList<Expression*>* args) { | 6056 void CodeGenerator::GenerateCharFromCode(ZoneList<Expression*>* args) { |
| 5965 Comment(masm_, "[ GenerateCharFromCode"); | 6057 Comment(masm_, "[ GenerateCharFromCode"); |
| 5966 ASSERT(args->length() == 1); | 6058 ASSERT(args->length() == 1); |
| 5967 | 6059 |
| 5968 Load(args->at(0)); | 6060 Load(args->at(0)); |
| 5969 | |
| 5970 Result code = frame_->Pop(); | 6061 Result code = frame_->Pop(); |
| 5971 code.ToRegister(); | 6062 code.ToRegister(); |
| 5972 ASSERT(code.is_valid()); | 6063 ASSERT(code.is_valid()); |
| 5973 | 6064 |
| 5974 // StringHelper::GenerateCharFromCode may do a runtime call. | 6065 Result temp = allocator()->Allocate(); |
| 5975 frame_->SpillAll(); | 6066 ASSERT(temp.is_valid()); |
| 5976 | 6067 |
| 5977 Result result = allocator()->Allocate(); | 6068 JumpTarget slow_case; |
| 5978 ASSERT(result.is_valid()); | 6069 JumpTarget exit; |
| 5979 | 6070 |
| 5980 StringHelper::GenerateCharFromCode(masm_, | 6071 // Fast case of Heap::LookupSingleCharacterStringFromCode. |
| 5981 code.reg(), | 6072 ASSERT(kSmiTag == 0); |
| 5982 result.reg(), | 6073 ASSERT(kSmiShiftSize == 0); |
| 5983 CALL_FUNCTION); | 6074 ASSERT(IsPowerOf2(String::kMaxAsciiCharCode + 1)); |
| 6075 __ test(code.reg(), |
| 6076 Immediate(kSmiTagMask | |
| 6077 ((~String::kMaxAsciiCharCode) << kSmiTagSize))); |
| 6078 slow_case.Branch(not_zero, &code, not_taken); |
| 6079 |
| 6080 __ Set(temp.reg(), Immediate(Factory::single_character_string_cache())); |
| 6081 ASSERT(kSmiTag == 0); |
| 6082 ASSERT(kSmiTagSize == 1); |
| 6083 ASSERT(kSmiShiftSize == 0); |
| 6084 // At this point code register contains smi tagged ascii char code. |
| 6085 __ mov(temp.reg(), FieldOperand(temp.reg(), |
| 6086 code.reg(), times_half_pointer_size, |
| 6087 FixedArray::kHeaderSize)); |
| 6088 __ cmp(temp.reg(), Factory::undefined_value()); |
| 6089 slow_case.Branch(equal, &code, not_taken); |
| 6090 code.Unuse(); |
| 6091 |
| 6092 frame_->Push(&temp); |
| 6093 exit.Jump(); |
| 6094 |
| 6095 slow_case.Bind(&code); |
| 6096 frame_->Push(&code); |
| 6097 Result result = frame_->CallRuntime(Runtime::kCharFromCode, 1); |
| 5984 frame_->Push(&result); | 6098 frame_->Push(&result); |
| 6099 |
| 6100 exit.Bind(); |
| 5985 } | 6101 } |
| 5986 | 6102 |
| 5987 | 6103 |
| 5988 void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) { | 6104 void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) { |
| 5989 ASSERT(args->length() == 1); | 6105 ASSERT(args->length() == 1); |
| 5990 Load(args->at(0)); | 6106 Load(args->at(0)); |
| 5991 Result value = frame_->Pop(); | 6107 Result value = frame_->Pop(); |
| 5992 value.ToRegister(); | 6108 value.ToRegister(); |
| 5993 ASSERT(value.is_valid()); | 6109 ASSERT(value.is_valid()); |
| 5994 __ test(value.reg(), Immediate(kSmiTagMask)); | 6110 __ test(value.reg(), Immediate(kSmiTagMask)); |
| (...skipping 2404 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8399 tmp.reg()); | 8515 tmp.reg()); |
| 8400 | 8516 |
| 8401 // Check that the value is a smi if it is not a constant. We can skip | 8517 // Check that the value is a smi if it is not a constant. We can skip |
| 8402 // the write barrier for smis and constants. | 8518 // the write barrier for smis and constants. |
| 8403 if (!value_is_constant) { | 8519 if (!value_is_constant) { |
| 8404 __ test(result.reg(), Immediate(kSmiTagMask)); | 8520 __ test(result.reg(), Immediate(kSmiTagMask)); |
| 8405 deferred->Branch(not_zero); | 8521 deferred->Branch(not_zero); |
| 8406 } | 8522 } |
| 8407 | 8523 |
| 8408 // Check that the key is a non-negative smi. | 8524 // Check that the key is a non-negative smi. |
| 8409 __ test(key.reg(), Immediate(kSmiTagMask | kSmiSignMask)); | 8525 __ test(key.reg(), Immediate(kSmiTagMask | 0x80000000)); |
| 8410 deferred->Branch(not_zero); | 8526 deferred->Branch(not_zero); |
| 8411 | 8527 |
| 8412 // Check that the receiver is not a smi. | 8528 // Check that the receiver is not a smi. |
| 8413 __ test(receiver.reg(), Immediate(kSmiTagMask)); | 8529 __ test(receiver.reg(), Immediate(kSmiTagMask)); |
| 8414 deferred->Branch(zero); | 8530 deferred->Branch(zero); |
| 8415 | 8531 |
| 8416 // Check that the receiver is a JSArray. | 8532 // Check that the receiver is a JSArray. |
| 8417 __ mov(tmp.reg(), | 8533 __ mov(tmp.reg(), |
| 8418 FieldOperand(receiver.reg(), HeapObject::kMapOffset)); | 8534 FieldOperand(receiver.reg(), HeapObject::kMapOffset)); |
| 8419 __ movzx_b(tmp.reg(), | 8535 __ movzx_b(tmp.reg(), |
| (...skipping 3611 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 12031 OS::SNPrintF(Vector<char>(name_, kMaxNameLength), | 12147 OS::SNPrintF(Vector<char>(name_, kMaxNameLength), |
| 12032 "CompareStub_%s%s%s%s", | 12148 "CompareStub_%s%s%s%s", |
| 12033 cc_name, | 12149 cc_name, |
| 12034 strict_name, | 12150 strict_name, |
| 12035 never_nan_nan_name, | 12151 never_nan_nan_name, |
| 12036 include_number_compare_name); | 12152 include_number_compare_name); |
| 12037 return name_; | 12153 return name_; |
| 12038 } | 12154 } |
| 12039 | 12155 |
| 12040 | 12156 |
| 12041 void StringHelper::GenerateFastCharCodeAt(MacroAssembler* masm, | |
| 12042 Register object, | |
| 12043 Register index, | |
| 12044 Register scratch, | |
| 12045 Register result, | |
| 12046 Label* receiver_not_string, | |
| 12047 Label* index_not_positive_smi, | |
| 12048 Label* slow_case) { | |
| 12049 Label not_a_flat_string; | |
| 12050 Label try_again_with_new_string; | |
| 12051 Label ascii_string; | |
| 12052 Label got_char_code; | |
| 12053 | |
| 12054 // If the receiver is a smi trigger the non-string case. | |
| 12055 ASSERT(kSmiTag == 0); | |
| 12056 __ test(object, Immediate(kSmiTagMask)); | |
| 12057 __ j(zero, receiver_not_string); | |
| 12058 | |
| 12059 // Fetch the instance type of the receiver into result register. | |
| 12060 __ mov(result, FieldOperand(object, HeapObject::kMapOffset)); | |
| 12061 __ movzx_b(result, FieldOperand(result, Map::kInstanceTypeOffset)); | |
| 12062 // If the receiver is not a string trigger the non-string case. | |
| 12063 __ test(result, Immediate(kIsNotStringMask)); | |
| 12064 __ j(not_zero, receiver_not_string); | |
| 12065 | |
| 12066 // If the index is negative or non-smi trigger the non-positive-smi | |
| 12067 // case. | |
| 12068 ASSERT(kSmiTag == 0); | |
| 12069 __ test(index, Immediate(kSmiTagMask | kSmiSignMask)); | |
| 12070 __ j(not_zero, index_not_positive_smi); | |
| 12071 | |
| 12072 // Put untagged index into scratch register. | |
| 12073 __ mov(scratch, index); | |
| 12074 __ SmiUntag(scratch); | |
| 12075 | |
| 12076 // Check for index out of range. | |
| 12077 __ cmp(scratch, FieldOperand(object, String::kLengthOffset)); | |
| 12078 __ j(greater_equal, slow_case); | |
| 12079 | |
| 12080 __ bind(&try_again_with_new_string); | |
| 12081 // ----------- S t a t e ------------- | |
| 12082 // -- object : string to access | |
| 12083 // -- result : instance type of the string | |
| 12084 // -- scratch : positive smi index < length | |
| 12085 // ----------------------------------- | |
| 12086 | |
| 12087 // We need special handling for non-flat strings. | |
| 12088 ASSERT(kSeqStringTag == 0); | |
| 12089 __ test(result, Immediate(kStringRepresentationMask)); | |
| 12090 __ j(not_zero, ¬_a_flat_string); | |
| 12091 | |
| 12092 // Check for 1-byte or 2-byte string. | |
| 12093 ASSERT(kAsciiStringTag != 0); | |
| 12094 __ test(result, Immediate(kStringEncodingMask)); | |
| 12095 __ j(not_zero, &ascii_string); | |
| 12096 | |
| 12097 // 2-byte string. | |
| 12098 // Load the 2-byte character code into the temp register. | |
| 12099 __ movzx_w(result, FieldOperand(object, | |
| 12100 scratch, times_2, | |
| 12101 SeqTwoByteString::kHeaderSize)); | |
| 12102 __ jmp(&got_char_code); | |
| 12103 | |
| 12104 // Handle non-flat strings. | |
| 12105 __ bind(¬_a_flat_string); | |
| 12106 __ and_(result, kStringRepresentationMask); | |
| 12107 __ cmp(result, kConsStringTag); | |
| 12108 __ j(not_equal, slow_case); | |
| 12109 | |
| 12110 // ConsString. | |
| 12111 // Check whether the right hand side is the empty string (i.e. if | |
| 12112 // this is really a flat string in a cons string). If that is not | |
| 12113 // the case we would rather go to the runtime system now to flatten | |
| 12114 // the string. | |
| 12115 __ mov(result, FieldOperand(object, ConsString::kSecondOffset)); | |
| 12116 __ cmp(Operand(result), Factory::empty_string()); | |
| 12117 __ j(not_equal, slow_case); | |
| 12118 // Get the first of the two strings and load its instance type. | |
| 12119 __ mov(object, FieldOperand(object, ConsString::kFirstOffset)); | |
| 12120 __ mov(result, FieldOperand(object, HeapObject::kMapOffset)); | |
| 12121 __ movzx_b(result, FieldOperand(result, Map::kInstanceTypeOffset)); | |
| 12122 __ jmp(&try_again_with_new_string); | |
| 12123 | |
| 12124 // ASCII string. | |
| 12125 __ bind(&ascii_string); | |
| 12126 // Load the byte into the temp register. | |
| 12127 __ movzx_b(result, FieldOperand(object, | |
| 12128 scratch, times_1, | |
| 12129 SeqAsciiString::kHeaderSize)); | |
| 12130 __ bind(&got_char_code); | |
| 12131 __ SmiTag(result); | |
| 12132 } | |
| 12133 | |
| 12134 | |
| 12135 void StringHelper::GenerateCharFromCode(MacroAssembler* masm, | |
| 12136 Register code, | |
| 12137 Register result, | |
| 12138 InvokeFlag flag) { | |
| 12139 ASSERT(!code.is(result)); | |
| 12140 | |
| 12141 Label slow_case; | |
| 12142 Label exit; | |
| 12143 | |
| 12144 // Fast case of Heap::LookupSingleCharacterStringFromCode. | |
| 12145 ASSERT(kSmiTag == 0); | |
| 12146 ASSERT(kSmiShiftSize == 0); | |
| 12147 ASSERT(IsPowerOf2(String::kMaxAsciiCharCode + 1)); | |
| 12148 __ test(code, | |
| 12149 Immediate(kSmiTagMask | | |
| 12150 ((~String::kMaxAsciiCharCode) << kSmiTagSize))); | |
| 12151 __ j(not_zero, &slow_case, not_taken); | |
| 12152 | |
| 12153 __ Set(result, Immediate(Factory::single_character_string_cache())); | |
| 12154 ASSERT(kSmiTag == 0); | |
| 12155 ASSERT(kSmiTagSize == 1); | |
| 12156 ASSERT(kSmiShiftSize == 0); | |
| 12157 // At this point code register contains smi tagged ascii char code. | |
| 12158 __ mov(result, FieldOperand(result, | |
| 12159 code, times_half_pointer_size, | |
| 12160 FixedArray::kHeaderSize)); | |
| 12161 __ cmp(result, Factory::undefined_value()); | |
| 12162 __ j(equal, &slow_case, not_taken); | |
| 12163 __ jmp(&exit); | |
| 12164 | |
| 12165 __ bind(&slow_case); | |
| 12166 if (flag == CALL_FUNCTION) { | |
| 12167 __ push(code); | |
| 12168 __ CallRuntime(Runtime::kCharFromCode, 1); | |
| 12169 if (!result.is(eax)) { | |
| 12170 __ mov(result, eax); | |
| 12171 } | |
| 12172 } else { | |
| 12173 ASSERT(flag == JUMP_FUNCTION); | |
| 12174 ASSERT(result.is(eax)); | |
| 12175 __ pop(eax); // Save return address. | |
| 12176 __ push(code); | |
| 12177 __ push(eax); // Restore return address. | |
| 12178 __ TailCallRuntime(Runtime::kCharFromCode, 1, 1); | |
| 12179 } | |
| 12180 | |
| 12181 __ bind(&exit); | |
| 12182 if (flag == JUMP_FUNCTION) { | |
| 12183 ASSERT(result.is(eax)); | |
| 12184 __ ret(0); | |
| 12185 } | |
| 12186 } | |
| 12187 | |
| 12188 | |
| 12189 void StringAddStub::Generate(MacroAssembler* masm) { | 12157 void StringAddStub::Generate(MacroAssembler* masm) { |
| 12190 Label string_add_runtime; | 12158 Label string_add_runtime; |
| 12191 | 12159 |
| 12192 // Load the two arguments. | 12160 // Load the two arguments. |
| 12193 __ mov(eax, Operand(esp, 2 * kPointerSize)); // First argument. | 12161 __ mov(eax, Operand(esp, 2 * kPointerSize)); // First argument. |
| 12194 __ mov(edx, Operand(esp, 1 * kPointerSize)); // Second argument. | 12162 __ mov(edx, Operand(esp, 1 * kPointerSize)); // Second argument. |
| 12195 | 12163 |
| 12196 // Make sure that both arguments are strings if not known in advance. | 12164 // Make sure that both arguments are strings if not known in advance. |
| 12197 if (string_check_) { | 12165 if (string_check_) { |
| 12198 __ test(eax, Immediate(kSmiTagMask)); | 12166 __ test(eax, Immediate(kSmiTagMask)); |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 12245 __ JumpIfNotBothSequentialAsciiStrings(eax, edx, ebx, ecx, | 12213 __ JumpIfNotBothSequentialAsciiStrings(eax, edx, ebx, ecx, |
| 12246 &string_add_runtime); | 12214 &string_add_runtime); |
| 12247 | 12215 |
| 12248 // Get the two characters forming the sub string. | 12216 // Get the two characters forming the sub string. |
| 12249 __ movzx_b(ebx, FieldOperand(eax, SeqAsciiString::kHeaderSize)); | 12217 __ movzx_b(ebx, FieldOperand(eax, SeqAsciiString::kHeaderSize)); |
| 12250 __ movzx_b(ecx, FieldOperand(edx, SeqAsciiString::kHeaderSize)); | 12218 __ movzx_b(ecx, FieldOperand(edx, SeqAsciiString::kHeaderSize)); |
| 12251 | 12219 |
| 12252 // Try to lookup two character string in symbol table. If it is not found | 12220 // Try to lookup two character string in symbol table. If it is not found |
| 12253 // just allocate a new one. | 12221 // just allocate a new one. |
| 12254 Label make_two_character_string, make_flat_ascii_string; | 12222 Label make_two_character_string, make_flat_ascii_string; |
| 12255 StringHelper::GenerateTwoCharacterSymbolTableProbe( | 12223 GenerateTwoCharacterSymbolTableProbe(masm, ebx, ecx, eax, edx, edi, |
| 12256 masm, ebx, ecx, eax, edx, edi, &make_two_character_string); | 12224 &make_two_character_string); |
| 12257 __ IncrementCounter(&Counters::string_add_native, 1); | 12225 __ IncrementCounter(&Counters::string_add_native, 1); |
| 12258 __ ret(2 * kPointerSize); | 12226 __ ret(2 * kPointerSize); |
| 12259 | 12227 |
| 12260 __ bind(&make_two_character_string); | 12228 __ bind(&make_two_character_string); |
| 12261 __ Set(ebx, Immediate(2)); | 12229 __ Set(ebx, Immediate(2)); |
| 12262 __ jmp(&make_flat_ascii_string); | 12230 __ jmp(&make_flat_ascii_string); |
| 12263 | 12231 |
| 12264 __ bind(&longer_than_two); | 12232 __ bind(&longer_than_two); |
| 12265 // Check if resulting string will be flat. | 12233 // Check if resulting string will be flat. |
| 12266 __ cmp(ebx, String::kMinNonFlatLength); | 12234 __ cmp(ebx, String::kMinNonFlatLength); |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 12338 // Locate first character of result. | 12306 // Locate first character of result. |
| 12339 __ add(Operand(ecx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | 12307 __ add(Operand(ecx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
| 12340 // Load first argument and locate first character. | 12308 // Load first argument and locate first character. |
| 12341 __ mov(edx, Operand(esp, 2 * kPointerSize)); | 12309 __ mov(edx, Operand(esp, 2 * kPointerSize)); |
| 12342 __ mov(edi, FieldOperand(edx, String::kLengthOffset)); | 12310 __ mov(edi, FieldOperand(edx, String::kLengthOffset)); |
| 12343 __ add(Operand(edx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | 12311 __ add(Operand(edx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
| 12344 // eax: result string | 12312 // eax: result string |
| 12345 // ecx: first character of result | 12313 // ecx: first character of result |
| 12346 // edx: first char of first argument | 12314 // edx: first char of first argument |
| 12347 // edi: length of first argument | 12315 // edi: length of first argument |
| 12348 StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true); | 12316 GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true); |
| 12349 // Load second argument and locate first character. | 12317 // Load second argument and locate first character. |
| 12350 __ mov(edx, Operand(esp, 1 * kPointerSize)); | 12318 __ mov(edx, Operand(esp, 1 * kPointerSize)); |
| 12351 __ mov(edi, FieldOperand(edx, String::kLengthOffset)); | 12319 __ mov(edi, FieldOperand(edx, String::kLengthOffset)); |
| 12352 __ add(Operand(edx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | 12320 __ add(Operand(edx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
| 12353 // eax: result string | 12321 // eax: result string |
| 12354 // ecx: next character of result | 12322 // ecx: next character of result |
| 12355 // edx: first char of second argument | 12323 // edx: first char of second argument |
| 12356 // edi: length of second argument | 12324 // edi: length of second argument |
| 12357 StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true); | 12325 GenerateCopyCharacters(masm, ecx, edx, edi, ebx, true); |
| 12358 __ IncrementCounter(&Counters::string_add_native, 1); | 12326 __ IncrementCounter(&Counters::string_add_native, 1); |
| 12359 __ ret(2 * kPointerSize); | 12327 __ ret(2 * kPointerSize); |
| 12360 | 12328 |
| 12361 // Handle creating a flat two byte result. | 12329 // Handle creating a flat two byte result. |
| 12362 // eax: first string - known to be two byte | 12330 // eax: first string - known to be two byte |
| 12363 // ebx: length of resulting flat string | 12331 // ebx: length of resulting flat string |
| 12364 // edx: second string | 12332 // edx: second string |
| 12365 __ bind(&non_ascii_string_add_flat_result); | 12333 __ bind(&non_ascii_string_add_flat_result); |
| 12366 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); | 12334 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); |
| 12367 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); | 12335 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); |
| 12368 __ and_(ecx, kAsciiStringTag); | 12336 __ and_(ecx, kAsciiStringTag); |
| 12369 __ j(not_zero, &string_add_runtime); | 12337 __ j(not_zero, &string_add_runtime); |
| 12370 // Both strings are two byte strings. As they are short they are both | 12338 // Both strings are two byte strings. As they are short they are both |
| 12371 // flat. | 12339 // flat. |
| 12372 __ AllocateTwoByteString(eax, ebx, ecx, edx, edi, &string_add_runtime); | 12340 __ AllocateTwoByteString(eax, ebx, ecx, edx, edi, &string_add_runtime); |
| 12373 // eax: result string | 12341 // eax: result string |
| 12374 __ mov(ecx, eax); | 12342 __ mov(ecx, eax); |
| 12375 // Locate first character of result. | 12343 // Locate first character of result. |
| 12376 __ add(Operand(ecx), | 12344 __ add(Operand(ecx), |
| 12377 Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); | 12345 Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); |
| 12378 // Load first argument and locate first character. | 12346 // Load first argument and locate first character. |
| 12379 __ mov(edx, Operand(esp, 2 * kPointerSize)); | 12347 __ mov(edx, Operand(esp, 2 * kPointerSize)); |
| 12380 __ mov(edi, FieldOperand(edx, String::kLengthOffset)); | 12348 __ mov(edi, FieldOperand(edx, String::kLengthOffset)); |
| 12381 __ add(Operand(edx), | 12349 __ add(Operand(edx), |
| 12382 Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); | 12350 Immediate(SeqTwoByteString::kHeaderSize - kHeapObjectTag)); |
| 12383 // eax: result string | 12351 // eax: result string |
| 12384 // ecx: first character of result | 12352 // ecx: first character of result |
| 12385 // edx: first char of first argument | 12353 // edx: first char of first argument |
| 12386 // edi: length of first argument | 12354 // edi: length of first argument |
| 12387 StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false); | 12355 GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false); |
| 12388 // Load second argument and locate first character. | 12356 // Load second argument and locate first character. |
| 12389 __ mov(edx, Operand(esp, 1 * kPointerSize)); | 12357 __ mov(edx, Operand(esp, 1 * kPointerSize)); |
| 12390 __ mov(edi, FieldOperand(edx, String::kLengthOffset)); | 12358 __ mov(edi, FieldOperand(edx, String::kLengthOffset)); |
| 12391 __ add(Operand(edx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | 12359 __ add(Operand(edx), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
| 12392 // eax: result string | 12360 // eax: result string |
| 12393 // ecx: next character of result | 12361 // ecx: next character of result |
| 12394 // edx: first char of second argument | 12362 // edx: first char of second argument |
| 12395 // edi: length of second argument | 12363 // edi: length of second argument |
| 12396 StringHelper::GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false); | 12364 GenerateCopyCharacters(masm, ecx, edx, edi, ebx, false); |
| 12397 __ IncrementCounter(&Counters::string_add_native, 1); | 12365 __ IncrementCounter(&Counters::string_add_native, 1); |
| 12398 __ ret(2 * kPointerSize); | 12366 __ ret(2 * kPointerSize); |
| 12399 | 12367 |
| 12400 // Just jump to runtime to add the two strings. | 12368 // Just jump to runtime to add the two strings. |
| 12401 __ bind(&string_add_runtime); | 12369 __ bind(&string_add_runtime); |
| 12402 __ TailCallRuntime(Runtime::kStringAdd, 2, 1); | 12370 __ TailCallRuntime(Runtime::kStringAdd, 2, 1); |
| 12403 } | 12371 } |
| 12404 | 12372 |
| 12405 | 12373 |
| 12406 void StringHelper::GenerateCopyCharacters(MacroAssembler* masm, | 12374 void StringStubBase::GenerateCopyCharacters(MacroAssembler* masm, |
| 12407 Register dest, | 12375 Register dest, |
| 12408 Register src, | 12376 Register src, |
| 12409 Register count, | 12377 Register count, |
| 12410 Register scratch, | 12378 Register scratch, |
| 12411 bool ascii) { | 12379 bool ascii) { |
| 12412 Label loop; | 12380 Label loop; |
| 12413 __ bind(&loop); | 12381 __ bind(&loop); |
| 12414 // This loop just copies one character at a time, as it is only used for very | 12382 // This loop just copies one character at a time, as it is only used for very |
| 12415 // short strings. | 12383 // short strings. |
| 12416 if (ascii) { | 12384 if (ascii) { |
| 12417 __ mov_b(scratch, Operand(src, 0)); | 12385 __ mov_b(scratch, Operand(src, 0)); |
| 12418 __ mov_b(Operand(dest, 0), scratch); | 12386 __ mov_b(Operand(dest, 0), scratch); |
| 12419 __ add(Operand(src), Immediate(1)); | 12387 __ add(Operand(src), Immediate(1)); |
| 12420 __ add(Operand(dest), Immediate(1)); | 12388 __ add(Operand(dest), Immediate(1)); |
| 12421 } else { | 12389 } else { |
| 12422 __ mov_w(scratch, Operand(src, 0)); | 12390 __ mov_w(scratch, Operand(src, 0)); |
| 12423 __ mov_w(Operand(dest, 0), scratch); | 12391 __ mov_w(Operand(dest, 0), scratch); |
| 12424 __ add(Operand(src), Immediate(2)); | 12392 __ add(Operand(src), Immediate(2)); |
| 12425 __ add(Operand(dest), Immediate(2)); | 12393 __ add(Operand(dest), Immediate(2)); |
| 12426 } | 12394 } |
| 12427 __ sub(Operand(count), Immediate(1)); | 12395 __ sub(Operand(count), Immediate(1)); |
| 12428 __ j(not_zero, &loop); | 12396 __ j(not_zero, &loop); |
| 12429 } | 12397 } |
| 12430 | 12398 |
| 12431 | 12399 |
| 12432 void StringHelper::GenerateCopyCharactersREP(MacroAssembler* masm, | 12400 void StringStubBase::GenerateCopyCharactersREP(MacroAssembler* masm, |
| 12433 Register dest, | 12401 Register dest, |
| 12434 Register src, | 12402 Register src, |
| 12435 Register count, | 12403 Register count, |
| 12436 Register scratch, | 12404 Register scratch, |
| 12437 bool ascii) { | 12405 bool ascii) { |
| 12438 // Copy characters using rep movs of doublewords. Align destination on 4 byte | 12406 // Copy characters using rep movs of doublewords. Align destination on 4 byte |
| 12439 // boundary before starting rep movs. Copy remaining characters after running | 12407 // boundary before starting rep movs. Copy remaining characters after running |
| 12440 // rep movs. | 12408 // rep movs. |
| 12441 ASSERT(dest.is(edi)); // rep movs destination | 12409 ASSERT(dest.is(edi)); // rep movs destination |
| 12442 ASSERT(src.is(esi)); // rep movs source | 12410 ASSERT(src.is(esi)); // rep movs source |
| 12443 ASSERT(count.is(ecx)); // rep movs count | 12411 ASSERT(count.is(ecx)); // rep movs count |
| 12444 ASSERT(!scratch.is(dest)); | 12412 ASSERT(!scratch.is(dest)); |
| 12445 ASSERT(!scratch.is(src)); | 12413 ASSERT(!scratch.is(src)); |
| 12446 ASSERT(!scratch.is(count)); | 12414 ASSERT(!scratch.is(count)); |
| 12447 | 12415 |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 12482 __ mov_b(Operand(dest, 0), scratch); | 12450 __ mov_b(Operand(dest, 0), scratch); |
| 12483 __ add(Operand(src), Immediate(1)); | 12451 __ add(Operand(src), Immediate(1)); |
| 12484 __ add(Operand(dest), Immediate(1)); | 12452 __ add(Operand(dest), Immediate(1)); |
| 12485 __ sub(Operand(count), Immediate(1)); | 12453 __ sub(Operand(count), Immediate(1)); |
| 12486 __ j(not_zero, &loop); | 12454 __ j(not_zero, &loop); |
| 12487 | 12455 |
| 12488 __ bind(&done); | 12456 __ bind(&done); |
| 12489 } | 12457 } |
| 12490 | 12458 |
| 12491 | 12459 |
| 12492 void StringHelper::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, | 12460 void StringStubBase::GenerateTwoCharacterSymbolTableProbe(MacroAssembler* masm, |
| 12493 Register c1, | 12461 Register c1, |
| 12494 Register c2, | 12462 Register c2, |
| 12495 Register scratch1, | 12463 Register scratch1, |
| 12496 Register scratch2, | 12464 Register scratch2, |
| 12497 Register scratch3, | 12465 Register scratch3, |
| 12498 Label* not_found) { | 12466 Label* not_found) { |
| 12499 // Register scratch3 is the general scratch register in this function. | 12467 // Register scratch3 is the general scratch register in this function. |
| 12500 Register scratch = scratch3; | 12468 Register scratch = scratch3; |
| 12501 | 12469 |
| 12502 // Make sure that both characters are not digits as such strings has a | 12470 // Make sure that both characters are not digits as such strings has a |
| 12503 // different hash algorithm. Don't try to look for these in the symbol table. | 12471 // different hash algorithm. Don't try to look for these in the symbol table. |
| 12504 Label not_array_index; | 12472 Label not_array_index; |
| 12505 __ mov(scratch, c1); | 12473 __ mov(scratch, c1); |
| 12506 __ sub(Operand(scratch), Immediate(static_cast<int>('0'))); | 12474 __ sub(Operand(scratch), Immediate(static_cast<int>('0'))); |
| 12507 __ cmp(Operand(scratch), Immediate(static_cast<int>('9' - '0'))); | 12475 __ cmp(Operand(scratch), Immediate(static_cast<int>('9' - '0'))); |
| 12508 __ j(above, ¬_array_index); | 12476 __ j(above, ¬_array_index); |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 12602 // Scratch register contains result when we fall through to here. | 12570 // Scratch register contains result when we fall through to here. |
| 12603 Register result = scratch; | 12571 Register result = scratch; |
| 12604 __ bind(&found_in_symbol_table); | 12572 __ bind(&found_in_symbol_table); |
| 12605 __ pop(mask); // Pop temporally saved mask from the stack. | 12573 __ pop(mask); // Pop temporally saved mask from the stack. |
| 12606 if (!result.is(eax)) { | 12574 if (!result.is(eax)) { |
| 12607 __ mov(eax, result); | 12575 __ mov(eax, result); |
| 12608 } | 12576 } |
| 12609 } | 12577 } |
| 12610 | 12578 |
| 12611 | 12579 |
| 12612 void StringHelper::GenerateHashInit(MacroAssembler* masm, | 12580 void StringStubBase::GenerateHashInit(MacroAssembler* masm, |
| 12613 Register hash, | 12581 Register hash, |
| 12614 Register character, | 12582 Register character, |
| 12615 Register scratch) { | 12583 Register scratch) { |
| 12616 // hash = character + (character << 10); | 12584 // hash = character + (character << 10); |
| 12617 __ mov(hash, character); | 12585 __ mov(hash, character); |
| 12618 __ shl(hash, 10); | 12586 __ shl(hash, 10); |
| 12619 __ add(hash, Operand(character)); | 12587 __ add(hash, Operand(character)); |
| 12620 // hash ^= hash >> 6; | 12588 // hash ^= hash >> 6; |
| 12621 __ mov(scratch, hash); | 12589 __ mov(scratch, hash); |
| 12622 __ sar(scratch, 6); | 12590 __ sar(scratch, 6); |
| 12623 __ xor_(hash, Operand(scratch)); | 12591 __ xor_(hash, Operand(scratch)); |
| 12624 } | 12592 } |
| 12625 | 12593 |
| 12626 | 12594 |
| 12627 void StringHelper::GenerateHashAddCharacter(MacroAssembler* masm, | 12595 void StringStubBase::GenerateHashAddCharacter(MacroAssembler* masm, |
| 12628 Register hash, | 12596 Register hash, |
| 12629 Register character, | 12597 Register character, |
| 12630 Register scratch) { | 12598 Register scratch) { |
| 12631 // hash += character; | 12599 // hash += character; |
| 12632 __ add(hash, Operand(character)); | 12600 __ add(hash, Operand(character)); |
| 12633 // hash += hash << 10; | 12601 // hash += hash << 10; |
| 12634 __ mov(scratch, hash); | 12602 __ mov(scratch, hash); |
| 12635 __ shl(scratch, 10); | 12603 __ shl(scratch, 10); |
| 12636 __ add(hash, Operand(scratch)); | 12604 __ add(hash, Operand(scratch)); |
| 12637 // hash ^= hash >> 6; | 12605 // hash ^= hash >> 6; |
| 12638 __ mov(scratch, hash); | 12606 __ mov(scratch, hash); |
| 12639 __ sar(scratch, 6); | 12607 __ sar(scratch, 6); |
| 12640 __ xor_(hash, Operand(scratch)); | 12608 __ xor_(hash, Operand(scratch)); |
| 12641 } | 12609 } |
| 12642 | 12610 |
| 12643 | 12611 |
| 12644 void StringHelper::GenerateHashGetHash(MacroAssembler* masm, | 12612 void StringStubBase::GenerateHashGetHash(MacroAssembler* masm, |
| 12645 Register hash, | 12613 Register hash, |
| 12646 Register scratch) { | 12614 Register scratch) { |
| 12647 // hash += hash << 3; | 12615 // hash += hash << 3; |
| 12648 __ mov(scratch, hash); | 12616 __ mov(scratch, hash); |
| 12649 __ shl(scratch, 3); | 12617 __ shl(scratch, 3); |
| 12650 __ add(hash, Operand(scratch)); | 12618 __ add(hash, Operand(scratch)); |
| 12651 // hash ^= hash >> 11; | 12619 // hash ^= hash >> 11; |
| 12652 __ mov(scratch, hash); | 12620 __ mov(scratch, hash); |
| 12653 __ sar(scratch, 11); | 12621 __ sar(scratch, 11); |
| 12654 __ xor_(hash, Operand(scratch)); | 12622 __ xor_(hash, Operand(scratch)); |
| 12655 // hash += hash << 15; | 12623 // hash += hash << 15; |
| 12656 __ mov(scratch, hash); | 12624 __ mov(scratch, hash); |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 12710 __ JumpIfInstanceTypeIsNotSequentialAscii(ebx, ebx, &runtime); | 12678 __ JumpIfInstanceTypeIsNotSequentialAscii(ebx, ebx, &runtime); |
| 12711 | 12679 |
| 12712 // Get the two characters forming the sub string. | 12680 // Get the two characters forming the sub string. |
| 12713 __ SmiUntag(edx); // From index is no longer smi. | 12681 __ SmiUntag(edx); // From index is no longer smi. |
| 12714 __ movzx_b(ebx, FieldOperand(eax, edx, times_1, SeqAsciiString::kHeaderSize)); | 12682 __ movzx_b(ebx, FieldOperand(eax, edx, times_1, SeqAsciiString::kHeaderSize)); |
| 12715 __ movzx_b(ecx, | 12683 __ movzx_b(ecx, |
| 12716 FieldOperand(eax, edx, times_1, SeqAsciiString::kHeaderSize + 1)); | 12684 FieldOperand(eax, edx, times_1, SeqAsciiString::kHeaderSize + 1)); |
| 12717 | 12685 |
| 12718 // Try to lookup two character string in symbol table. | 12686 // Try to lookup two character string in symbol table. |
| 12719 Label make_two_character_string; | 12687 Label make_two_character_string; |
| 12720 StringHelper::GenerateTwoCharacterSymbolTableProbe( | 12688 GenerateTwoCharacterSymbolTableProbe(masm, ebx, ecx, eax, edx, edi, |
| 12721 masm, ebx, ecx, eax, edx, edi, &make_two_character_string); | 12689 &make_two_character_string); |
| 12722 __ ret(3 * kPointerSize); | 12690 __ ret(3 * kPointerSize); |
| 12723 | 12691 |
| 12724 __ bind(&make_two_character_string); | 12692 __ bind(&make_two_character_string); |
| 12725 // Setup registers for allocating the two character string. | 12693 // Setup registers for allocating the two character string. |
| 12726 __ mov(eax, Operand(esp, 3 * kPointerSize)); | 12694 __ mov(eax, Operand(esp, 3 * kPointerSize)); |
| 12727 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); | 12695 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); |
| 12728 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); | 12696 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); |
| 12729 __ Set(ecx, Immediate(2)); | 12697 __ Set(ecx, Immediate(2)); |
| 12730 | 12698 |
| 12731 __ bind(&result_longer_than_two); | 12699 __ bind(&result_longer_than_two); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 12750 __ add(Operand(esi), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); | 12718 __ add(Operand(esi), Immediate(SeqAsciiString::kHeaderSize - kHeapObjectTag)); |
| 12751 __ mov(ebx, Operand(esp, 2 * kPointerSize)); // from | 12719 __ mov(ebx, Operand(esp, 2 * kPointerSize)); // from |
| 12752 __ SmiUntag(ebx); | 12720 __ SmiUntag(ebx); |
| 12753 __ add(esi, Operand(ebx)); | 12721 __ add(esi, Operand(ebx)); |
| 12754 | 12722 |
| 12755 // eax: result string | 12723 // eax: result string |
| 12756 // ecx: result length | 12724 // ecx: result length |
| 12757 // edx: original value of esi | 12725 // edx: original value of esi |
| 12758 // edi: first character of result | 12726 // edi: first character of result |
| 12759 // esi: character of sub string start | 12727 // esi: character of sub string start |
| 12760 StringHelper::GenerateCopyCharactersREP(masm, edi, esi, ecx, ebx, true); | 12728 GenerateCopyCharactersREP(masm, edi, esi, ecx, ebx, true); |
| 12761 __ mov(esi, edx); // Restore esi. | 12729 __ mov(esi, edx); // Restore esi. |
| 12762 __ IncrementCounter(&Counters::sub_string_native, 1); | 12730 __ IncrementCounter(&Counters::sub_string_native, 1); |
| 12763 __ ret(3 * kPointerSize); | 12731 __ ret(3 * kPointerSize); |
| 12764 | 12732 |
| 12765 __ bind(&non_ascii_flat); | 12733 __ bind(&non_ascii_flat); |
| 12766 // eax: string | 12734 // eax: string |
| 12767 // ebx: instance type & kStringRepresentationMask | kStringEncodingMask | 12735 // ebx: instance type & kStringRepresentationMask | kStringEncodingMask |
| 12768 // ecx: result string length | 12736 // ecx: result string length |
| 12769 // Check for flat two byte string | 12737 // Check for flat two byte string |
| 12770 __ cmp(ebx, kSeqStringTag | kTwoByteStringTag); | 12738 __ cmp(ebx, kSeqStringTag | kTwoByteStringTag); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 12789 // byte character. | 12757 // byte character. |
| 12790 ASSERT_EQ(0, kSmiTag); | 12758 ASSERT_EQ(0, kSmiTag); |
| 12791 ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize); | 12759 ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize); |
| 12792 __ add(esi, Operand(ebx)); | 12760 __ add(esi, Operand(ebx)); |
| 12793 | 12761 |
| 12794 // eax: result string | 12762 // eax: result string |
| 12795 // ecx: result length | 12763 // ecx: result length |
| 12796 // edx: original value of esi | 12764 // edx: original value of esi |
| 12797 // edi: first character of result | 12765 // edi: first character of result |
| 12798 // esi: character of sub string start | 12766 // esi: character of sub string start |
| 12799 StringHelper::GenerateCopyCharactersREP(masm, edi, esi, ecx, ebx, false); | 12767 GenerateCopyCharactersREP(masm, edi, esi, ecx, ebx, false); |
| 12800 __ mov(esi, edx); // Restore esi. | 12768 __ mov(esi, edx); // Restore esi. |
| 12801 __ IncrementCounter(&Counters::sub_string_native, 1); | 12769 __ IncrementCounter(&Counters::sub_string_native, 1); |
| 12802 __ ret(3 * kPointerSize); | 12770 __ ret(3 * kPointerSize); |
| 12803 | 12771 |
| 12804 // Just jump to runtime to create the sub string. | 12772 // Just jump to runtime to create the sub string. |
| 12805 __ bind(&runtime); | 12773 __ bind(&runtime); |
| 12806 __ TailCallRuntime(Runtime::kSubString, 3, 1); | 12774 __ TailCallRuntime(Runtime::kSubString, 3, 1); |
| 12807 } | 12775 } |
| 12808 | 12776 |
| 12809 | 12777 |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 12920 | 12888 |
| 12921 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) | 12889 // Call the runtime; it returns -1 (less), 0 (equal), or 1 (greater) |
| 12922 // tagged as a small integer. | 12890 // tagged as a small integer. |
| 12923 __ bind(&runtime); | 12891 __ bind(&runtime); |
| 12924 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); | 12892 __ TailCallRuntime(Runtime::kStringCompare, 2, 1); |
| 12925 } | 12893 } |
| 12926 | 12894 |
| 12927 #undef __ | 12895 #undef __ |
| 12928 | 12896 |
| 12929 } } // namespace v8::internal | 12897 } } // namespace v8::internal |
| OLD | NEW |