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 16 matching lines...) Expand all Loading... |
27 | 27 |
28 #include "v8.h" | 28 #include "v8.h" |
29 | 29 |
30 #if defined(V8_TARGET_ARCH_IA32) | 30 #if defined(V8_TARGET_ARCH_IA32) |
31 | 31 |
32 #include "bootstrapper.h" | 32 #include "bootstrapper.h" |
33 #include "code-stubs.h" | 33 #include "code-stubs.h" |
34 #include "isolate.h" | 34 #include "isolate.h" |
35 #include "jsregexp.h" | 35 #include "jsregexp.h" |
36 #include "regexp-macro-assembler.h" | 36 #include "regexp-macro-assembler.h" |
| 37 #include "stub-cache.h" |
37 | 38 |
38 namespace v8 { | 39 namespace v8 { |
39 namespace internal { | 40 namespace internal { |
40 | 41 |
41 #define __ ACCESS_MASM(masm) | 42 #define __ ACCESS_MASM(masm) |
42 | 43 |
43 void ToNumberStub::Generate(MacroAssembler* masm) { | 44 void ToNumberStub::Generate(MacroAssembler* masm) { |
44 // The ToNumber stub takes one argument in eax. | 45 // The ToNumber stub takes one argument in eax. |
45 Label check_heap_number, call_builtin; | 46 Label check_heap_number, call_builtin; |
46 __ JumpIfNotSmi(eax, &check_heap_number, Label::kNear); | 47 __ JumpIfNotSmi(eax, &check_heap_number, Label::kNear); |
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
231 | 232 |
232 | 233 |
233 void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) { | 234 void FastCloneShallowArrayStub::Generate(MacroAssembler* masm) { |
234 // Stack layout on entry: | 235 // Stack layout on entry: |
235 // | 236 // |
236 // [esp + kPointerSize]: constant elements. | 237 // [esp + kPointerSize]: constant elements. |
237 // [esp + (2 * kPointerSize)]: literal index. | 238 // [esp + (2 * kPointerSize)]: literal index. |
238 // [esp + (3 * kPointerSize)]: literals array. | 239 // [esp + (3 * kPointerSize)]: literals array. |
239 | 240 |
240 // All sizes here are multiples of kPointerSize. | 241 // All sizes here are multiples of kPointerSize. |
241 int elements_size = (length_ > 0) ? FixedArray::SizeFor(length_) : 0; | 242 int elements_size = 0; |
| 243 if (length_ > 0) { |
| 244 elements_size = mode_ == CLONE_DOUBLE_ELEMENTS |
| 245 ? FixedDoubleArray::SizeFor(length_) |
| 246 : FixedArray::SizeFor(length_); |
| 247 } |
242 int size = JSArray::kSize + elements_size; | 248 int size = JSArray::kSize + elements_size; |
243 | 249 |
244 // Load boilerplate object into ecx and check if we need to create a | 250 // Load boilerplate object into ecx and check if we need to create a |
245 // boilerplate. | 251 // boilerplate. |
246 Label slow_case; | 252 Label slow_case; |
247 __ mov(ecx, Operand(esp, 3 * kPointerSize)); | 253 __ mov(ecx, Operand(esp, 3 * kPointerSize)); |
248 __ mov(eax, Operand(esp, 2 * kPointerSize)); | 254 __ mov(eax, Operand(esp, 2 * kPointerSize)); |
249 STATIC_ASSERT(kPointerSize == 4); | 255 STATIC_ASSERT(kPointerSize == 4); |
250 STATIC_ASSERT(kSmiTagSize == 1); | 256 STATIC_ASSERT(kSmiTagSize == 1); |
251 STATIC_ASSERT(kSmiTag == 0); | 257 STATIC_ASSERT(kSmiTag == 0); |
252 __ mov(ecx, FieldOperand(ecx, eax, times_half_pointer_size, | 258 __ mov(ecx, FieldOperand(ecx, eax, times_half_pointer_size, |
253 FixedArray::kHeaderSize)); | 259 FixedArray::kHeaderSize)); |
254 Factory* factory = masm->isolate()->factory(); | 260 Factory* factory = masm->isolate()->factory(); |
255 __ cmp(ecx, factory->undefined_value()); | 261 __ cmp(ecx, factory->undefined_value()); |
256 __ j(equal, &slow_case); | 262 __ j(equal, &slow_case); |
257 | 263 |
258 if (FLAG_debug_code) { | 264 if (FLAG_debug_code) { |
259 const char* message; | 265 const char* message; |
260 Handle<Map> expected_map; | 266 Handle<Map> expected_map; |
261 if (mode_ == CLONE_ELEMENTS) { | 267 if (mode_ == CLONE_ELEMENTS) { |
262 message = "Expected (writable) fixed array"; | 268 message = "Expected (writable) fixed array"; |
263 expected_map = factory->fixed_array_map(); | 269 expected_map = factory->fixed_array_map(); |
| 270 } else if (mode_ == CLONE_DOUBLE_ELEMENTS) { |
| 271 message = "Expected (writable) fixed double array"; |
| 272 expected_map = factory->fixed_double_array_map(); |
264 } else { | 273 } else { |
265 ASSERT(mode_ == COPY_ON_WRITE_ELEMENTS); | 274 ASSERT(mode_ == COPY_ON_WRITE_ELEMENTS); |
266 message = "Expected copy-on-write fixed array"; | 275 message = "Expected copy-on-write fixed array"; |
267 expected_map = factory->fixed_cow_array_map(); | 276 expected_map = factory->fixed_cow_array_map(); |
268 } | 277 } |
269 __ push(ecx); | 278 __ push(ecx); |
270 __ mov(ecx, FieldOperand(ecx, JSArray::kElementsOffset)); | 279 __ mov(ecx, FieldOperand(ecx, JSArray::kElementsOffset)); |
271 __ cmp(FieldOperand(ecx, HeapObject::kMapOffset), expected_map); | 280 __ cmp(FieldOperand(ecx, HeapObject::kMapOffset), expected_map); |
272 __ Assert(equal, message); | 281 __ Assert(equal, message); |
273 __ pop(ecx); | 282 __ pop(ecx); |
(...skipping 12 matching lines...) Expand all Loading... |
286 } | 295 } |
287 | 296 |
288 if (length_ > 0) { | 297 if (length_ > 0) { |
289 // Get hold of the elements array of the boilerplate and setup the | 298 // Get hold of the elements array of the boilerplate and setup the |
290 // elements pointer in the resulting object. | 299 // elements pointer in the resulting object. |
291 __ mov(ecx, FieldOperand(ecx, JSArray::kElementsOffset)); | 300 __ mov(ecx, FieldOperand(ecx, JSArray::kElementsOffset)); |
292 __ lea(edx, Operand(eax, JSArray::kSize)); | 301 __ lea(edx, Operand(eax, JSArray::kSize)); |
293 __ mov(FieldOperand(eax, JSArray::kElementsOffset), edx); | 302 __ mov(FieldOperand(eax, JSArray::kElementsOffset), edx); |
294 | 303 |
295 // Copy the elements array. | 304 // Copy the elements array. |
296 for (int i = 0; i < elements_size; i += kPointerSize) { | 305 if (mode_ == CLONE_ELEMENTS) { |
297 __ mov(ebx, FieldOperand(ecx, i)); | 306 for (int i = 0; i < elements_size; i += kPointerSize) { |
298 __ mov(FieldOperand(edx, i), ebx); | 307 __ mov(ebx, FieldOperand(ecx, i)); |
| 308 __ mov(FieldOperand(edx, i), ebx); |
| 309 } |
| 310 } else { |
| 311 ASSERT(mode_ == CLONE_DOUBLE_ELEMENTS); |
| 312 int i; |
| 313 for (i = 0; i < FixedDoubleArray::kHeaderSize; i += kPointerSize) { |
| 314 __ mov(ebx, FieldOperand(ecx, i)); |
| 315 __ mov(FieldOperand(edx, i), ebx); |
| 316 } |
| 317 while (i < elements_size) { |
| 318 __ fld_d(FieldOperand(ecx, i)); |
| 319 __ fstp_d(FieldOperand(edx, i)); |
| 320 i += kDoubleSize; |
| 321 } |
| 322 ASSERT(i == elements_size); |
299 } | 323 } |
300 } | 324 } |
301 | 325 |
302 // Return and remove the on-stack parameters. | 326 // Return and remove the on-stack parameters. |
303 __ ret(3 * kPointerSize); | 327 __ ret(3 * kPointerSize); |
304 | 328 |
305 __ bind(&slow_case); | 329 __ bind(&slow_case); |
306 __ TailCallRuntime(Runtime::kCreateArrayLiteralShallow, 3, 1); | 330 __ TailCallRuntime(Runtime::kCreateArrayLiteralShallow, 3, 1); |
307 } | 331 } |
308 | 332 |
(...skipping 3542 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3851 Register scratch1, | 3875 Register scratch1, |
3852 Register scratch2, | 3876 Register scratch2, |
3853 bool object_is_smi, | 3877 bool object_is_smi, |
3854 Label* not_found) { | 3878 Label* not_found) { |
3855 // Use of registers. Register result is used as a temporary. | 3879 // Use of registers. Register result is used as a temporary. |
3856 Register number_string_cache = result; | 3880 Register number_string_cache = result; |
3857 Register mask = scratch1; | 3881 Register mask = scratch1; |
3858 Register scratch = scratch2; | 3882 Register scratch = scratch2; |
3859 | 3883 |
3860 // Load the number string cache. | 3884 // Load the number string cache. |
3861 ExternalReference roots_address = | 3885 ExternalReference roots_array_start = |
3862 ExternalReference::roots_address(masm->isolate()); | 3886 ExternalReference::roots_array_start(masm->isolate()); |
3863 __ mov(scratch, Immediate(Heap::kNumberStringCacheRootIndex)); | 3887 __ mov(scratch, Immediate(Heap::kNumberStringCacheRootIndex)); |
3864 __ mov(number_string_cache, | 3888 __ mov(number_string_cache, |
3865 Operand::StaticArray(scratch, times_pointer_size, roots_address)); | 3889 Operand::StaticArray(scratch, times_pointer_size, roots_array_start)); |
3866 // Make the hash mask from the length of the number string cache. It | 3890 // Make the hash mask from the length of the number string cache. It |
3867 // contains two elements (number and string) for each cache entry. | 3891 // contains two elements (number and string) for each cache entry. |
3868 __ mov(mask, FieldOperand(number_string_cache, FixedArray::kLengthOffset)); | 3892 __ mov(mask, FieldOperand(number_string_cache, FixedArray::kLengthOffset)); |
3869 __ shr(mask, kSmiTagSize + 1); // Untag length and divide it by two. | 3893 __ shr(mask, kSmiTagSize + 1); // Untag length and divide it by two. |
3870 __ sub(mask, Immediate(1)); // Make mask. | 3894 __ sub(mask, Immediate(1)); // Make mask. |
3871 | 3895 |
3872 // Calculate the entry in the number string cache. The hash value in the | 3896 // Calculate the entry in the number string cache. The hash value in the |
3873 // number string cache for smis is just the smi value, and the hash for | 3897 // number string cache for smis is just the smi value, and the hash for |
3874 // doubles is the xor of the upper and lower words. See | 3898 // doubles is the xor of the upper and lower words. See |
3875 // Heap::GetNumberStringCache. | 3899 // Heap::GetNumberStringCache. |
(...skipping 947 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4823 Register scratch = ecx; | 4847 Register scratch = ecx; |
4824 | 4848 |
4825 // Constants describing the call site code to patch. | 4849 // Constants describing the call site code to patch. |
4826 static const int kDeltaToCmpImmediate = 2; | 4850 static const int kDeltaToCmpImmediate = 2; |
4827 static const int kDeltaToMov = 8; | 4851 static const int kDeltaToMov = 8; |
4828 static const int kDeltaToMovImmediate = 9; | 4852 static const int kDeltaToMovImmediate = 9; |
4829 static const int8_t kCmpEdiImmediateByte1 = BitCast<int8_t, uint8_t>(0x81); | 4853 static const int8_t kCmpEdiImmediateByte1 = BitCast<int8_t, uint8_t>(0x81); |
4830 static const int8_t kCmpEdiImmediateByte2 = BitCast<int8_t, uint8_t>(0xff); | 4854 static const int8_t kCmpEdiImmediateByte2 = BitCast<int8_t, uint8_t>(0xff); |
4831 static const int8_t kMovEaxImmediateByte = BitCast<int8_t, uint8_t>(0xb8); | 4855 static const int8_t kMovEaxImmediateByte = BitCast<int8_t, uint8_t>(0xb8); |
4832 | 4856 |
4833 ExternalReference roots_address = | 4857 ExternalReference roots_array_start = |
4834 ExternalReference::roots_address(masm->isolate()); | 4858 ExternalReference::roots_array_start(masm->isolate()); |
4835 | 4859 |
4836 ASSERT_EQ(object.code(), InstanceofStub::left().code()); | 4860 ASSERT_EQ(object.code(), InstanceofStub::left().code()); |
4837 ASSERT_EQ(function.code(), InstanceofStub::right().code()); | 4861 ASSERT_EQ(function.code(), InstanceofStub::right().code()); |
4838 | 4862 |
4839 // Get the object and function - they are always both needed. | 4863 // Get the object and function - they are always both needed. |
4840 Label slow, not_js_object; | 4864 Label slow, not_js_object; |
4841 if (!HasArgsInRegisters()) { | 4865 if (!HasArgsInRegisters()) { |
4842 __ mov(object, Operand(esp, 2 * kPointerSize)); | 4866 __ mov(object, Operand(esp, 2 * kPointerSize)); |
4843 __ mov(function, Operand(esp, 1 * kPointerSize)); | 4867 __ mov(function, Operand(esp, 1 * kPointerSize)); |
4844 } | 4868 } |
4845 | 4869 |
4846 // Check that the left hand is a JS object. | 4870 // Check that the left hand is a JS object. |
4847 __ JumpIfSmi(object, ¬_js_object); | 4871 __ JumpIfSmi(object, ¬_js_object); |
4848 __ IsObjectJSObjectType(object, map, scratch, ¬_js_object); | 4872 __ IsObjectJSObjectType(object, map, scratch, ¬_js_object); |
4849 | 4873 |
4850 // If there is a call site cache don't look in the global cache, but do the | 4874 // If there is a call site cache don't look in the global cache, but do the |
4851 // real lookup and update the call site cache. | 4875 // real lookup and update the call site cache. |
4852 if (!HasCallSiteInlineCheck()) { | 4876 if (!HasCallSiteInlineCheck()) { |
4853 // Look up the function and the map in the instanceof cache. | 4877 // Look up the function and the map in the instanceof cache. |
4854 Label miss; | 4878 Label miss; |
4855 __ mov(scratch, Immediate(Heap::kInstanceofCacheFunctionRootIndex)); | 4879 __ mov(scratch, Immediate(Heap::kInstanceofCacheFunctionRootIndex)); |
4856 __ cmp(function, | 4880 __ cmp(function, Operand::StaticArray(scratch, |
4857 Operand::StaticArray(scratch, times_pointer_size, roots_address)); | 4881 times_pointer_size, |
| 4882 roots_array_start)); |
4858 __ j(not_equal, &miss, Label::kNear); | 4883 __ j(not_equal, &miss, Label::kNear); |
4859 __ mov(scratch, Immediate(Heap::kInstanceofCacheMapRootIndex)); | 4884 __ mov(scratch, Immediate(Heap::kInstanceofCacheMapRootIndex)); |
4860 __ cmp(map, Operand::StaticArray( | 4885 __ cmp(map, Operand::StaticArray( |
4861 scratch, times_pointer_size, roots_address)); | 4886 scratch, times_pointer_size, roots_array_start)); |
4862 __ j(not_equal, &miss, Label::kNear); | 4887 __ j(not_equal, &miss, Label::kNear); |
4863 __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex)); | 4888 __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex)); |
4864 __ mov(eax, Operand::StaticArray( | 4889 __ mov(eax, Operand::StaticArray( |
4865 scratch, times_pointer_size, roots_address)); | 4890 scratch, times_pointer_size, roots_array_start)); |
4866 __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); | 4891 __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); |
4867 __ bind(&miss); | 4892 __ bind(&miss); |
4868 } | 4893 } |
4869 | 4894 |
4870 // Get the prototype of the function. | 4895 // Get the prototype of the function. |
4871 __ TryGetFunctionPrototype(function, prototype, scratch, &slow); | 4896 __ TryGetFunctionPrototype(function, prototype, scratch, &slow, true); |
4872 | 4897 |
4873 // Check that the function prototype is a JS object. | 4898 // Check that the function prototype is a JS object. |
4874 __ JumpIfSmi(prototype, &slow); | 4899 __ JumpIfSmi(prototype, &slow); |
4875 __ IsObjectJSObjectType(prototype, scratch, scratch, &slow); | 4900 __ IsObjectJSObjectType(prototype, scratch, scratch, &slow); |
4876 | 4901 |
4877 // Update the global instanceof or call site inlined cache with the current | 4902 // Update the global instanceof or call site inlined cache with the current |
4878 // map and function. The cached answer will be set when it is known below. | 4903 // map and function. The cached answer will be set when it is known below. |
4879 if (!HasCallSiteInlineCheck()) { | 4904 if (!HasCallSiteInlineCheck()) { |
4880 __ mov(scratch, Immediate(Heap::kInstanceofCacheMapRootIndex)); | 4905 __ mov(scratch, Immediate(Heap::kInstanceofCacheMapRootIndex)); |
4881 __ mov(Operand::StaticArray(scratch, times_pointer_size, roots_address), map); | 4906 __ mov(Operand::StaticArray(scratch, times_pointer_size, roots_array_start), |
| 4907 map); |
4882 __ mov(scratch, Immediate(Heap::kInstanceofCacheFunctionRootIndex)); | 4908 __ mov(scratch, Immediate(Heap::kInstanceofCacheFunctionRootIndex)); |
4883 __ mov(Operand::StaticArray(scratch, times_pointer_size, roots_address), | 4909 __ mov(Operand::StaticArray(scratch, times_pointer_size, roots_array_start), |
4884 function); | 4910 function); |
4885 } else { | 4911 } else { |
4886 // The constants for the code patching are based on no push instructions | 4912 // The constants for the code patching are based on no push instructions |
4887 // at the call site. | 4913 // at the call site. |
4888 ASSERT(HasArgsInRegisters()); | 4914 ASSERT(HasArgsInRegisters()); |
4889 // Get return address and delta to inlined map check. | 4915 // Get return address and delta to inlined map check. |
4890 __ mov(scratch, Operand(esp, 0 * kPointerSize)); | 4916 __ mov(scratch, Operand(esp, 0 * kPointerSize)); |
4891 __ sub(scratch, Operand(esp, 1 * kPointerSize)); | 4917 __ sub(scratch, Operand(esp, 1 * kPointerSize)); |
4892 if (FLAG_debug_code) { | 4918 if (FLAG_debug_code) { |
4893 __ cmpb(Operand(scratch, 0), kCmpEdiImmediateByte1); | 4919 __ cmpb(Operand(scratch, 0), kCmpEdiImmediateByte1); |
(...skipping 16 matching lines...) Expand all Loading... |
4910 __ j(equal, &is_not_instance, Label::kNear); | 4936 __ j(equal, &is_not_instance, Label::kNear); |
4911 __ mov(scratch, FieldOperand(scratch, HeapObject::kMapOffset)); | 4937 __ mov(scratch, FieldOperand(scratch, HeapObject::kMapOffset)); |
4912 __ mov(scratch, FieldOperand(scratch, Map::kPrototypeOffset)); | 4938 __ mov(scratch, FieldOperand(scratch, Map::kPrototypeOffset)); |
4913 __ jmp(&loop); | 4939 __ jmp(&loop); |
4914 | 4940 |
4915 __ bind(&is_instance); | 4941 __ bind(&is_instance); |
4916 if (!HasCallSiteInlineCheck()) { | 4942 if (!HasCallSiteInlineCheck()) { |
4917 __ Set(eax, Immediate(0)); | 4943 __ Set(eax, Immediate(0)); |
4918 __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex)); | 4944 __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex)); |
4919 __ mov(Operand::StaticArray(scratch, | 4945 __ mov(Operand::StaticArray(scratch, |
4920 times_pointer_size, roots_address), eax); | 4946 times_pointer_size, roots_array_start), eax); |
4921 } else { | 4947 } else { |
4922 // Get return address and delta to inlined map check. | 4948 // Get return address and delta to inlined map check. |
4923 __ mov(eax, factory->true_value()); | 4949 __ mov(eax, factory->true_value()); |
4924 __ mov(scratch, Operand(esp, 0 * kPointerSize)); | 4950 __ mov(scratch, Operand(esp, 0 * kPointerSize)); |
4925 __ sub(scratch, Operand(esp, 1 * kPointerSize)); | 4951 __ sub(scratch, Operand(esp, 1 * kPointerSize)); |
4926 if (FLAG_debug_code) { | 4952 if (FLAG_debug_code) { |
4927 __ cmpb(Operand(scratch, kDeltaToMov), kMovEaxImmediateByte); | 4953 __ cmpb(Operand(scratch, kDeltaToMov), kMovEaxImmediateByte); |
4928 __ Assert(equal, "InstanceofStub unexpected call site cache (mov)"); | 4954 __ Assert(equal, "InstanceofStub unexpected call site cache (mov)"); |
4929 } | 4955 } |
4930 __ mov(Operand(scratch, kDeltaToMovImmediate), eax); | 4956 __ mov(Operand(scratch, kDeltaToMovImmediate), eax); |
4931 if (!ReturnTrueFalseObject()) { | 4957 if (!ReturnTrueFalseObject()) { |
4932 __ Set(eax, Immediate(0)); | 4958 __ Set(eax, Immediate(0)); |
4933 } | 4959 } |
4934 } | 4960 } |
4935 __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); | 4961 __ ret((HasArgsInRegisters() ? 0 : 2) * kPointerSize); |
4936 | 4962 |
4937 __ bind(&is_not_instance); | 4963 __ bind(&is_not_instance); |
4938 if (!HasCallSiteInlineCheck()) { | 4964 if (!HasCallSiteInlineCheck()) { |
4939 __ Set(eax, Immediate(Smi::FromInt(1))); | 4965 __ Set(eax, Immediate(Smi::FromInt(1))); |
4940 __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex)); | 4966 __ mov(scratch, Immediate(Heap::kInstanceofCacheAnswerRootIndex)); |
4941 __ mov(Operand::StaticArray( | 4967 __ mov(Operand::StaticArray( |
4942 scratch, times_pointer_size, roots_address), eax); | 4968 scratch, times_pointer_size, roots_array_start), eax); |
4943 } else { | 4969 } else { |
4944 // Get return address and delta to inlined map check. | 4970 // Get return address and delta to inlined map check. |
4945 __ mov(eax, factory->false_value()); | 4971 __ mov(eax, factory->false_value()); |
4946 __ mov(scratch, Operand(esp, 0 * kPointerSize)); | 4972 __ mov(scratch, Operand(esp, 0 * kPointerSize)); |
4947 __ sub(scratch, Operand(esp, 1 * kPointerSize)); | 4973 __ sub(scratch, Operand(esp, 1 * kPointerSize)); |
4948 if (FLAG_debug_code) { | 4974 if (FLAG_debug_code) { |
4949 __ cmpb(Operand(scratch, kDeltaToMov), kMovEaxImmediateByte); | 4975 __ cmpb(Operand(scratch, kDeltaToMov), kMovEaxImmediateByte); |
4950 __ Assert(equal, "InstanceofStub unexpected call site cache (mov)"); | 4976 __ Assert(equal, "InstanceofStub unexpected call site cache (mov)"); |
4951 } | 4977 } |
4952 __ mov(Operand(scratch, kDeltaToMovImmediate), eax); | 4978 __ mov(Operand(scratch, kDeltaToMovImmediate), eax); |
(...skipping 768 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5721 // Collect the two characters in a register. | 5747 // Collect the two characters in a register. |
5722 Register chars = c1; | 5748 Register chars = c1; |
5723 __ shl(c2, kBitsPerByte); | 5749 __ shl(c2, kBitsPerByte); |
5724 __ or_(chars, c2); | 5750 __ or_(chars, c2); |
5725 | 5751 |
5726 // chars: two character string, char 1 in byte 0 and char 2 in byte 1. | 5752 // chars: two character string, char 1 in byte 0 and char 2 in byte 1. |
5727 // hash: hash of two character string. | 5753 // hash: hash of two character string. |
5728 | 5754 |
5729 // Load the symbol table. | 5755 // Load the symbol table. |
5730 Register symbol_table = c2; | 5756 Register symbol_table = c2; |
5731 ExternalReference roots_address = | 5757 ExternalReference roots_array_start = |
5732 ExternalReference::roots_address(masm->isolate()); | 5758 ExternalReference::roots_array_start(masm->isolate()); |
5733 __ mov(scratch, Immediate(Heap::kSymbolTableRootIndex)); | 5759 __ mov(scratch, Immediate(Heap::kSymbolTableRootIndex)); |
5734 __ mov(symbol_table, | 5760 __ mov(symbol_table, |
5735 Operand::StaticArray(scratch, times_pointer_size, roots_address)); | 5761 Operand::StaticArray(scratch, times_pointer_size, roots_array_start)); |
5736 | 5762 |
5737 // Calculate capacity mask from the symbol table capacity. | 5763 // Calculate capacity mask from the symbol table capacity. |
5738 Register mask = scratch2; | 5764 Register mask = scratch2; |
5739 __ mov(mask, FieldOperand(symbol_table, SymbolTable::kCapacityOffset)); | 5765 __ mov(mask, FieldOperand(symbol_table, SymbolTable::kCapacityOffset)); |
5740 __ SmiUntag(mask); | 5766 __ SmiUntag(mask); |
5741 __ sub(mask, Immediate(1)); | 5767 __ sub(mask, Immediate(1)); |
5742 | 5768 |
5743 // Registers | 5769 // Registers |
5744 // chars: two character string, char 1 in byte 0 and char 2 in byte 1. | 5770 // chars: two character string, char 1 in byte 0 and char 2 in byte 1. |
5745 // hash: hash of two character string | 5771 // hash: hash of two character string |
(...skipping 762 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6508 // Do a tail call to the rewritten stub. | 6534 // Do a tail call to the rewritten stub. |
6509 __ jmp(edi); | 6535 __ jmp(edi); |
6510 } | 6536 } |
6511 | 6537 |
6512 | 6538 |
6513 // Helper function used to check that the dictionary doesn't contain | 6539 // Helper function used to check that the dictionary doesn't contain |
6514 // the property. This function may return false negatives, so miss_label | 6540 // the property. This function may return false negatives, so miss_label |
6515 // must always call a backup property check that is complete. | 6541 // must always call a backup property check that is complete. |
6516 // This function is safe to call if the receiver has fast properties. | 6542 // This function is safe to call if the receiver has fast properties. |
6517 // Name must be a symbol and receiver must be a heap object. | 6543 // Name must be a symbol and receiver must be a heap object. |
6518 MaybeObject* StringDictionaryLookupStub::GenerateNegativeLookup( | 6544 void StringDictionaryLookupStub::GenerateNegativeLookup(MacroAssembler* masm, |
| 6545 Label* miss, |
| 6546 Label* done, |
| 6547 Register properties, |
| 6548 Handle<String> name, |
| 6549 Register r0) { |
| 6550 ASSERT(name->IsSymbol()); |
| 6551 |
| 6552 // If names of slots in range from 1 to kProbes - 1 for the hash value are |
| 6553 // not equal to the name and kProbes-th slot is not used (its name is the |
| 6554 // undefined value), it guarantees the hash table doesn't contain the |
| 6555 // property. It's true even if some slots represent deleted properties |
| 6556 // (their names are the null value). |
| 6557 for (int i = 0; i < kInlinedProbes; i++) { |
| 6558 // Compute the masked index: (hash + i + i * i) & mask. |
| 6559 Register index = r0; |
| 6560 // Capacity is smi 2^n. |
| 6561 __ mov(index, FieldOperand(properties, kCapacityOffset)); |
| 6562 __ dec(index); |
| 6563 __ and_(index, |
| 6564 Immediate(Smi::FromInt(name->Hash() + |
| 6565 StringDictionary::GetProbeOffset(i)))); |
| 6566 |
| 6567 // Scale the index by multiplying by the entry size. |
| 6568 ASSERT(StringDictionary::kEntrySize == 3); |
| 6569 __ lea(index, Operand(index, index, times_2, 0)); // index *= 3. |
| 6570 Register entity_name = r0; |
| 6571 // Having undefined at this place means the name is not contained. |
| 6572 ASSERT_EQ(kSmiTagSize, 1); |
| 6573 __ mov(entity_name, Operand(properties, index, times_half_pointer_size, |
| 6574 kElementsStartOffset - kHeapObjectTag)); |
| 6575 __ cmp(entity_name, masm->isolate()->factory()->undefined_value()); |
| 6576 __ j(equal, done); |
| 6577 |
| 6578 // Stop if found the property. |
| 6579 __ cmp(entity_name, Handle<String>(name)); |
| 6580 __ j(equal, miss); |
| 6581 |
| 6582 // Check if the entry name is not a symbol. |
| 6583 __ mov(entity_name, FieldOperand(entity_name, HeapObject::kMapOffset)); |
| 6584 __ test_b(FieldOperand(entity_name, Map::kInstanceTypeOffset), |
| 6585 kIsSymbolMask); |
| 6586 __ j(zero, miss); |
| 6587 } |
| 6588 |
| 6589 StringDictionaryLookupStub stub(properties, |
| 6590 r0, |
| 6591 r0, |
| 6592 StringDictionaryLookupStub::NEGATIVE_LOOKUP); |
| 6593 __ push(Immediate(Handle<Object>(name))); |
| 6594 __ push(Immediate(name->Hash())); |
| 6595 __ CallStub(&stub); |
| 6596 __ test(r0, r0); |
| 6597 __ j(not_zero, miss); |
| 6598 __ jmp(done); |
| 6599 } |
| 6600 |
| 6601 |
| 6602 // TODO(kmillikin): Eliminate this function when the stub cache is fully |
| 6603 // handlified. |
| 6604 MaybeObject* StringDictionaryLookupStub::TryGenerateNegativeLookup( |
6519 MacroAssembler* masm, | 6605 MacroAssembler* masm, |
6520 Label* miss, | 6606 Label* miss, |
6521 Label* done, | 6607 Label* done, |
6522 Register properties, | 6608 Register properties, |
6523 String* name, | 6609 String* name, |
6524 Register r0) { | 6610 Register r0) { |
6525 ASSERT(name->IsSymbol()); | 6611 ASSERT(name->IsSymbol()); |
6526 | 6612 |
6527 // If names of slots in range from 1 to kProbes - 1 for the hash value are | 6613 // If names of slots in range from 1 to kProbes - 1 for the hash value are |
6528 // not equal to the name and kProbes-th slot is not used (its name is the | 6614 // not equal to the name and kProbes-th slot is not used (its name is the |
(...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6742 { edx, ecx, ebx, EMIT_REMEMBERED_SET }, | 6828 { edx, ecx, ebx, EMIT_REMEMBERED_SET }, |
6743 // GenerateStoreField calls the stub with two different permutations of | 6829 // GenerateStoreField calls the stub with two different permutations of |
6744 // registers. This is the second. | 6830 // registers. This is the second. |
6745 { ebx, ecx, edx, EMIT_REMEMBERED_SET }, | 6831 { ebx, ecx, edx, EMIT_REMEMBERED_SET }, |
6746 // StoreIC::GenerateNormal via GenerateDictionaryStore | 6832 // StoreIC::GenerateNormal via GenerateDictionaryStore |
6747 { ebx, edi, edx, EMIT_REMEMBERED_SET }, | 6833 { ebx, edi, edx, EMIT_REMEMBERED_SET }, |
6748 // KeyedStoreIC::GenerateGeneric. | 6834 // KeyedStoreIC::GenerateGeneric. |
6749 { ebx, edx, ecx, EMIT_REMEMBERED_SET}, | 6835 { ebx, edx, ecx, EMIT_REMEMBERED_SET}, |
6750 // KeyedStoreStubCompiler::GenerateStoreFastElement. | 6836 // KeyedStoreStubCompiler::GenerateStoreFastElement. |
6751 { edi, edx, ecx, EMIT_REMEMBERED_SET}, | 6837 { edi, edx, ecx, EMIT_REMEMBERED_SET}, |
| 6838 // ElementsTransitionGenerator::GenerateSmiOnlyToObject |
| 6839 // and ElementsTransitionGenerator::GenerateSmiOnlyToDouble |
| 6840 // and ElementsTransitionGenerator::GenerateDoubleToObject |
| 6841 { edx, ebx, edi, EMIT_REMEMBERED_SET}, |
| 6842 // ElementsTransitionGenerator::GenerateDoubleToObject |
| 6843 { eax, edx, esi, EMIT_REMEMBERED_SET}, |
| 6844 { edx, eax, edi, EMIT_REMEMBERED_SET}, |
6752 // Null termination. | 6845 // Null termination. |
6753 { no_reg, no_reg, no_reg, EMIT_REMEMBERED_SET} | 6846 { no_reg, no_reg, no_reg, EMIT_REMEMBERED_SET} |
6754 }; | 6847 }; |
6755 | 6848 |
6756 | 6849 |
6757 bool RecordWriteStub::IsPregenerated() { | 6850 bool RecordWriteStub::IsPregenerated() { |
6758 for (AheadOfTimeWriteBarrierStubList* entry = kAheadOfTime; | 6851 for (AheadOfTimeWriteBarrierStubList* entry = kAheadOfTime; |
6759 !entry->object.is(no_reg); | 6852 !entry->object.is(no_reg); |
6760 entry++) { | 6853 entry++) { |
6761 if (object_.is(entry->object) && | 6854 if (object_.is(entry->object) && |
(...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6984 } | 7077 } |
6985 | 7078 |
6986 __ bind(&need_incremental_pop_object); | 7079 __ bind(&need_incremental_pop_object); |
6987 __ pop(regs_.object()); | 7080 __ pop(regs_.object()); |
6988 | 7081 |
6989 __ bind(&need_incremental); | 7082 __ bind(&need_incremental); |
6990 | 7083 |
6991 // Fall through when we need to inform the incremental marker. | 7084 // Fall through when we need to inform the incremental marker. |
6992 } | 7085 } |
6993 | 7086 |
6994 | |
6995 #undef __ | 7087 #undef __ |
6996 | 7088 |
6997 } } // namespace v8::internal | 7089 } } // namespace v8::internal |
6998 | 7090 |
6999 #endif // V8_TARGET_ARCH_IA32 | 7091 #endif // V8_TARGET_ARCH_IA32 |
OLD | NEW |