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 5069 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5080 Load(args->at(i + 1)); | 5080 Load(args->at(i + 1)); |
5081 } | 5081 } |
5082 Load(args->at(n_args + 1)); // function | 5082 Load(args->at(n_args + 1)); // function |
5083 frame_->CallJSFunction(n_args); | 5083 frame_->CallJSFunction(n_args); |
5084 frame_->EmitPush(r0); | 5084 frame_->EmitPush(r0); |
5085 } | 5085 } |
5086 | 5086 |
5087 | 5087 |
5088 void CodeGenerator::GenerateMathSin(ZoneList<Expression*>* args) { | 5088 void CodeGenerator::GenerateMathSin(ZoneList<Expression*>* args) { |
5089 ASSERT_EQ(args->length(), 1); | 5089 ASSERT_EQ(args->length(), 1); |
5090 // Load the argument on the stack and jump to the runtime. | |
5091 Load(args->at(0)); | 5090 Load(args->at(0)); |
5092 frame_->CallRuntime(Runtime::kMath_sin, 1); | 5091 if (CpuFeatures::IsSupported(VFP3)) { |
| 5092 TranscendentalCacheStub stub(TranscendentalCache::SIN); |
| 5093 frame_->SpillAllButCopyTOSToR0(); |
| 5094 frame_->CallStub(&stub, 1); |
| 5095 } else { |
| 5096 frame_->CallRuntime(Runtime::kMath_sin, 1); |
| 5097 } |
5093 frame_->EmitPush(r0); | 5098 frame_->EmitPush(r0); |
5094 } | 5099 } |
5095 | 5100 |
5096 | 5101 |
5097 void CodeGenerator::GenerateMathCos(ZoneList<Expression*>* args) { | 5102 void CodeGenerator::GenerateMathCos(ZoneList<Expression*>* args) { |
5098 ASSERT_EQ(args->length(), 1); | 5103 ASSERT_EQ(args->length(), 1); |
5099 // Load the argument on the stack and jump to the runtime. | |
5100 Load(args->at(0)); | 5104 Load(args->at(0)); |
5101 frame_->CallRuntime(Runtime::kMath_cos, 1); | 5105 if (CpuFeatures::IsSupported(VFP3)) { |
| 5106 TranscendentalCacheStub stub(TranscendentalCache::COS); |
| 5107 frame_->SpillAllButCopyTOSToR0(); |
| 5108 frame_->CallStub(&stub, 1); |
| 5109 } else { |
| 5110 frame_->CallRuntime(Runtime::kMath_cos, 1); |
| 5111 } |
5102 frame_->EmitPush(r0); | 5112 frame_->EmitPush(r0); |
5103 } | 5113 } |
5104 | 5114 |
5105 | 5115 |
5106 void CodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* args) { | 5116 void CodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* args) { |
5107 ASSERT(args->length() == 2); | 5117 ASSERT(args->length() == 2); |
5108 | 5118 |
5109 // Load the two objects into registers and perform the comparison. | 5119 // Load the two objects into registers and perform the comparison. |
5110 Load(args->at(0)); | 5120 Load(args->at(0)); |
5111 Load(args->at(1)); | 5121 Load(args->at(1)); |
(...skipping 1971 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7083 // doubles is the xor of the upper and lower words. See | 7093 // doubles is the xor of the upper and lower words. See |
7084 // Heap::GetNumberStringCache. | 7094 // Heap::GetNumberStringCache. |
7085 Label is_smi; | 7095 Label is_smi; |
7086 Label load_result_from_cache; | 7096 Label load_result_from_cache; |
7087 if (!object_is_smi) { | 7097 if (!object_is_smi) { |
7088 __ BranchOnSmi(object, &is_smi); | 7098 __ BranchOnSmi(object, &is_smi); |
7089 if (CpuFeatures::IsSupported(VFP3)) { | 7099 if (CpuFeatures::IsSupported(VFP3)) { |
7090 CpuFeatures::Scope scope(VFP3); | 7100 CpuFeatures::Scope scope(VFP3); |
7091 __ CheckMap(object, | 7101 __ CheckMap(object, |
7092 scratch1, | 7102 scratch1, |
7093 Factory::heap_number_map(), | 7103 Heap::kHeapNumberMapRootIndex, |
7094 not_found, | 7104 not_found, |
7095 true); | 7105 true); |
7096 | 7106 |
7097 ASSERT_EQ(8, kDoubleSize); | 7107 ASSERT_EQ(8, kDoubleSize); |
7098 __ add(scratch1, | 7108 __ add(scratch1, |
7099 object, | 7109 object, |
7100 Operand(HeapNumber::kValueOffset - kHeapObjectTag)); | 7110 Operand(HeapNumber::kValueOffset - kHeapObjectTag)); |
7101 __ ldm(ia, scratch1, scratch1.bit() | scratch2.bit()); | 7111 __ ldm(ia, scratch1, scratch1.bit() | scratch2.bit()); |
7102 __ eor(scratch1, scratch1, Operand(scratch2)); | 7112 __ eor(scratch1, scratch1, Operand(scratch2)); |
7103 __ and_(scratch1, scratch1, Operand(mask)); | 7113 __ and_(scratch1, scratch1, Operand(mask)); |
(...skipping 1125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8229 __ bind(&get_result); | 8239 __ bind(&get_result); |
8230 } | 8240 } |
8231 | 8241 |
8232 | 8242 |
8233 Handle<Code> GetBinaryOpStub(int key, BinaryOpIC::TypeInfo type_info) { | 8243 Handle<Code> GetBinaryOpStub(int key, BinaryOpIC::TypeInfo type_info) { |
8234 GenericBinaryOpStub stub(key, type_info); | 8244 GenericBinaryOpStub stub(key, type_info); |
8235 return stub.GetCode(); | 8245 return stub.GetCode(); |
8236 } | 8246 } |
8237 | 8247 |
8238 | 8248 |
| 8249 void TranscendentalCacheStub::Generate(MacroAssembler* masm) { |
| 8250 // Argument is a number and is on stack and in r0. |
| 8251 Label runtime_call; |
| 8252 Label input_not_smi; |
| 8253 Label loaded; |
| 8254 |
| 8255 if (CpuFeatures::IsSupported(VFP3)) { |
| 8256 // Load argument and check if it is a smi. |
| 8257 __ BranchOnNotSmi(r0, &input_not_smi); |
| 8258 |
| 8259 CpuFeatures::Scope scope(VFP3); |
| 8260 // Input is a smi. Convert to double and load the low and high words |
| 8261 // of the double into r2, r3. |
| 8262 __ IntegerToDoubleConversionWithVFP3(r0, r3, r2); |
| 8263 __ b(&loaded); |
| 8264 |
| 8265 __ bind(&input_not_smi); |
| 8266 // Check if input is a HeapNumber. |
| 8267 __ CheckMap(r0, |
| 8268 r1, |
| 8269 Heap::kHeapNumberMapRootIndex, |
| 8270 &runtime_call, |
| 8271 true); |
| 8272 // Input is a HeapNumber. Load it to a double register and store the |
| 8273 // low and high words into r2, r3. |
| 8274 __ Ldrd(r2, r3, FieldMemOperand(r0, HeapNumber::kValueOffset)); |
| 8275 |
| 8276 __ bind(&loaded); |
| 8277 // r2 = low 32 bits of double value |
| 8278 // r3 = high 32 bits of double value |
| 8279 // Compute hash: |
| 8280 // h = (low ^ high); h ^= h >> 16; h ^= h >> 8; h = h & (cacheSize - 1); |
| 8281 __ eor(r1, r2, Operand(r2)); |
| 8282 __ eor(r1, r1, Operand(r1, LSR, 16)); |
| 8283 __ eor(r1, r1, Operand(r1, LSR, 8)); |
| 8284 ASSERT(IsPowerOf2(TranscendentalCache::kCacheSize)); |
| 8285 if (CpuFeatures::IsSupported(ARMv7)) { |
| 8286 const int kTranscendentalCacheSizeBits = 9; |
| 8287 ASSERT_EQ(1 << kTranscendentalCacheSizeBits, |
| 8288 TranscendentalCache::kCacheSize); |
| 8289 __ ubfx(r1, r1, 0, kTranscendentalCacheSizeBits); |
| 8290 } else { |
| 8291 __ and_(r1, r1, Operand(TranscendentalCache::kCacheSize - 1)); |
| 8292 } |
| 8293 |
| 8294 // r2 = low 32 bits of double value. |
| 8295 // r3 = high 32 bits of double value. |
| 8296 // r1 = TranscendentalCache::hash(double value). |
| 8297 __ mov(r0, |
| 8298 Operand(ExternalReference::transcendental_cache_array_address())); |
| 8299 // r0 points to cache array. |
| 8300 __ ldr(r0, MemOperand(r0, type_ * sizeof(TranscendentalCache::caches_[0]))); |
| 8301 // r0 points to the cache for the type type_. |
| 8302 // If NULL, the cache hasn't been initialized yet, so go through runtime. |
| 8303 __ cmp(r0, Operand(0)); |
| 8304 __ b(eq, &runtime_call); |
| 8305 |
| 8306 #ifdef DEBUG |
| 8307 // Check that the layout of cache elements match expectations. |
| 8308 { TranscendentalCache::Element test_elem[2]; |
| 8309 char* elem_start = reinterpret_cast<char*>(&test_elem[0]); |
| 8310 char* elem2_start = reinterpret_cast<char*>(&test_elem[1]); |
| 8311 char* elem_in0 = reinterpret_cast<char*>(&(test_elem[0].in[0])); |
| 8312 char* elem_in1 = reinterpret_cast<char*>(&(test_elem[0].in[1])); |
| 8313 char* elem_out = reinterpret_cast<char*>(&(test_elem[0].output)); |
| 8314 CHECK_EQ(12, elem2_start - elem_start); // Two uint_32's and a pointer. |
| 8315 CHECK_EQ(0, elem_in0 - elem_start); |
| 8316 CHECK_EQ(kIntSize, elem_in1 - elem_start); |
| 8317 CHECK_EQ(2 * kIntSize, elem_out - elem_start); |
| 8318 } |
| 8319 #endif |
| 8320 |
| 8321 // Find the address of the r1'st entry in the cache, i.e., &r0[r1*12]. |
| 8322 __ add(r1, r1, Operand(r1, LSL, 1)); |
| 8323 __ add(r0, r0, Operand(r1, LSL, 2)); |
| 8324 // Check if cache matches: Double value is stored in uint32_t[2] array. |
| 8325 __ ldm(ia, r0, r4.bit()| r5.bit() | r6.bit()); |
| 8326 __ cmp(r2, r4); |
| 8327 __ b(ne, &runtime_call); |
| 8328 __ cmp(r3, r5); |
| 8329 __ b(ne, &runtime_call); |
| 8330 // Cache hit. Load result, pop argument and return. |
| 8331 __ mov(r0, Operand(r6)); |
| 8332 __ pop(); |
| 8333 __ Ret(); |
| 8334 } |
| 8335 |
| 8336 __ bind(&runtime_call); |
| 8337 __ TailCallExternalReference(ExternalReference(RuntimeFunction()), 1, 1); |
| 8338 } |
| 8339 |
| 8340 |
| 8341 Runtime::FunctionId TranscendentalCacheStub::RuntimeFunction() { |
| 8342 switch (type_) { |
| 8343 // Add more cases when necessary. |
| 8344 case TranscendentalCache::SIN: return Runtime::kMath_sin; |
| 8345 case TranscendentalCache::COS: return Runtime::kMath_cos; |
| 8346 default: |
| 8347 UNIMPLEMENTED(); |
| 8348 return Runtime::kAbort; |
| 8349 } |
| 8350 } |
| 8351 |
| 8352 |
8239 void StackCheckStub::Generate(MacroAssembler* masm) { | 8353 void StackCheckStub::Generate(MacroAssembler* masm) { |
8240 // Do tail-call to runtime routine. Runtime routines expect at least one | 8354 // Do tail-call to runtime routine. Runtime routines expect at least one |
8241 // argument, so give it a Smi. | 8355 // argument, so give it a Smi. |
8242 __ mov(r0, Operand(Smi::FromInt(0))); | 8356 __ mov(r0, Operand(Smi::FromInt(0))); |
8243 __ push(r0); | 8357 __ push(r0); |
8244 __ TailCallRuntime(Runtime::kStackGuard, 1, 1); | 8358 __ TailCallRuntime(Runtime::kStackGuard, 1, 1); |
8245 | 8359 |
8246 __ StubReturn(1); | 8360 __ StubReturn(1); |
8247 } | 8361 } |
8248 | 8362 |
(...skipping 1294 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
9543 } | 9657 } |
9544 | 9658 |
9545 | 9659 |
9546 void StringCharCodeAtGenerator::GenerateSlow( | 9660 void StringCharCodeAtGenerator::GenerateSlow( |
9547 MacroAssembler* masm, const RuntimeCallHelper& call_helper) { | 9661 MacroAssembler* masm, const RuntimeCallHelper& call_helper) { |
9548 __ Abort("Unexpected fallthrough to CharCodeAt slow case"); | 9662 __ Abort("Unexpected fallthrough to CharCodeAt slow case"); |
9549 | 9663 |
9550 // Index is not a smi. | 9664 // Index is not a smi. |
9551 __ bind(&index_not_smi_); | 9665 __ bind(&index_not_smi_); |
9552 // If index is a heap number, try converting it to an integer. | 9666 // If index is a heap number, try converting it to an integer. |
9553 __ CheckMap(index_, scratch_, | 9667 __ CheckMap(index_, |
9554 Factory::heap_number_map(), index_not_number_, true); | 9668 scratch_, |
| 9669 Heap::kHeapNumberMapRootIndex, |
| 9670 index_not_number_, |
| 9671 true); |
9555 call_helper.BeforeCall(masm); | 9672 call_helper.BeforeCall(masm); |
9556 __ Push(object_, index_); | 9673 __ Push(object_, index_); |
9557 __ push(index_); // Consumed by runtime conversion function. | 9674 __ push(index_); // Consumed by runtime conversion function. |
9558 if (index_flags_ == STRING_INDEX_IS_NUMBER) { | 9675 if (index_flags_ == STRING_INDEX_IS_NUMBER) { |
9559 __ CallRuntime(Runtime::kNumberToIntegerMapMinusZero, 1); | 9676 __ CallRuntime(Runtime::kNumberToIntegerMapMinusZero, 1); |
9560 } else { | 9677 } else { |
9561 ASSERT(index_flags_ == STRING_INDEX_IS_ARRAY_INDEX); | 9678 ASSERT(index_flags_ == STRING_INDEX_IS_ARRAY_INDEX); |
9562 // NumberToSmi discards numbers that are not exact integers. | 9679 // NumberToSmi discards numbers that are not exact integers. |
9563 __ CallRuntime(Runtime::kNumberToSmi, 1); | 9680 __ CallRuntime(Runtime::kNumberToSmi, 1); |
9564 } | 9681 } |
(...skipping 973 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10538 __ bind(&string_add_runtime); | 10655 __ bind(&string_add_runtime); |
10539 __ TailCallRuntime(Runtime::kStringAdd, 2, 1); | 10656 __ TailCallRuntime(Runtime::kStringAdd, 2, 1); |
10540 } | 10657 } |
10541 | 10658 |
10542 | 10659 |
10543 #undef __ | 10660 #undef __ |
10544 | 10661 |
10545 } } // namespace v8::internal | 10662 } } // namespace v8::internal |
10546 | 10663 |
10547 #endif // V8_TARGET_ARCH_ARM | 10664 #endif // V8_TARGET_ARCH_ARM |
OLD | NEW |