| 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 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 50 ExternalReference value_offset(isolate->stub_cache()->value_reference(table)); | 50 ExternalReference value_offset(isolate->stub_cache()->value_reference(table)); |
| 51 | 51 |
| 52 Label miss; | 52 Label miss; |
| 53 | 53 |
| 54 if (extra.is_valid()) { | 54 if (extra.is_valid()) { |
| 55 // Get the code entry from the cache. | 55 // Get the code entry from the cache. |
| 56 __ mov(extra, Operand::StaticArray(offset, times_2, value_offset)); | 56 __ mov(extra, Operand::StaticArray(offset, times_2, value_offset)); |
| 57 | 57 |
| 58 // Check that the key in the entry matches the name. | 58 // Check that the key in the entry matches the name. |
| 59 __ cmp(name, Operand::StaticArray(offset, times_2, key_offset)); | 59 __ cmp(name, Operand::StaticArray(offset, times_2, key_offset)); |
| 60 __ j(not_equal, &miss, not_taken); | 60 __ j(not_equal, &miss); |
| 61 | 61 |
| 62 // Check that the flags match what we're looking for. | 62 // Check that the flags match what we're looking for. |
| 63 __ mov(offset, FieldOperand(extra, Code::kFlagsOffset)); | 63 __ mov(offset, FieldOperand(extra, Code::kFlagsOffset)); |
| 64 __ and_(offset, ~Code::kFlagsNotUsedInLookup); | 64 __ and_(offset, ~Code::kFlagsNotUsedInLookup); |
| 65 __ cmp(offset, flags); | 65 __ cmp(offset, flags); |
| 66 __ j(not_equal, &miss); | 66 __ j(not_equal, &miss); |
| 67 | 67 |
| 68 // Jump to the first instruction in the code stub. | 68 // Jump to the first instruction in the code stub. |
| 69 __ add(Operand(extra), Immediate(Code::kHeaderSize - kHeapObjectTag)); | 69 __ add(Operand(extra), Immediate(Code::kHeaderSize - kHeapObjectTag)); |
| 70 __ jmp(Operand(extra)); | 70 __ jmp(Operand(extra)); |
| 71 | 71 |
| 72 __ bind(&miss); | 72 __ bind(&miss); |
| 73 } else { | 73 } else { |
| 74 // Save the offset on the stack. | 74 // Save the offset on the stack. |
| 75 __ push(offset); | 75 __ push(offset); |
| 76 | 76 |
| 77 // Check that the key in the entry matches the name. | 77 // Check that the key in the entry matches the name. |
| 78 __ cmp(name, Operand::StaticArray(offset, times_2, key_offset)); | 78 __ cmp(name, Operand::StaticArray(offset, times_2, key_offset)); |
| 79 __ j(not_equal, &miss, not_taken); | 79 __ j(not_equal, &miss); |
| 80 | 80 |
| 81 // Get the code entry from the cache. | 81 // Get the code entry from the cache. |
| 82 __ mov(offset, Operand::StaticArray(offset, times_2, value_offset)); | 82 __ mov(offset, Operand::StaticArray(offset, times_2, value_offset)); |
| 83 | 83 |
| 84 // Check that the flags match what we're looking for. | 84 // Check that the flags match what we're looking for. |
| 85 __ mov(offset, FieldOperand(offset, Code::kFlagsOffset)); | 85 __ mov(offset, FieldOperand(offset, Code::kFlagsOffset)); |
| 86 __ and_(offset, ~Code::kFlagsNotUsedInLookup); | 86 __ and_(offset, ~Code::kFlagsNotUsedInLookup); |
| 87 __ cmp(offset, flags); | 87 __ cmp(offset, flags); |
| 88 __ j(not_equal, &miss); | 88 __ j(not_equal, &miss); |
| 89 | 89 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 100 __ pop(offset); | 100 __ pop(offset); |
| 101 } | 101 } |
| 102 } | 102 } |
| 103 | 103 |
| 104 | 104 |
| 105 // Helper function used to check that the dictionary doesn't contain | 105 // Helper function used to check that the dictionary doesn't contain |
| 106 // the property. This function may return false negatives, so miss_label | 106 // the property. This function may return false negatives, so miss_label |
| 107 // must always call a backup property check that is complete. | 107 // must always call a backup property check that is complete. |
| 108 // This function is safe to call if the receiver has fast properties. | 108 // This function is safe to call if the receiver has fast properties. |
| 109 // Name must be a symbol and receiver must be a heap object. | 109 // Name must be a symbol and receiver must be a heap object. |
| 110 static void GenerateDictionaryNegativeLookup(MacroAssembler* masm, | 110 static MaybeObject* GenerateDictionaryNegativeLookup(MacroAssembler* masm, |
| 111 Label* miss_label, | 111 Label* miss_label, |
| 112 Register receiver, | 112 Register receiver, |
| 113 String* name, | 113 String* name, |
| 114 Register r0, | 114 Register r0, |
| 115 Register r1) { | 115 Register r1) { |
| 116 ASSERT(name->IsSymbol()); | 116 ASSERT(name->IsSymbol()); |
| 117 Counters* counters = masm->isolate()->counters(); | 117 Counters* counters = masm->isolate()->counters(); |
| 118 __ IncrementCounter(counters->negative_lookups(), 1); | 118 __ IncrementCounter(counters->negative_lookups(), 1); |
| 119 __ IncrementCounter(counters->negative_lookups_miss(), 1); | 119 __ IncrementCounter(counters->negative_lookups_miss(), 1); |
| 120 | 120 |
| 121 Label done; | |
| 122 __ mov(r0, FieldOperand(receiver, HeapObject::kMapOffset)); | 121 __ mov(r0, FieldOperand(receiver, HeapObject::kMapOffset)); |
| 123 | 122 |
| 124 const int kInterceptorOrAccessCheckNeededMask = | 123 const int kInterceptorOrAccessCheckNeededMask = |
| 125 (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded); | 124 (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded); |
| 126 | 125 |
| 127 // Bail out if the receiver has a named interceptor or requires access checks. | 126 // Bail out if the receiver has a named interceptor or requires access checks. |
| 128 __ test_b(FieldOperand(r0, Map::kBitFieldOffset), | 127 __ test_b(FieldOperand(r0, Map::kBitFieldOffset), |
| 129 kInterceptorOrAccessCheckNeededMask); | 128 kInterceptorOrAccessCheckNeededMask); |
| 130 __ j(not_zero, miss_label, not_taken); | 129 __ j(not_zero, miss_label); |
| 131 | 130 |
| 132 // Check that receiver is a JSObject. | 131 // Check that receiver is a JSObject. |
| 133 __ CmpInstanceType(r0, FIRST_JS_OBJECT_TYPE); | 132 __ CmpInstanceType(r0, FIRST_JS_OBJECT_TYPE); |
| 134 __ j(below, miss_label, not_taken); | 133 __ j(below, miss_label); |
| 135 | 134 |
| 136 // Load properties array. | 135 // Load properties array. |
| 137 Register properties = r0; | 136 Register properties = r0; |
| 138 __ mov(properties, FieldOperand(receiver, JSObject::kPropertiesOffset)); | 137 __ mov(properties, FieldOperand(receiver, JSObject::kPropertiesOffset)); |
| 139 | 138 |
| 140 // Check that the properties array is a dictionary. | 139 // Check that the properties array is a dictionary. |
| 141 __ cmp(FieldOperand(properties, HeapObject::kMapOffset), | 140 __ cmp(FieldOperand(properties, HeapObject::kMapOffset), |
| 142 Immediate(masm->isolate()->factory()->hash_table_map())); | 141 Immediate(masm->isolate()->factory()->hash_table_map())); |
| 143 __ j(not_equal, miss_label); | 142 __ j(not_equal, miss_label); |
| 144 | 143 |
| 145 // Compute the capacity mask. | 144 Label done; |
| 146 const int kCapacityOffset = | 145 MaybeObject* result = |
| 147 StringDictionary::kHeaderSize + | 146 StringDictionaryLookupStub::GenerateNegativeLookup(masm, |
| 148 StringDictionary::kCapacityIndex * kPointerSize; | 147 miss_label, |
| 149 | 148 &done, |
| 150 // Generate an unrolled loop that performs a few probes before | 149 properties, |
| 151 // giving up. | 150 name, |
| 152 static const int kProbes = 4; | 151 r1); |
| 153 const int kElementsStartOffset = | 152 if (result->IsFailure()) return result; |
| 154 StringDictionary::kHeaderSize + | |
| 155 StringDictionary::kElementsStartIndex * kPointerSize; | |
| 156 | |
| 157 // If names of slots in range from 1 to kProbes - 1 for the hash value are | |
| 158 // not equal to the name and kProbes-th slot is not used (its name is the | |
| 159 // undefined value), it guarantees the hash table doesn't contain the | |
| 160 // property. It's true even if some slots represent deleted properties | |
| 161 // (their names are the null value). | |
| 162 for (int i = 0; i < kProbes; i++) { | |
| 163 // r0 points to properties hash. | |
| 164 // Compute the masked index: (hash + i + i * i) & mask. | |
| 165 Register index = r1; | |
| 166 // Capacity is smi 2^n. | |
| 167 __ mov(index, FieldOperand(properties, kCapacityOffset)); | |
| 168 __ dec(index); | |
| 169 __ and_(Operand(index), | |
| 170 Immediate(Smi::FromInt(name->Hash() + | |
| 171 StringDictionary::GetProbeOffset(i)))); | |
| 172 | |
| 173 // Scale the index by multiplying by the entry size. | |
| 174 ASSERT(StringDictionary::kEntrySize == 3); | |
| 175 __ lea(index, Operand(index, index, times_2, 0)); // index *= 3. | |
| 176 | |
| 177 Register entity_name = r1; | |
| 178 // Having undefined at this place means the name is not contained. | |
| 179 ASSERT_EQ(kSmiTagSize, 1); | |
| 180 __ mov(entity_name, Operand(properties, index, times_half_pointer_size, | |
| 181 kElementsStartOffset - kHeapObjectTag)); | |
| 182 __ cmp(entity_name, masm->isolate()->factory()->undefined_value()); | |
| 183 if (i != kProbes - 1) { | |
| 184 __ j(equal, &done, taken); | |
| 185 | |
| 186 // Stop if found the property. | |
| 187 __ cmp(entity_name, Handle<String>(name)); | |
| 188 __ j(equal, miss_label, not_taken); | |
| 189 | |
| 190 // Check if the entry name is not a symbol. | |
| 191 __ mov(entity_name, FieldOperand(entity_name, HeapObject::kMapOffset)); | |
| 192 __ test_b(FieldOperand(entity_name, Map::kInstanceTypeOffset), | |
| 193 kIsSymbolMask); | |
| 194 __ j(zero, miss_label, not_taken); | |
| 195 } else { | |
| 196 // Give up probing if still not found the undefined value. | |
| 197 __ j(not_equal, miss_label, not_taken); | |
| 198 } | |
| 199 } | |
| 200 | 153 |
| 201 __ bind(&done); | 154 __ bind(&done); |
| 202 __ DecrementCounter(counters->negative_lookups_miss(), 1); | 155 __ DecrementCounter(counters->negative_lookups_miss(), 1); |
| 156 |
| 157 return result; |
| 203 } | 158 } |
| 204 | 159 |
| 205 | 160 |
| 206 void StubCache::GenerateProbe(MacroAssembler* masm, | 161 void StubCache::GenerateProbe(MacroAssembler* masm, |
| 207 Code::Flags flags, | 162 Code::Flags flags, |
| 208 Register receiver, | 163 Register receiver, |
| 209 Register name, | 164 Register name, |
| 210 Register scratch, | 165 Register scratch, |
| 211 Register extra, | 166 Register extra, |
| 212 Register extra2) { | 167 Register extra2) { |
| (...skipping 14 matching lines...) Expand all Loading... |
| 227 ASSERT(!extra.is(receiver)); | 182 ASSERT(!extra.is(receiver)); |
| 228 ASSERT(!extra.is(name)); | 183 ASSERT(!extra.is(name)); |
| 229 ASSERT(!extra.is(scratch)); | 184 ASSERT(!extra.is(scratch)); |
| 230 | 185 |
| 231 // Check scratch and extra registers are valid, and extra2 is unused. | 186 // Check scratch and extra registers are valid, and extra2 is unused. |
| 232 ASSERT(!scratch.is(no_reg)); | 187 ASSERT(!scratch.is(no_reg)); |
| 233 ASSERT(extra2.is(no_reg)); | 188 ASSERT(extra2.is(no_reg)); |
| 234 | 189 |
| 235 // Check that the receiver isn't a smi. | 190 // Check that the receiver isn't a smi. |
| 236 __ test(receiver, Immediate(kSmiTagMask)); | 191 __ test(receiver, Immediate(kSmiTagMask)); |
| 237 __ j(zero, &miss, not_taken); | 192 __ j(zero, &miss); |
| 238 | 193 |
| 239 // Get the map of the receiver and compute the hash. | 194 // Get the map of the receiver and compute the hash. |
| 240 __ mov(scratch, FieldOperand(name, String::kHashFieldOffset)); | 195 __ mov(scratch, FieldOperand(name, String::kHashFieldOffset)); |
| 241 __ add(scratch, FieldOperand(receiver, HeapObject::kMapOffset)); | 196 __ add(scratch, FieldOperand(receiver, HeapObject::kMapOffset)); |
| 242 __ xor_(scratch, flags); | 197 __ xor_(scratch, flags); |
| 243 __ and_(scratch, (kPrimaryTableSize - 1) << kHeapObjectTagSize); | 198 __ and_(scratch, (kPrimaryTableSize - 1) << kHeapObjectTagSize); |
| 244 | 199 |
| 245 // Probe the primary table. | 200 // Probe the primary table. |
| 246 ProbeTable(isolate, masm, flags, kPrimary, name, scratch, extra); | 201 ProbeTable(isolate, masm, flags, kPrimary, name, scratch, extra); |
| 247 | 202 |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 288 __ mov(prototype, FieldOperand(prototype, Map::kPrototypeOffset)); | 243 __ mov(prototype, FieldOperand(prototype, Map::kPrototypeOffset)); |
| 289 } | 244 } |
| 290 | 245 |
| 291 | 246 |
| 292 void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm, | 247 void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm, |
| 293 Register receiver, | 248 Register receiver, |
| 294 Register scratch, | 249 Register scratch, |
| 295 Label* miss_label) { | 250 Label* miss_label) { |
| 296 // Check that the receiver isn't a smi. | 251 // Check that the receiver isn't a smi. |
| 297 __ test(receiver, Immediate(kSmiTagMask)); | 252 __ test(receiver, Immediate(kSmiTagMask)); |
| 298 __ j(zero, miss_label, not_taken); | 253 __ j(zero, miss_label); |
| 299 | 254 |
| 300 // Check that the object is a JS array. | 255 // Check that the object is a JS array. |
| 301 __ CmpObjectType(receiver, JS_ARRAY_TYPE, scratch); | 256 __ CmpObjectType(receiver, JS_ARRAY_TYPE, scratch); |
| 302 __ j(not_equal, miss_label, not_taken); | 257 __ j(not_equal, miss_label); |
| 303 | 258 |
| 304 // Load length directly from the JS array. | 259 // Load length directly from the JS array. |
| 305 __ mov(eax, FieldOperand(receiver, JSArray::kLengthOffset)); | 260 __ mov(eax, FieldOperand(receiver, JSArray::kLengthOffset)); |
| 306 __ ret(0); | 261 __ ret(0); |
| 307 } | 262 } |
| 308 | 263 |
| 309 | 264 |
| 310 // Generate code to check if an object is a string. If the object is | 265 // Generate code to check if an object is a string. If the object is |
| 311 // a string, the map's instance type is left in the scratch register. | 266 // a string, the map's instance type is left in the scratch register. |
| 312 static void GenerateStringCheck(MacroAssembler* masm, | 267 static void GenerateStringCheck(MacroAssembler* masm, |
| 313 Register receiver, | 268 Register receiver, |
| 314 Register scratch, | 269 Register scratch, |
| 315 Label* smi, | 270 Label* smi, |
| 316 Label* non_string_object) { | 271 Label* non_string_object) { |
| 317 // Check that the object isn't a smi. | 272 // Check that the object isn't a smi. |
| 318 __ test(receiver, Immediate(kSmiTagMask)); | 273 __ test(receiver, Immediate(kSmiTagMask)); |
| 319 __ j(zero, smi, not_taken); | 274 __ j(zero, smi); |
| 320 | 275 |
| 321 // Check that the object is a string. | 276 // Check that the object is a string. |
| 322 __ mov(scratch, FieldOperand(receiver, HeapObject::kMapOffset)); | 277 __ mov(scratch, FieldOperand(receiver, HeapObject::kMapOffset)); |
| 323 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); | 278 __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset)); |
| 324 ASSERT(kNotStringTag != 0); | 279 ASSERT(kNotStringTag != 0); |
| 325 __ test(scratch, Immediate(kNotStringTag)); | 280 __ test(scratch, Immediate(kNotStringTag)); |
| 326 __ j(not_zero, non_string_object, not_taken); | 281 __ j(not_zero, non_string_object); |
| 327 } | 282 } |
| 328 | 283 |
| 329 | 284 |
| 330 void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm, | 285 void StubCompiler::GenerateLoadStringLength(MacroAssembler* masm, |
| 331 Register receiver, | 286 Register receiver, |
| 332 Register scratch1, | 287 Register scratch1, |
| 333 Register scratch2, | 288 Register scratch2, |
| 334 Label* miss, | 289 Label* miss, |
| 335 bool support_wrappers) { | 290 bool support_wrappers) { |
| 336 Label check_wrapper; | 291 Label check_wrapper; |
| 337 | 292 |
| 338 // Check if the object is a string leaving the instance type in the | 293 // Check if the object is a string leaving the instance type in the |
| 339 // scratch register. | 294 // scratch register. |
| 340 GenerateStringCheck(masm, receiver, scratch1, miss, | 295 GenerateStringCheck(masm, receiver, scratch1, miss, |
| 341 support_wrappers ? &check_wrapper : miss); | 296 support_wrappers ? &check_wrapper : miss); |
| 342 | 297 |
| 343 // Load length from the string and convert to a smi. | 298 // Load length from the string and convert to a smi. |
| 344 __ mov(eax, FieldOperand(receiver, String::kLengthOffset)); | 299 __ mov(eax, FieldOperand(receiver, String::kLengthOffset)); |
| 345 __ ret(0); | 300 __ ret(0); |
| 346 | 301 |
| 347 if (support_wrappers) { | 302 if (support_wrappers) { |
| 348 // Check if the object is a JSValue wrapper. | 303 // Check if the object is a JSValue wrapper. |
| 349 __ bind(&check_wrapper); | 304 __ bind(&check_wrapper); |
| 350 __ cmp(scratch1, JS_VALUE_TYPE); | 305 __ cmp(scratch1, JS_VALUE_TYPE); |
| 351 __ j(not_equal, miss, not_taken); | 306 __ j(not_equal, miss); |
| 352 | 307 |
| 353 // Check if the wrapped value is a string and load the length | 308 // Check if the wrapped value is a string and load the length |
| 354 // directly if it is. | 309 // directly if it is. |
| 355 __ mov(scratch2, FieldOperand(receiver, JSValue::kValueOffset)); | 310 __ mov(scratch2, FieldOperand(receiver, JSValue::kValueOffset)); |
| 356 GenerateStringCheck(masm, scratch2, scratch1, miss, miss); | 311 GenerateStringCheck(masm, scratch2, scratch1, miss, miss); |
| 357 __ mov(eax, FieldOperand(scratch2, String::kLengthOffset)); | 312 __ mov(eax, FieldOperand(scratch2, String::kLengthOffset)); |
| 358 __ ret(0); | 313 __ ret(0); |
| 359 } | 314 } |
| 360 } | 315 } |
| 361 | 316 |
| (...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 546 Register receiver, | 501 Register receiver, |
| 547 Register scratch1, | 502 Register scratch1, |
| 548 Register scratch2, | 503 Register scratch2, |
| 549 Register scratch3, | 504 Register scratch3, |
| 550 Label* miss) { | 505 Label* miss) { |
| 551 ASSERT(holder->HasNamedInterceptor()); | 506 ASSERT(holder->HasNamedInterceptor()); |
| 552 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined()); | 507 ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined()); |
| 553 | 508 |
| 554 // Check that the receiver isn't a smi. | 509 // Check that the receiver isn't a smi. |
| 555 __ test(receiver, Immediate(kSmiTagMask)); | 510 __ test(receiver, Immediate(kSmiTagMask)); |
| 556 __ j(zero, miss, not_taken); | 511 __ j(zero, miss); |
| 557 | 512 |
| 558 CallOptimization optimization(lookup); | 513 CallOptimization optimization(lookup); |
| 559 | 514 |
| 560 if (optimization.is_constant_call()) { | 515 if (optimization.is_constant_call()) { |
| 561 return CompileCacheable(masm, | 516 return CompileCacheable(masm, |
| 562 object, | 517 object, |
| 563 receiver, | 518 receiver, |
| 564 scratch1, | 519 scratch1, |
| 565 scratch2, | 520 scratch2, |
| 566 scratch3, | 521 scratch3, |
| (...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 751 code = masm->isolate()->builtins()->builtin(Builtins::kLoadIC_Miss); | 706 code = masm->isolate()->builtins()->builtin(Builtins::kLoadIC_Miss); |
| 752 } else { | 707 } else { |
| 753 code = masm->isolate()->builtins()->builtin(Builtins::kKeyedLoadIC_Miss); | 708 code = masm->isolate()->builtins()->builtin(Builtins::kKeyedLoadIC_Miss); |
| 754 } | 709 } |
| 755 | 710 |
| 756 Handle<Code> ic(code); | 711 Handle<Code> ic(code); |
| 757 __ jmp(ic, RelocInfo::CODE_TARGET); | 712 __ jmp(ic, RelocInfo::CODE_TARGET); |
| 758 } | 713 } |
| 759 | 714 |
| 760 | 715 |
| 716 void StubCompiler::GenerateKeyedLoadMissForceGeneric(MacroAssembler* masm) { |
| 717 Code* code = masm->isolate()->builtins()->builtin( |
| 718 Builtins::kKeyedLoadIC_MissForceGeneric); |
| 719 Handle<Code> ic(code); |
| 720 __ jmp(ic, RelocInfo::CODE_TARGET); |
| 721 } |
| 722 |
| 723 |
| 761 // Both name_reg and receiver_reg are preserved on jumps to miss_label, | 724 // Both name_reg and receiver_reg are preserved on jumps to miss_label, |
| 762 // but may be destroyed if store is successful. | 725 // but may be destroyed if store is successful. |
| 763 void StubCompiler::GenerateStoreField(MacroAssembler* masm, | 726 void StubCompiler::GenerateStoreField(MacroAssembler* masm, |
| 764 JSObject* object, | 727 JSObject* object, |
| 765 int index, | 728 int index, |
| 766 Map* transition, | 729 Map* transition, |
| 767 Register receiver_reg, | 730 Register receiver_reg, |
| 768 Register name_reg, | 731 Register name_reg, |
| 769 Register scratch, | 732 Register scratch, |
| 770 Label* miss_label) { | 733 Label* miss_label) { |
| 771 // Check that the object isn't a smi. | 734 // Check that the object isn't a smi. |
| 772 __ test(receiver_reg, Immediate(kSmiTagMask)); | 735 __ test(receiver_reg, Immediate(kSmiTagMask)); |
| 773 __ j(zero, miss_label, not_taken); | 736 __ j(zero, miss_label); |
| 774 | 737 |
| 775 // Check that the map of the object hasn't changed. | 738 // Check that the map of the object hasn't changed. |
| 776 __ cmp(FieldOperand(receiver_reg, HeapObject::kMapOffset), | 739 __ cmp(FieldOperand(receiver_reg, HeapObject::kMapOffset), |
| 777 Immediate(Handle<Map>(object->map()))); | 740 Immediate(Handle<Map>(object->map()))); |
| 778 __ j(not_equal, miss_label, not_taken); | 741 __ j(not_equal, miss_label); |
| 779 | 742 |
| 780 // Perform global security token check if needed. | 743 // Perform global security token check if needed. |
| 781 if (object->IsJSGlobalProxy()) { | 744 if (object->IsJSGlobalProxy()) { |
| 782 __ CheckAccessGlobalProxy(receiver_reg, scratch, miss_label); | 745 __ CheckAccessGlobalProxy(receiver_reg, scratch, miss_label); |
| 783 } | 746 } |
| 784 | 747 |
| 785 // Stub never generated for non-global objects that require access | 748 // Stub never generated for non-global objects that require access |
| 786 // checks. | 749 // checks. |
| 787 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); | 750 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); |
| 788 | 751 |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 866 JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(probe); | 829 JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(probe); |
| 867 ASSERT(cell->value()->IsTheHole()); | 830 ASSERT(cell->value()->IsTheHole()); |
| 868 if (Serializer::enabled()) { | 831 if (Serializer::enabled()) { |
| 869 __ mov(scratch, Immediate(Handle<Object>(cell))); | 832 __ mov(scratch, Immediate(Handle<Object>(cell))); |
| 870 __ cmp(FieldOperand(scratch, JSGlobalPropertyCell::kValueOffset), | 833 __ cmp(FieldOperand(scratch, JSGlobalPropertyCell::kValueOffset), |
| 871 Immediate(masm->isolate()->factory()->the_hole_value())); | 834 Immediate(masm->isolate()->factory()->the_hole_value())); |
| 872 } else { | 835 } else { |
| 873 __ cmp(Operand::Cell(Handle<JSGlobalPropertyCell>(cell)), | 836 __ cmp(Operand::Cell(Handle<JSGlobalPropertyCell>(cell)), |
| 874 Immediate(masm->isolate()->factory()->the_hole_value())); | 837 Immediate(masm->isolate()->factory()->the_hole_value())); |
| 875 } | 838 } |
| 876 __ j(not_equal, miss, not_taken); | 839 __ j(not_equal, miss); |
| 877 return cell; | 840 return cell; |
| 878 } | 841 } |
| 879 | 842 |
| 880 | 843 |
| 881 // Calls GenerateCheckPropertyCell for each global object in the prototype chain | 844 // Calls GenerateCheckPropertyCell for each global object in the prototype chain |
| 882 // from object to (but not including) holder. | 845 // from object to (but not including) holder. |
| 883 MUST_USE_RESULT static MaybeObject* GenerateCheckPropertyCells( | 846 MUST_USE_RESULT static MaybeObject* GenerateCheckPropertyCells( |
| 884 MacroAssembler* masm, | 847 MacroAssembler* masm, |
| 885 JSObject* object, | 848 JSObject* object, |
| 886 JSObject* holder, | 849 JSObject* holder, |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 952 Object* lookup_result = NULL; // Initialization to please compiler. | 915 Object* lookup_result = NULL; // Initialization to please compiler. |
| 953 if (!maybe_lookup_result->ToObject(&lookup_result)) { | 916 if (!maybe_lookup_result->ToObject(&lookup_result)) { |
| 954 set_failure(Failure::cast(maybe_lookup_result)); | 917 set_failure(Failure::cast(maybe_lookup_result)); |
| 955 return reg; | 918 return reg; |
| 956 } | 919 } |
| 957 name = String::cast(lookup_result); | 920 name = String::cast(lookup_result); |
| 958 } | 921 } |
| 959 ASSERT(current->property_dictionary()->FindEntry(name) == | 922 ASSERT(current->property_dictionary()->FindEntry(name) == |
| 960 StringDictionary::kNotFound); | 923 StringDictionary::kNotFound); |
| 961 | 924 |
| 962 GenerateDictionaryNegativeLookup(masm(), | 925 MaybeObject* negative_lookup = GenerateDictionaryNegativeLookup(masm(), |
| 963 miss, | 926 miss, |
| 964 reg, | 927 reg, |
| 965 name, | 928 name, |
| 966 scratch1, | 929 scratch1, |
| 967 scratch2); | 930 scratch2); |
| 931 if (negative_lookup->IsFailure()) { |
| 932 set_failure(Failure::cast(negative_lookup)); |
| 933 return reg; |
| 934 } |
| 935 |
| 968 __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset)); | 936 __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset)); |
| 969 reg = holder_reg; // from now the object is in holder_reg | 937 reg = holder_reg; // from now the object is in holder_reg |
| 970 __ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset)); | 938 __ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset)); |
| 971 } else if (heap()->InNewSpace(prototype)) { | 939 } else if (heap()->InNewSpace(prototype)) { |
| 972 // Get the map of the current object. | 940 // Get the map of the current object. |
| 973 __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset)); | 941 __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset)); |
| 974 __ cmp(Operand(scratch1), Immediate(Handle<Map>(current->map()))); | 942 __ cmp(Operand(scratch1), Immediate(Handle<Map>(current->map()))); |
| 975 // Branch on the result of the map check. | 943 // Branch on the result of the map check. |
| 976 __ j(not_equal, miss, not_taken); | 944 __ j(not_equal, miss); |
| 977 // Check access rights to the global object. This has to happen | 945 // Check access rights to the global object. This has to happen |
| 978 // after the map check so that we know that the object is | 946 // after the map check so that we know that the object is |
| 979 // actually a global object. | 947 // actually a global object. |
| 980 if (current->IsJSGlobalProxy()) { | 948 if (current->IsJSGlobalProxy()) { |
| 981 __ CheckAccessGlobalProxy(reg, scratch1, miss); | 949 __ CheckAccessGlobalProxy(reg, scratch1, miss); |
| 982 | 950 |
| 983 // Restore scratch register to be the map of the object. | 951 // Restore scratch register to be the map of the object. |
| 984 // We load the prototype from the map in the scratch register. | 952 // We load the prototype from the map in the scratch register. |
| 985 __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset)); | 953 __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset)); |
| 986 } | 954 } |
| 987 // The prototype is in new space; we cannot store a reference | 955 // The prototype is in new space; we cannot store a reference |
| 988 // to it in the code. Load it from the map. | 956 // to it in the code. Load it from the map. |
| 989 reg = holder_reg; // from now the object is in holder_reg | 957 reg = holder_reg; // from now the object is in holder_reg |
| 990 __ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset)); | 958 __ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset)); |
| 991 } else { | 959 } else { |
| 992 // Check the map of the current object. | 960 // Check the map of the current object. |
| 993 __ cmp(FieldOperand(reg, HeapObject::kMapOffset), | 961 __ cmp(FieldOperand(reg, HeapObject::kMapOffset), |
| 994 Immediate(Handle<Map>(current->map()))); | 962 Immediate(Handle<Map>(current->map()))); |
| 995 // Branch on the result of the map check. | 963 // Branch on the result of the map check. |
| 996 __ j(not_equal, miss, not_taken); | 964 __ j(not_equal, miss); |
| 997 // Check access rights to the global object. This has to happen | 965 // Check access rights to the global object. This has to happen |
| 998 // after the map check so that we know that the object is | 966 // after the map check so that we know that the object is |
| 999 // actually a global object. | 967 // actually a global object. |
| 1000 if (current->IsJSGlobalProxy()) { | 968 if (current->IsJSGlobalProxy()) { |
| 1001 __ CheckAccessGlobalProxy(reg, scratch1, miss); | 969 __ CheckAccessGlobalProxy(reg, scratch1, miss); |
| 1002 } | 970 } |
| 1003 // The prototype is in old space; load it directly. | 971 // The prototype is in old space; load it directly. |
| 1004 reg = holder_reg; // from now the object is in holder_reg | 972 reg = holder_reg; // from now the object is in holder_reg |
| 1005 __ mov(reg, Handle<JSObject>(prototype)); | 973 __ mov(reg, Handle<JSObject>(prototype)); |
| 1006 } | 974 } |
| 1007 | 975 |
| 1008 if (save_at_depth == depth) { | 976 if (save_at_depth == depth) { |
| 1009 __ mov(Operand(esp, kPointerSize), reg); | 977 __ mov(Operand(esp, kPointerSize), reg); |
| 1010 } | 978 } |
| 1011 | 979 |
| 1012 // Go to the next object in the prototype chain. | 980 // Go to the next object in the prototype chain. |
| 1013 current = prototype; | 981 current = prototype; |
| 1014 } | 982 } |
| 1015 ASSERT(current == holder); | 983 ASSERT(current == holder); |
| 1016 | 984 |
| 1017 // Log the check depth. | 985 // Log the check depth. |
| 1018 LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); | 986 LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); |
| 1019 | 987 |
| 1020 // Check the holder map. | 988 // Check the holder map. |
| 1021 __ cmp(FieldOperand(reg, HeapObject::kMapOffset), | 989 __ cmp(FieldOperand(reg, HeapObject::kMapOffset), |
| 1022 Immediate(Handle<Map>(holder->map()))); | 990 Immediate(Handle<Map>(holder->map()))); |
| 1023 __ j(not_equal, miss, not_taken); | 991 __ j(not_equal, miss); |
| 1024 | 992 |
| 1025 // Perform security check for access to the global object. | 993 // Perform security check for access to the global object. |
| 1026 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded()); | 994 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded()); |
| 1027 if (holder->IsJSGlobalProxy()) { | 995 if (holder->IsJSGlobalProxy()) { |
| 1028 __ CheckAccessGlobalProxy(reg, scratch1, miss); | 996 __ CheckAccessGlobalProxy(reg, scratch1, miss); |
| 1029 }; | 997 }; |
| 1030 | 998 |
| 1031 // If we've skipped any global objects, it's not enough to verify | 999 // If we've skipped any global objects, it's not enough to verify |
| 1032 // that their maps haven't changed. We also need to check that the | 1000 // that their maps haven't changed. We also need to check that the |
| 1033 // property cell for the property is still empty. | 1001 // property cell for the property is still empty. |
| (...skipping 14 matching lines...) Expand all Loading... |
| 1048 JSObject* holder, | 1016 JSObject* holder, |
| 1049 Register receiver, | 1017 Register receiver, |
| 1050 Register scratch1, | 1018 Register scratch1, |
| 1051 Register scratch2, | 1019 Register scratch2, |
| 1052 Register scratch3, | 1020 Register scratch3, |
| 1053 int index, | 1021 int index, |
| 1054 String* name, | 1022 String* name, |
| 1055 Label* miss) { | 1023 Label* miss) { |
| 1056 // Check that the receiver isn't a smi. | 1024 // Check that the receiver isn't a smi. |
| 1057 __ test(receiver, Immediate(kSmiTagMask)); | 1025 __ test(receiver, Immediate(kSmiTagMask)); |
| 1058 __ j(zero, miss, not_taken); | 1026 __ j(zero, miss); |
| 1059 | 1027 |
| 1060 // Check the prototype chain. | 1028 // Check the prototype chain. |
| 1061 Register reg = | 1029 Register reg = |
| 1062 CheckPrototypes(object, receiver, holder, | 1030 CheckPrototypes(object, receiver, holder, |
| 1063 scratch1, scratch2, scratch3, name, miss); | 1031 scratch1, scratch2, scratch3, name, miss); |
| 1064 | 1032 |
| 1065 // Get the value from the properties. | 1033 // Get the value from the properties. |
| 1066 GenerateFastPropertyLoad(masm(), eax, reg, holder, index); | 1034 GenerateFastPropertyLoad(masm(), eax, reg, holder, index); |
| 1067 __ ret(0); | 1035 __ ret(0); |
| 1068 } | 1036 } |
| 1069 | 1037 |
| 1070 | 1038 |
| 1071 MaybeObject* StubCompiler::GenerateLoadCallback(JSObject* object, | 1039 MaybeObject* StubCompiler::GenerateLoadCallback(JSObject* object, |
| 1072 JSObject* holder, | 1040 JSObject* holder, |
| 1073 Register receiver, | 1041 Register receiver, |
| 1074 Register name_reg, | 1042 Register name_reg, |
| 1075 Register scratch1, | 1043 Register scratch1, |
| 1076 Register scratch2, | 1044 Register scratch2, |
| 1077 Register scratch3, | 1045 Register scratch3, |
| 1078 AccessorInfo* callback, | 1046 AccessorInfo* callback, |
| 1079 String* name, | 1047 String* name, |
| 1080 Label* miss) { | 1048 Label* miss) { |
| 1081 // Check that the receiver isn't a smi. | 1049 // Check that the receiver isn't a smi. |
| 1082 __ test(receiver, Immediate(kSmiTagMask)); | 1050 __ test(receiver, Immediate(kSmiTagMask)); |
| 1083 __ j(zero, miss, not_taken); | 1051 __ j(zero, miss); |
| 1084 | 1052 |
| 1085 // Check that the maps haven't changed. | 1053 // Check that the maps haven't changed. |
| 1086 Register reg = | 1054 Register reg = |
| 1087 CheckPrototypes(object, receiver, holder, scratch1, | 1055 CheckPrototypes(object, receiver, holder, scratch1, |
| 1088 scratch2, scratch3, name, miss); | 1056 scratch2, scratch3, name, miss); |
| 1089 | 1057 |
| 1090 Handle<AccessorInfo> callback_handle(callback); | 1058 Handle<AccessorInfo> callback_handle(callback); |
| 1091 | 1059 |
| 1092 // Insert additional parameters into the stack frame above return address. | 1060 // Insert additional parameters into the stack frame above return address. |
| 1093 ASSERT(!scratch3.is(reg)); | 1061 ASSERT(!scratch3.is(reg)); |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1140 JSObject* holder, | 1108 JSObject* holder, |
| 1141 Register receiver, | 1109 Register receiver, |
| 1142 Register scratch1, | 1110 Register scratch1, |
| 1143 Register scratch2, | 1111 Register scratch2, |
| 1144 Register scratch3, | 1112 Register scratch3, |
| 1145 Object* value, | 1113 Object* value, |
| 1146 String* name, | 1114 String* name, |
| 1147 Label* miss) { | 1115 Label* miss) { |
| 1148 // Check that the receiver isn't a smi. | 1116 // Check that the receiver isn't a smi. |
| 1149 __ test(receiver, Immediate(kSmiTagMask)); | 1117 __ test(receiver, Immediate(kSmiTagMask)); |
| 1150 __ j(zero, miss, not_taken); | 1118 __ j(zero, miss); |
| 1151 | 1119 |
| 1152 // Check that the maps haven't changed. | 1120 // Check that the maps haven't changed. |
| 1153 CheckPrototypes(object, receiver, holder, | 1121 CheckPrototypes(object, receiver, holder, |
| 1154 scratch1, scratch2, scratch3, name, miss); | 1122 scratch1, scratch2, scratch3, name, miss); |
| 1155 | 1123 |
| 1156 // Return the constant value. | 1124 // Return the constant value. |
| 1157 __ mov(eax, Handle<Object>(value)); | 1125 __ mov(eax, Handle<Object>(value)); |
| 1158 __ ret(0); | 1126 __ ret(0); |
| 1159 } | 1127 } |
| 1160 | 1128 |
| 1161 | 1129 |
| 1162 void StubCompiler::GenerateLoadInterceptor(JSObject* object, | 1130 void StubCompiler::GenerateLoadInterceptor(JSObject* object, |
| 1163 JSObject* interceptor_holder, | 1131 JSObject* interceptor_holder, |
| 1164 LookupResult* lookup, | 1132 LookupResult* lookup, |
| 1165 Register receiver, | 1133 Register receiver, |
| 1166 Register name_reg, | 1134 Register name_reg, |
| 1167 Register scratch1, | 1135 Register scratch1, |
| 1168 Register scratch2, | 1136 Register scratch2, |
| 1169 Register scratch3, | 1137 Register scratch3, |
| 1170 String* name, | 1138 String* name, |
| 1171 Label* miss) { | 1139 Label* miss) { |
| 1172 ASSERT(interceptor_holder->HasNamedInterceptor()); | 1140 ASSERT(interceptor_holder->HasNamedInterceptor()); |
| 1173 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined()); | 1141 ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined()); |
| 1174 | 1142 |
| 1175 // Check that the receiver isn't a smi. | 1143 // Check that the receiver isn't a smi. |
| 1176 __ test(receiver, Immediate(kSmiTagMask)); | 1144 __ test(receiver, Immediate(kSmiTagMask)); |
| 1177 __ j(zero, miss, not_taken); | 1145 __ j(zero, miss); |
| 1178 | 1146 |
| 1179 // So far the most popular follow ups for interceptor loads are FIELD | 1147 // So far the most popular follow ups for interceptor loads are FIELD |
| 1180 // and CALLBACKS, so inline only them, other cases may be added | 1148 // and CALLBACKS, so inline only them, other cases may be added |
| 1181 // later. | 1149 // later. |
| 1182 bool compile_followup_inline = false; | 1150 bool compile_followup_inline = false; |
| 1183 if (lookup->IsProperty() && lookup->IsCacheable()) { | 1151 if (lookup->IsProperty() && lookup->IsCacheable()) { |
| 1184 if (lookup->type() == FIELD) { | 1152 if (lookup->type() == FIELD) { |
| 1185 compile_followup_inline = true; | 1153 compile_followup_inline = true; |
| 1186 } else if (lookup->type() == CALLBACKS && | 1154 } else if (lookup->type() == CALLBACKS && |
| 1187 lookup->GetCallbackObject()->IsAccessorInfo() && | 1155 lookup->GetCallbackObject()->IsAccessorInfo() && |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1296 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), | 1264 ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForLoad), |
| 1297 isolate()); | 1265 isolate()); |
| 1298 __ TailCallExternalReference(ref, 5, 1); | 1266 __ TailCallExternalReference(ref, 5, 1); |
| 1299 } | 1267 } |
| 1300 } | 1268 } |
| 1301 | 1269 |
| 1302 | 1270 |
| 1303 void CallStubCompiler::GenerateNameCheck(String* name, Label* miss) { | 1271 void CallStubCompiler::GenerateNameCheck(String* name, Label* miss) { |
| 1304 if (kind_ == Code::KEYED_CALL_IC) { | 1272 if (kind_ == Code::KEYED_CALL_IC) { |
| 1305 __ cmp(Operand(ecx), Immediate(Handle<String>(name))); | 1273 __ cmp(Operand(ecx), Immediate(Handle<String>(name))); |
| 1306 __ j(not_equal, miss, not_taken); | 1274 __ j(not_equal, miss); |
| 1307 } | 1275 } |
| 1308 } | 1276 } |
| 1309 | 1277 |
| 1310 | 1278 |
| 1311 void CallStubCompiler::GenerateGlobalReceiverCheck(JSObject* object, | 1279 void CallStubCompiler::GenerateGlobalReceiverCheck(JSObject* object, |
| 1312 JSObject* holder, | 1280 JSObject* holder, |
| 1313 String* name, | 1281 String* name, |
| 1314 Label* miss) { | 1282 Label* miss) { |
| 1315 ASSERT(holder->IsGlobalObject()); | 1283 ASSERT(holder->IsGlobalObject()); |
| 1316 | 1284 |
| 1317 // Get the number of arguments. | 1285 // Get the number of arguments. |
| 1318 const int argc = arguments().immediate(); | 1286 const int argc = arguments().immediate(); |
| 1319 | 1287 |
| 1320 // Get the receiver from the stack. | 1288 // Get the receiver from the stack. |
| 1321 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); | 1289 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); |
| 1322 | 1290 |
| 1323 // If the object is the holder then we know that it's a global | 1291 // If the object is the holder then we know that it's a global |
| 1324 // object which can only happen for contextual calls. In this case, | 1292 // object which can only happen for contextual calls. In this case, |
| 1325 // the receiver cannot be a smi. | 1293 // the receiver cannot be a smi. |
| 1326 if (object != holder) { | 1294 if (object != holder) { |
| 1327 __ test(edx, Immediate(kSmiTagMask)); | 1295 __ test(edx, Immediate(kSmiTagMask)); |
| 1328 __ j(zero, miss, not_taken); | 1296 __ j(zero, miss); |
| 1329 } | 1297 } |
| 1330 | 1298 |
| 1331 // Check that the maps haven't changed. | 1299 // Check that the maps haven't changed. |
| 1332 CheckPrototypes(object, edx, holder, ebx, eax, edi, name, miss); | 1300 CheckPrototypes(object, edx, holder, ebx, eax, edi, name, miss); |
| 1333 } | 1301 } |
| 1334 | 1302 |
| 1335 | 1303 |
| 1336 void CallStubCompiler::GenerateLoadFunctionFromCell(JSGlobalPropertyCell* cell, | 1304 void CallStubCompiler::GenerateLoadFunctionFromCell(JSGlobalPropertyCell* cell, |
| 1337 JSFunction* function, | 1305 JSFunction* function, |
| 1338 Label* miss) { | 1306 Label* miss) { |
| 1339 // Get the value from the cell. | 1307 // Get the value from the cell. |
| 1340 if (Serializer::enabled()) { | 1308 if (Serializer::enabled()) { |
| 1341 __ mov(edi, Immediate(Handle<JSGlobalPropertyCell>(cell))); | 1309 __ mov(edi, Immediate(Handle<JSGlobalPropertyCell>(cell))); |
| 1342 __ mov(edi, FieldOperand(edi, JSGlobalPropertyCell::kValueOffset)); | 1310 __ mov(edi, FieldOperand(edi, JSGlobalPropertyCell::kValueOffset)); |
| 1343 } else { | 1311 } else { |
| 1344 __ mov(edi, Operand::Cell(Handle<JSGlobalPropertyCell>(cell))); | 1312 __ mov(edi, Operand::Cell(Handle<JSGlobalPropertyCell>(cell))); |
| 1345 } | 1313 } |
| 1346 | 1314 |
| 1347 // Check that the cell contains the same function. | 1315 // Check that the cell contains the same function. |
| 1348 if (isolate()->heap()->InNewSpace(function)) { | 1316 if (isolate()->heap()->InNewSpace(function)) { |
| 1349 // We can't embed a pointer to a function in new space so we have | 1317 // We can't embed a pointer to a function in new space so we have |
| 1350 // to verify that the shared function info is unchanged. This has | 1318 // to verify that the shared function info is unchanged. This has |
| 1351 // the nice side effect that multiple closures based on the same | 1319 // the nice side effect that multiple closures based on the same |
| 1352 // function can all use this call IC. Before we load through the | 1320 // function can all use this call IC. Before we load through the |
| 1353 // function, we have to verify that it still is a function. | 1321 // function, we have to verify that it still is a function. |
| 1354 __ test(edi, Immediate(kSmiTagMask)); | 1322 __ test(edi, Immediate(kSmiTagMask)); |
| 1355 __ j(zero, miss, not_taken); | 1323 __ j(zero, miss); |
| 1356 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ebx); | 1324 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ebx); |
| 1357 __ j(not_equal, miss, not_taken); | 1325 __ j(not_equal, miss); |
| 1358 | 1326 |
| 1359 // Check the shared function info. Make sure it hasn't changed. | 1327 // Check the shared function info. Make sure it hasn't changed. |
| 1360 __ cmp(FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset), | 1328 __ cmp(FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset), |
| 1361 Immediate(Handle<SharedFunctionInfo>(function->shared()))); | 1329 Immediate(Handle<SharedFunctionInfo>(function->shared()))); |
| 1362 __ j(not_equal, miss, not_taken); | 1330 __ j(not_equal, miss); |
| 1363 } else { | 1331 } else { |
| 1364 __ cmp(Operand(edi), Immediate(Handle<JSFunction>(function))); | 1332 __ cmp(Operand(edi), Immediate(Handle<JSFunction>(function))); |
| 1365 __ j(not_equal, miss, not_taken); | 1333 __ j(not_equal, miss); |
| 1366 } | 1334 } |
| 1367 } | 1335 } |
| 1368 | 1336 |
| 1369 | 1337 |
| 1370 MaybeObject* CallStubCompiler::GenerateMissBranch() { | 1338 MaybeObject* CallStubCompiler::GenerateMissBranch() { |
| 1371 MaybeObject* maybe_obj = | 1339 MaybeObject* maybe_obj = |
| 1372 isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(), | 1340 isolate()->stub_cache()->ComputeCallMiss(arguments().immediate(), |
| 1373 kind_); | 1341 kind_); |
| 1374 Object* obj; | 1342 Object* obj; |
| 1375 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 1343 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| (...skipping 17 matching lines...) Expand all Loading... |
| 1393 Label miss; | 1361 Label miss; |
| 1394 | 1362 |
| 1395 GenerateNameCheck(name, &miss); | 1363 GenerateNameCheck(name, &miss); |
| 1396 | 1364 |
| 1397 // Get the receiver from the stack. | 1365 // Get the receiver from the stack. |
| 1398 const int argc = arguments().immediate(); | 1366 const int argc = arguments().immediate(); |
| 1399 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); | 1367 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); |
| 1400 | 1368 |
| 1401 // Check that the receiver isn't a smi. | 1369 // Check that the receiver isn't a smi. |
| 1402 __ test(edx, Immediate(kSmiTagMask)); | 1370 __ test(edx, Immediate(kSmiTagMask)); |
| 1403 __ j(zero, &miss, not_taken); | 1371 __ j(zero, &miss); |
| 1404 | 1372 |
| 1405 // Do the right check and compute the holder register. | 1373 // Do the right check and compute the holder register. |
| 1406 Register reg = CheckPrototypes(object, edx, holder, ebx, eax, edi, | 1374 Register reg = CheckPrototypes(object, edx, holder, ebx, eax, edi, |
| 1407 name, &miss); | 1375 name, &miss); |
| 1408 | 1376 |
| 1409 GenerateFastPropertyLoad(masm(), edi, reg, holder, index); | 1377 GenerateFastPropertyLoad(masm(), edi, reg, holder, index); |
| 1410 | 1378 |
| 1411 // Check that the function really is a function. | 1379 // Check that the function really is a function. |
| 1412 __ test(edi, Immediate(kSmiTagMask)); | 1380 __ test(edi, Immediate(kSmiTagMask)); |
| 1413 __ j(zero, &miss, not_taken); | 1381 __ j(zero, &miss); |
| 1414 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ebx); | 1382 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ebx); |
| 1415 __ j(not_equal, &miss, not_taken); | 1383 __ j(not_equal, &miss); |
| 1416 | 1384 |
| 1417 // Patch the receiver on the stack with the global proxy if | 1385 // Patch the receiver on the stack with the global proxy if |
| 1418 // necessary. | 1386 // necessary. |
| 1419 if (object->IsGlobalObject()) { | 1387 if (object->IsGlobalObject()) { |
| 1420 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset)); | 1388 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset)); |
| 1421 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx); | 1389 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx); |
| 1422 } | 1390 } |
| 1423 | 1391 |
| 1424 // Invoke the function. | 1392 // Invoke the function. |
| 1425 __ InvokeFunction(edi, arguments(), JUMP_FUNCTION); | 1393 __ InvokeFunction(edi, arguments(), JUMP_FUNCTION); |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1477 | 1445 |
| 1478 // Get the elements array of the object. | 1446 // Get the elements array of the object. |
| 1479 __ mov(ebx, FieldOperand(edx, JSArray::kElementsOffset)); | 1447 __ mov(ebx, FieldOperand(edx, JSArray::kElementsOffset)); |
| 1480 | 1448 |
| 1481 // Check that the elements are in fast mode and writable. | 1449 // Check that the elements are in fast mode and writable. |
| 1482 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset), | 1450 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset), |
| 1483 Immediate(factory()->fixed_array_map())); | 1451 Immediate(factory()->fixed_array_map())); |
| 1484 __ j(not_equal, &call_builtin); | 1452 __ j(not_equal, &call_builtin); |
| 1485 | 1453 |
| 1486 if (argc == 1) { // Otherwise fall through to call builtin. | 1454 if (argc == 1) { // Otherwise fall through to call builtin. |
| 1487 Label exit, attempt_to_grow_elements; | 1455 Label exit, attempt_to_grow_elements, with_write_barrier; |
| 1488 NearLabel with_write_barrier; | |
| 1489 | 1456 |
| 1490 // Get the array's length into eax and calculate new length. | 1457 // Get the array's length into eax and calculate new length. |
| 1491 __ mov(eax, FieldOperand(edx, JSArray::kLengthOffset)); | 1458 __ mov(eax, FieldOperand(edx, JSArray::kLengthOffset)); |
| 1492 STATIC_ASSERT(kSmiTagSize == 1); | 1459 STATIC_ASSERT(kSmiTagSize == 1); |
| 1493 STATIC_ASSERT(kSmiTag == 0); | 1460 STATIC_ASSERT(kSmiTag == 0); |
| 1494 __ add(Operand(eax), Immediate(Smi::FromInt(argc))); | 1461 __ add(Operand(eax), Immediate(Smi::FromInt(argc))); |
| 1495 | 1462 |
| 1496 // Get the element's length into ecx. | 1463 // Get the element's length into ecx. |
| 1497 __ mov(ecx, FieldOperand(ebx, FixedArray::kLengthOffset)); | 1464 __ mov(ecx, FieldOperand(ebx, FixedArray::kLengthOffset)); |
| 1498 | 1465 |
| 1499 // Check if we could survive without allocation. | 1466 // Check if we could survive without allocation. |
| 1500 __ cmp(eax, Operand(ecx)); | 1467 __ cmp(eax, Operand(ecx)); |
| 1501 __ j(greater, &attempt_to_grow_elements); | 1468 __ j(greater, &attempt_to_grow_elements); |
| 1502 | 1469 |
| 1503 // Save new length. | 1470 // Save new length. |
| 1504 __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax); | 1471 __ mov(FieldOperand(edx, JSArray::kLengthOffset), eax); |
| 1505 | 1472 |
| 1506 // Push the element. | 1473 // Push the element. |
| 1507 __ lea(edx, FieldOperand(ebx, | 1474 __ lea(edx, FieldOperand(ebx, |
| 1508 eax, times_half_pointer_size, | 1475 eax, times_half_pointer_size, |
| 1509 FixedArray::kHeaderSize - argc * kPointerSize)); | 1476 FixedArray::kHeaderSize - argc * kPointerSize)); |
| 1510 __ mov(ecx, Operand(esp, argc * kPointerSize)); | 1477 __ mov(ecx, Operand(esp, argc * kPointerSize)); |
| 1511 __ mov(Operand(edx, 0), ecx); | 1478 __ mov(Operand(edx, 0), ecx); |
| 1512 | 1479 |
| 1513 // Check if value is a smi. | 1480 // Check if value is a smi. |
| 1514 __ test(ecx, Immediate(kSmiTagMask)); | 1481 __ test(ecx, Immediate(kSmiTagMask)); |
| 1515 __ j(not_zero, &with_write_barrier); | 1482 __ j(not_zero, &with_write_barrier, Label::kNear); |
| 1516 | 1483 |
| 1517 __ bind(&exit); | 1484 __ bind(&exit); |
| 1518 __ ret((argc + 1) * kPointerSize); | 1485 __ ret((argc + 1) * kPointerSize); |
| 1519 | 1486 |
| 1520 __ bind(&with_write_barrier); | 1487 __ bind(&with_write_barrier); |
| 1521 | 1488 |
| 1522 __ RecordWrite( | 1489 __ RecordWrite( |
| 1523 ebx, edx, ecx, kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); | 1490 ebx, edx, ecx, kDontSaveFPRegs, EMIT_REMEMBERED_SET, OMIT_SMI_CHECK); |
| 1524 | 1491 |
| 1525 __ ret((argc + 1) * kPointerSize); | 1492 __ ret((argc + 1) * kPointerSize); |
| (...skipping 451 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1977 __ mov(eax, Operand(esp, 1 * kPointerSize)); | 1944 __ mov(eax, Operand(esp, 1 * kPointerSize)); |
| 1978 | 1945 |
| 1979 // Check if the argument is a smi. | 1946 // Check if the argument is a smi. |
| 1980 Label smi; | 1947 Label smi; |
| 1981 STATIC_ASSERT(kSmiTag == 0); | 1948 STATIC_ASSERT(kSmiTag == 0); |
| 1982 __ test(eax, Immediate(kSmiTagMask)); | 1949 __ test(eax, Immediate(kSmiTagMask)); |
| 1983 __ j(zero, &smi); | 1950 __ j(zero, &smi); |
| 1984 | 1951 |
| 1985 // Check if the argument is a heap number and load its value into xmm0. | 1952 // Check if the argument is a heap number and load its value into xmm0. |
| 1986 Label slow; | 1953 Label slow; |
| 1987 __ CheckMap(eax, factory()->heap_number_map(), &slow, true); | 1954 __ CheckMap(eax, factory()->heap_number_map(), &slow, DONT_DO_SMI_CHECK); |
| 1988 __ movdbl(xmm0, FieldOperand(eax, HeapNumber::kValueOffset)); | 1955 __ movdbl(xmm0, FieldOperand(eax, HeapNumber::kValueOffset)); |
| 1989 | 1956 |
| 1990 // Check if the argument is strictly positive. Note this also | 1957 // Check if the argument is strictly positive. Note this also |
| 1991 // discards NaN. | 1958 // discards NaN. |
| 1992 __ xorpd(xmm1, xmm1); | 1959 __ xorpd(xmm1, xmm1); |
| 1993 __ ucomisd(xmm0, xmm1); | 1960 __ ucomisd(xmm0, xmm1); |
| 1994 __ j(below_equal, &slow); | 1961 __ j(below_equal, &slow); |
| 1995 | 1962 |
| 1996 // Do a truncating conversion. | 1963 // Do a truncating conversion. |
| 1997 __ cvttsd2si(eax, Operand(xmm0)); | 1964 __ cvttsd2si(eax, Operand(xmm0)); |
| (...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2121 // This only happens for the most negative smi. | 2088 // This only happens for the most negative smi. |
| 2122 Label slow; | 2089 Label slow; |
| 2123 __ j(negative, &slow); | 2090 __ j(negative, &slow); |
| 2124 | 2091 |
| 2125 // Smi case done. | 2092 // Smi case done. |
| 2126 __ ret(2 * kPointerSize); | 2093 __ ret(2 * kPointerSize); |
| 2127 | 2094 |
| 2128 // Check if the argument is a heap number and load its exponent and | 2095 // Check if the argument is a heap number and load its exponent and |
| 2129 // sign into ebx. | 2096 // sign into ebx. |
| 2130 __ bind(¬_smi); | 2097 __ bind(¬_smi); |
| 2131 __ CheckMap(eax, factory()->heap_number_map(), &slow, true); | 2098 __ CheckMap(eax, factory()->heap_number_map(), &slow, DONT_DO_SMI_CHECK); |
| 2132 __ mov(ebx, FieldOperand(eax, HeapNumber::kExponentOffset)); | 2099 __ mov(ebx, FieldOperand(eax, HeapNumber::kExponentOffset)); |
| 2133 | 2100 |
| 2134 // Check the sign of the argument. If the argument is positive, | 2101 // Check the sign of the argument. If the argument is positive, |
| 2135 // just return it. | 2102 // just return it. |
| 2136 Label negative_sign; | 2103 Label negative_sign; |
| 2137 __ test(ebx, Immediate(HeapNumber::kSignMask)); | 2104 __ test(ebx, Immediate(HeapNumber::kSignMask)); |
| 2138 __ j(not_zero, &negative_sign); | 2105 __ j(not_zero, &negative_sign); |
| 2139 __ ret(2 * kPointerSize); | 2106 __ ret(2 * kPointerSize); |
| 2140 | 2107 |
| 2141 // If the argument is negative, clear the sign, and return a new | 2108 // If the argument is negative, clear the sign, and return a new |
| (...skipping 26 matching lines...) Expand all Loading... |
| 2168 Object* object, | 2135 Object* object, |
| 2169 JSObject* holder, | 2136 JSObject* holder, |
| 2170 JSGlobalPropertyCell* cell, | 2137 JSGlobalPropertyCell* cell, |
| 2171 JSFunction* function, | 2138 JSFunction* function, |
| 2172 String* name) { | 2139 String* name) { |
| 2173 ASSERT(optimization.is_simple_api_call()); | 2140 ASSERT(optimization.is_simple_api_call()); |
| 2174 // Bail out if object is a global object as we don't want to | 2141 // Bail out if object is a global object as we don't want to |
| 2175 // repatch it to global receiver. | 2142 // repatch it to global receiver. |
| 2176 if (object->IsGlobalObject()) return heap()->undefined_value(); | 2143 if (object->IsGlobalObject()) return heap()->undefined_value(); |
| 2177 if (cell != NULL) return heap()->undefined_value(); | 2144 if (cell != NULL) return heap()->undefined_value(); |
| 2145 if (!object->IsJSObject()) return heap()->undefined_value(); |
| 2178 int depth = optimization.GetPrototypeDepthOfExpectedType( | 2146 int depth = optimization.GetPrototypeDepthOfExpectedType( |
| 2179 JSObject::cast(object), holder); | 2147 JSObject::cast(object), holder); |
| 2180 if (depth == kInvalidProtoDepth) return heap()->undefined_value(); | 2148 if (depth == kInvalidProtoDepth) return heap()->undefined_value(); |
| 2181 | 2149 |
| 2182 Label miss, miss_before_stack_reserved; | 2150 Label miss, miss_before_stack_reserved; |
| 2183 | 2151 |
| 2184 GenerateNameCheck(name, &miss_before_stack_reserved); | 2152 GenerateNameCheck(name, &miss_before_stack_reserved); |
| 2185 | 2153 |
| 2186 // Get the receiver from the stack. | 2154 // Get the receiver from the stack. |
| 2187 const int argc = arguments().immediate(); | 2155 const int argc = arguments().immediate(); |
| 2188 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); | 2156 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); |
| 2189 | 2157 |
| 2190 // Check that the receiver isn't a smi. | 2158 // Check that the receiver isn't a smi. |
| 2191 __ test(edx, Immediate(kSmiTagMask)); | 2159 __ test(edx, Immediate(kSmiTagMask)); |
| 2192 __ j(zero, &miss_before_stack_reserved, not_taken); | 2160 __ j(zero, &miss_before_stack_reserved); |
| 2193 | 2161 |
| 2194 Counters* counters = isolate()->counters(); | 2162 Counters* counters = isolate()->counters(); |
| 2195 __ IncrementCounter(counters->call_const(), 1); | 2163 __ IncrementCounter(counters->call_const(), 1); |
| 2196 __ IncrementCounter(counters->call_const_fast_api(), 1); | 2164 __ IncrementCounter(counters->call_const_fast_api(), 1); |
| 2197 | 2165 |
| 2198 // Allocate space for v8::Arguments implicit values. Must be initialized | 2166 // Allocate space for v8::Arguments implicit values. Must be initialized |
| 2199 // before calling any runtime function. | 2167 // before calling any runtime function. |
| 2200 __ sub(Operand(esp), Immediate(kFastApiCallArguments * kPointerSize)); | 2168 __ sub(Operand(esp), Immediate(kFastApiCallArguments * kPointerSize)); |
| 2201 | 2169 |
| 2202 // Check that the maps haven't changed and find a Holder as a side effect. | 2170 // Check that the maps haven't changed and find a Holder as a side effect. |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2250 | 2218 |
| 2251 GenerateNameCheck(name, &miss); | 2219 GenerateNameCheck(name, &miss); |
| 2252 | 2220 |
| 2253 // Get the receiver from the stack. | 2221 // Get the receiver from the stack. |
| 2254 const int argc = arguments().immediate(); | 2222 const int argc = arguments().immediate(); |
| 2255 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); | 2223 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); |
| 2256 | 2224 |
| 2257 // Check that the receiver isn't a smi. | 2225 // Check that the receiver isn't a smi. |
| 2258 if (check != NUMBER_CHECK) { | 2226 if (check != NUMBER_CHECK) { |
| 2259 __ test(edx, Immediate(kSmiTagMask)); | 2227 __ test(edx, Immediate(kSmiTagMask)); |
| 2260 __ j(zero, &miss, not_taken); | 2228 __ j(zero, &miss); |
| 2261 } | 2229 } |
| 2262 | 2230 |
| 2263 // Make sure that it's okay not to patch the on stack receiver | 2231 // Make sure that it's okay not to patch the on stack receiver |
| 2264 // unless we're doing a receiver map check. | 2232 // unless we're doing a receiver map check. |
| 2265 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK); | 2233 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK); |
| 2266 | 2234 |
| 2267 SharedFunctionInfo* function_info = function->shared(); | 2235 SharedFunctionInfo* function_info = function->shared(); |
| 2268 switch (check) { | 2236 switch (check) { |
| 2269 case RECEIVER_MAP_CHECK: | 2237 case RECEIVER_MAP_CHECK: |
| 2270 __ IncrementCounter(isolate()->counters()->call_const(), 1); | 2238 __ IncrementCounter(isolate()->counters()->call_const(), 1); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 2282 break; | 2250 break; |
| 2283 | 2251 |
| 2284 case STRING_CHECK: | 2252 case STRING_CHECK: |
| 2285 if (!function->IsBuiltin() && !function_info->strict_mode()) { | 2253 if (!function->IsBuiltin() && !function_info->strict_mode()) { |
| 2286 // Calling non-strict non-builtins with a value as the receiver | 2254 // Calling non-strict non-builtins with a value as the receiver |
| 2287 // requires boxing. | 2255 // requires boxing. |
| 2288 __ jmp(&miss); | 2256 __ jmp(&miss); |
| 2289 } else { | 2257 } else { |
| 2290 // Check that the object is a string or a symbol. | 2258 // Check that the object is a string or a symbol. |
| 2291 __ CmpObjectType(edx, FIRST_NONSTRING_TYPE, eax); | 2259 __ CmpObjectType(edx, FIRST_NONSTRING_TYPE, eax); |
| 2292 __ j(above_equal, &miss, not_taken); | 2260 __ j(above_equal, &miss); |
| 2293 // Check that the maps starting from the prototype haven't changed. | 2261 // Check that the maps starting from the prototype haven't changed. |
| 2294 GenerateDirectLoadGlobalFunctionPrototype( | 2262 GenerateDirectLoadGlobalFunctionPrototype( |
| 2295 masm(), Context::STRING_FUNCTION_INDEX, eax, &miss); | 2263 masm(), Context::STRING_FUNCTION_INDEX, eax, &miss); |
| 2296 CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder, | 2264 CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder, |
| 2297 ebx, edx, edi, name, &miss); | 2265 ebx, edx, edi, name, &miss); |
| 2298 } | 2266 } |
| 2299 break; | 2267 break; |
| 2300 | 2268 |
| 2301 case NUMBER_CHECK: { | 2269 case NUMBER_CHECK: { |
| 2302 if (!function->IsBuiltin() && !function_info->strict_mode()) { | 2270 if (!function->IsBuiltin() && !function_info->strict_mode()) { |
| 2303 // Calling non-strict non-builtins with a value as the receiver | 2271 // Calling non-strict non-builtins with a value as the receiver |
| 2304 // requires boxing. | 2272 // requires boxing. |
| 2305 __ jmp(&miss); | 2273 __ jmp(&miss); |
| 2306 } else { | 2274 } else { |
| 2307 Label fast; | 2275 Label fast; |
| 2308 // Check that the object is a smi or a heap number. | 2276 // Check that the object is a smi or a heap number. |
| 2309 __ test(edx, Immediate(kSmiTagMask)); | 2277 __ test(edx, Immediate(kSmiTagMask)); |
| 2310 __ j(zero, &fast, taken); | 2278 __ j(zero, &fast); |
| 2311 __ CmpObjectType(edx, HEAP_NUMBER_TYPE, eax); | 2279 __ CmpObjectType(edx, HEAP_NUMBER_TYPE, eax); |
| 2312 __ j(not_equal, &miss, not_taken); | 2280 __ j(not_equal, &miss); |
| 2313 __ bind(&fast); | 2281 __ bind(&fast); |
| 2314 // Check that the maps starting from the prototype haven't changed. | 2282 // Check that the maps starting from the prototype haven't changed. |
| 2315 GenerateDirectLoadGlobalFunctionPrototype( | 2283 GenerateDirectLoadGlobalFunctionPrototype( |
| 2316 masm(), Context::NUMBER_FUNCTION_INDEX, eax, &miss); | 2284 masm(), Context::NUMBER_FUNCTION_INDEX, eax, &miss); |
| 2317 CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder, | 2285 CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder, |
| 2318 ebx, edx, edi, name, &miss); | 2286 ebx, edx, edi, name, &miss); |
| 2319 } | 2287 } |
| 2320 break; | 2288 break; |
| 2321 } | 2289 } |
| 2322 | 2290 |
| 2323 case BOOLEAN_CHECK: { | 2291 case BOOLEAN_CHECK: { |
| 2324 if (!function->IsBuiltin() && !function_info->strict_mode()) { | 2292 if (!function->IsBuiltin() && !function_info->strict_mode()) { |
| 2325 // Calling non-strict non-builtins with a value as the receiver | 2293 // Calling non-strict non-builtins with a value as the receiver |
| 2326 // requires boxing. | 2294 // requires boxing. |
| 2327 __ jmp(&miss); | 2295 __ jmp(&miss); |
| 2328 } else { | 2296 } else { |
| 2329 Label fast; | 2297 Label fast; |
| 2330 // Check that the object is a boolean. | 2298 // Check that the object is a boolean. |
| 2331 __ cmp(edx, factory()->true_value()); | 2299 __ cmp(edx, factory()->true_value()); |
| 2332 __ j(equal, &fast, taken); | 2300 __ j(equal, &fast); |
| 2333 __ cmp(edx, factory()->false_value()); | 2301 __ cmp(edx, factory()->false_value()); |
| 2334 __ j(not_equal, &miss, not_taken); | 2302 __ j(not_equal, &miss); |
| 2335 __ bind(&fast); | 2303 __ bind(&fast); |
| 2336 // Check that the maps starting from the prototype haven't changed. | 2304 // Check that the maps starting from the prototype haven't changed. |
| 2337 GenerateDirectLoadGlobalFunctionPrototype( | 2305 GenerateDirectLoadGlobalFunctionPrototype( |
| 2338 masm(), Context::BOOLEAN_FUNCTION_INDEX, eax, &miss); | 2306 masm(), Context::BOOLEAN_FUNCTION_INDEX, eax, &miss); |
| 2339 CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder, | 2307 CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder, |
| 2340 ebx, edx, edi, name, &miss); | 2308 ebx, edx, edi, name, &miss); |
| 2341 } | 2309 } |
| 2342 break; | 2310 break; |
| 2343 } | 2311 } |
| 2344 | 2312 |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2392 edi, | 2360 edi, |
| 2393 eax, | 2361 eax, |
| 2394 &miss); | 2362 &miss); |
| 2395 if (result->IsFailure()) return result; | 2363 if (result->IsFailure()) return result; |
| 2396 | 2364 |
| 2397 // Restore receiver. | 2365 // Restore receiver. |
| 2398 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); | 2366 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); |
| 2399 | 2367 |
| 2400 // Check that the function really is a function. | 2368 // Check that the function really is a function. |
| 2401 __ test(eax, Immediate(kSmiTagMask)); | 2369 __ test(eax, Immediate(kSmiTagMask)); |
| 2402 __ j(zero, &miss, not_taken); | 2370 __ j(zero, &miss); |
| 2403 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx); | 2371 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx); |
| 2404 __ j(not_equal, &miss, not_taken); | 2372 __ j(not_equal, &miss); |
| 2405 | 2373 |
| 2406 // Patch the receiver on the stack with the global proxy if | 2374 // Patch the receiver on the stack with the global proxy if |
| 2407 // necessary. | 2375 // necessary. |
| 2408 if (object->IsGlobalObject()) { | 2376 if (object->IsGlobalObject()) { |
| 2409 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset)); | 2377 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset)); |
| 2410 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx); | 2378 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx); |
| 2411 } | 2379 } |
| 2412 | 2380 |
| 2413 // Invoke the function. | 2381 // Invoke the function. |
| 2414 __ mov(edi, eax); | 2382 __ mov(edi, eax); |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2531 // ----------- S t a t e ------------- | 2499 // ----------- S t a t e ------------- |
| 2532 // -- eax : value | 2500 // -- eax : value |
| 2533 // -- ecx : name | 2501 // -- ecx : name |
| 2534 // -- edx : receiver | 2502 // -- edx : receiver |
| 2535 // -- esp[0] : return address | 2503 // -- esp[0] : return address |
| 2536 // ----------------------------------- | 2504 // ----------------------------------- |
| 2537 Label miss; | 2505 Label miss; |
| 2538 | 2506 |
| 2539 // Check that the object isn't a smi. | 2507 // Check that the object isn't a smi. |
| 2540 __ test(edx, Immediate(kSmiTagMask)); | 2508 __ test(edx, Immediate(kSmiTagMask)); |
| 2541 __ j(zero, &miss, not_taken); | 2509 __ j(zero, &miss); |
| 2542 | 2510 |
| 2543 // Check that the map of the object hasn't changed. | 2511 // Check that the map of the object hasn't changed. |
| 2544 __ cmp(FieldOperand(edx, HeapObject::kMapOffset), | 2512 __ cmp(FieldOperand(edx, HeapObject::kMapOffset), |
| 2545 Immediate(Handle<Map>(object->map()))); | 2513 Immediate(Handle<Map>(object->map()))); |
| 2546 __ j(not_equal, &miss, not_taken); | 2514 __ j(not_equal, &miss); |
| 2547 | 2515 |
| 2548 // Perform global security token check if needed. | 2516 // Perform global security token check if needed. |
| 2549 if (object->IsJSGlobalProxy()) { | 2517 if (object->IsJSGlobalProxy()) { |
| 2550 __ CheckAccessGlobalProxy(edx, ebx, &miss); | 2518 __ CheckAccessGlobalProxy(edx, ebx, &miss); |
| 2551 } | 2519 } |
| 2552 | 2520 |
| 2553 // Stub never generated for non-global objects that require access | 2521 // Stub never generated for non-global objects that require access |
| 2554 // checks. | 2522 // checks. |
| 2555 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); | 2523 ASSERT(object->IsJSGlobalProxy() || !object->IsAccessCheckNeeded()); |
| 2556 | 2524 |
| (...skipping 24 matching lines...) Expand all Loading... |
| 2581 // ----------- S t a t e ------------- | 2549 // ----------- S t a t e ------------- |
| 2582 // -- eax : value | 2550 // -- eax : value |
| 2583 // -- ecx : name | 2551 // -- ecx : name |
| 2584 // -- edx : receiver | 2552 // -- edx : receiver |
| 2585 // -- esp[0] : return address | 2553 // -- esp[0] : return address |
| 2586 // ----------------------------------- | 2554 // ----------------------------------- |
| 2587 Label miss; | 2555 Label miss; |
| 2588 | 2556 |
| 2589 // Check that the object isn't a smi. | 2557 // Check that the object isn't a smi. |
| 2590 __ test(edx, Immediate(kSmiTagMask)); | 2558 __ test(edx, Immediate(kSmiTagMask)); |
| 2591 __ j(zero, &miss, not_taken); | 2559 __ j(zero, &miss); |
| 2592 | 2560 |
| 2593 // Check that the map of the object hasn't changed. | 2561 // Check that the map of the object hasn't changed. |
| 2594 __ cmp(FieldOperand(edx, HeapObject::kMapOffset), | 2562 __ cmp(FieldOperand(edx, HeapObject::kMapOffset), |
| 2595 Immediate(Handle<Map>(receiver->map()))); | 2563 Immediate(Handle<Map>(receiver->map()))); |
| 2596 __ j(not_equal, &miss, not_taken); | 2564 __ j(not_equal, &miss); |
| 2597 | 2565 |
| 2598 // Perform global security token check if needed. | 2566 // Perform global security token check if needed. |
| 2599 if (receiver->IsJSGlobalProxy()) { | 2567 if (receiver->IsJSGlobalProxy()) { |
| 2600 __ CheckAccessGlobalProxy(edx, ebx, &miss); | 2568 __ CheckAccessGlobalProxy(edx, ebx, &miss); |
| 2601 } | 2569 } |
| 2602 | 2570 |
| 2603 // Stub never generated for non-global objects that require access | 2571 // Stub never generated for non-global objects that require access |
| 2604 // checks. | 2572 // checks. |
| 2605 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded()); | 2573 ASSERT(receiver->IsJSGlobalProxy() || !receiver->IsAccessCheckNeeded()); |
| 2606 | 2574 |
| (...skipping 26 matching lines...) Expand all Loading... |
| 2633 // -- eax : value | 2601 // -- eax : value |
| 2634 // -- ecx : name | 2602 // -- ecx : name |
| 2635 // -- edx : receiver | 2603 // -- edx : receiver |
| 2636 // -- esp[0] : return address | 2604 // -- esp[0] : return address |
| 2637 // ----------------------------------- | 2605 // ----------------------------------- |
| 2638 Label miss; | 2606 Label miss; |
| 2639 | 2607 |
| 2640 // Check that the map of the global has not changed. | 2608 // Check that the map of the global has not changed. |
| 2641 __ cmp(FieldOperand(edx, HeapObject::kMapOffset), | 2609 __ cmp(FieldOperand(edx, HeapObject::kMapOffset), |
| 2642 Immediate(Handle<Map>(object->map()))); | 2610 Immediate(Handle<Map>(object->map()))); |
| 2643 __ j(not_equal, &miss, not_taken); | 2611 __ j(not_equal, &miss); |
| 2644 | 2612 |
| 2645 // Compute the cell operand to use. | 2613 // Compute the cell operand to use. |
| 2646 __ mov(ebx, Immediate(Handle<JSGlobalPropertyCell>(cell))); | 2614 __ mov(ebx, Immediate(Handle<JSGlobalPropertyCell>(cell))); |
| 2647 Operand cell_operand = FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset); | 2615 Operand cell_operand = FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset); |
| 2648 | 2616 |
| 2649 // Check that the value in the cell is not the hole. If it is, this | 2617 // Check that the value in the cell is not the hole. If it is, this |
| 2650 // cell could have been deleted and reintroducing the global needs | 2618 // cell could have been deleted and reintroducing the global needs |
| 2651 // to update the property details in the property dictionary of the | 2619 // to update the property details in the property dictionary of the |
| 2652 // global object. We bail out to the runtime system to do that. | 2620 // global object. We bail out to the runtime system to do that. |
| 2653 __ cmp(cell_operand, factory()->the_hole_value()); | 2621 __ cmp(cell_operand, factory()->the_hole_value()); |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2697 // -- edx : receiver | 2665 // -- edx : receiver |
| 2698 // -- esp[0] : return address | 2666 // -- esp[0] : return address |
| 2699 // ----------------------------------- | 2667 // ----------------------------------- |
| 2700 Label miss; | 2668 Label miss; |
| 2701 | 2669 |
| 2702 Counters* counters = isolate()->counters(); | 2670 Counters* counters = isolate()->counters(); |
| 2703 __ IncrementCounter(counters->keyed_store_field(), 1); | 2671 __ IncrementCounter(counters->keyed_store_field(), 1); |
| 2704 | 2672 |
| 2705 // Check that the name has not changed. | 2673 // Check that the name has not changed. |
| 2706 __ cmp(Operand(ecx), Immediate(Handle<String>(name))); | 2674 __ cmp(Operand(ecx), Immediate(Handle<String>(name))); |
| 2707 __ j(not_equal, &miss, not_taken); | 2675 __ j(not_equal, &miss); |
| 2708 | 2676 |
| 2709 // Generate store field code. Trashes the name register. | 2677 // Generate store field code. Trashes the name register. |
| 2710 GenerateStoreField(masm(), | 2678 GenerateStoreField(masm(), |
| 2711 object, | 2679 object, |
| 2712 index, | 2680 index, |
| 2713 transition, | 2681 transition, |
| 2714 edx, ecx, ebx, | 2682 edx, ecx, ebx, |
| 2715 &miss); | 2683 &miss); |
| 2716 | 2684 |
| 2717 // Handle store cache miss. | 2685 // Handle store cache miss. |
| 2718 __ bind(&miss); | 2686 __ bind(&miss); |
| 2719 __ DecrementCounter(counters->keyed_store_field(), 1); | 2687 __ DecrementCounter(counters->keyed_store_field(), 1); |
| 2720 Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss(); | 2688 Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss(); |
| 2721 __ jmp(ic, RelocInfo::CODE_TARGET); | 2689 __ jmp(ic, RelocInfo::CODE_TARGET); |
| 2722 | 2690 |
| 2723 // Return the generated code. | 2691 // Return the generated code. |
| 2724 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name); | 2692 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name); |
| 2725 } | 2693 } |
| 2726 | 2694 |
| 2727 | 2695 |
| 2728 MaybeObject* KeyedStoreStubCompiler::CompileStoreSpecialized( | 2696 MaybeObject* KeyedStoreStubCompiler::CompileStoreFastElement( |
| 2729 JSObject* receiver) { | 2697 Map* receiver_map) { |
| 2730 // ----------- S t a t e ------------- | 2698 // ----------- S t a t e ------------- |
| 2731 // -- eax : value | 2699 // -- eax : value |
| 2732 // -- ecx : key | 2700 // -- ecx : key |
| 2733 // -- edx : receiver | 2701 // -- edx : receiver |
| 2734 // -- esp[0] : return address | 2702 // -- esp[0] : return address |
| 2735 // ----------------------------------- | 2703 // ----------------------------------- |
| 2736 Label miss; | 2704 bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE; |
| 2705 MaybeObject* maybe_stub = |
| 2706 KeyedStoreFastElementStub(is_js_array).TryGetCode(); |
| 2707 Code* stub; |
| 2708 if (!maybe_stub->To(&stub)) return maybe_stub; |
| 2709 __ DispatchMap(edx, |
| 2710 Handle<Map>(receiver_map), |
| 2711 Handle<Code>(stub), |
| 2712 DO_SMI_CHECK); |
| 2737 | 2713 |
| 2738 // Check that the receiver isn't a smi. | |
| 2739 __ test(edx, Immediate(kSmiTagMask)); | |
| 2740 __ j(zero, &miss, not_taken); | |
| 2741 | |
| 2742 // Check that the map matches. | |
| 2743 __ cmp(FieldOperand(edx, HeapObject::kMapOffset), | |
| 2744 Immediate(Handle<Map>(receiver->map()))); | |
| 2745 __ j(not_equal, &miss, not_taken); | |
| 2746 | |
| 2747 // Check that the key is a smi. | |
| 2748 __ test(ecx, Immediate(kSmiTagMask)); | |
| 2749 __ j(not_zero, &miss, not_taken); | |
| 2750 | |
| 2751 // Get the elements array and make sure it is a fast element array, not 'cow'. | |
| 2752 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset)); | |
| 2753 __ cmp(FieldOperand(edi, HeapObject::kMapOffset), | |
| 2754 Immediate(factory()->fixed_array_map())); | |
| 2755 __ j(not_equal, &miss, not_taken); | |
| 2756 | |
| 2757 // Check that the key is within bounds. | |
| 2758 if (receiver->IsJSArray()) { | |
| 2759 __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset)); // Compare smis. | |
| 2760 __ j(above_equal, &miss, not_taken); | |
| 2761 } else { | |
| 2762 __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset)); // Compare smis. | |
| 2763 __ j(above_equal, &miss, not_taken); | |
| 2764 } | |
| 2765 | |
| 2766 // Do the store and update the write barrier. Make sure to preserve | |
| 2767 // the value in register eax. | |
| 2768 __ mov(edx, Operand(eax)); | |
| 2769 __ mov(FieldOperand(edi, ecx, times_2, FixedArray::kHeaderSize), eax); | |
| 2770 __ RecordWriteArray(edi, edx, ecx, kDontSaveFPRegs); | |
| 2771 | |
| 2772 // Done. | |
| 2773 __ ret(0); | |
| 2774 | |
| 2775 // Handle store cache miss. | |
| 2776 __ bind(&miss); | |
| 2777 Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss(); | 2714 Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss(); |
| 2778 __ jmp(ic, RelocInfo::CODE_TARGET); | 2715 __ jmp(ic, RelocInfo::CODE_TARGET); |
| 2779 | 2716 |
| 2780 // Return the generated code. | 2717 // Return the generated code. |
| 2781 return GetCode(NORMAL, NULL); | 2718 return GetCode(NORMAL, NULL); |
| 2782 } | 2719 } |
| 2783 | 2720 |
| 2784 | 2721 |
| 2722 MaybeObject* KeyedStoreStubCompiler::CompileStoreMegamorphic( |
| 2723 MapList* receiver_maps, |
| 2724 CodeList* handler_ics) { |
| 2725 // ----------- S t a t e ------------- |
| 2726 // -- eax : value |
| 2727 // -- ecx : key |
| 2728 // -- edx : receiver |
| 2729 // -- esp[0] : return address |
| 2730 // ----------------------------------- |
| 2731 Label miss; |
| 2732 __ JumpIfSmi(edx, &miss); |
| 2733 |
| 2734 Register map_reg = ebx; |
| 2735 __ mov(map_reg, FieldOperand(edx, HeapObject::kMapOffset)); |
| 2736 int receiver_count = receiver_maps->length(); |
| 2737 for (int current = 0; current < receiver_count; ++current) { |
| 2738 Handle<Map> map(receiver_maps->at(current)); |
| 2739 __ cmp(map_reg, map); |
| 2740 __ j(equal, Handle<Code>(handler_ics->at(current))); |
| 2741 } |
| 2742 __ bind(&miss); |
| 2743 Handle<Code> miss_ic = isolate()->builtins()->KeyedStoreIC_Miss(); |
| 2744 __ jmp(miss_ic, RelocInfo::CODE_TARGET); |
| 2745 |
| 2746 // Return the generated code. |
| 2747 return GetCode(NORMAL, NULL, MEGAMORPHIC); |
| 2748 } |
| 2749 |
| 2750 |
| 2785 MaybeObject* LoadStubCompiler::CompileLoadNonexistent(String* name, | 2751 MaybeObject* LoadStubCompiler::CompileLoadNonexistent(String* name, |
| 2786 JSObject* object, | 2752 JSObject* object, |
| 2787 JSObject* last) { | 2753 JSObject* last) { |
| 2788 // ----------- S t a t e ------------- | 2754 // ----------- S t a t e ------------- |
| 2789 // -- eax : receiver | 2755 // -- eax : receiver |
| 2790 // -- ecx : name | 2756 // -- ecx : name |
| 2791 // -- esp[0] : return address | 2757 // -- esp[0] : return address |
| 2792 // ----------------------------------- | 2758 // ----------------------------------- |
| 2793 Label miss; | 2759 Label miss; |
| 2794 | 2760 |
| 2795 // Check that the receiver isn't a smi. | 2761 // Check that the receiver isn't a smi. |
| 2796 __ test(eax, Immediate(kSmiTagMask)); | 2762 __ test(eax, Immediate(kSmiTagMask)); |
| 2797 __ j(zero, &miss, not_taken); | 2763 __ j(zero, &miss); |
| 2798 | 2764 |
| 2799 ASSERT(last->IsGlobalObject() || last->HasFastProperties()); | 2765 ASSERT(last->IsGlobalObject() || last->HasFastProperties()); |
| 2800 | 2766 |
| 2801 // Check the maps of the full prototype chain. Also check that | 2767 // Check the maps of the full prototype chain. Also check that |
| 2802 // global property cells up to (but not including) the last object | 2768 // global property cells up to (but not including) the last object |
| 2803 // in the prototype chain are empty. | 2769 // in the prototype chain are empty. |
| 2804 CheckPrototypes(object, eax, last, ebx, edx, edi, name, &miss); | 2770 CheckPrototypes(object, eax, last, ebx, edx, edi, name, &miss); |
| 2805 | 2771 |
| 2806 // If the last object in the prototype chain is a global object, | 2772 // If the last object in the prototype chain is a global object, |
| 2807 // check that the global property cell is empty. | 2773 // check that the global property cell is empty. |
| (...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2940 // -- ecx : name | 2906 // -- ecx : name |
| 2941 // -- esp[0] : return address | 2907 // -- esp[0] : return address |
| 2942 // ----------------------------------- | 2908 // ----------------------------------- |
| 2943 Label miss; | 2909 Label miss; |
| 2944 | 2910 |
| 2945 // If the object is the holder then we know that it's a global | 2911 // If the object is the holder then we know that it's a global |
| 2946 // object which can only happen for contextual loads. In this case, | 2912 // object which can only happen for contextual loads. In this case, |
| 2947 // the receiver cannot be a smi. | 2913 // the receiver cannot be a smi. |
| 2948 if (object != holder) { | 2914 if (object != holder) { |
| 2949 __ test(eax, Immediate(kSmiTagMask)); | 2915 __ test(eax, Immediate(kSmiTagMask)); |
| 2950 __ j(zero, &miss, not_taken); | 2916 __ j(zero, &miss); |
| 2951 } | 2917 } |
| 2952 | 2918 |
| 2953 // Check that the maps haven't changed. | 2919 // Check that the maps haven't changed. |
| 2954 CheckPrototypes(object, eax, holder, ebx, edx, edi, name, &miss); | 2920 CheckPrototypes(object, eax, holder, ebx, edx, edi, name, &miss); |
| 2955 | 2921 |
| 2956 // Get the value from the cell. | 2922 // Get the value from the cell. |
| 2957 if (Serializer::enabled()) { | 2923 if (Serializer::enabled()) { |
| 2958 __ mov(ebx, Immediate(Handle<JSGlobalPropertyCell>(cell))); | 2924 __ mov(ebx, Immediate(Handle<JSGlobalPropertyCell>(cell))); |
| 2959 __ mov(ebx, FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset)); | 2925 __ mov(ebx, FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset)); |
| 2960 } else { | 2926 } else { |
| 2961 __ mov(ebx, Operand::Cell(Handle<JSGlobalPropertyCell>(cell))); | 2927 __ mov(ebx, Operand::Cell(Handle<JSGlobalPropertyCell>(cell))); |
| 2962 } | 2928 } |
| 2963 | 2929 |
| 2964 // Check for deleted property if property can actually be deleted. | 2930 // Check for deleted property if property can actually be deleted. |
| 2965 if (!is_dont_delete) { | 2931 if (!is_dont_delete) { |
| 2966 __ cmp(ebx, factory()->the_hole_value()); | 2932 __ cmp(ebx, factory()->the_hole_value()); |
| 2967 __ j(equal, &miss, not_taken); | 2933 __ j(equal, &miss); |
| 2968 } else if (FLAG_debug_code) { | 2934 } else if (FLAG_debug_code) { |
| 2969 __ cmp(ebx, factory()->the_hole_value()); | 2935 __ cmp(ebx, factory()->the_hole_value()); |
| 2970 __ Check(not_equal, "DontDelete cells can't contain the hole"); | 2936 __ Check(not_equal, "DontDelete cells can't contain the hole"); |
| 2971 } | 2937 } |
| 2972 | 2938 |
| 2973 Counters* counters = isolate()->counters(); | 2939 Counters* counters = isolate()->counters(); |
| 2974 __ IncrementCounter(counters->named_load_global_stub(), 1); | 2940 __ IncrementCounter(counters->named_load_global_stub(), 1); |
| 2975 __ mov(eax, ebx); | 2941 __ mov(eax, ebx); |
| 2976 __ ret(0); | 2942 __ ret(0); |
| 2977 | 2943 |
| (...skipping 15 matching lines...) Expand all Loading... |
| 2993 // -- edx : receiver | 2959 // -- edx : receiver |
| 2994 // -- esp[0] : return address | 2960 // -- esp[0] : return address |
| 2995 // ----------------------------------- | 2961 // ----------------------------------- |
| 2996 Label miss; | 2962 Label miss; |
| 2997 | 2963 |
| 2998 Counters* counters = isolate()->counters(); | 2964 Counters* counters = isolate()->counters(); |
| 2999 __ IncrementCounter(counters->keyed_load_field(), 1); | 2965 __ IncrementCounter(counters->keyed_load_field(), 1); |
| 3000 | 2966 |
| 3001 // Check that the name has not changed. | 2967 // Check that the name has not changed. |
| 3002 __ cmp(Operand(eax), Immediate(Handle<String>(name))); | 2968 __ cmp(Operand(eax), Immediate(Handle<String>(name))); |
| 3003 __ j(not_equal, &miss, not_taken); | 2969 __ j(not_equal, &miss); |
| 3004 | 2970 |
| 3005 GenerateLoadField(receiver, holder, edx, ebx, ecx, edi, index, name, &miss); | 2971 GenerateLoadField(receiver, holder, edx, ebx, ecx, edi, index, name, &miss); |
| 3006 | 2972 |
| 3007 __ bind(&miss); | 2973 __ bind(&miss); |
| 3008 __ DecrementCounter(counters->keyed_load_field(), 1); | 2974 __ DecrementCounter(counters->keyed_load_field(), 1); |
| 3009 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); | 2975 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); |
| 3010 | 2976 |
| 3011 // Return the generated code. | 2977 // Return the generated code. |
| 3012 return GetCode(FIELD, name); | 2978 return GetCode(FIELD, name); |
| 3013 } | 2979 } |
| 3014 | 2980 |
| 3015 | 2981 |
| 3016 MaybeObject* KeyedLoadStubCompiler::CompileLoadCallback( | 2982 MaybeObject* KeyedLoadStubCompiler::CompileLoadCallback( |
| 3017 String* name, | 2983 String* name, |
| 3018 JSObject* receiver, | 2984 JSObject* receiver, |
| 3019 JSObject* holder, | 2985 JSObject* holder, |
| 3020 AccessorInfo* callback) { | 2986 AccessorInfo* callback) { |
| 3021 // ----------- S t a t e ------------- | 2987 // ----------- S t a t e ------------- |
| 3022 // -- eax : key | 2988 // -- eax : key |
| 3023 // -- edx : receiver | 2989 // -- edx : receiver |
| 3024 // -- esp[0] : return address | 2990 // -- esp[0] : return address |
| 3025 // ----------------------------------- | 2991 // ----------------------------------- |
| 3026 Label miss; | 2992 Label miss; |
| 3027 | 2993 |
| 3028 Counters* counters = isolate()->counters(); | 2994 Counters* counters = isolate()->counters(); |
| 3029 __ IncrementCounter(counters->keyed_load_callback(), 1); | 2995 __ IncrementCounter(counters->keyed_load_callback(), 1); |
| 3030 | 2996 |
| 3031 // Check that the name has not changed. | 2997 // Check that the name has not changed. |
| 3032 __ cmp(Operand(eax), Immediate(Handle<String>(name))); | 2998 __ cmp(Operand(eax), Immediate(Handle<String>(name))); |
| 3033 __ j(not_equal, &miss, not_taken); | 2999 __ j(not_equal, &miss); |
| 3034 | 3000 |
| 3035 MaybeObject* result = GenerateLoadCallback(receiver, holder, edx, eax, ebx, | 3001 MaybeObject* result = GenerateLoadCallback(receiver, holder, edx, eax, ebx, |
| 3036 ecx, edi, callback, name, &miss); | 3002 ecx, edi, callback, name, &miss); |
| 3037 if (result->IsFailure()) { | 3003 if (result->IsFailure()) { |
| 3038 miss.Unuse(); | 3004 miss.Unuse(); |
| 3039 return result; | 3005 return result; |
| 3040 } | 3006 } |
| 3041 | 3007 |
| 3042 __ bind(&miss); | 3008 __ bind(&miss); |
| 3043 | 3009 |
| (...skipping 14 matching lines...) Expand all Loading... |
| 3058 // -- edx : receiver | 3024 // -- edx : receiver |
| 3059 // -- esp[0] : return address | 3025 // -- esp[0] : return address |
| 3060 // ----------------------------------- | 3026 // ----------------------------------- |
| 3061 Label miss; | 3027 Label miss; |
| 3062 | 3028 |
| 3063 Counters* counters = isolate()->counters(); | 3029 Counters* counters = isolate()->counters(); |
| 3064 __ IncrementCounter(counters->keyed_load_constant_function(), 1); | 3030 __ IncrementCounter(counters->keyed_load_constant_function(), 1); |
| 3065 | 3031 |
| 3066 // Check that the name has not changed. | 3032 // Check that the name has not changed. |
| 3067 __ cmp(Operand(eax), Immediate(Handle<String>(name))); | 3033 __ cmp(Operand(eax), Immediate(Handle<String>(name))); |
| 3068 __ j(not_equal, &miss, not_taken); | 3034 __ j(not_equal, &miss); |
| 3069 | 3035 |
| 3070 GenerateLoadConstant(receiver, holder, edx, ebx, ecx, edi, | 3036 GenerateLoadConstant(receiver, holder, edx, ebx, ecx, edi, |
| 3071 value, name, &miss); | 3037 value, name, &miss); |
| 3072 __ bind(&miss); | 3038 __ bind(&miss); |
| 3073 __ DecrementCounter(counters->keyed_load_constant_function(), 1); | 3039 __ DecrementCounter(counters->keyed_load_constant_function(), 1); |
| 3074 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); | 3040 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); |
| 3075 | 3041 |
| 3076 // Return the generated code. | 3042 // Return the generated code. |
| 3077 return GetCode(CONSTANT_FUNCTION, name); | 3043 return GetCode(CONSTANT_FUNCTION, name); |
| 3078 } | 3044 } |
| 3079 | 3045 |
| 3080 | 3046 |
| 3081 MaybeObject* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver, | 3047 MaybeObject* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver, |
| 3082 JSObject* holder, | 3048 JSObject* holder, |
| 3083 String* name) { | 3049 String* name) { |
| 3084 // ----------- S t a t e ------------- | 3050 // ----------- S t a t e ------------- |
| 3085 // -- eax : key | 3051 // -- eax : key |
| 3086 // -- edx : receiver | 3052 // -- edx : receiver |
| 3087 // -- esp[0] : return address | 3053 // -- esp[0] : return address |
| 3088 // ----------------------------------- | 3054 // ----------------------------------- |
| 3089 Label miss; | 3055 Label miss; |
| 3090 | 3056 |
| 3091 Counters* counters = isolate()->counters(); | 3057 Counters* counters = isolate()->counters(); |
| 3092 __ IncrementCounter(counters->keyed_load_interceptor(), 1); | 3058 __ IncrementCounter(counters->keyed_load_interceptor(), 1); |
| 3093 | 3059 |
| 3094 // Check that the name has not changed. | 3060 // Check that the name has not changed. |
| 3095 __ cmp(Operand(eax), Immediate(Handle<String>(name))); | 3061 __ cmp(Operand(eax), Immediate(Handle<String>(name))); |
| 3096 __ j(not_equal, &miss, not_taken); | 3062 __ j(not_equal, &miss); |
| 3097 | 3063 |
| 3098 LookupResult lookup; | 3064 LookupResult lookup; |
| 3099 LookupPostInterceptor(holder, name, &lookup); | 3065 LookupPostInterceptor(holder, name, &lookup); |
| 3100 GenerateLoadInterceptor(receiver, | 3066 GenerateLoadInterceptor(receiver, |
| 3101 holder, | 3067 holder, |
| 3102 &lookup, | 3068 &lookup, |
| 3103 edx, | 3069 edx, |
| 3104 eax, | 3070 eax, |
| 3105 ecx, | 3071 ecx, |
| 3106 ebx, | 3072 ebx, |
| (...skipping 15 matching lines...) Expand all Loading... |
| 3122 // -- edx : receiver | 3088 // -- edx : receiver |
| 3123 // -- esp[0] : return address | 3089 // -- esp[0] : return address |
| 3124 // ----------------------------------- | 3090 // ----------------------------------- |
| 3125 Label miss; | 3091 Label miss; |
| 3126 | 3092 |
| 3127 Counters* counters = isolate()->counters(); | 3093 Counters* counters = isolate()->counters(); |
| 3128 __ IncrementCounter(counters->keyed_load_array_length(), 1); | 3094 __ IncrementCounter(counters->keyed_load_array_length(), 1); |
| 3129 | 3095 |
| 3130 // Check that the name has not changed. | 3096 // Check that the name has not changed. |
| 3131 __ cmp(Operand(eax), Immediate(Handle<String>(name))); | 3097 __ cmp(Operand(eax), Immediate(Handle<String>(name))); |
| 3132 __ j(not_equal, &miss, not_taken); | 3098 __ j(not_equal, &miss); |
| 3133 | 3099 |
| 3134 GenerateLoadArrayLength(masm(), edx, ecx, &miss); | 3100 GenerateLoadArrayLength(masm(), edx, ecx, &miss); |
| 3135 __ bind(&miss); | 3101 __ bind(&miss); |
| 3136 __ DecrementCounter(counters->keyed_load_array_length(), 1); | 3102 __ DecrementCounter(counters->keyed_load_array_length(), 1); |
| 3137 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); | 3103 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); |
| 3138 | 3104 |
| 3139 // Return the generated code. | 3105 // Return the generated code. |
| 3140 return GetCode(CALLBACKS, name); | 3106 return GetCode(CALLBACKS, name); |
| 3141 } | 3107 } |
| 3142 | 3108 |
| 3143 | 3109 |
| 3144 MaybeObject* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) { | 3110 MaybeObject* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) { |
| 3145 // ----------- S t a t e ------------- | 3111 // ----------- S t a t e ------------- |
| 3146 // -- eax : key | 3112 // -- eax : key |
| 3147 // -- edx : receiver | 3113 // -- edx : receiver |
| 3148 // -- esp[0] : return address | 3114 // -- esp[0] : return address |
| 3149 // ----------------------------------- | 3115 // ----------------------------------- |
| 3150 Label miss; | 3116 Label miss; |
| 3151 | 3117 |
| 3152 Counters* counters = isolate()->counters(); | 3118 Counters* counters = isolate()->counters(); |
| 3153 __ IncrementCounter(counters->keyed_load_string_length(), 1); | 3119 __ IncrementCounter(counters->keyed_load_string_length(), 1); |
| 3154 | 3120 |
| 3155 // Check that the name has not changed. | 3121 // Check that the name has not changed. |
| 3156 __ cmp(Operand(eax), Immediate(Handle<String>(name))); | 3122 __ cmp(Operand(eax), Immediate(Handle<String>(name))); |
| 3157 __ j(not_equal, &miss, not_taken); | 3123 __ j(not_equal, &miss); |
| 3158 | 3124 |
| 3159 GenerateLoadStringLength(masm(), edx, ecx, ebx, &miss, true); | 3125 GenerateLoadStringLength(masm(), edx, ecx, ebx, &miss, true); |
| 3160 __ bind(&miss); | 3126 __ bind(&miss); |
| 3161 __ DecrementCounter(counters->keyed_load_string_length(), 1); | 3127 __ DecrementCounter(counters->keyed_load_string_length(), 1); |
| 3162 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); | 3128 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); |
| 3163 | 3129 |
| 3164 // Return the generated code. | 3130 // Return the generated code. |
| 3165 return GetCode(CALLBACKS, name); | 3131 return GetCode(CALLBACKS, name); |
| 3166 } | 3132 } |
| 3167 | 3133 |
| 3168 | 3134 |
| 3169 MaybeObject* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) { | 3135 MaybeObject* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) { |
| 3170 // ----------- S t a t e ------------- | 3136 // ----------- S t a t e ------------- |
| 3171 // -- eax : key | 3137 // -- eax : key |
| 3172 // -- edx : receiver | 3138 // -- edx : receiver |
| 3173 // -- esp[0] : return address | 3139 // -- esp[0] : return address |
| 3174 // ----------------------------------- | 3140 // ----------------------------------- |
| 3175 Label miss; | 3141 Label miss; |
| 3176 | 3142 |
| 3177 Counters* counters = isolate()->counters(); | 3143 Counters* counters = isolate()->counters(); |
| 3178 __ IncrementCounter(counters->keyed_load_function_prototype(), 1); | 3144 __ IncrementCounter(counters->keyed_load_function_prototype(), 1); |
| 3179 | 3145 |
| 3180 // Check that the name has not changed. | 3146 // Check that the name has not changed. |
| 3181 __ cmp(Operand(eax), Immediate(Handle<String>(name))); | 3147 __ cmp(Operand(eax), Immediate(Handle<String>(name))); |
| 3182 __ j(not_equal, &miss, not_taken); | 3148 __ j(not_equal, &miss); |
| 3183 | 3149 |
| 3184 GenerateLoadFunctionPrototype(masm(), edx, ecx, ebx, &miss); | 3150 GenerateLoadFunctionPrototype(masm(), edx, ecx, ebx, &miss); |
| 3185 __ bind(&miss); | 3151 __ bind(&miss); |
| 3186 __ DecrementCounter(counters->keyed_load_function_prototype(), 1); | 3152 __ DecrementCounter(counters->keyed_load_function_prototype(), 1); |
| 3187 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); | 3153 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); |
| 3188 | 3154 |
| 3189 // Return the generated code. | 3155 // Return the generated code. |
| 3190 return GetCode(CALLBACKS, name); | 3156 return GetCode(CALLBACKS, name); |
| 3191 } | 3157 } |
| 3192 | 3158 |
| 3193 | 3159 |
| 3194 MaybeObject* KeyedLoadStubCompiler::CompileLoadSpecialized(JSObject* receiver) { | 3160 MaybeObject* KeyedLoadStubCompiler::CompileLoadFastElement(Map* receiver_map) { |
| 3195 // ----------- S t a t e ------------- | 3161 // ----------- S t a t e ------------- |
| 3196 // -- eax : key | 3162 // -- eax : key |
| 3197 // -- edx : receiver | 3163 // -- edx : receiver |
| 3198 // -- esp[0] : return address | 3164 // -- esp[0] : return address |
| 3199 // ----------------------------------- | 3165 // ----------------------------------- |
| 3200 Label miss; | 3166 MaybeObject* maybe_stub = KeyedLoadFastElementStub().TryGetCode(); |
| 3167 Code* stub; |
| 3168 if (!maybe_stub->To(&stub)) return maybe_stub; |
| 3169 __ DispatchMap(edx, |
| 3170 Handle<Map>(receiver_map), |
| 3171 Handle<Code>(stub), |
| 3172 DO_SMI_CHECK); |
| 3201 | 3173 |
| 3202 // Check that the receiver isn't a smi. | |
| 3203 __ test(edx, Immediate(kSmiTagMask)); | |
| 3204 __ j(zero, &miss, not_taken); | |
| 3205 | |
| 3206 // Check that the map matches. | |
| 3207 __ cmp(FieldOperand(edx, HeapObject::kMapOffset), | |
| 3208 Immediate(Handle<Map>(receiver->map()))); | |
| 3209 __ j(not_equal, &miss, not_taken); | |
| 3210 | |
| 3211 // Check that the key is a smi. | |
| 3212 __ test(eax, Immediate(kSmiTagMask)); | |
| 3213 __ j(not_zero, &miss, not_taken); | |
| 3214 | |
| 3215 // Get the elements array. | |
| 3216 __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset)); | |
| 3217 __ AssertFastElements(ecx); | |
| 3218 | |
| 3219 // Check that the key is within bounds. | |
| 3220 __ cmp(eax, FieldOperand(ecx, FixedArray::kLengthOffset)); | |
| 3221 __ j(above_equal, &miss, not_taken); | |
| 3222 | |
| 3223 // Load the result and make sure it's not the hole. | |
| 3224 __ mov(ebx, Operand(ecx, eax, times_2, | |
| 3225 FixedArray::kHeaderSize - kHeapObjectTag)); | |
| 3226 __ cmp(ebx, factory()->the_hole_value()); | |
| 3227 __ j(equal, &miss, not_taken); | |
| 3228 __ mov(eax, ebx); | |
| 3229 __ ret(0); | |
| 3230 | |
| 3231 __ bind(&miss); | |
| 3232 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); | 3174 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); |
| 3233 | 3175 |
| 3234 // Return the generated code. | 3176 // Return the generated code. |
| 3235 return GetCode(NORMAL, NULL); | 3177 return GetCode(NORMAL, NULL); |
| 3236 } | 3178 } |
| 3237 | 3179 |
| 3238 | 3180 |
| 3181 MaybeObject* KeyedLoadStubCompiler::CompileLoadMegamorphic( |
| 3182 MapList* receiver_maps, |
| 3183 CodeList* handler_ics) { |
| 3184 // ----------- S t a t e ------------- |
| 3185 // -- eax : key |
| 3186 // -- edx : receiver |
| 3187 // -- esp[0] : return address |
| 3188 // ----------------------------------- |
| 3189 Label miss; |
| 3190 __ JumpIfSmi(edx, &miss); |
| 3191 |
| 3192 Register map_reg = ebx; |
| 3193 __ mov(map_reg, FieldOperand(edx, HeapObject::kMapOffset)); |
| 3194 int receiver_count = receiver_maps->length(); |
| 3195 for (int current = 0; current < receiver_count; ++current) { |
| 3196 Handle<Map> map(receiver_maps->at(current)); |
| 3197 __ cmp(map_reg, map); |
| 3198 __ j(equal, Handle<Code>(handler_ics->at(current))); |
| 3199 } |
| 3200 |
| 3201 __ bind(&miss); |
| 3202 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); |
| 3203 |
| 3204 // Return the generated code. |
| 3205 return GetCode(NORMAL, NULL, MEGAMORPHIC); |
| 3206 } |
| 3207 |
| 3208 |
| 3239 // Specialized stub for constructing objects from functions which only have only | 3209 // Specialized stub for constructing objects from functions which only have only |
| 3240 // simple assignments of the form this.x = ...; in their body. | 3210 // simple assignments of the form this.x = ...; in their body. |
| 3241 MaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) { | 3211 MaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) { |
| 3242 // ----------- S t a t e ------------- | 3212 // ----------- S t a t e ------------- |
| 3243 // -- eax : argc | 3213 // -- eax : argc |
| 3244 // -- edi : constructor | 3214 // -- edi : constructor |
| 3245 // -- esp[0] : return address | 3215 // -- esp[0] : return address |
| 3246 // -- esp[4] : last argument | 3216 // -- esp[4] : last argument |
| 3247 // ----------------------------------- | 3217 // ----------------------------------- |
| 3248 Label generic_stub_call; | 3218 Label generic_stub_call; |
| 3249 #ifdef ENABLE_DEBUGGER_SUPPORT | 3219 #ifdef ENABLE_DEBUGGER_SUPPORT |
| 3250 // Check to see whether there are any break points in the function code. If | 3220 // Check to see whether there are any break points in the function code. If |
| 3251 // there are jump to the generic constructor stub which calls the actual | 3221 // there are jump to the generic constructor stub which calls the actual |
| 3252 // code for the function thereby hitting the break points. | 3222 // code for the function thereby hitting the break points. |
| 3253 __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); | 3223 __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); |
| 3254 __ mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kDebugInfoOffset)); | 3224 __ mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kDebugInfoOffset)); |
| 3255 __ cmp(ebx, factory()->undefined_value()); | 3225 __ cmp(ebx, factory()->undefined_value()); |
| 3256 __ j(not_equal, &generic_stub_call, not_taken); | 3226 __ j(not_equal, &generic_stub_call); |
| 3257 #endif | 3227 #endif |
| 3258 | 3228 |
| 3259 // Load the initial map and verify that it is in fact a map. | 3229 // Load the initial map and verify that it is in fact a map. |
| 3260 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset)); | 3230 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset)); |
| 3261 // Will both indicate a NULL and a Smi. | 3231 // Will both indicate a NULL and a Smi. |
| 3262 __ test(ebx, Immediate(kSmiTagMask)); | 3232 __ test(ebx, Immediate(kSmiTagMask)); |
| 3263 __ j(zero, &generic_stub_call); | 3233 __ j(zero, &generic_stub_call); |
| 3264 __ CmpObjectType(ebx, MAP_TYPE, ecx); | 3234 __ CmpObjectType(ebx, MAP_TYPE, ecx); |
| 3265 __ j(not_equal, &generic_stub_call); | 3235 __ j(not_equal, &generic_stub_call); |
| 3266 | 3236 |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3368 __ bind(&generic_stub_call); | 3338 __ bind(&generic_stub_call); |
| 3369 Handle<Code> generic_construct_stub = | 3339 Handle<Code> generic_construct_stub = |
| 3370 isolate()->builtins()->JSConstructStubGeneric(); | 3340 isolate()->builtins()->JSConstructStubGeneric(); |
| 3371 __ jmp(generic_construct_stub, RelocInfo::CODE_TARGET); | 3341 __ jmp(generic_construct_stub, RelocInfo::CODE_TARGET); |
| 3372 | 3342 |
| 3373 // Return the generated code. | 3343 // Return the generated code. |
| 3374 return GetCode(); | 3344 return GetCode(); |
| 3375 } | 3345 } |
| 3376 | 3346 |
| 3377 | 3347 |
| 3378 MaybeObject* ExternalArrayStubCompiler::CompileKeyedLoadStub( | 3348 MaybeObject* ExternalArrayLoadStubCompiler::CompileLoad( |
| 3379 JSObject*receiver, ExternalArrayType array_type, Code::Flags flags) { | 3349 JSObject*receiver, ExternalArrayType array_type) { |
| 3380 // ----------- S t a t e ------------- | 3350 // ----------- S t a t e ------------- |
| 3381 // -- eax : key | 3351 // -- eax : key |
| 3382 // -- edx : receiver | 3352 // -- edx : receiver |
| 3383 // -- esp[0] : return address | 3353 // -- esp[0] : return address |
| 3384 // ----------------------------------- | 3354 // ----------------------------------- |
| 3385 Label slow, failed_allocation; | 3355 MaybeObject* maybe_stub = |
| 3356 KeyedLoadExternalArrayStub(array_type).TryGetCode(); |
| 3357 Code* stub; |
| 3358 if (!maybe_stub->To(&stub)) return maybe_stub; |
| 3359 __ DispatchMap(edx, |
| 3360 Handle<Map>(receiver->map()), |
| 3361 Handle<Code>(stub), |
| 3362 DO_SMI_CHECK); |
| 3386 | 3363 |
| 3387 // Check that the object isn't a smi. | 3364 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Miss(); |
| 3388 __ test(edx, Immediate(kSmiTagMask)); | 3365 __ jmp(ic, RelocInfo::CODE_TARGET); |
| 3389 __ j(zero, &slow, not_taken); | 3366 |
| 3367 // Return the generated code. |
| 3368 return GetCode(); |
| 3369 } |
| 3370 |
| 3371 |
| 3372 MaybeObject* ExternalArrayStoreStubCompiler::CompileStore( |
| 3373 JSObject* receiver, ExternalArrayType array_type) { |
| 3374 // ----------- S t a t e ------------- |
| 3375 // -- eax : value |
| 3376 // -- ecx : key |
| 3377 // -- edx : receiver |
| 3378 // -- esp[0] : return address |
| 3379 // ----------------------------------- |
| 3380 MaybeObject* maybe_stub = |
| 3381 KeyedStoreExternalArrayStub(array_type).TryGetCode(); |
| 3382 Code* stub; |
| 3383 if (!maybe_stub->To(&stub)) return maybe_stub; |
| 3384 __ DispatchMap(edx, |
| 3385 Handle<Map>(receiver->map()), |
| 3386 Handle<Code>(stub), |
| 3387 DO_SMI_CHECK); |
| 3388 |
| 3389 Handle<Code> ic = isolate()->builtins()->KeyedStoreIC_Miss(); |
| 3390 __ jmp(ic, RelocInfo::CODE_TARGET); |
| 3391 |
| 3392 return GetCode(); |
| 3393 } |
| 3394 |
| 3395 |
| 3396 #undef __ |
| 3397 #define __ ACCESS_MASM(masm) |
| 3398 |
| 3399 |
| 3400 void KeyedLoadStubCompiler::GenerateLoadExternalArray( |
| 3401 MacroAssembler* masm, |
| 3402 ExternalArrayType array_type) { |
| 3403 // ----------- S t a t e ------------- |
| 3404 // -- eax : key |
| 3405 // -- edx : receiver |
| 3406 // -- esp[0] : return address |
| 3407 // ----------------------------------- |
| 3408 Label miss_force_generic, failed_allocation, slow; |
| 3409 |
| 3410 // This stub is meant to be tail-jumped to, the receiver must already |
| 3411 // have been verified by the caller to not be a smi. |
| 3390 | 3412 |
| 3391 // Check that the key is a smi. | 3413 // Check that the key is a smi. |
| 3392 __ test(eax, Immediate(kSmiTagMask)); | 3414 __ test(eax, Immediate(kSmiTagMask)); |
| 3393 __ j(not_zero, &slow, not_taken); | 3415 __ j(not_zero, &miss_force_generic); |
| 3394 | 3416 |
| 3395 // Check that the map matches. | |
| 3396 __ CheckMap(edx, Handle<Map>(receiver->map()), &slow, false); | |
| 3397 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset)); | |
| 3398 | |
| 3399 // eax: key, known to be a smi. | |
| 3400 // edx: receiver, known to be a JSObject. | |
| 3401 // ebx: elements object, known to be an external array. | |
| 3402 // Check that the index is in range. | 3417 // Check that the index is in range. |
| 3403 __ mov(ecx, eax); | 3418 __ mov(ecx, eax); |
| 3404 __ SmiUntag(ecx); // Untag the index. | 3419 __ SmiUntag(ecx); // Untag the index. |
| 3420 __ mov(ebx, FieldOperand(edx, JSObject::kElementsOffset)); |
| 3405 __ cmp(ecx, FieldOperand(ebx, ExternalArray::kLengthOffset)); | 3421 __ cmp(ecx, FieldOperand(ebx, ExternalArray::kLengthOffset)); |
| 3406 // Unsigned comparison catches both negative and too-large values. | 3422 // Unsigned comparison catches both negative and too-large values. |
| 3407 __ j(above_equal, &slow); | 3423 __ j(above_equal, &miss_force_generic); |
| 3408 __ mov(ebx, FieldOperand(ebx, ExternalArray::kExternalPointerOffset)); | 3424 __ mov(ebx, FieldOperand(ebx, ExternalArray::kExternalPointerOffset)); |
| 3409 // ebx: base pointer of external storage | 3425 // ebx: base pointer of external storage |
| 3410 switch (array_type) { | 3426 switch (array_type) { |
| 3411 case kExternalByteArray: | 3427 case kExternalByteArray: |
| 3412 __ movsx_b(eax, Operand(ebx, ecx, times_1, 0)); | 3428 __ movsx_b(eax, Operand(ebx, ecx, times_1, 0)); |
| 3413 break; | 3429 break; |
| 3414 case kExternalUnsignedByteArray: | 3430 case kExternalUnsignedByteArray: |
| 3415 case kExternalPixelArray: | 3431 case kExternalPixelArray: |
| 3416 __ movzx_b(eax, Operand(ebx, ecx, times_1, 0)); | 3432 __ movzx_b(eax, Operand(ebx, ecx, times_1, 0)); |
| 3417 break; | 3433 break; |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3504 | 3520 |
| 3505 // If we fail allocation of the HeapNumber, we still have a value on | 3521 // If we fail allocation of the HeapNumber, we still have a value on |
| 3506 // top of the FPU stack. Remove it. | 3522 // top of the FPU stack. Remove it. |
| 3507 __ bind(&failed_allocation); | 3523 __ bind(&failed_allocation); |
| 3508 __ ffree(); | 3524 __ ffree(); |
| 3509 __ fincstp(); | 3525 __ fincstp(); |
| 3510 // Fall through to slow case. | 3526 // Fall through to slow case. |
| 3511 | 3527 |
| 3512 // Slow case: Jump to runtime. | 3528 // Slow case: Jump to runtime. |
| 3513 __ bind(&slow); | 3529 __ bind(&slow); |
| 3514 Counters* counters = isolate()->counters(); | 3530 Counters* counters = masm->isolate()->counters(); |
| 3515 __ IncrementCounter(counters->keyed_load_external_array_slow(), 1); | 3531 __ IncrementCounter(counters->keyed_load_external_array_slow(), 1); |
| 3532 |
| 3516 // ----------- S t a t e ------------- | 3533 // ----------- S t a t e ------------- |
| 3517 // -- eax : key | 3534 // -- eax : key |
| 3518 // -- edx : receiver | 3535 // -- edx : receiver |
| 3519 // -- esp[0] : return address | 3536 // -- esp[0] : return address |
| 3520 // ----------------------------------- | 3537 // ----------------------------------- |
| 3521 | 3538 |
| 3522 __ pop(ebx); | 3539 Handle<Code> ic = masm->isolate()->builtins()->KeyedLoadIC_Slow(); |
| 3523 __ push(edx); // receiver | 3540 __ jmp(ic, RelocInfo::CODE_TARGET); |
| 3524 __ push(eax); // name | |
| 3525 __ push(ebx); // return address | |
| 3526 | 3541 |
| 3527 // Perform tail call to the entry. | 3542 // ----------- S t a t e ------------- |
| 3528 __ TailCallRuntime(Runtime::kKeyedGetProperty, 2, 1); | 3543 // -- eax : key |
| 3544 // -- edx : receiver |
| 3545 // -- esp[0] : return address |
| 3546 // ----------------------------------- |
| 3529 | 3547 |
| 3530 // Return the generated code. | 3548 // Miss case: Jump to runtime. |
| 3531 return GetCode(flags); | 3549 __ bind(&miss_force_generic); |
| 3550 Handle<Code> miss_ic = |
| 3551 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric(); |
| 3552 __ jmp(miss_ic, RelocInfo::CODE_TARGET); |
| 3532 } | 3553 } |
| 3533 | 3554 |
| 3534 | 3555 |
| 3535 MaybeObject* ExternalArrayStubCompiler::CompileKeyedStoreStub( | 3556 void KeyedStoreStubCompiler::GenerateStoreExternalArray( |
| 3536 JSObject* receiver, ExternalArrayType array_type, Code::Flags flags) { | 3557 MacroAssembler* masm, |
| 3558 ExternalArrayType array_type) { |
| 3537 // ----------- S t a t e ------------- | 3559 // ----------- S t a t e ------------- |
| 3538 // -- eax : value | 3560 // -- eax : key |
| 3539 // -- ecx : key | |
| 3540 // -- edx : receiver | 3561 // -- edx : receiver |
| 3541 // -- esp[0] : return address | 3562 // -- esp[0] : return address |
| 3542 // ----------------------------------- | 3563 // ----------------------------------- |
| 3543 Label slow, check_heap_number; | 3564 Label miss_force_generic, slow, check_heap_number; |
| 3544 | 3565 |
| 3545 // Check that the object isn't a smi. | 3566 // This stub is meant to be tail-jumped to, the receiver must already |
| 3546 __ test(edx, Immediate(kSmiTagMask)); | 3567 // have been verified by the caller to not be a smi. |
| 3547 __ j(zero, &slow); | |
| 3548 | |
| 3549 // Check that the map matches. | |
| 3550 __ CheckMap(edx, Handle<Map>(receiver->map()), &slow, false); | |
| 3551 | 3568 |
| 3552 // Check that the key is a smi. | 3569 // Check that the key is a smi. |
| 3553 __ test(ecx, Immediate(kSmiTagMask)); | 3570 __ test(ecx, Immediate(kSmiTagMask)); |
| 3554 __ j(not_zero, &slow); | 3571 __ j(not_zero, &miss_force_generic); |
| 3555 | 3572 |
| 3556 // Check that the index is in range. | 3573 // Check that the index is in range. |
| 3557 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset)); | 3574 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset)); |
| 3558 __ mov(ebx, ecx); | 3575 __ mov(ebx, ecx); |
| 3559 __ SmiUntag(ebx); | 3576 __ SmiUntag(ebx); |
| 3560 __ cmp(ebx, FieldOperand(edi, ExternalArray::kLengthOffset)); | 3577 __ cmp(ebx, FieldOperand(edi, ExternalArray::kLengthOffset)); |
| 3561 // Unsigned comparison catches both negative and too-large values. | 3578 // Unsigned comparison catches both negative and too-large values. |
| 3562 __ j(above_equal, &slow); | 3579 __ j(above_equal, &slow); |
| 3563 | 3580 |
| 3564 // Handle both smis and HeapNumbers in the fast path. Go to the | 3581 // Handle both smis and HeapNumbers in the fast path. Go to the |
| (...skipping 10 matching lines...) Expand all Loading... |
| 3575 __ j(not_equal, &check_heap_number); | 3592 __ j(not_equal, &check_heap_number); |
| 3576 | 3593 |
| 3577 // smi case | 3594 // smi case |
| 3578 __ mov(ecx, eax); // Preserve the value in eax. Key is no longer needed. | 3595 __ mov(ecx, eax); // Preserve the value in eax. Key is no longer needed. |
| 3579 __ SmiUntag(ecx); | 3596 __ SmiUntag(ecx); |
| 3580 __ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset)); | 3597 __ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset)); |
| 3581 // ecx: base pointer of external storage | 3598 // ecx: base pointer of external storage |
| 3582 switch (array_type) { | 3599 switch (array_type) { |
| 3583 case kExternalPixelArray: | 3600 case kExternalPixelArray: |
| 3584 { // Clamp the value to [0..255]. | 3601 { // Clamp the value to [0..255]. |
| 3585 NearLabel done; | 3602 Label done; |
| 3586 __ test(ecx, Immediate(0xFFFFFF00)); | 3603 __ test(ecx, Immediate(0xFFFFFF00)); |
| 3587 __ j(zero, &done); | 3604 __ j(zero, &done, Label::kNear); |
| 3588 __ setcc(negative, ecx); // 1 if negative, 0 if positive. | 3605 __ setcc(negative, ecx); // 1 if negative, 0 if positive. |
| 3589 __ dec_b(ecx); // 0 if negative, 255 if positive. | 3606 __ dec_b(ecx); // 0 if negative, 255 if positive. |
| 3590 __ bind(&done); | 3607 __ bind(&done); |
| 3591 } | 3608 } |
| 3592 __ mov_b(Operand(edi, ebx, times_1, 0), ecx); | 3609 __ mov_b(Operand(edi, ebx, times_1, 0), ecx); |
| 3593 break; | 3610 break; |
| 3594 case kExternalByteArray: | 3611 case kExternalByteArray: |
| 3595 case kExternalUnsignedByteArray: | 3612 case kExternalUnsignedByteArray: |
| 3596 __ mov_b(Operand(edi, ebx, times_1, 0), ecx); | 3613 __ mov_b(Operand(edi, ebx, times_1, 0), ecx); |
| 3597 break; | 3614 break; |
| (...skipping 25 matching lines...) Expand all Loading... |
| 3623 | 3640 |
| 3624 // TODO(danno): handle heap number -> pixel array conversion | 3641 // TODO(danno): handle heap number -> pixel array conversion |
| 3625 if (array_type != kExternalPixelArray) { | 3642 if (array_type != kExternalPixelArray) { |
| 3626 __ bind(&check_heap_number); | 3643 __ bind(&check_heap_number); |
| 3627 // eax: value | 3644 // eax: value |
| 3628 // edx: receiver | 3645 // edx: receiver |
| 3629 // ecx: key | 3646 // ecx: key |
| 3630 // edi: elements array | 3647 // edi: elements array |
| 3631 // ebx: untagged index | 3648 // ebx: untagged index |
| 3632 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), | 3649 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), |
| 3633 Immediate(factory()->heap_number_map())); | 3650 Immediate(masm->isolate()->factory()->heap_number_map())); |
| 3634 __ j(not_equal, &slow); | 3651 __ j(not_equal, &slow); |
| 3635 | 3652 |
| 3636 // The WebGL specification leaves the behavior of storing NaN and | 3653 // The WebGL specification leaves the behavior of storing NaN and |
| 3637 // +/-Infinity into integer arrays basically undefined. For more | 3654 // +/-Infinity into integer arrays basically undefined. For more |
| 3638 // reproducible behavior, convert these to zero. | 3655 // reproducible behavior, convert these to zero. |
| 3639 __ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset)); | 3656 __ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset)); |
| 3640 // ebx: untagged index | 3657 // ebx: untagged index |
| 3641 // edi: base pointer of external storage | 3658 // edi: base pointer of external storage |
| 3642 if (array_type == kExternalFloatArray) { | 3659 if (array_type == kExternalFloatArray) { |
| 3643 __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); | 3660 __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 3658 if (CpuFeatures::IsSupported(SSE2)) { | 3675 if (CpuFeatures::IsSupported(SSE2)) { |
| 3659 if (array_type != kExternalIntArray && | 3676 if (array_type != kExternalIntArray && |
| 3660 array_type != kExternalUnsignedIntArray) { | 3677 array_type != kExternalUnsignedIntArray) { |
| 3661 ASSERT(CpuFeatures::IsSupported(SSE2)); | 3678 ASSERT(CpuFeatures::IsSupported(SSE2)); |
| 3662 CpuFeatures::Scope scope(SSE2); | 3679 CpuFeatures::Scope scope(SSE2); |
| 3663 __ cvttsd2si(ecx, FieldOperand(eax, HeapNumber::kValueOffset)); | 3680 __ cvttsd2si(ecx, FieldOperand(eax, HeapNumber::kValueOffset)); |
| 3664 // ecx: untagged integer value | 3681 // ecx: untagged integer value |
| 3665 switch (array_type) { | 3682 switch (array_type) { |
| 3666 case kExternalPixelArray: | 3683 case kExternalPixelArray: |
| 3667 { // Clamp the value to [0..255]. | 3684 { // Clamp the value to [0..255]. |
| 3668 NearLabel done; | 3685 Label done; |
| 3669 __ test(ecx, Immediate(0xFFFFFF00)); | 3686 __ test(ecx, Immediate(0xFFFFFF00)); |
| 3670 __ j(zero, &done); | 3687 __ j(zero, &done, Label::kNear); |
| 3671 __ setcc(negative, ecx); // 1 if negative, 0 if positive. | 3688 __ setcc(negative, ecx); // 1 if negative, 0 if positive. |
| 3672 __ dec_b(ecx); // 0 if negative, 255 if positive. | 3689 __ dec_b(ecx); // 0 if negative, 255 if positive. |
| 3673 __ bind(&done); | 3690 __ bind(&done); |
| 3674 } | 3691 } |
| 3675 __ mov_b(Operand(edi, ebx, times_1, 0), ecx); | 3692 __ mov_b(Operand(edi, ebx, times_1, 0), ecx); |
| 3676 break; | 3693 break; |
| 3677 case kExternalByteArray: | 3694 case kExternalByteArray: |
| 3678 case kExternalUnsignedByteArray: | 3695 case kExternalUnsignedByteArray: |
| 3679 __ mov_b(Operand(edi, ebx, times_1, 0), ecx); | 3696 __ mov_b(Operand(edi, ebx, times_1, 0), ecx); |
| 3680 break; | 3697 break; |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3718 // ecx: untagged integer value | 3735 // ecx: untagged integer value |
| 3719 __ mov(Operand(edi, ebx, times_4, 0), ecx); | 3736 __ mov(Operand(edi, ebx, times_4, 0), ecx); |
| 3720 } | 3737 } |
| 3721 __ ret(0); // Return original value. | 3738 __ ret(0); // Return original value. |
| 3722 } | 3739 } |
| 3723 } | 3740 } |
| 3724 } | 3741 } |
| 3725 | 3742 |
| 3726 // Slow case: call runtime. | 3743 // Slow case: call runtime. |
| 3727 __ bind(&slow); | 3744 __ bind(&slow); |
| 3745 Counters* counters = masm->isolate()->counters(); |
| 3746 __ IncrementCounter(counters->keyed_store_external_array_slow(), 1); |
| 3747 |
| 3728 // ----------- S t a t e ------------- | 3748 // ----------- S t a t e ------------- |
| 3729 // -- eax : value | 3749 // -- eax : value |
| 3730 // -- ecx : key | 3750 // -- ecx : key |
| 3731 // -- edx : receiver | 3751 // -- edx : receiver |
| 3732 // -- esp[0] : return address | 3752 // -- esp[0] : return address |
| 3733 // ----------------------------------- | 3753 // ----------------------------------- |
| 3734 | 3754 |
| 3735 __ pop(ebx); | 3755 Handle<Code> ic = masm->isolate()->builtins()->KeyedStoreIC_Slow(); |
| 3736 __ push(edx); | 3756 __ jmp(ic, RelocInfo::CODE_TARGET); |
| 3737 __ push(ecx); | |
| 3738 __ push(eax); | |
| 3739 __ push(Immediate(Smi::FromInt(NONE))); // PropertyAttributes | |
| 3740 __ push(Immediate(Smi::FromInt( | |
| 3741 Code::ExtractExtraICStateFromFlags(flags) & kStrictMode))); | |
| 3742 __ push(ebx); // return address | |
| 3743 | 3757 |
| 3744 // Do tail-call to runtime routine. | 3758 // ----------- S t a t e ------------- |
| 3745 __ TailCallRuntime(Runtime::kSetProperty, 5, 1); | 3759 // -- eax : value |
| 3760 // -- ecx : key |
| 3761 // -- edx : receiver |
| 3762 // -- esp[0] : return address |
| 3763 // ----------------------------------- |
| 3746 | 3764 |
| 3747 return GetCode(flags); | 3765 __ bind(&miss_force_generic); |
| 3766 Handle<Code> miss_ic = |
| 3767 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric(); |
| 3768 __ jmp(miss_ic, RelocInfo::CODE_TARGET); |
| 3769 } |
| 3770 |
| 3771 |
| 3772 |
| 3773 |
| 3774 void KeyedLoadStubCompiler::GenerateLoadFastElement(MacroAssembler* masm) { |
| 3775 // ----------- S t a t e ------------- |
| 3776 // -- eax : key |
| 3777 // -- edx : receiver |
| 3778 // -- esp[0] : return address |
| 3779 // ----------------------------------- |
| 3780 Label miss_force_generic; |
| 3781 |
| 3782 // This stub is meant to be tail-jumped to, the receiver must already |
| 3783 // have been verified by the caller to not be a smi. |
| 3784 |
| 3785 // Check that the key is a smi. |
| 3786 __ test(eax, Immediate(kSmiTagMask)); |
| 3787 __ j(not_zero, &miss_force_generic); |
| 3788 |
| 3789 // Get the elements array. |
| 3790 __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset)); |
| 3791 __ AssertFastElements(ecx); |
| 3792 |
| 3793 // Check that the key is within bounds. |
| 3794 __ cmp(eax, FieldOperand(ecx, FixedArray::kLengthOffset)); |
| 3795 __ j(above_equal, &miss_force_generic); |
| 3796 |
| 3797 // Load the result and make sure it's not the hole. |
| 3798 __ mov(ebx, Operand(ecx, eax, times_2, |
| 3799 FixedArray::kHeaderSize - kHeapObjectTag)); |
| 3800 __ cmp(ebx, masm->isolate()->factory()->the_hole_value()); |
| 3801 __ j(equal, &miss_force_generic); |
| 3802 __ mov(eax, ebx); |
| 3803 __ ret(0); |
| 3804 |
| 3805 __ bind(&miss_force_generic); |
| 3806 Handle<Code> miss_ic = |
| 3807 masm->isolate()->builtins()->KeyedLoadIC_MissForceGeneric(); |
| 3808 __ jmp(miss_ic, RelocInfo::CODE_TARGET); |
| 3809 } |
| 3810 |
| 3811 |
| 3812 void KeyedStoreStubCompiler::GenerateStoreFastElement(MacroAssembler* masm, |
| 3813 bool is_js_array) { |
| 3814 // ----------- S t a t e ------------- |
| 3815 // -- eax : key |
| 3816 // -- edx : receiver |
| 3817 // -- esp[0] : return address |
| 3818 // ----------------------------------- |
| 3819 Label miss_force_generic; |
| 3820 |
| 3821 // This stub is meant to be tail-jumped to, the receiver must already |
| 3822 // have been verified by the caller to not be a smi. |
| 3823 |
| 3824 // Check that the key is a smi. |
| 3825 __ test(ecx, Immediate(kSmiTagMask)); |
| 3826 __ j(not_zero, &miss_force_generic); |
| 3827 |
| 3828 // Get the elements array and make sure it is a fast element array, not 'cow'. |
| 3829 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset)); |
| 3830 __ cmp(FieldOperand(edi, HeapObject::kMapOffset), |
| 3831 Immediate(masm->isolate()->factory()->fixed_array_map())); |
| 3832 __ j(not_equal, &miss_force_generic); |
| 3833 |
| 3834 if (is_js_array) { |
| 3835 // Check that the key is within bounds. |
| 3836 __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset)); // smis. |
| 3837 __ j(above_equal, &miss_force_generic); |
| 3838 } else { |
| 3839 // Check that the key is within bounds. |
| 3840 __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset)); // smis. |
| 3841 __ j(above_equal, &miss_force_generic); |
| 3842 } |
| 3843 |
| 3844 // Do the store and update the write barrier. |
| 3845 __ lea(ecx, FieldOperand(edi, ecx, times_2, FixedArray::kHeaderSize)); |
| 3846 __ mov(Operand(ecx, 0), eax); |
| 3847 // Make sure to preserve the value in register eax. |
| 3848 __ mov(edx, Operand(eax)); |
| 3849 __ RecordWrite(edi, ecx, edx, kDontSaveFPRegs); |
| 3850 |
| 3851 // Done. |
| 3852 __ ret(0); |
| 3853 |
| 3854 // Handle store cache miss, replacing the ic with the generic stub. |
| 3855 __ bind(&miss_force_generic); |
| 3856 Handle<Code> ic_force_generic = |
| 3857 masm->isolate()->builtins()->KeyedStoreIC_MissForceGeneric(); |
| 3858 __ jmp(ic_force_generic, RelocInfo::CODE_TARGET); |
| 3748 } | 3859 } |
| 3749 | 3860 |
| 3750 | 3861 |
| 3751 #undef __ | 3862 #undef __ |
| 3752 | 3863 |
| 3753 } } // namespace v8::internal | 3864 } } // namespace v8::internal |
| 3754 | 3865 |
| 3755 #endif // V8_TARGET_ARCH_IA32 | 3866 #endif // V8_TARGET_ARCH_IA32 |
| OLD | NEW |