| OLD | NEW |
| 1 // Copyright 2006-2009 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2009 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 21 matching lines...) Expand all Loading... |
| 32 #include "ic-inl.h" | 32 #include "ic-inl.h" |
| 33 #include "codegen-inl.h" | 33 #include "codegen-inl.h" |
| 34 #include "stub-cache.h" | 34 #include "stub-cache.h" |
| 35 | 35 |
| 36 namespace v8 { | 36 namespace v8 { |
| 37 namespace internal { | 37 namespace internal { |
| 38 | 38 |
| 39 #define __ ACCESS_MASM(masm) | 39 #define __ ACCESS_MASM(masm) |
| 40 | 40 |
| 41 | 41 |
| 42 static void ProbeTable(MacroAssembler* masm, | 42 static void ProbeTable(Isolate* isolate, |
| 43 MacroAssembler* masm, |
| 43 Code::Flags flags, | 44 Code::Flags flags, |
| 44 StubCache::Table table, | 45 StubCache::Table table, |
| 45 Register name, | 46 Register name, |
| 46 Register offset, | 47 Register offset, |
| 47 Register extra) { | 48 Register extra) { |
| 48 ExternalReference key_offset(SCTableReference::keyReference(table)); | 49 ExternalReference key_offset(isolate->stub_cache()->key_reference(table)); |
| 49 ExternalReference value_offset(SCTableReference::valueReference(table)); | 50 ExternalReference value_offset(isolate->stub_cache()->value_reference(table)); |
| 50 | 51 |
| 51 Label miss; | 52 Label miss; |
| 52 | 53 |
| 53 if (extra.is_valid()) { | 54 if (extra.is_valid()) { |
| 54 // Get the code entry from the cache. | 55 // Get the code entry from the cache. |
| 55 __ mov(extra, Operand::StaticArray(offset, times_2, value_offset)); | 56 __ mov(extra, Operand::StaticArray(offset, times_2, value_offset)); |
| 56 | 57 |
| 57 // Check that the key in the entry matches the name. | 58 // Check that the key in the entry matches the name. |
| 58 __ cmp(name, Operand::StaticArray(offset, times_2, key_offset)); | 59 __ cmp(name, Operand::StaticArray(offset, times_2, key_offset)); |
| 59 __ j(not_equal, &miss, not_taken); | 60 __ j(not_equal, &miss, not_taken); |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 106 // must always call a backup property check that is complete. | 107 // must always call a backup property check that is complete. |
| 107 // 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. |
| 108 // 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. |
| 109 static void GenerateDictionaryNegativeLookup(MacroAssembler* masm, | 110 static void GenerateDictionaryNegativeLookup(MacroAssembler* masm, |
| 110 Label* miss_label, | 111 Label* miss_label, |
| 111 Register receiver, | 112 Register receiver, |
| 112 String* name, | 113 String* name, |
| 113 Register r0, | 114 Register r0, |
| 114 Register r1) { | 115 Register r1) { |
| 115 ASSERT(name->IsSymbol()); | 116 ASSERT(name->IsSymbol()); |
| 116 __ IncrementCounter(&Counters::negative_lookups, 1); | 117 __ IncrementCounter(COUNTERS->negative_lookups(), 1); |
| 117 __ IncrementCounter(&Counters::negative_lookups_miss, 1); | 118 __ IncrementCounter(COUNTERS->negative_lookups_miss(), 1); |
| 118 | 119 |
| 119 Label done; | 120 Label done; |
| 120 __ mov(r0, FieldOperand(receiver, HeapObject::kMapOffset)); | 121 __ mov(r0, FieldOperand(receiver, HeapObject::kMapOffset)); |
| 121 | 122 |
| 122 const int kInterceptorOrAccessCheckNeededMask = | 123 const int kInterceptorOrAccessCheckNeededMask = |
| 123 (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded); | 124 (1 << Map::kHasNamedInterceptor) | (1 << Map::kIsAccessCheckNeeded); |
| 124 | 125 |
| 125 // 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. |
| 126 __ test_b(FieldOperand(r0, Map::kBitFieldOffset), | 127 __ test_b(FieldOperand(r0, Map::kBitFieldOffset), |
| 127 kInterceptorOrAccessCheckNeededMask); | 128 kInterceptorOrAccessCheckNeededMask); |
| 128 __ j(not_zero, miss_label, not_taken); | 129 __ j(not_zero, miss_label, not_taken); |
| 129 | 130 |
| 130 // Check that receiver is a JSObject. | 131 // Check that receiver is a JSObject. |
| 131 __ CmpInstanceType(r0, FIRST_JS_OBJECT_TYPE); | 132 __ CmpInstanceType(r0, FIRST_JS_OBJECT_TYPE); |
| 132 __ j(below, miss_label, not_taken); | 133 __ j(below, miss_label, not_taken); |
| 133 | 134 |
| 134 // Load properties array. | 135 // Load properties array. |
| 135 Register properties = r0; | 136 Register properties = r0; |
| 136 __ mov(properties, FieldOperand(receiver, JSObject::kPropertiesOffset)); | 137 __ mov(properties, FieldOperand(receiver, JSObject::kPropertiesOffset)); |
| 137 | 138 |
| 138 // Check that the properties array is a dictionary. | 139 // Check that the properties array is a dictionary. |
| 139 __ cmp(FieldOperand(properties, HeapObject::kMapOffset), | 140 __ cmp(FieldOperand(properties, HeapObject::kMapOffset), |
| 140 Immediate(Factory::hash_table_map())); | 141 Immediate(FACTORY->hash_table_map())); |
| 141 __ j(not_equal, miss_label); | 142 __ j(not_equal, miss_label); |
| 142 | 143 |
| 143 // Compute the capacity mask. | 144 // Compute the capacity mask. |
| 144 const int kCapacityOffset = | 145 const int kCapacityOffset = |
| 145 StringDictionary::kHeaderSize + | 146 StringDictionary::kHeaderSize + |
| 146 StringDictionary::kCapacityIndex * kPointerSize; | 147 StringDictionary::kCapacityIndex * kPointerSize; |
| 147 | 148 |
| 148 // Generate an unrolled loop that performs a few probes before | 149 // Generate an unrolled loop that performs a few probes before |
| 149 // giving up. | 150 // giving up. |
| 150 static const int kProbes = 4; | 151 static const int kProbes = 4; |
| (...skipping 19 matching lines...) Expand all Loading... |
| 170 | 171 |
| 171 // Scale the index by multiplying by the entry size. | 172 // Scale the index by multiplying by the entry size. |
| 172 ASSERT(StringDictionary::kEntrySize == 3); | 173 ASSERT(StringDictionary::kEntrySize == 3); |
| 173 __ lea(index, Operand(index, index, times_2, 0)); // index *= 3. | 174 __ lea(index, Operand(index, index, times_2, 0)); // index *= 3. |
| 174 | 175 |
| 175 Register entity_name = r1; | 176 Register entity_name = r1; |
| 176 // Having undefined at this place means the name is not contained. | 177 // Having undefined at this place means the name is not contained. |
| 177 ASSERT_EQ(kSmiTagSize, 1); | 178 ASSERT_EQ(kSmiTagSize, 1); |
| 178 __ mov(entity_name, Operand(properties, index, times_half_pointer_size, | 179 __ mov(entity_name, Operand(properties, index, times_half_pointer_size, |
| 179 kElementsStartOffset - kHeapObjectTag)); | 180 kElementsStartOffset - kHeapObjectTag)); |
| 180 __ cmp(entity_name, Factory::undefined_value()); | 181 __ cmp(entity_name, FACTORY->undefined_value()); |
| 181 if (i != kProbes - 1) { | 182 if (i != kProbes - 1) { |
| 182 __ j(equal, &done, taken); | 183 __ j(equal, &done, taken); |
| 183 | 184 |
| 184 // Stop if found the property. | 185 // Stop if found the property. |
| 185 __ cmp(entity_name, Handle<String>(name)); | 186 __ cmp(entity_name, Handle<String>(name)); |
| 186 __ j(equal, miss_label, not_taken); | 187 __ j(equal, miss_label, not_taken); |
| 187 | 188 |
| 188 // Check if the entry name is not a symbol. | 189 // Check if the entry name is not a symbol. |
| 189 __ mov(entity_name, FieldOperand(entity_name, HeapObject::kMapOffset)); | 190 __ mov(entity_name, FieldOperand(entity_name, HeapObject::kMapOffset)); |
| 190 __ test_b(FieldOperand(entity_name, Map::kInstanceTypeOffset), | 191 __ test_b(FieldOperand(entity_name, Map::kInstanceTypeOffset), |
| 191 kIsSymbolMask); | 192 kIsSymbolMask); |
| 192 __ j(zero, miss_label, not_taken); | 193 __ j(zero, miss_label, not_taken); |
| 193 } else { | 194 } else { |
| 194 // Give up probing if still not found the undefined value. | 195 // Give up probing if still not found the undefined value. |
| 195 __ j(not_equal, miss_label, not_taken); | 196 __ j(not_equal, miss_label, not_taken); |
| 196 } | 197 } |
| 197 } | 198 } |
| 198 | 199 |
| 199 __ bind(&done); | 200 __ bind(&done); |
| 200 __ DecrementCounter(&Counters::negative_lookups_miss, 1); | 201 __ DecrementCounter(COUNTERS->negative_lookups_miss(), 1); |
| 201 } | 202 } |
| 202 | 203 |
| 203 | 204 |
| 204 void StubCache::GenerateProbe(MacroAssembler* masm, | 205 void StubCache::GenerateProbe(MacroAssembler* masm, |
| 205 Code::Flags flags, | 206 Code::Flags flags, |
| 206 Register receiver, | 207 Register receiver, |
| 207 Register name, | 208 Register name, |
| 208 Register scratch, | 209 Register scratch, |
| 209 Register extra, | 210 Register extra, |
| 210 Register extra2) { | 211 Register extra2) { |
| 212 Isolate* isolate = Isolate::Current(); |
| 211 Label miss; | 213 Label miss; |
| 212 USE(extra2); // The register extra2 is not used on the ia32 platform. | 214 USE(extra2); // The register extra2 is not used on the ia32 platform. |
| 213 | 215 |
| 214 // Make sure that code is valid. The shifting code relies on the | 216 // Make sure that code is valid. The shifting code relies on the |
| 215 // entry size being 8. | 217 // entry size being 8. |
| 216 ASSERT(sizeof(Entry) == 8); | 218 ASSERT(sizeof(Entry) == 8); |
| 217 | 219 |
| 218 // Make sure the flags does not name a specific type. | 220 // Make sure the flags does not name a specific type. |
| 219 ASSERT(Code::ExtractTypeFromFlags(flags) == 0); | 221 ASSERT(Code::ExtractTypeFromFlags(flags) == 0); |
| 220 | 222 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 233 __ test(receiver, Immediate(kSmiTagMask)); | 235 __ test(receiver, Immediate(kSmiTagMask)); |
| 234 __ j(zero, &miss, not_taken); | 236 __ j(zero, &miss, not_taken); |
| 235 | 237 |
| 236 // Get the map of the receiver and compute the hash. | 238 // Get the map of the receiver and compute the hash. |
| 237 __ mov(scratch, FieldOperand(name, String::kHashFieldOffset)); | 239 __ mov(scratch, FieldOperand(name, String::kHashFieldOffset)); |
| 238 __ add(scratch, FieldOperand(receiver, HeapObject::kMapOffset)); | 240 __ add(scratch, FieldOperand(receiver, HeapObject::kMapOffset)); |
| 239 __ xor_(scratch, flags); | 241 __ xor_(scratch, flags); |
| 240 __ and_(scratch, (kPrimaryTableSize - 1) << kHeapObjectTagSize); | 242 __ and_(scratch, (kPrimaryTableSize - 1) << kHeapObjectTagSize); |
| 241 | 243 |
| 242 // Probe the primary table. | 244 // Probe the primary table. |
| 243 ProbeTable(masm, flags, kPrimary, name, scratch, extra); | 245 ProbeTable(isolate, masm, flags, kPrimary, name, scratch, extra); |
| 244 | 246 |
| 245 // Primary miss: Compute hash for secondary probe. | 247 // Primary miss: Compute hash for secondary probe. |
| 246 __ mov(scratch, FieldOperand(name, String::kHashFieldOffset)); | 248 __ mov(scratch, FieldOperand(name, String::kHashFieldOffset)); |
| 247 __ add(scratch, FieldOperand(receiver, HeapObject::kMapOffset)); | 249 __ add(scratch, FieldOperand(receiver, HeapObject::kMapOffset)); |
| 248 __ xor_(scratch, flags); | 250 __ xor_(scratch, flags); |
| 249 __ and_(scratch, (kPrimaryTableSize - 1) << kHeapObjectTagSize); | 251 __ and_(scratch, (kPrimaryTableSize - 1) << kHeapObjectTagSize); |
| 250 __ sub(scratch, Operand(name)); | 252 __ sub(scratch, Operand(name)); |
| 251 __ add(Operand(scratch), Immediate(flags)); | 253 __ add(Operand(scratch), Immediate(flags)); |
| 252 __ and_(scratch, (kSecondaryTableSize - 1) << kHeapObjectTagSize); | 254 __ and_(scratch, (kSecondaryTableSize - 1) << kHeapObjectTagSize); |
| 253 | 255 |
| 254 // Probe the secondary table. | 256 // Probe the secondary table. |
| 255 ProbeTable(masm, flags, kSecondary, name, scratch, extra); | 257 ProbeTable(isolate, masm, flags, kSecondary, name, scratch, extra); |
| 256 | 258 |
| 257 // Cache miss: Fall-through and let caller handle the miss by | 259 // Cache miss: Fall-through and let caller handle the miss by |
| 258 // entering the runtime system. | 260 // entering the runtime system. |
| 259 __ bind(&miss); | 261 __ bind(&miss); |
| 260 } | 262 } |
| 261 | 263 |
| 262 | 264 |
| 263 void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm, | 265 void StubCompiler::GenerateLoadGlobalFunctionPrototype(MacroAssembler* masm, |
| 264 int index, | 266 int index, |
| 265 Register prototype) { | 267 Register prototype) { |
| 266 __ LoadGlobalFunction(index, prototype); | 268 __ LoadGlobalFunction(index, prototype); |
| 267 __ LoadGlobalFunctionInitialMap(prototype, prototype); | 269 __ LoadGlobalFunctionInitialMap(prototype, prototype); |
| 268 // Load the prototype from the initial map. | 270 // Load the prototype from the initial map. |
| 269 __ mov(prototype, FieldOperand(prototype, Map::kPrototypeOffset)); | 271 __ mov(prototype, FieldOperand(prototype, Map::kPrototypeOffset)); |
| 270 } | 272 } |
| 271 | 273 |
| 272 | 274 |
| 273 void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype( | 275 void StubCompiler::GenerateDirectLoadGlobalFunctionPrototype( |
| 274 MacroAssembler* masm, int index, Register prototype, Label* miss) { | 276 MacroAssembler* masm, int index, Register prototype, Label* miss) { |
| 275 // Check we're still in the same context. | 277 // Check we're still in the same context. |
| 276 __ cmp(Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)), | 278 __ cmp(Operand(esi, Context::SlotOffset(Context::GLOBAL_INDEX)), |
| 277 Top::global()); | 279 Isolate::Current()->global()); |
| 278 __ j(not_equal, miss); | 280 __ j(not_equal, miss); |
| 279 // Get the global function with the given index. | 281 // Get the global function with the given index. |
| 280 JSFunction* function = JSFunction::cast(Top::global_context()->get(index)); | 282 JSFunction* function = JSFunction::cast( |
| 283 Isolate::Current()->global_context()->get(index)); |
| 281 // Load its initial map. The global functions all have initial maps. | 284 // Load its initial map. The global functions all have initial maps. |
| 282 __ Set(prototype, Immediate(Handle<Map>(function->initial_map()))); | 285 __ Set(prototype, Immediate(Handle<Map>(function->initial_map()))); |
| 283 // Load the prototype from the initial map. | 286 // Load the prototype from the initial map. |
| 284 __ mov(prototype, FieldOperand(prototype, Map::kPrototypeOffset)); | 287 __ mov(prototype, FieldOperand(prototype, Map::kPrototypeOffset)); |
| 285 } | 288 } |
| 286 | 289 |
| 287 | 290 |
| 288 void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm, | 291 void StubCompiler::GenerateLoadArrayLength(MacroAssembler* masm, |
| 289 Register receiver, | 292 Register receiver, |
| 290 Register scratch, | 293 Register scratch, |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 388 } | 391 } |
| 389 | 392 |
| 390 | 393 |
| 391 static void PushInterceptorArguments(MacroAssembler* masm, | 394 static void PushInterceptorArguments(MacroAssembler* masm, |
| 392 Register receiver, | 395 Register receiver, |
| 393 Register holder, | 396 Register holder, |
| 394 Register name, | 397 Register name, |
| 395 JSObject* holder_obj) { | 398 JSObject* holder_obj) { |
| 396 __ push(name); | 399 __ push(name); |
| 397 InterceptorInfo* interceptor = holder_obj->GetNamedInterceptor(); | 400 InterceptorInfo* interceptor = holder_obj->GetNamedInterceptor(); |
| 398 ASSERT(!Heap::InNewSpace(interceptor)); | 401 ASSERT(!HEAP->InNewSpace(interceptor)); |
| 399 Register scratch = name; | 402 Register scratch = name; |
| 400 __ mov(scratch, Immediate(Handle<Object>(interceptor))); | 403 __ mov(scratch, Immediate(Handle<Object>(interceptor))); |
| 401 __ push(scratch); | 404 __ push(scratch); |
| 402 __ push(receiver); | 405 __ push(receiver); |
| 403 __ push(holder); | 406 __ push(holder); |
| 404 __ push(FieldOperand(scratch, InterceptorInfo::kDataOffset)); | 407 __ push(FieldOperand(scratch, InterceptorInfo::kDataOffset)); |
| 405 } | 408 } |
| 406 | 409 |
| 407 | 410 |
| 408 static void CompileCallLoadPropertyWithInterceptor(MacroAssembler* masm, | 411 static void CompileCallLoadPropertyWithInterceptor(MacroAssembler* masm, |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 473 // ----------------------------------- | 476 // ----------------------------------- |
| 474 // Get the function and setup the context. | 477 // Get the function and setup the context. |
| 475 JSFunction* function = optimization.constant_function(); | 478 JSFunction* function = optimization.constant_function(); |
| 476 __ mov(edi, Immediate(Handle<JSFunction>(function))); | 479 __ mov(edi, Immediate(Handle<JSFunction>(function))); |
| 477 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); | 480 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); |
| 478 | 481 |
| 479 // Pass the additional arguments. | 482 // Pass the additional arguments. |
| 480 __ mov(Operand(esp, 2 * kPointerSize), edi); | 483 __ mov(Operand(esp, 2 * kPointerSize), edi); |
| 481 Object* call_data = optimization.api_call_info()->data(); | 484 Object* call_data = optimization.api_call_info()->data(); |
| 482 Handle<CallHandlerInfo> api_call_info_handle(optimization.api_call_info()); | 485 Handle<CallHandlerInfo> api_call_info_handle(optimization.api_call_info()); |
| 483 if (Heap::InNewSpace(call_data)) { | 486 if (HEAP->InNewSpace(call_data)) { |
| 484 __ mov(ecx, api_call_info_handle); | 487 __ mov(ecx, api_call_info_handle); |
| 485 __ mov(ebx, FieldOperand(ecx, CallHandlerInfo::kDataOffset)); | 488 __ mov(ebx, FieldOperand(ecx, CallHandlerInfo::kDataOffset)); |
| 486 __ mov(Operand(esp, 3 * kPointerSize), ebx); | 489 __ mov(Operand(esp, 3 * kPointerSize), ebx); |
| 487 } else { | 490 } else { |
| 488 __ mov(Operand(esp, 3 * kPointerSize), | 491 __ mov(Operand(esp, 3 * kPointerSize), |
| 489 Immediate(Handle<Object>(call_data))); | 492 Immediate(Handle<Object>(call_data))); |
| 490 } | 493 } |
| 491 | 494 |
| 492 // Prepare arguments. | 495 // Prepare arguments. |
| 493 __ lea(eax, Operand(esp, 3 * kPointerSize)); | 496 __ lea(eax, Operand(esp, 3 * kPointerSize)); |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 567 } else { | 570 } else { |
| 568 CompileRegular(masm, | 571 CompileRegular(masm, |
| 569 object, | 572 object, |
| 570 receiver, | 573 receiver, |
| 571 scratch1, | 574 scratch1, |
| 572 scratch2, | 575 scratch2, |
| 573 scratch3, | 576 scratch3, |
| 574 name, | 577 name, |
| 575 holder, | 578 holder, |
| 576 miss); | 579 miss); |
| 577 return Heap::undefined_value(); // Success. | 580 return HEAP->undefined_value(); // Success. |
| 578 } | 581 } |
| 579 } | 582 } |
| 580 | 583 |
| 581 private: | 584 private: |
| 582 MaybeObject* CompileCacheable(MacroAssembler* masm, | 585 MaybeObject* CompileCacheable(MacroAssembler* masm, |
| 583 JSObject* object, | 586 JSObject* object, |
| 584 Register receiver, | 587 Register receiver, |
| 585 Register scratch1, | 588 Register scratch1, |
| 586 Register scratch2, | 589 Register scratch2, |
| 587 Register scratch3, | 590 Register scratch3, |
| (...skipping 15 matching lines...) Expand all Loading... |
| 603 interceptor_holder); | 606 interceptor_holder); |
| 604 if (depth1 == kInvalidProtoDepth) { | 607 if (depth1 == kInvalidProtoDepth) { |
| 605 depth2 = | 608 depth2 = |
| 606 optimization.GetPrototypeDepthOfExpectedType(interceptor_holder, | 609 optimization.GetPrototypeDepthOfExpectedType(interceptor_holder, |
| 607 lookup->holder()); | 610 lookup->holder()); |
| 608 } | 611 } |
| 609 can_do_fast_api_call = (depth1 != kInvalidProtoDepth) || | 612 can_do_fast_api_call = (depth1 != kInvalidProtoDepth) || |
| 610 (depth2 != kInvalidProtoDepth); | 613 (depth2 != kInvalidProtoDepth); |
| 611 } | 614 } |
| 612 | 615 |
| 613 __ IncrementCounter(&Counters::call_const_interceptor, 1); | 616 __ IncrementCounter(COUNTERS->call_const_interceptor(), 1); |
| 614 | 617 |
| 615 if (can_do_fast_api_call) { | 618 if (can_do_fast_api_call) { |
| 616 __ IncrementCounter(&Counters::call_const_interceptor_fast_api, 1); | 619 __ IncrementCounter(COUNTERS->call_const_interceptor_fast_api(), 1); |
| 617 ReserveSpaceForFastApiCall(masm, scratch1); | 620 ReserveSpaceForFastApiCall(masm, scratch1); |
| 618 } | 621 } |
| 619 | 622 |
| 620 // Check that the maps from receiver to interceptor's holder | 623 // Check that the maps from receiver to interceptor's holder |
| 621 // haven't changed and thus we can invoke interceptor. | 624 // haven't changed and thus we can invoke interceptor. |
| 622 Label miss_cleanup; | 625 Label miss_cleanup; |
| 623 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label; | 626 Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label; |
| 624 Register holder = | 627 Register holder = |
| 625 stub_compiler_->CheckPrototypes(object, receiver, | 628 stub_compiler_->CheckPrototypes(object, receiver, |
| 626 interceptor_holder, scratch1, | 629 interceptor_holder, scratch1, |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 665 FreeSpaceForFastApiCall(masm, scratch1); | 668 FreeSpaceForFastApiCall(masm, scratch1); |
| 666 __ jmp(miss_label); | 669 __ jmp(miss_label); |
| 667 } | 670 } |
| 668 | 671 |
| 669 // Invoke a regular function. | 672 // Invoke a regular function. |
| 670 __ bind(®ular_invoke); | 673 __ bind(®ular_invoke); |
| 671 if (can_do_fast_api_call) { | 674 if (can_do_fast_api_call) { |
| 672 FreeSpaceForFastApiCall(masm, scratch1); | 675 FreeSpaceForFastApiCall(masm, scratch1); |
| 673 } | 676 } |
| 674 | 677 |
| 675 return Heap::undefined_value(); // Success. | 678 return HEAP->undefined_value(); // Success. |
| 676 } | 679 } |
| 677 | 680 |
| 678 void CompileRegular(MacroAssembler* masm, | 681 void CompileRegular(MacroAssembler* masm, |
| 679 JSObject* object, | 682 JSObject* object, |
| 680 Register receiver, | 683 Register receiver, |
| 681 Register scratch1, | 684 Register scratch1, |
| 682 Register scratch2, | 685 Register scratch2, |
| 683 Register scratch3, | 686 Register scratch3, |
| 684 String* name, | 687 String* name, |
| 685 JSObject* interceptor_holder, | 688 JSObject* interceptor_holder, |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 721 CompileCallLoadPropertyWithInterceptor(masm, | 724 CompileCallLoadPropertyWithInterceptor(masm, |
| 722 receiver, | 725 receiver, |
| 723 holder, | 726 holder, |
| 724 name_, | 727 name_, |
| 725 holder_obj); | 728 holder_obj); |
| 726 | 729 |
| 727 __ pop(name_); // Restore the name. | 730 __ pop(name_); // Restore the name. |
| 728 __ pop(receiver); // Restore the holder. | 731 __ pop(receiver); // Restore the holder. |
| 729 __ LeaveInternalFrame(); | 732 __ LeaveInternalFrame(); |
| 730 | 733 |
| 731 __ cmp(eax, Factory::no_interceptor_result_sentinel()); | 734 __ cmp(eax, FACTORY->no_interceptor_result_sentinel()); |
| 732 __ j(not_equal, interceptor_succeeded); | 735 __ j(not_equal, interceptor_succeeded); |
| 733 } | 736 } |
| 734 | 737 |
| 735 StubCompiler* stub_compiler_; | 738 StubCompiler* stub_compiler_; |
| 736 const ParameterCount& arguments_; | 739 const ParameterCount& arguments_; |
| 737 Register name_; | 740 Register name_; |
| 738 }; | 741 }; |
| 739 | 742 |
| 740 | 743 |
| 741 void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) { | 744 void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) { |
| 742 ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC); | 745 ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC); |
| 743 Code* code = NULL; | 746 Code* code = NULL; |
| 744 if (kind == Code::LOAD_IC) { | 747 if (kind == Code::LOAD_IC) { |
| 745 code = Builtins::builtin(Builtins::LoadIC_Miss); | 748 code = Isolate::Current()->builtins()->builtin(Builtins::LoadIC_Miss); |
| 746 } else { | 749 } else { |
| 747 code = Builtins::builtin(Builtins::KeyedLoadIC_Miss); | 750 code = Isolate::Current()->builtins()->builtin(Builtins::KeyedLoadIC_Miss); |
| 748 } | 751 } |
| 749 | 752 |
| 750 Handle<Code> ic(code); | 753 Handle<Code> ic(code); |
| 751 __ jmp(ic, RelocInfo::CODE_TARGET); | 754 __ jmp(ic, RelocInfo::CODE_TARGET); |
| 752 } | 755 } |
| 753 | 756 |
| 754 | 757 |
| 755 // Both name_reg and receiver_reg are preserved on jumps to miss_label, | 758 // Both name_reg and receiver_reg are preserved on jumps to miss_label, |
| 756 // but may be destroyed if store is successful. | 759 // but may be destroyed if store is successful. |
| 757 void StubCompiler::GenerateStoreField(MacroAssembler* masm, | 760 void StubCompiler::GenerateStoreField(MacroAssembler* masm, |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 844 Label* miss) { | 847 Label* miss) { |
| 845 Object* probe; | 848 Object* probe; |
| 846 { MaybeObject* maybe_probe = global->EnsurePropertyCell(name); | 849 { MaybeObject* maybe_probe = global->EnsurePropertyCell(name); |
| 847 if (!maybe_probe->ToObject(&probe)) return maybe_probe; | 850 if (!maybe_probe->ToObject(&probe)) return maybe_probe; |
| 848 } | 851 } |
| 849 JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(probe); | 852 JSGlobalPropertyCell* cell = JSGlobalPropertyCell::cast(probe); |
| 850 ASSERT(cell->value()->IsTheHole()); | 853 ASSERT(cell->value()->IsTheHole()); |
| 851 if (Serializer::enabled()) { | 854 if (Serializer::enabled()) { |
| 852 __ mov(scratch, Immediate(Handle<Object>(cell))); | 855 __ mov(scratch, Immediate(Handle<Object>(cell))); |
| 853 __ cmp(FieldOperand(scratch, JSGlobalPropertyCell::kValueOffset), | 856 __ cmp(FieldOperand(scratch, JSGlobalPropertyCell::kValueOffset), |
| 854 Immediate(Factory::the_hole_value())); | 857 Immediate(FACTORY->the_hole_value())); |
| 855 } else { | 858 } else { |
| 856 __ cmp(Operand::Cell(Handle<JSGlobalPropertyCell>(cell)), | 859 __ cmp(Operand::Cell(Handle<JSGlobalPropertyCell>(cell)), |
| 857 Immediate(Factory::the_hole_value())); | 860 Immediate(FACTORY->the_hole_value())); |
| 858 } | 861 } |
| 859 __ j(not_equal, miss, not_taken); | 862 __ j(not_equal, miss, not_taken); |
| 860 return cell; | 863 return cell; |
| 861 } | 864 } |
| 862 | 865 |
| 863 | 866 |
| 864 // Calls GenerateCheckPropertyCell for each global object in the prototype chain | 867 // Calls GenerateCheckPropertyCell for each global object in the prototype chain |
| 865 // from object to (but not including) holder. | 868 // from object to (but not including) holder. |
| 866 MUST_USE_RESULT static MaybeObject* GenerateCheckPropertyCells( | 869 MUST_USE_RESULT static MaybeObject* GenerateCheckPropertyCells( |
| 867 MacroAssembler* masm, | 870 MacroAssembler* masm, |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 923 // Only global objects and objects that do not require access | 926 // Only global objects and objects that do not require access |
| 924 // checks are allowed in stubs. | 927 // checks are allowed in stubs. |
| 925 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded()); | 928 ASSERT(current->IsJSGlobalProxy() || !current->IsAccessCheckNeeded()); |
| 926 | 929 |
| 927 ASSERT(current->GetPrototype()->IsJSObject()); | 930 ASSERT(current->GetPrototype()->IsJSObject()); |
| 928 JSObject* prototype = JSObject::cast(current->GetPrototype()); | 931 JSObject* prototype = JSObject::cast(current->GetPrototype()); |
| 929 if (!current->HasFastProperties() && | 932 if (!current->HasFastProperties() && |
| 930 !current->IsJSGlobalObject() && | 933 !current->IsJSGlobalObject() && |
| 931 !current->IsJSGlobalProxy()) { | 934 !current->IsJSGlobalProxy()) { |
| 932 if (!name->IsSymbol()) { | 935 if (!name->IsSymbol()) { |
| 933 MaybeObject* maybe_lookup_result = Heap::LookupSymbol(name); | 936 MaybeObject* maybe_lookup_result = HEAP->LookupSymbol(name); |
| 934 Object* lookup_result = NULL; // Initialization to please compiler. | 937 Object* lookup_result = NULL; // Initialization to please compiler. |
| 935 if (!maybe_lookup_result->ToObject(&lookup_result)) { | 938 if (!maybe_lookup_result->ToObject(&lookup_result)) { |
| 936 set_failure(Failure::cast(maybe_lookup_result)); | 939 set_failure(Failure::cast(maybe_lookup_result)); |
| 937 return reg; | 940 return reg; |
| 938 } | 941 } |
| 939 name = String::cast(lookup_result); | 942 name = String::cast(lookup_result); |
| 940 } | 943 } |
| 941 ASSERT(current->property_dictionary()->FindEntry(name) == | 944 ASSERT(current->property_dictionary()->FindEntry(name) == |
| 942 StringDictionary::kNotFound); | 945 StringDictionary::kNotFound); |
| 943 | 946 |
| 944 GenerateDictionaryNegativeLookup(masm(), | 947 GenerateDictionaryNegativeLookup(masm(), |
| 945 miss, | 948 miss, |
| 946 reg, | 949 reg, |
| 947 name, | 950 name, |
| 948 scratch1, | 951 scratch1, |
| 949 scratch2); | 952 scratch2); |
| 950 __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset)); | 953 __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset)); |
| 951 reg = holder_reg; // from now the object is in holder_reg | 954 reg = holder_reg; // from now the object is in holder_reg |
| 952 __ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset)); | 955 __ mov(reg, FieldOperand(scratch1, Map::kPrototypeOffset)); |
| 953 } else if (Heap::InNewSpace(prototype)) { | 956 } else if (HEAP->InNewSpace(prototype)) { |
| 954 // Get the map of the current object. | 957 // Get the map of the current object. |
| 955 __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset)); | 958 __ mov(scratch1, FieldOperand(reg, HeapObject::kMapOffset)); |
| 956 __ cmp(Operand(scratch1), Immediate(Handle<Map>(current->map()))); | 959 __ cmp(Operand(scratch1), Immediate(Handle<Map>(current->map()))); |
| 957 // Branch on the result of the map check. | 960 // Branch on the result of the map check. |
| 958 __ j(not_equal, miss, not_taken); | 961 __ j(not_equal, miss, not_taken); |
| 959 // Check access rights to the global object. This has to happen | 962 // Check access rights to the global object. This has to happen |
| 960 // after the map check so that we know that the object is | 963 // after the map check so that we know that the object is |
| 961 // actually a global object. | 964 // actually a global object. |
| 962 if (current->IsJSGlobalProxy()) { | 965 if (current->IsJSGlobalProxy()) { |
| 963 __ CheckAccessGlobalProxy(reg, scratch1, miss); | 966 __ CheckAccessGlobalProxy(reg, scratch1, miss); |
| (...skipping 26 matching lines...) Expand all Loading... |
| 990 if (save_at_depth == depth) { | 993 if (save_at_depth == depth) { |
| 991 __ mov(Operand(esp, kPointerSize), reg); | 994 __ mov(Operand(esp, kPointerSize), reg); |
| 992 } | 995 } |
| 993 | 996 |
| 994 // Go to the next object in the prototype chain. | 997 // Go to the next object in the prototype chain. |
| 995 current = prototype; | 998 current = prototype; |
| 996 } | 999 } |
| 997 ASSERT(current == holder); | 1000 ASSERT(current == holder); |
| 998 | 1001 |
| 999 // Log the check depth. | 1002 // Log the check depth. |
| 1000 LOG(IntEvent("check-maps-depth", depth + 1)); | 1003 LOG(isolate(), IntEvent("check-maps-depth", depth + 1)); |
| 1001 | 1004 |
| 1002 // Check the holder map. | 1005 // Check the holder map. |
| 1003 __ cmp(FieldOperand(reg, HeapObject::kMapOffset), | 1006 __ cmp(FieldOperand(reg, HeapObject::kMapOffset), |
| 1004 Immediate(Handle<Map>(holder->map()))); | 1007 Immediate(Handle<Map>(holder->map()))); |
| 1005 __ j(not_equal, miss, not_taken); | 1008 __ j(not_equal, miss, not_taken); |
| 1006 | 1009 |
| 1007 // Perform security check for access to the global object. | 1010 // Perform security check for access to the global object. |
| 1008 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded()); | 1011 ASSERT(holder->IsJSGlobalProxy() || !holder->IsAccessCheckNeeded()); |
| 1009 if (holder->IsJSGlobalProxy()) { | 1012 if (holder->IsJSGlobalProxy()) { |
| 1010 __ CheckAccessGlobalProxy(reg, scratch1, miss); | 1013 __ CheckAccessGlobalProxy(reg, scratch1, miss); |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1073 | 1076 |
| 1074 // Insert additional parameters into the stack frame above return address. | 1077 // Insert additional parameters into the stack frame above return address. |
| 1075 ASSERT(!scratch3.is(reg)); | 1078 ASSERT(!scratch3.is(reg)); |
| 1076 __ pop(scratch3); // Get return address to place it below. | 1079 __ pop(scratch3); // Get return address to place it below. |
| 1077 | 1080 |
| 1078 __ push(receiver); // receiver | 1081 __ push(receiver); // receiver |
| 1079 __ mov(scratch2, Operand(esp)); | 1082 __ mov(scratch2, Operand(esp)); |
| 1080 ASSERT(!scratch2.is(reg)); | 1083 ASSERT(!scratch2.is(reg)); |
| 1081 __ push(reg); // holder | 1084 __ push(reg); // holder |
| 1082 // Push data from AccessorInfo. | 1085 // Push data from AccessorInfo. |
| 1083 if (Heap::InNewSpace(callback_handle->data())) { | 1086 if (HEAP->InNewSpace(callback_handle->data())) { |
| 1084 __ mov(scratch1, Immediate(callback_handle)); | 1087 __ mov(scratch1, Immediate(callback_handle)); |
| 1085 __ push(FieldOperand(scratch1, AccessorInfo::kDataOffset)); | 1088 __ push(FieldOperand(scratch1, AccessorInfo::kDataOffset)); |
| 1086 } else { | 1089 } else { |
| 1087 __ push(Immediate(Handle<Object>(callback_handle->data()))); | 1090 __ push(Immediate(Handle<Object>(callback_handle->data()))); |
| 1088 } | 1091 } |
| 1089 | 1092 |
| 1090 // Save a pointer to where we pushed the arguments pointer. | 1093 // Save a pointer to where we pushed the arguments pointer. |
| 1091 // This will be passed as the const AccessorInfo& to the C++ callback. | 1094 // This will be passed as the const AccessorInfo& to the C++ callback. |
| 1092 __ push(scratch2); | 1095 __ push(scratch2); |
| 1093 | 1096 |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1197 // of this method.) | 1200 // of this method.) |
| 1198 CompileCallLoadPropertyWithInterceptor(masm(), | 1201 CompileCallLoadPropertyWithInterceptor(masm(), |
| 1199 receiver, | 1202 receiver, |
| 1200 holder_reg, | 1203 holder_reg, |
| 1201 name_reg, | 1204 name_reg, |
| 1202 interceptor_holder); | 1205 interceptor_holder); |
| 1203 | 1206 |
| 1204 // Check if interceptor provided a value for property. If it's | 1207 // Check if interceptor provided a value for property. If it's |
| 1205 // the case, return immediately. | 1208 // the case, return immediately. |
| 1206 Label interceptor_failed; | 1209 Label interceptor_failed; |
| 1207 __ cmp(eax, Factory::no_interceptor_result_sentinel()); | 1210 __ cmp(eax, FACTORY->no_interceptor_result_sentinel()); |
| 1208 __ j(equal, &interceptor_failed); | 1211 __ j(equal, &interceptor_failed); |
| 1209 __ LeaveInternalFrame(); | 1212 __ LeaveInternalFrame(); |
| 1210 __ ret(0); | 1213 __ ret(0); |
| 1211 | 1214 |
| 1212 __ bind(&interceptor_failed); | 1215 __ bind(&interceptor_failed); |
| 1213 __ pop(name_reg); | 1216 __ pop(name_reg); |
| 1214 __ pop(holder_reg); | 1217 __ pop(holder_reg); |
| 1215 if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) { | 1218 if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) { |
| 1216 __ pop(receiver); | 1219 __ pop(receiver); |
| 1217 } | 1220 } |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1318 Label* miss) { | 1321 Label* miss) { |
| 1319 // Get the value from the cell. | 1322 // Get the value from the cell. |
| 1320 if (Serializer::enabled()) { | 1323 if (Serializer::enabled()) { |
| 1321 __ mov(edi, Immediate(Handle<JSGlobalPropertyCell>(cell))); | 1324 __ mov(edi, Immediate(Handle<JSGlobalPropertyCell>(cell))); |
| 1322 __ mov(edi, FieldOperand(edi, JSGlobalPropertyCell::kValueOffset)); | 1325 __ mov(edi, FieldOperand(edi, JSGlobalPropertyCell::kValueOffset)); |
| 1323 } else { | 1326 } else { |
| 1324 __ mov(edi, Operand::Cell(Handle<JSGlobalPropertyCell>(cell))); | 1327 __ mov(edi, Operand::Cell(Handle<JSGlobalPropertyCell>(cell))); |
| 1325 } | 1328 } |
| 1326 | 1329 |
| 1327 // Check that the cell contains the same function. | 1330 // Check that the cell contains the same function. |
| 1328 if (Heap::InNewSpace(function)) { | 1331 if (HEAP->InNewSpace(function)) { |
| 1329 // We can't embed a pointer to a function in new space so we have | 1332 // We can't embed a pointer to a function in new space so we have |
| 1330 // to verify that the shared function info is unchanged. This has | 1333 // to verify that the shared function info is unchanged. This has |
| 1331 // the nice side effect that multiple closures based on the same | 1334 // the nice side effect that multiple closures based on the same |
| 1332 // function can all use this call IC. Before we load through the | 1335 // function can all use this call IC. Before we load through the |
| 1333 // function, we have to verify that it still is a function. | 1336 // function, we have to verify that it still is a function. |
| 1334 __ test(edi, Immediate(kSmiTagMask)); | 1337 __ test(edi, Immediate(kSmiTagMask)); |
| 1335 __ j(zero, miss, not_taken); | 1338 __ j(zero, miss, not_taken); |
| 1336 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ebx); | 1339 __ CmpObjectType(edi, JS_FUNCTION_TYPE, ebx); |
| 1337 __ j(not_equal, miss, not_taken); | 1340 __ j(not_equal, miss, not_taken); |
| 1338 | 1341 |
| 1339 // Check the shared function info. Make sure it hasn't changed. | 1342 // Check the shared function info. Make sure it hasn't changed. |
| 1340 __ cmp(FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset), | 1343 __ cmp(FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset), |
| 1341 Immediate(Handle<SharedFunctionInfo>(function->shared()))); | 1344 Immediate(Handle<SharedFunctionInfo>(function->shared()))); |
| 1342 __ j(not_equal, miss, not_taken); | 1345 __ j(not_equal, miss, not_taken); |
| 1343 } else { | 1346 } else { |
| 1344 __ cmp(Operand(edi), Immediate(Handle<JSFunction>(function))); | 1347 __ cmp(Operand(edi), Immediate(Handle<JSFunction>(function))); |
| 1345 __ j(not_equal, miss, not_taken); | 1348 __ j(not_equal, miss, not_taken); |
| 1346 } | 1349 } |
| 1347 } | 1350 } |
| 1348 | 1351 |
| 1349 | 1352 |
| 1350 MaybeObject* CallStubCompiler::GenerateMissBranch() { | 1353 MaybeObject* CallStubCompiler::GenerateMissBranch() { |
| 1351 MaybeObject* maybe_obj = StubCache::ComputeCallMiss(arguments().immediate(), | 1354 MaybeObject* maybe_obj = |
| 1352 kind_); | 1355 Isolate::Current()->stub_cache()->ComputeCallMiss( |
| 1356 arguments().immediate(), kind_); |
| 1353 Object* obj; | 1357 Object* obj; |
| 1354 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 1358 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| 1355 __ jmp(Handle<Code>(Code::cast(obj)), RelocInfo::CODE_TARGET); | 1359 __ jmp(Handle<Code>(Code::cast(obj)), RelocInfo::CODE_TARGET); |
| 1356 return obj; | 1360 return obj; |
| 1357 } | 1361 } |
| 1358 | 1362 |
| 1359 | 1363 |
| 1360 MUST_USE_RESULT MaybeObject* CallStubCompiler::CompileCallField( | 1364 MUST_USE_RESULT MaybeObject* CallStubCompiler::CompileCallField( |
| 1361 JSObject* object, | 1365 JSObject* object, |
| 1362 JSObject* holder, | 1366 JSObject* holder, |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1422 String* name) { | 1426 String* name) { |
| 1423 // ----------- S t a t e ------------- | 1427 // ----------- S t a t e ------------- |
| 1424 // -- ecx : name | 1428 // -- ecx : name |
| 1425 // -- esp[0] : return address | 1429 // -- esp[0] : return address |
| 1426 // -- esp[(argc - n) * 4] : arg[n] (zero-based) | 1430 // -- esp[(argc - n) * 4] : arg[n] (zero-based) |
| 1427 // -- ... | 1431 // -- ... |
| 1428 // -- esp[(argc + 1) * 4] : receiver | 1432 // -- esp[(argc + 1) * 4] : receiver |
| 1429 // ----------------------------------- | 1433 // ----------------------------------- |
| 1430 | 1434 |
| 1431 // If object is not an array, bail out to regular call. | 1435 // If object is not an array, bail out to regular call. |
| 1432 if (!object->IsJSArray() || cell != NULL) return Heap::undefined_value(); | 1436 if (!object->IsJSArray() || cell != NULL) return HEAP->undefined_value(); |
| 1433 | 1437 |
| 1434 Label miss; | 1438 Label miss; |
| 1435 | 1439 |
| 1436 GenerateNameCheck(name, &miss); | 1440 GenerateNameCheck(name, &miss); |
| 1437 | 1441 |
| 1438 // Get the receiver from the stack. | 1442 // Get the receiver from the stack. |
| 1439 const int argc = arguments().immediate(); | 1443 const int argc = arguments().immediate(); |
| 1440 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); | 1444 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); |
| 1441 | 1445 |
| 1442 // Check that the receiver isn't a smi. | 1446 // Check that the receiver isn't a smi. |
| 1443 __ test(edx, Immediate(kSmiTagMask)); | 1447 __ test(edx, Immediate(kSmiTagMask)); |
| 1444 __ j(zero, &miss); | 1448 __ j(zero, &miss); |
| 1445 | 1449 |
| 1446 CheckPrototypes(JSObject::cast(object), edx, | 1450 CheckPrototypes(JSObject::cast(object), edx, |
| 1447 holder, ebx, | 1451 holder, ebx, |
| 1448 eax, edi, name, &miss); | 1452 eax, edi, name, &miss); |
| 1449 | 1453 |
| 1450 if (argc == 0) { | 1454 if (argc == 0) { |
| 1451 // Noop, return the length. | 1455 // Noop, return the length. |
| 1452 __ mov(eax, FieldOperand(edx, JSArray::kLengthOffset)); | 1456 __ mov(eax, FieldOperand(edx, JSArray::kLengthOffset)); |
| 1453 __ ret((argc + 1) * kPointerSize); | 1457 __ ret((argc + 1) * kPointerSize); |
| 1454 } else { | 1458 } else { |
| 1455 Label call_builtin; | 1459 Label call_builtin; |
| 1456 | 1460 |
| 1457 // Get the elements array of the object. | 1461 // Get the elements array of the object. |
| 1458 __ mov(ebx, FieldOperand(edx, JSArray::kElementsOffset)); | 1462 __ mov(ebx, FieldOperand(edx, JSArray::kElementsOffset)); |
| 1459 | 1463 |
| 1460 // Check that the elements are in fast mode and writable. | 1464 // Check that the elements are in fast mode and writable. |
| 1461 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset), | 1465 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset), |
| 1462 Immediate(Factory::fixed_array_map())); | 1466 Immediate(FACTORY->fixed_array_map())); |
| 1463 __ j(not_equal, &call_builtin); | 1467 __ j(not_equal, &call_builtin); |
| 1464 | 1468 |
| 1465 if (argc == 1) { // Otherwise fall through to call builtin. | 1469 if (argc == 1) { // Otherwise fall through to call builtin. |
| 1466 Label exit, attempt_to_grow_elements; | 1470 Label exit, attempt_to_grow_elements; |
| 1467 NearLabel with_write_barrier; | 1471 NearLabel with_write_barrier; |
| 1468 | 1472 |
| 1469 // Get the array's length into eax and calculate new length. | 1473 // Get the array's length into eax and calculate new length. |
| 1470 __ mov(eax, FieldOperand(edx, JSArray::kLengthOffset)); | 1474 __ mov(eax, FieldOperand(edx, JSArray::kLengthOffset)); |
| 1471 STATIC_ASSERT(kSmiTagSize == 1); | 1475 STATIC_ASSERT(kSmiTagSize == 1); |
| 1472 STATIC_ASSERT(kSmiTag == 0); | 1476 STATIC_ASSERT(kSmiTag == 0); |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1533 | 1537 |
| 1534 // We fit and could grow elements. | 1538 // We fit and could grow elements. |
| 1535 __ mov(Operand::StaticVariable(new_space_allocation_top), ecx); | 1539 __ mov(Operand::StaticVariable(new_space_allocation_top), ecx); |
| 1536 __ mov(ecx, Operand(esp, argc * kPointerSize)); | 1540 __ mov(ecx, Operand(esp, argc * kPointerSize)); |
| 1537 | 1541 |
| 1538 // Push the argument... | 1542 // Push the argument... |
| 1539 __ mov(Operand(edx, 0), ecx); | 1543 __ mov(Operand(edx, 0), ecx); |
| 1540 // ... and fill the rest with holes. | 1544 // ... and fill the rest with holes. |
| 1541 for (int i = 1; i < kAllocationDelta; i++) { | 1545 for (int i = 1; i < kAllocationDelta; i++) { |
| 1542 __ mov(Operand(edx, i * kPointerSize), | 1546 __ mov(Operand(edx, i * kPointerSize), |
| 1543 Immediate(Factory::the_hole_value())); | 1547 Immediate(FACTORY->the_hole_value())); |
| 1544 } | 1548 } |
| 1545 | 1549 |
| 1546 // We know the elements array is in new space so we don't need the | 1550 // We know the elements array is in new space so we don't need the |
| 1547 // remembered set, but we just pushed a value onto it so we may have to | 1551 // remembered set, but we just pushed a value onto it so we may have to |
| 1548 // tell the incremental marker to rescan the object that we just grew. We | 1552 // tell the incremental marker to rescan the object that we just grew. We |
| 1549 // don't need to worry about the holes because they are in old space and | 1553 // don't need to worry about the holes because they are in old space and |
| 1550 // already marked black. | 1554 // already marked black. |
| 1551 __ mov(edi, ebx); | 1555 __ mov(edi, ebx); |
| 1552 __ RecordWrite(edi, edx, ecx, OMIT_REMEMBERED_SET, kDontSaveFPRegs); | 1556 __ RecordWrite(edi, edx, ecx, OMIT_REMEMBERED_SET, kDontSaveFPRegs); |
| 1553 | 1557 |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1587 String* name) { | 1591 String* name) { |
| 1588 // ----------- S t a t e ------------- | 1592 // ----------- S t a t e ------------- |
| 1589 // -- ecx : name | 1593 // -- ecx : name |
| 1590 // -- esp[0] : return address | 1594 // -- esp[0] : return address |
| 1591 // -- esp[(argc - n) * 4] : arg[n] (zero-based) | 1595 // -- esp[(argc - n) * 4] : arg[n] (zero-based) |
| 1592 // -- ... | 1596 // -- ... |
| 1593 // -- esp[(argc + 1) * 4] : receiver | 1597 // -- esp[(argc + 1) * 4] : receiver |
| 1594 // ----------------------------------- | 1598 // ----------------------------------- |
| 1595 | 1599 |
| 1596 // If object is not an array, bail out to regular call. | 1600 // If object is not an array, bail out to regular call. |
| 1597 if (!object->IsJSArray() || cell != NULL) return Heap::undefined_value(); | 1601 if (!object->IsJSArray() || cell != NULL) return HEAP->undefined_value(); |
| 1598 | 1602 |
| 1599 Label miss, return_undefined, call_builtin; | 1603 Label miss, return_undefined, call_builtin; |
| 1600 | 1604 |
| 1601 GenerateNameCheck(name, &miss); | 1605 GenerateNameCheck(name, &miss); |
| 1602 | 1606 |
| 1603 // Get the receiver from the stack. | 1607 // Get the receiver from the stack. |
| 1604 const int argc = arguments().immediate(); | 1608 const int argc = arguments().immediate(); |
| 1605 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); | 1609 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); |
| 1606 | 1610 |
| 1607 // Check that the receiver isn't a smi. | 1611 // Check that the receiver isn't a smi. |
| 1608 __ test(edx, Immediate(kSmiTagMask)); | 1612 __ test(edx, Immediate(kSmiTagMask)); |
| 1609 __ j(zero, &miss); | 1613 __ j(zero, &miss); |
| 1610 CheckPrototypes(JSObject::cast(object), edx, | 1614 CheckPrototypes(JSObject::cast(object), edx, |
| 1611 holder, ebx, | 1615 holder, ebx, |
| 1612 eax, edi, name, &miss); | 1616 eax, edi, name, &miss); |
| 1613 | 1617 |
| 1614 // Get the elements array of the object. | 1618 // Get the elements array of the object. |
| 1615 __ mov(ebx, FieldOperand(edx, JSArray::kElementsOffset)); | 1619 __ mov(ebx, FieldOperand(edx, JSArray::kElementsOffset)); |
| 1616 | 1620 |
| 1617 // Check that the elements are in fast mode and writable. | 1621 // Check that the elements are in fast mode and writable. |
| 1618 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset), | 1622 __ cmp(FieldOperand(ebx, HeapObject::kMapOffset), |
| 1619 Immediate(Factory::fixed_array_map())); | 1623 Immediate(FACTORY->fixed_array_map())); |
| 1620 __ j(not_equal, &call_builtin); | 1624 __ j(not_equal, &call_builtin); |
| 1621 | 1625 |
| 1622 // Get the array's length into ecx and calculate new length. | 1626 // Get the array's length into ecx and calculate new length. |
| 1623 __ mov(ecx, FieldOperand(edx, JSArray::kLengthOffset)); | 1627 __ mov(ecx, FieldOperand(edx, JSArray::kLengthOffset)); |
| 1624 __ sub(Operand(ecx), Immediate(Smi::FromInt(1))); | 1628 __ sub(Operand(ecx), Immediate(Smi::FromInt(1))); |
| 1625 __ j(negative, &return_undefined); | 1629 __ j(negative, &return_undefined); |
| 1626 | 1630 |
| 1627 // Get the last element. | 1631 // Get the last element. |
| 1628 STATIC_ASSERT(kSmiTagSize == 1); | 1632 STATIC_ASSERT(kSmiTagSize == 1); |
| 1629 STATIC_ASSERT(kSmiTag == 0); | 1633 STATIC_ASSERT(kSmiTag == 0); |
| 1630 __ mov(eax, FieldOperand(ebx, | 1634 __ mov(eax, FieldOperand(ebx, |
| 1631 ecx, times_half_pointer_size, | 1635 ecx, times_half_pointer_size, |
| 1632 FixedArray::kHeaderSize)); | 1636 FixedArray::kHeaderSize)); |
| 1633 __ cmp(Operand(eax), Immediate(Factory::the_hole_value())); | 1637 __ cmp(Operand(eax), Immediate(FACTORY->the_hole_value())); |
| 1634 __ j(equal, &call_builtin); | 1638 __ j(equal, &call_builtin); |
| 1635 | 1639 |
| 1636 // Set the array's length. | 1640 // Set the array's length. |
| 1637 __ mov(FieldOperand(edx, JSArray::kLengthOffset), ecx); | 1641 __ mov(FieldOperand(edx, JSArray::kLengthOffset), ecx); |
| 1638 | 1642 |
| 1639 // Fill with the hole. | 1643 // Fill with the hole. |
| 1640 __ mov(FieldOperand(ebx, | 1644 __ mov(FieldOperand(ebx, |
| 1641 ecx, times_half_pointer_size, | 1645 ecx, times_half_pointer_size, |
| 1642 FixedArray::kHeaderSize), | 1646 FixedArray::kHeaderSize), |
| 1643 Immediate(Factory::the_hole_value())); | 1647 Immediate(FACTORY->the_hole_value())); |
| 1644 __ ret((argc + 1) * kPointerSize); | 1648 __ ret((argc + 1) * kPointerSize); |
| 1645 | 1649 |
| 1646 __ bind(&return_undefined); | 1650 __ bind(&return_undefined); |
| 1647 __ mov(eax, Immediate(Factory::undefined_value())); | 1651 __ mov(eax, Immediate(FACTORY->undefined_value())); |
| 1648 __ ret((argc + 1) * kPointerSize); | 1652 __ ret((argc + 1) * kPointerSize); |
| 1649 | 1653 |
| 1650 __ bind(&call_builtin); | 1654 __ bind(&call_builtin); |
| 1651 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPop), | 1655 __ TailCallExternalReference(ExternalReference(Builtins::c_ArrayPop), |
| 1652 argc + 1, | 1656 argc + 1, |
| 1653 1); | 1657 1); |
| 1654 | 1658 |
| 1655 __ bind(&miss); | 1659 __ bind(&miss); |
| 1656 Object* obj; | 1660 Object* obj; |
| 1657 { MaybeObject* maybe_obj = GenerateMissBranch(); | 1661 { MaybeObject* maybe_obj = GenerateMissBranch(); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 1671 String* name) { | 1675 String* name) { |
| 1672 // ----------- S t a t e ------------- | 1676 // ----------- S t a t e ------------- |
| 1673 // -- ecx : function name | 1677 // -- ecx : function name |
| 1674 // -- esp[0] : return address | 1678 // -- esp[0] : return address |
| 1675 // -- esp[(argc - n) * 4] : arg[n] (zero-based) | 1679 // -- esp[(argc - n) * 4] : arg[n] (zero-based) |
| 1676 // -- ... | 1680 // -- ... |
| 1677 // -- esp[(argc + 1) * 4] : receiver | 1681 // -- esp[(argc + 1) * 4] : receiver |
| 1678 // ----------------------------------- | 1682 // ----------------------------------- |
| 1679 | 1683 |
| 1680 // If object is not a string, bail out to regular call. | 1684 // If object is not a string, bail out to regular call. |
| 1681 if (!object->IsString() || cell != NULL) return Heap::undefined_value(); | 1685 if (!object->IsString() || cell != NULL) return HEAP->undefined_value(); |
| 1682 | 1686 |
| 1683 const int argc = arguments().immediate(); | 1687 const int argc = arguments().immediate(); |
| 1684 | 1688 |
| 1685 Label miss; | 1689 Label miss; |
| 1686 Label name_miss; | 1690 Label name_miss; |
| 1687 Label index_out_of_range; | 1691 Label index_out_of_range; |
| 1688 Label* index_out_of_range_label = &index_out_of_range; | 1692 Label* index_out_of_range_label = &index_out_of_range; |
| 1689 | 1693 |
| 1690 if (kind_ == Code::CALL_IC && extra_ic_state_ == DEFAULT_STRING_STUB) { | 1694 if (kind_ == Code::CALL_IC && extra_ic_state_ == DEFAULT_STRING_STUB) { |
| 1691 index_out_of_range_label = &miss; | 1695 index_out_of_range_label = &miss; |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1703 ebx, edx, edi, name, &miss); | 1707 ebx, edx, edi, name, &miss); |
| 1704 | 1708 |
| 1705 Register receiver = ebx; | 1709 Register receiver = ebx; |
| 1706 Register index = edi; | 1710 Register index = edi; |
| 1707 Register scratch = edx; | 1711 Register scratch = edx; |
| 1708 Register result = eax; | 1712 Register result = eax; |
| 1709 __ mov(receiver, Operand(esp, (argc + 1) * kPointerSize)); | 1713 __ mov(receiver, Operand(esp, (argc + 1) * kPointerSize)); |
| 1710 if (argc > 0) { | 1714 if (argc > 0) { |
| 1711 __ mov(index, Operand(esp, (argc - 0) * kPointerSize)); | 1715 __ mov(index, Operand(esp, (argc - 0) * kPointerSize)); |
| 1712 } else { | 1716 } else { |
| 1713 __ Set(index, Immediate(Factory::undefined_value())); | 1717 __ Set(index, Immediate(FACTORY->undefined_value())); |
| 1714 } | 1718 } |
| 1715 | 1719 |
| 1716 StringCharCodeAtGenerator char_code_at_generator(receiver, | 1720 StringCharCodeAtGenerator char_code_at_generator(receiver, |
| 1717 index, | 1721 index, |
| 1718 scratch, | 1722 scratch, |
| 1719 result, | 1723 result, |
| 1720 &miss, // When not a string. | 1724 &miss, // When not a string. |
| 1721 &miss, // When not a number. | 1725 &miss, // When not a number. |
| 1722 index_out_of_range_label, | 1726 index_out_of_range_label, |
| 1723 STRING_INDEX_IS_NUMBER); | 1727 STRING_INDEX_IS_NUMBER); |
| 1724 char_code_at_generator.GenerateFast(masm()); | 1728 char_code_at_generator.GenerateFast(masm()); |
| 1725 __ ret((argc + 1) * kPointerSize); | 1729 __ ret((argc + 1) * kPointerSize); |
| 1726 | 1730 |
| 1727 StubRuntimeCallHelper call_helper; | 1731 StubRuntimeCallHelper call_helper; |
| 1728 char_code_at_generator.GenerateSlow(masm(), call_helper); | 1732 char_code_at_generator.GenerateSlow(masm(), call_helper); |
| 1729 | 1733 |
| 1730 if (index_out_of_range.is_linked()) { | 1734 if (index_out_of_range.is_linked()) { |
| 1731 __ bind(&index_out_of_range); | 1735 __ bind(&index_out_of_range); |
| 1732 __ Set(eax, Immediate(Factory::nan_value())); | 1736 __ Set(eax, Immediate(FACTORY->nan_value())); |
| 1733 __ ret((argc + 1) * kPointerSize); | 1737 __ ret((argc + 1) * kPointerSize); |
| 1734 } | 1738 } |
| 1735 | 1739 |
| 1736 __ bind(&miss); | 1740 __ bind(&miss); |
| 1737 // Restore function name in ecx. | 1741 // Restore function name in ecx. |
| 1738 __ Set(ecx, Immediate(Handle<String>(name))); | 1742 __ Set(ecx, Immediate(Handle<String>(name))); |
| 1739 __ bind(&name_miss); | 1743 __ bind(&name_miss); |
| 1740 Object* obj; | 1744 Object* obj; |
| 1741 { MaybeObject* maybe_obj = GenerateMissBranch(); | 1745 { MaybeObject* maybe_obj = GenerateMissBranch(); |
| 1742 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 1746 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1755 String* name) { | 1759 String* name) { |
| 1756 // ----------- S t a t e ------------- | 1760 // ----------- S t a t e ------------- |
| 1757 // -- ecx : function name | 1761 // -- ecx : function name |
| 1758 // -- esp[0] : return address | 1762 // -- esp[0] : return address |
| 1759 // -- esp[(argc - n) * 4] : arg[n] (zero-based) | 1763 // -- esp[(argc - n) * 4] : arg[n] (zero-based) |
| 1760 // -- ... | 1764 // -- ... |
| 1761 // -- esp[(argc + 1) * 4] : receiver | 1765 // -- esp[(argc + 1) * 4] : receiver |
| 1762 // ----------------------------------- | 1766 // ----------------------------------- |
| 1763 | 1767 |
| 1764 // If object is not a string, bail out to regular call. | 1768 // If object is not a string, bail out to regular call. |
| 1765 if (!object->IsString() || cell != NULL) return Heap::undefined_value(); | 1769 if (!object->IsString() || cell != NULL) return HEAP->undefined_value(); |
| 1766 | 1770 |
| 1767 const int argc = arguments().immediate(); | 1771 const int argc = arguments().immediate(); |
| 1768 | 1772 |
| 1769 Label miss; | 1773 Label miss; |
| 1770 Label name_miss; | 1774 Label name_miss; |
| 1771 Label index_out_of_range; | 1775 Label index_out_of_range; |
| 1772 Label* index_out_of_range_label = &index_out_of_range; | 1776 Label* index_out_of_range_label = &index_out_of_range; |
| 1773 | 1777 |
| 1774 if (kind_ == Code::CALL_IC && extra_ic_state_ == DEFAULT_STRING_STUB) { | 1778 if (kind_ == Code::CALL_IC && extra_ic_state_ == DEFAULT_STRING_STUB) { |
| 1775 index_out_of_range_label = &miss; | 1779 index_out_of_range_label = &miss; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1788 | 1792 |
| 1789 Register receiver = eax; | 1793 Register receiver = eax; |
| 1790 Register index = edi; | 1794 Register index = edi; |
| 1791 Register scratch1 = ebx; | 1795 Register scratch1 = ebx; |
| 1792 Register scratch2 = edx; | 1796 Register scratch2 = edx; |
| 1793 Register result = eax; | 1797 Register result = eax; |
| 1794 __ mov(receiver, Operand(esp, (argc + 1) * kPointerSize)); | 1798 __ mov(receiver, Operand(esp, (argc + 1) * kPointerSize)); |
| 1795 if (argc > 0) { | 1799 if (argc > 0) { |
| 1796 __ mov(index, Operand(esp, (argc - 0) * kPointerSize)); | 1800 __ mov(index, Operand(esp, (argc - 0) * kPointerSize)); |
| 1797 } else { | 1801 } else { |
| 1798 __ Set(index, Immediate(Factory::undefined_value())); | 1802 __ Set(index, Immediate(FACTORY->undefined_value())); |
| 1799 } | 1803 } |
| 1800 | 1804 |
| 1801 StringCharAtGenerator char_at_generator(receiver, | 1805 StringCharAtGenerator char_at_generator(receiver, |
| 1802 index, | 1806 index, |
| 1803 scratch1, | 1807 scratch1, |
| 1804 scratch2, | 1808 scratch2, |
| 1805 result, | 1809 result, |
| 1806 &miss, // When not a string. | 1810 &miss, // When not a string. |
| 1807 &miss, // When not a number. | 1811 &miss, // When not a number. |
| 1808 index_out_of_range_label, | 1812 index_out_of_range_label, |
| 1809 STRING_INDEX_IS_NUMBER); | 1813 STRING_INDEX_IS_NUMBER); |
| 1810 char_at_generator.GenerateFast(masm()); | 1814 char_at_generator.GenerateFast(masm()); |
| 1811 __ ret((argc + 1) * kPointerSize); | 1815 __ ret((argc + 1) * kPointerSize); |
| 1812 | 1816 |
| 1813 StubRuntimeCallHelper call_helper; | 1817 StubRuntimeCallHelper call_helper; |
| 1814 char_at_generator.GenerateSlow(masm(), call_helper); | 1818 char_at_generator.GenerateSlow(masm(), call_helper); |
| 1815 | 1819 |
| 1816 if (index_out_of_range.is_linked()) { | 1820 if (index_out_of_range.is_linked()) { |
| 1817 __ bind(&index_out_of_range); | 1821 __ bind(&index_out_of_range); |
| 1818 __ Set(eax, Immediate(Factory::empty_string())); | 1822 __ Set(eax, Immediate(FACTORY->empty_string())); |
| 1819 __ ret((argc + 1) * kPointerSize); | 1823 __ ret((argc + 1) * kPointerSize); |
| 1820 } | 1824 } |
| 1821 | 1825 |
| 1822 __ bind(&miss); | 1826 __ bind(&miss); |
| 1823 // Restore function name in ecx. | 1827 // Restore function name in ecx. |
| 1824 __ Set(ecx, Immediate(Handle<String>(name))); | 1828 __ Set(ecx, Immediate(Handle<String>(name))); |
| 1825 __ bind(&name_miss); | 1829 __ bind(&name_miss); |
| 1826 Object* obj; | 1830 Object* obj; |
| 1827 { MaybeObject* maybe_obj = GenerateMissBranch(); | 1831 { MaybeObject* maybe_obj = GenerateMissBranch(); |
| 1828 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 1832 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| (...skipping 15 matching lines...) Expand all Loading... |
| 1844 // -- esp[0] : return address | 1848 // -- esp[0] : return address |
| 1845 // -- esp[(argc - n) * 4] : arg[n] (zero-based) | 1849 // -- esp[(argc - n) * 4] : arg[n] (zero-based) |
| 1846 // -- ... | 1850 // -- ... |
| 1847 // -- esp[(argc + 1) * 4] : receiver | 1851 // -- esp[(argc + 1) * 4] : receiver |
| 1848 // ----------------------------------- | 1852 // ----------------------------------- |
| 1849 | 1853 |
| 1850 const int argc = arguments().immediate(); | 1854 const int argc = arguments().immediate(); |
| 1851 | 1855 |
| 1852 // If the object is not a JSObject or we got an unexpected number of | 1856 // If the object is not a JSObject or we got an unexpected number of |
| 1853 // arguments, bail out to the regular call. | 1857 // arguments, bail out to the regular call. |
| 1854 if (!object->IsJSObject() || argc != 1) return Heap::undefined_value(); | 1858 if (!object->IsJSObject() || argc != 1) return HEAP->undefined_value(); |
| 1855 | 1859 |
| 1856 Label miss; | 1860 Label miss; |
| 1857 GenerateNameCheck(name, &miss); | 1861 GenerateNameCheck(name, &miss); |
| 1858 | 1862 |
| 1859 if (cell == NULL) { | 1863 if (cell == NULL) { |
| 1860 __ mov(edx, Operand(esp, 2 * kPointerSize)); | 1864 __ mov(edx, Operand(esp, 2 * kPointerSize)); |
| 1861 | 1865 |
| 1862 STATIC_ASSERT(kSmiTag == 0); | 1866 STATIC_ASSERT(kSmiTag == 0); |
| 1863 __ test(edx, Immediate(kSmiTagMask)); | 1867 __ test(edx, Immediate(kSmiTagMask)); |
| 1864 __ j(zero, &miss); | 1868 __ j(zero, &miss); |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1914 JSFunction* function, | 1918 JSFunction* function, |
| 1915 String* name) { | 1919 String* name) { |
| 1916 // ----------- S t a t e ------------- | 1920 // ----------- S t a t e ------------- |
| 1917 // -- ecx : name | 1921 // -- ecx : name |
| 1918 // -- esp[0] : return address | 1922 // -- esp[0] : return address |
| 1919 // -- esp[(argc - n) * 4] : arg[n] (zero-based) | 1923 // -- esp[(argc - n) * 4] : arg[n] (zero-based) |
| 1920 // -- ... | 1924 // -- ... |
| 1921 // -- esp[(argc + 1) * 4] : receiver | 1925 // -- esp[(argc + 1) * 4] : receiver |
| 1922 // ----------------------------------- | 1926 // ----------------------------------- |
| 1923 | 1927 |
| 1924 if (!CpuFeatures::IsSupported(SSE2)) return Heap::undefined_value(); | 1928 if (!Isolate::Current()->cpu_features()->IsSupported(SSE2)) |
| 1929 return HEAP->undefined_value(); |
| 1925 CpuFeatures::Scope use_sse2(SSE2); | 1930 CpuFeatures::Scope use_sse2(SSE2); |
| 1926 | 1931 |
| 1927 const int argc = arguments().immediate(); | 1932 const int argc = arguments().immediate(); |
| 1928 | 1933 |
| 1929 // If the object is not a JSObject or we got an unexpected number of | 1934 // If the object is not a JSObject or we got an unexpected number of |
| 1930 // arguments, bail out to the regular call. | 1935 // arguments, bail out to the regular call. |
| 1931 if (!object->IsJSObject() || argc != 1) return Heap::undefined_value(); | 1936 if (!object->IsJSObject() || argc != 1) return HEAP->undefined_value(); |
| 1932 | 1937 |
| 1933 Label miss; | 1938 Label miss; |
| 1934 GenerateNameCheck(name, &miss); | 1939 GenerateNameCheck(name, &miss); |
| 1935 | 1940 |
| 1936 if (cell == NULL) { | 1941 if (cell == NULL) { |
| 1937 __ mov(edx, Operand(esp, 2 * kPointerSize)); | 1942 __ mov(edx, Operand(esp, 2 * kPointerSize)); |
| 1938 | 1943 |
| 1939 STATIC_ASSERT(kSmiTag == 0); | 1944 STATIC_ASSERT(kSmiTag == 0); |
| 1940 __ test(edx, Immediate(kSmiTagMask)); | 1945 __ test(edx, Immediate(kSmiTagMask)); |
| 1941 __ j(zero, &miss); | 1946 __ j(zero, &miss); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1952 __ mov(eax, Operand(esp, 1 * kPointerSize)); | 1957 __ mov(eax, Operand(esp, 1 * kPointerSize)); |
| 1953 | 1958 |
| 1954 // Check if the argument is a smi. | 1959 // Check if the argument is a smi. |
| 1955 Label smi; | 1960 Label smi; |
| 1956 STATIC_ASSERT(kSmiTag == 0); | 1961 STATIC_ASSERT(kSmiTag == 0); |
| 1957 __ test(eax, Immediate(kSmiTagMask)); | 1962 __ test(eax, Immediate(kSmiTagMask)); |
| 1958 __ j(zero, &smi); | 1963 __ j(zero, &smi); |
| 1959 | 1964 |
| 1960 // Check if the argument is a heap number and load its value into xmm0. | 1965 // Check if the argument is a heap number and load its value into xmm0. |
| 1961 Label slow; | 1966 Label slow; |
| 1962 __ CheckMap(eax, Factory::heap_number_map(), &slow, true); | 1967 __ CheckMap(eax, FACTORY->heap_number_map(), &slow, true); |
| 1963 __ movdbl(xmm0, FieldOperand(eax, HeapNumber::kValueOffset)); | 1968 __ movdbl(xmm0, FieldOperand(eax, HeapNumber::kValueOffset)); |
| 1964 | 1969 |
| 1965 // Check if the argument is strictly positive. Note this also | 1970 // Check if the argument is strictly positive. Note this also |
| 1966 // discards NaN. | 1971 // discards NaN. |
| 1967 __ xorpd(xmm1, xmm1); | 1972 __ xorpd(xmm1, xmm1); |
| 1968 __ ucomisd(xmm0, xmm1); | 1973 __ ucomisd(xmm0, xmm1); |
| 1969 __ j(below_equal, &slow); | 1974 __ j(below_equal, &slow); |
| 1970 | 1975 |
| 1971 // Do a truncating conversion. | 1976 // Do a truncating conversion. |
| 1972 __ cvttsd2si(eax, Operand(xmm0)); | 1977 __ cvttsd2si(eax, Operand(xmm0)); |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2045 // -- esp[0] : return address | 2050 // -- esp[0] : return address |
| 2046 // -- esp[(argc - n) * 4] : arg[n] (zero-based) | 2051 // -- esp[(argc - n) * 4] : arg[n] (zero-based) |
| 2047 // -- ... | 2052 // -- ... |
| 2048 // -- esp[(argc + 1) * 4] : receiver | 2053 // -- esp[(argc + 1) * 4] : receiver |
| 2049 // ----------------------------------- | 2054 // ----------------------------------- |
| 2050 | 2055 |
| 2051 const int argc = arguments().immediate(); | 2056 const int argc = arguments().immediate(); |
| 2052 | 2057 |
| 2053 // If the object is not a JSObject or we got an unexpected number of | 2058 // If the object is not a JSObject or we got an unexpected number of |
| 2054 // arguments, bail out to the regular call. | 2059 // arguments, bail out to the regular call. |
| 2055 if (!object->IsJSObject() || argc != 1) return Heap::undefined_value(); | 2060 if (!object->IsJSObject() || argc != 1) return HEAP->undefined_value(); |
| 2056 | 2061 |
| 2057 Label miss; | 2062 Label miss; |
| 2058 GenerateNameCheck(name, &miss); | 2063 GenerateNameCheck(name, &miss); |
| 2059 | 2064 |
| 2060 if (cell == NULL) { | 2065 if (cell == NULL) { |
| 2061 __ mov(edx, Operand(esp, 2 * kPointerSize)); | 2066 __ mov(edx, Operand(esp, 2 * kPointerSize)); |
| 2062 | 2067 |
| 2063 STATIC_ASSERT(kSmiTag == 0); | 2068 STATIC_ASSERT(kSmiTag == 0); |
| 2064 __ test(edx, Immediate(kSmiTagMask)); | 2069 __ test(edx, Immediate(kSmiTagMask)); |
| 2065 __ j(zero, &miss); | 2070 __ j(zero, &miss); |
| (...skipping 30 matching lines...) Expand all Loading... |
| 2096 // This only happens for the most negative smi. | 2101 // This only happens for the most negative smi. |
| 2097 Label slow; | 2102 Label slow; |
| 2098 __ j(negative, &slow); | 2103 __ j(negative, &slow); |
| 2099 | 2104 |
| 2100 // Smi case done. | 2105 // Smi case done. |
| 2101 __ ret(2 * kPointerSize); | 2106 __ ret(2 * kPointerSize); |
| 2102 | 2107 |
| 2103 // Check if the argument is a heap number and load its exponent and | 2108 // Check if the argument is a heap number and load its exponent and |
| 2104 // sign into ebx. | 2109 // sign into ebx. |
| 2105 __ bind(¬_smi); | 2110 __ bind(¬_smi); |
| 2106 __ CheckMap(eax, Factory::heap_number_map(), &slow, true); | 2111 __ CheckMap(eax, FACTORY->heap_number_map(), &slow, true); |
| 2107 __ mov(ebx, FieldOperand(eax, HeapNumber::kExponentOffset)); | 2112 __ mov(ebx, FieldOperand(eax, HeapNumber::kExponentOffset)); |
| 2108 | 2113 |
| 2109 // Check the sign of the argument. If the argument is positive, | 2114 // Check the sign of the argument. If the argument is positive, |
| 2110 // just return it. | 2115 // just return it. |
| 2111 Label negative_sign; | 2116 Label negative_sign; |
| 2112 __ test(ebx, Immediate(HeapNumber::kSignMask)); | 2117 __ test(ebx, Immediate(HeapNumber::kSignMask)); |
| 2113 __ j(not_zero, &negative_sign); | 2118 __ j(not_zero, &negative_sign); |
| 2114 __ ret(2 * kPointerSize); | 2119 __ ret(2 * kPointerSize); |
| 2115 | 2120 |
| 2116 // If the argument is negative, clear the sign, and return a new | 2121 // If the argument is negative, clear the sign, and return a new |
| (...skipping 26 matching lines...) Expand all Loading... |
| 2143 MaybeObject* CallStubCompiler::CompileFastApiCall( | 2148 MaybeObject* CallStubCompiler::CompileFastApiCall( |
| 2144 const CallOptimization& optimization, | 2149 const CallOptimization& optimization, |
| 2145 Object* object, | 2150 Object* object, |
| 2146 JSObject* holder, | 2151 JSObject* holder, |
| 2147 JSGlobalPropertyCell* cell, | 2152 JSGlobalPropertyCell* cell, |
| 2148 JSFunction* function, | 2153 JSFunction* function, |
| 2149 String* name) { | 2154 String* name) { |
| 2150 ASSERT(optimization.is_simple_api_call()); | 2155 ASSERT(optimization.is_simple_api_call()); |
| 2151 // Bail out if object is a global object as we don't want to | 2156 // Bail out if object is a global object as we don't want to |
| 2152 // repatch it to global receiver. | 2157 // repatch it to global receiver. |
| 2153 if (object->IsGlobalObject()) return Heap::undefined_value(); | 2158 if (object->IsGlobalObject()) return HEAP->undefined_value(); |
| 2154 if (cell != NULL) return Heap::undefined_value(); | 2159 if (cell != NULL) return HEAP->undefined_value(); |
| 2155 int depth = optimization.GetPrototypeDepthOfExpectedType( | 2160 int depth = optimization.GetPrototypeDepthOfExpectedType( |
| 2156 JSObject::cast(object), holder); | 2161 JSObject::cast(object), holder); |
| 2157 if (depth == kInvalidProtoDepth) return Heap::undefined_value(); | 2162 if (depth == kInvalidProtoDepth) return HEAP->undefined_value(); |
| 2158 | 2163 |
| 2159 Label miss, miss_before_stack_reserved; | 2164 Label miss, miss_before_stack_reserved; |
| 2160 | 2165 |
| 2161 GenerateNameCheck(name, &miss_before_stack_reserved); | 2166 GenerateNameCheck(name, &miss_before_stack_reserved); |
| 2162 | 2167 |
| 2163 // Get the receiver from the stack. | 2168 // Get the receiver from the stack. |
| 2164 const int argc = arguments().immediate(); | 2169 const int argc = arguments().immediate(); |
| 2165 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); | 2170 __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); |
| 2166 | 2171 |
| 2167 // Check that the receiver isn't a smi. | 2172 // Check that the receiver isn't a smi. |
| 2168 __ test(edx, Immediate(kSmiTagMask)); | 2173 __ test(edx, Immediate(kSmiTagMask)); |
| 2169 __ j(zero, &miss_before_stack_reserved, not_taken); | 2174 __ j(zero, &miss_before_stack_reserved, not_taken); |
| 2170 | 2175 |
| 2171 __ IncrementCounter(&Counters::call_const, 1); | 2176 __ IncrementCounter(COUNTERS->call_const(), 1); |
| 2172 __ IncrementCounter(&Counters::call_const_fast_api, 1); | 2177 __ IncrementCounter(COUNTERS->call_const_fast_api(), 1); |
| 2173 | 2178 |
| 2174 // Allocate space for v8::Arguments implicit values. Must be initialized | 2179 // Allocate space for v8::Arguments implicit values. Must be initialized |
| 2175 // before calling any runtime function. | 2180 // before calling any runtime function. |
| 2176 __ sub(Operand(esp), Immediate(kFastApiCallArguments * kPointerSize)); | 2181 __ sub(Operand(esp), Immediate(kFastApiCallArguments * kPointerSize)); |
| 2177 | 2182 |
| 2178 // Check that the maps haven't changed and find a Holder as a side effect. | 2183 // Check that the maps haven't changed and find a Holder as a side effect. |
| 2179 CheckPrototypes(JSObject::cast(object), edx, holder, | 2184 CheckPrototypes(JSObject::cast(object), edx, holder, |
| 2180 ebx, eax, edi, name, depth, &miss); | 2185 ebx, eax, edi, name, depth, &miss); |
| 2181 | 2186 |
| 2182 // Move the return address on top of the stack. | 2187 // Move the return address on top of the stack. |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2238 __ j(zero, &miss, not_taken); | 2243 __ j(zero, &miss, not_taken); |
| 2239 } | 2244 } |
| 2240 | 2245 |
| 2241 // Make sure that it's okay not to patch the on stack receiver | 2246 // Make sure that it's okay not to patch the on stack receiver |
| 2242 // unless we're doing a receiver map check. | 2247 // unless we're doing a receiver map check. |
| 2243 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK); | 2248 ASSERT(!object->IsGlobalObject() || check == RECEIVER_MAP_CHECK); |
| 2244 | 2249 |
| 2245 SharedFunctionInfo* function_info = function->shared(); | 2250 SharedFunctionInfo* function_info = function->shared(); |
| 2246 switch (check) { | 2251 switch (check) { |
| 2247 case RECEIVER_MAP_CHECK: | 2252 case RECEIVER_MAP_CHECK: |
| 2248 __ IncrementCounter(&Counters::call_const, 1); | 2253 __ IncrementCounter(COUNTERS->call_const(), 1); |
| 2249 | 2254 |
| 2250 // Check that the maps haven't changed. | 2255 // Check that the maps haven't changed. |
| 2251 CheckPrototypes(JSObject::cast(object), edx, holder, | 2256 CheckPrototypes(JSObject::cast(object), edx, holder, |
| 2252 ebx, eax, edi, name, &miss); | 2257 ebx, eax, edi, name, &miss); |
| 2253 | 2258 |
| 2254 // Patch the receiver on the stack with the global proxy if | 2259 // Patch the receiver on the stack with the global proxy if |
| 2255 // necessary. | 2260 // necessary. |
| 2256 if (object->IsGlobalObject()) { | 2261 if (object->IsGlobalObject()) { |
| 2257 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset)); | 2262 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset)); |
| 2258 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx); | 2263 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2299 } | 2304 } |
| 2300 | 2305 |
| 2301 case BOOLEAN_CHECK: { | 2306 case BOOLEAN_CHECK: { |
| 2302 if (!function->IsBuiltin() && !function_info->strict_mode()) { | 2307 if (!function->IsBuiltin() && !function_info->strict_mode()) { |
| 2303 // Calling non-strict non-builtins with a value as the receiver | 2308 // Calling non-strict non-builtins with a value as the receiver |
| 2304 // requires boxing. | 2309 // requires boxing. |
| 2305 __ jmp(&miss); | 2310 __ jmp(&miss); |
| 2306 } else { | 2311 } else { |
| 2307 Label fast; | 2312 Label fast; |
| 2308 // Check that the object is a boolean. | 2313 // Check that the object is a boolean. |
| 2309 __ cmp(edx, Factory::true_value()); | 2314 __ cmp(edx, FACTORY->true_value()); |
| 2310 __ j(equal, &fast, taken); | 2315 __ j(equal, &fast, taken); |
| 2311 __ cmp(edx, Factory::false_value()); | 2316 __ cmp(edx, FACTORY->false_value()); |
| 2312 __ j(not_equal, &miss, not_taken); | 2317 __ j(not_equal, &miss, not_taken); |
| 2313 __ bind(&fast); | 2318 __ bind(&fast); |
| 2314 // Check that the maps starting from the prototype haven't changed. | 2319 // Check that the maps starting from the prototype haven't changed. |
| 2315 GenerateDirectLoadGlobalFunctionPrototype( | 2320 GenerateDirectLoadGlobalFunctionPrototype( |
| 2316 masm(), Context::BOOLEAN_FUNCTION_INDEX, eax, &miss); | 2321 masm(), Context::BOOLEAN_FUNCTION_INDEX, eax, &miss); |
| 2317 CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder, | 2322 CheckPrototypes(JSObject::cast(object->GetPrototype()), eax, holder, |
| 2318 ebx, edx, edi, name, &miss); | 2323 ebx, edx, edi, name, &miss); |
| 2319 } | 2324 } |
| 2320 break; | 2325 break; |
| 2321 } | 2326 } |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2442 // Patch the receiver on the stack with the global proxy. | 2447 // Patch the receiver on the stack with the global proxy. |
| 2443 if (object->IsGlobalObject()) { | 2448 if (object->IsGlobalObject()) { |
| 2444 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset)); | 2449 __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset)); |
| 2445 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx); | 2450 __ mov(Operand(esp, (argc + 1) * kPointerSize), edx); |
| 2446 } | 2451 } |
| 2447 | 2452 |
| 2448 // Setup the context (function already in edi). | 2453 // Setup the context (function already in edi). |
| 2449 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); | 2454 __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); |
| 2450 | 2455 |
| 2451 // Jump to the cached code (tail call). | 2456 // Jump to the cached code (tail call). |
| 2452 __ IncrementCounter(&Counters::call_global_inline, 1); | 2457 __ IncrementCounter(COUNTERS->call_global_inline(), 1); |
| 2453 ASSERT(function->is_compiled()); | 2458 ASSERT(function->is_compiled()); |
| 2454 ParameterCount expected(function->shared()->formal_parameter_count()); | 2459 ParameterCount expected(function->shared()->formal_parameter_count()); |
| 2455 if (V8::UseCrankshaft()) { | 2460 if (V8::UseCrankshaft()) { |
| 2456 // TODO(kasperl): For now, we always call indirectly through the | 2461 // TODO(kasperl): For now, we always call indirectly through the |
| 2457 // code field in the function to allow recompilation to take effect | 2462 // code field in the function to allow recompilation to take effect |
| 2458 // without changing any of the call sites. | 2463 // without changing any of the call sites. |
| 2459 __ InvokeCode(FieldOperand(edi, JSFunction::kCodeEntryOffset), | 2464 __ InvokeCode(FieldOperand(edi, JSFunction::kCodeEntryOffset), |
| 2460 expected, arguments(), JUMP_FUNCTION); | 2465 expected, arguments(), JUMP_FUNCTION); |
| 2461 } else { | 2466 } else { |
| 2462 Handle<Code> code(function->code()); | 2467 Handle<Code> code(function->code()); |
| 2463 __ InvokeCode(code, expected, arguments(), | 2468 __ InvokeCode(code, expected, arguments(), |
| 2464 RelocInfo::CODE_TARGET, JUMP_FUNCTION); | 2469 RelocInfo::CODE_TARGET, JUMP_FUNCTION); |
| 2465 } | 2470 } |
| 2466 | 2471 |
| 2467 // Handle call cache miss. | 2472 // Handle call cache miss. |
| 2468 __ bind(&miss); | 2473 __ bind(&miss); |
| 2469 __ IncrementCounter(&Counters::call_global_inline_miss, 1); | 2474 __ IncrementCounter(COUNTERS->call_global_inline_miss(), 1); |
| 2470 Object* obj; | 2475 Object* obj; |
| 2471 { MaybeObject* maybe_obj = GenerateMissBranch(); | 2476 { MaybeObject* maybe_obj = GenerateMissBranch(); |
| 2472 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 2477 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| 2473 } | 2478 } |
| 2474 | 2479 |
| 2475 // Return the generated code. | 2480 // Return the generated code. |
| 2476 return GetCode(NORMAL, name); | 2481 return GetCode(NORMAL, name); |
| 2477 } | 2482 } |
| 2478 | 2483 |
| 2479 | 2484 |
| (...skipping 13 matching lines...) Expand all Loading... |
| 2493 GenerateStoreField(masm(), | 2498 GenerateStoreField(masm(), |
| 2494 object, | 2499 object, |
| 2495 index, | 2500 index, |
| 2496 transition, | 2501 transition, |
| 2497 edx, ecx, ebx, | 2502 edx, ecx, ebx, |
| 2498 &miss); | 2503 &miss); |
| 2499 | 2504 |
| 2500 // Handle store cache miss. | 2505 // Handle store cache miss. |
| 2501 __ bind(&miss); | 2506 __ bind(&miss); |
| 2502 __ mov(ecx, Immediate(Handle<String>(name))); // restore name | 2507 __ mov(ecx, Immediate(Handle<String>(name))); // restore name |
| 2503 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss)); | 2508 Handle<Code> ic(Isolate::Current()->builtins()->builtin( |
| 2509 Builtins::StoreIC_Miss)); |
| 2504 __ jmp(ic, RelocInfo::CODE_TARGET); | 2510 __ jmp(ic, RelocInfo::CODE_TARGET); |
| 2505 | 2511 |
| 2506 // Return the generated code. | 2512 // Return the generated code. |
| 2507 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name); | 2513 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name); |
| 2508 } | 2514 } |
| 2509 | 2515 |
| 2510 | 2516 |
| 2511 MaybeObject* StoreStubCompiler::CompileStoreCallback(JSObject* object, | 2517 MaybeObject* StoreStubCompiler::CompileStoreCallback(JSObject* object, |
| 2512 AccessorInfo* callback, | 2518 AccessorInfo* callback, |
| 2513 String* name) { | 2519 String* name) { |
| (...skipping 30 matching lines...) Expand all Loading... |
| 2544 __ push(eax); // value | 2550 __ push(eax); // value |
| 2545 __ push(ebx); // restore return address | 2551 __ push(ebx); // restore return address |
| 2546 | 2552 |
| 2547 // Do tail-call to the runtime system. | 2553 // Do tail-call to the runtime system. |
| 2548 ExternalReference store_callback_property = | 2554 ExternalReference store_callback_property = |
| 2549 ExternalReference(IC_Utility(IC::kStoreCallbackProperty)); | 2555 ExternalReference(IC_Utility(IC::kStoreCallbackProperty)); |
| 2550 __ TailCallExternalReference(store_callback_property, 4, 1); | 2556 __ TailCallExternalReference(store_callback_property, 4, 1); |
| 2551 | 2557 |
| 2552 // Handle store cache miss. | 2558 // Handle store cache miss. |
| 2553 __ bind(&miss); | 2559 __ bind(&miss); |
| 2554 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss)); | 2560 Handle<Code> ic(Isolate::Current()->builtins()->builtin( |
| 2561 Builtins::StoreIC_Miss)); |
| 2555 __ jmp(ic, RelocInfo::CODE_TARGET); | 2562 __ jmp(ic, RelocInfo::CODE_TARGET); |
| 2556 | 2563 |
| 2557 // Return the generated code. | 2564 // Return the generated code. |
| 2558 return GetCode(CALLBACKS, name); | 2565 return GetCode(CALLBACKS, name); |
| 2559 } | 2566 } |
| 2560 | 2567 |
| 2561 | 2568 |
| 2562 MaybeObject* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver, | 2569 MaybeObject* StoreStubCompiler::CompileStoreInterceptor(JSObject* receiver, |
| 2563 String* name) { | 2570 String* name) { |
| 2564 // ----------- S t a t e ------------- | 2571 // ----------- S t a t e ------------- |
| (...skipping 29 matching lines...) Expand all Loading... |
| 2594 __ push(Immediate(Smi::FromInt(strict_mode_))); | 2601 __ push(Immediate(Smi::FromInt(strict_mode_))); |
| 2595 __ push(ebx); // restore return address | 2602 __ push(ebx); // restore return address |
| 2596 | 2603 |
| 2597 // Do tail-call to the runtime system. | 2604 // Do tail-call to the runtime system. |
| 2598 ExternalReference store_ic_property = | 2605 ExternalReference store_ic_property = |
| 2599 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty)); | 2606 ExternalReference(IC_Utility(IC::kStoreInterceptorProperty)); |
| 2600 __ TailCallExternalReference(store_ic_property, 4, 1); | 2607 __ TailCallExternalReference(store_ic_property, 4, 1); |
| 2601 | 2608 |
| 2602 // Handle store cache miss. | 2609 // Handle store cache miss. |
| 2603 __ bind(&miss); | 2610 __ bind(&miss); |
| 2604 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss)); | 2611 Handle<Code> ic(Isolate::Current()->builtins()->builtin( |
| 2612 Builtins::StoreIC_Miss)); |
| 2605 __ jmp(ic, RelocInfo::CODE_TARGET); | 2613 __ jmp(ic, RelocInfo::CODE_TARGET); |
| 2606 | 2614 |
| 2607 // Return the generated code. | 2615 // Return the generated code. |
| 2608 return GetCode(INTERCEPTOR, name); | 2616 return GetCode(INTERCEPTOR, name); |
| 2609 } | 2617 } |
| 2610 | 2618 |
| 2611 | 2619 |
| 2612 MaybeObject* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object, | 2620 MaybeObject* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object, |
| 2613 JSGlobalPropertyCell* cell, | 2621 JSGlobalPropertyCell* cell, |
| 2614 String* name) { | 2622 String* name) { |
| (...skipping 11 matching lines...) Expand all Loading... |
| 2626 __ j(not_equal, &miss, not_taken); | 2634 __ j(not_equal, &miss, not_taken); |
| 2627 | 2635 |
| 2628 // Compute the cell operand to use. | 2636 // Compute the cell operand to use. |
| 2629 __ mov(ebx, Immediate(Handle<JSGlobalPropertyCell>(cell))); | 2637 __ mov(ebx, Immediate(Handle<JSGlobalPropertyCell>(cell))); |
| 2630 Operand cell_operand = FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset); | 2638 Operand cell_operand = FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset); |
| 2631 | 2639 |
| 2632 // Check that the value in the cell is not the hole. If it is, this | 2640 // Check that the value in the cell is not the hole. If it is, this |
| 2633 // cell could have been deleted and reintroducing the global needs | 2641 // cell could have been deleted and reintroducing the global needs |
| 2634 // to update the property details in the property dictionary of the | 2642 // to update the property details in the property dictionary of the |
| 2635 // global object. We bail out to the runtime system to do that. | 2643 // global object. We bail out to the runtime system to do that. |
| 2636 __ cmp(cell_operand, Factory::the_hole_value()); | 2644 __ cmp(cell_operand, FACTORY->the_hole_value()); |
| 2637 __ j(equal, &miss); | 2645 __ j(equal, &miss); |
| 2638 | 2646 |
| 2639 // Store the value in the cell. | 2647 // Store the value in the cell. |
| 2640 __ mov(cell_operand, eax); | 2648 __ mov(cell_operand, eax); |
| 2641 Label done; | 2649 Label done; |
| 2642 __ test(eax, Immediate(kSmiTagMask)); | 2650 __ test(eax, Immediate(kSmiTagMask)); |
| 2643 __ j(zero, &done); | 2651 __ j(zero, &done); |
| 2644 | 2652 |
| 2645 __ mov(ecx, eax); | 2653 __ mov(ecx, eax); |
| 2646 // Cells are always in the remembered set. | 2654 // Cells are always in the remembered set. |
| 2647 __ RecordWrite(ebx, edx, ecx, OMIT_REMEMBERED_SET, kDontSaveFPRegs); | 2655 __ RecordWrite(ebx, edx, ecx, OMIT_REMEMBERED_SET, kDontSaveFPRegs); |
| 2648 | 2656 |
| 2649 // Return the value (register eax). | 2657 // Return the value (register eax). |
| 2650 __ bind(&done); | 2658 __ bind(&done); |
| 2651 | 2659 |
| 2652 // Return the value (register eax). | 2660 // Return the value (register eax). |
| 2653 __ IncrementCounter(&Counters::named_store_global_inline, 1); | 2661 __ IncrementCounter(COUNTERS->named_store_global_inline(), 1); |
| 2654 __ ret(0); | 2662 __ ret(0); |
| 2655 | 2663 |
| 2656 // Handle store cache miss. | 2664 // Handle store cache miss. |
| 2657 __ bind(&miss); | 2665 __ bind(&miss); |
| 2658 __ IncrementCounter(&Counters::named_store_global_inline_miss, 1); | 2666 __ IncrementCounter(COUNTERS->named_store_global_inline_miss(), 1); |
| 2659 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Miss)); | 2667 Handle<Code> ic(Isolate::Current()->builtins()->builtin( |
| 2668 Builtins::StoreIC_Miss)); |
| 2660 __ jmp(ic, RelocInfo::CODE_TARGET); | 2669 __ jmp(ic, RelocInfo::CODE_TARGET); |
| 2661 | 2670 |
| 2662 // Return the generated code. | 2671 // Return the generated code. |
| 2663 return GetCode(NORMAL, name); | 2672 return GetCode(NORMAL, name); |
| 2664 } | 2673 } |
| 2665 | 2674 |
| 2666 | 2675 |
| 2667 MaybeObject* KeyedStoreStubCompiler::CompileStoreField(JSObject* object, | 2676 MaybeObject* KeyedStoreStubCompiler::CompileStoreField(JSObject* object, |
| 2668 int index, | 2677 int index, |
| 2669 Map* transition, | 2678 Map* transition, |
| 2670 String* name) { | 2679 String* name) { |
| 2671 // ----------- S t a t e ------------- | 2680 // ----------- S t a t e ------------- |
| 2672 // -- eax : value | 2681 // -- eax : value |
| 2673 // -- ecx : key | 2682 // -- ecx : key |
| 2674 // -- edx : receiver | 2683 // -- edx : receiver |
| 2675 // -- esp[0] : return address | 2684 // -- esp[0] : return address |
| 2676 // ----------------------------------- | 2685 // ----------------------------------- |
| 2677 Label miss; | 2686 Label miss; |
| 2678 | 2687 |
| 2679 __ IncrementCounter(&Counters::keyed_store_field, 1); | 2688 __ IncrementCounter(COUNTERS->keyed_store_field(), 1); |
| 2680 | 2689 |
| 2681 // Check that the name has not changed. | 2690 // Check that the name has not changed. |
| 2682 __ cmp(Operand(ecx), Immediate(Handle<String>(name))); | 2691 __ cmp(Operand(ecx), Immediate(Handle<String>(name))); |
| 2683 __ j(not_equal, &miss, not_taken); | 2692 __ j(not_equal, &miss, not_taken); |
| 2684 | 2693 |
| 2685 // Generate store field code. Trashes the name register. | 2694 // Generate store field code. Trashes the name register. |
| 2686 GenerateStoreField(masm(), | 2695 GenerateStoreField(masm(), |
| 2687 object, | 2696 object, |
| 2688 index, | 2697 index, |
| 2689 transition, | 2698 transition, |
| 2690 edx, ecx, ebx, | 2699 edx, ecx, ebx, |
| 2691 &miss); | 2700 &miss); |
| 2692 | 2701 |
| 2693 // Handle store cache miss. | 2702 // Handle store cache miss. |
| 2694 __ bind(&miss); | 2703 __ bind(&miss); |
| 2695 __ DecrementCounter(&Counters::keyed_store_field, 1); | 2704 __ DecrementCounter(COUNTERS->keyed_store_field(), 1); |
| 2696 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss)); | 2705 Handle<Code> ic(Isolate::Current()->builtins()->builtin( |
| 2706 Builtins::KeyedStoreIC_Miss)); |
| 2697 __ jmp(ic, RelocInfo::CODE_TARGET); | 2707 __ jmp(ic, RelocInfo::CODE_TARGET); |
| 2698 | 2708 |
| 2699 // Return the generated code. | 2709 // Return the generated code. |
| 2700 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name); | 2710 return GetCode(transition == NULL ? FIELD : MAP_TRANSITION, name); |
| 2701 } | 2711 } |
| 2702 | 2712 |
| 2703 | 2713 |
| 2704 MaybeObject* KeyedStoreStubCompiler::CompileStoreSpecialized( | 2714 MaybeObject* KeyedStoreStubCompiler::CompileStoreSpecialized( |
| 2705 JSObject* receiver) { | 2715 JSObject* receiver) { |
| 2706 // ----------- S t a t e ------------- | 2716 // ----------- S t a t e ------------- |
| (...skipping 13 matching lines...) Expand all Loading... |
| 2720 Immediate(Handle<Map>(receiver->map()))); | 2730 Immediate(Handle<Map>(receiver->map()))); |
| 2721 __ j(not_equal, &miss, not_taken); | 2731 __ j(not_equal, &miss, not_taken); |
| 2722 | 2732 |
| 2723 // Check that the key is a smi. | 2733 // Check that the key is a smi. |
| 2724 __ test(ecx, Immediate(kSmiTagMask)); | 2734 __ test(ecx, Immediate(kSmiTagMask)); |
| 2725 __ j(not_zero, &miss, not_taken); | 2735 __ j(not_zero, &miss, not_taken); |
| 2726 | 2736 |
| 2727 // Get the elements array and make sure it is a fast element array, not 'cow'. | 2737 // Get the elements array and make sure it is a fast element array, not 'cow'. |
| 2728 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset)); | 2738 __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset)); |
| 2729 __ cmp(FieldOperand(edi, HeapObject::kMapOffset), | 2739 __ cmp(FieldOperand(edi, HeapObject::kMapOffset), |
| 2730 Immediate(Factory::fixed_array_map())); | 2740 Immediate(FACTORY->fixed_array_map())); |
| 2731 __ j(not_equal, &miss, not_taken); | 2741 __ j(not_equal, &miss, not_taken); |
| 2732 | 2742 |
| 2733 // Check that the key is within bounds. | 2743 // Check that the key is within bounds. |
| 2734 if (receiver->IsJSArray()) { | 2744 if (receiver->IsJSArray()) { |
| 2735 __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset)); // Compare smis. | 2745 __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset)); // Compare smis. |
| 2736 __ j(above_equal, &miss, not_taken); | 2746 __ j(above_equal, &miss, not_taken); |
| 2737 } else { | 2747 } else { |
| 2738 __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset)); // Compare smis. | 2748 __ cmp(ecx, FieldOperand(edi, FixedArray::kLengthOffset)); // Compare smis. |
| 2739 __ j(above_equal, &miss, not_taken); | 2749 __ j(above_equal, &miss, not_taken); |
| 2740 } | 2750 } |
| 2741 | 2751 |
| 2742 // Do the store and update the write barrier. Make sure to preserve | 2752 // Do the store and update the write barrier. Make sure to preserve |
| 2743 // the value in register eax. | 2753 // the value in register eax. |
| 2744 __ mov(edx, Operand(eax)); | 2754 __ mov(edx, Operand(eax)); |
| 2745 __ mov(FieldOperand(edi, ecx, times_2, FixedArray::kHeaderSize), eax); | 2755 __ mov(FieldOperand(edi, ecx, times_2, FixedArray::kHeaderSize), eax); |
| 2746 __ RecordWrite(edi, 0, edx, ecx, kDontSaveFPRegs); | 2756 __ RecordWrite(edi, 0, edx, ecx, kDontSaveFPRegs); |
| 2747 | 2757 |
| 2748 // Done. | 2758 // Done. |
| 2749 __ ret(0); | 2759 __ ret(0); |
| 2750 | 2760 |
| 2751 // Handle store cache miss. | 2761 // Handle store cache miss. |
| 2752 __ bind(&miss); | 2762 __ bind(&miss); |
| 2753 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Miss)); | 2763 Handle<Code> ic( |
| 2764 Isolate::Current()->builtins()->builtin(Builtins::KeyedStoreIC_Miss)); |
| 2754 __ jmp(ic, RelocInfo::CODE_TARGET); | 2765 __ jmp(ic, RelocInfo::CODE_TARGET); |
| 2755 | 2766 |
| 2756 // Return the generated code. | 2767 // Return the generated code. |
| 2757 return GetCode(NORMAL, NULL); | 2768 return GetCode(NORMAL, NULL); |
| 2758 } | 2769 } |
| 2759 | 2770 |
| 2760 | 2771 |
| 2761 MaybeObject* LoadStubCompiler::CompileLoadNonexistent(String* name, | 2772 MaybeObject* LoadStubCompiler::CompileLoadNonexistent(String* name, |
| 2762 JSObject* object, | 2773 JSObject* object, |
| 2763 JSObject* last) { | 2774 JSObject* last) { |
| (...skipping 24 matching lines...) Expand all Loading... |
| 2788 edx, | 2799 edx, |
| 2789 &miss); | 2800 &miss); |
| 2790 if (cell->IsFailure()) { | 2801 if (cell->IsFailure()) { |
| 2791 miss.Unuse(); | 2802 miss.Unuse(); |
| 2792 return cell; | 2803 return cell; |
| 2793 } | 2804 } |
| 2794 } | 2805 } |
| 2795 | 2806 |
| 2796 // Return undefined if maps of the full prototype chain are still the | 2807 // Return undefined if maps of the full prototype chain are still the |
| 2797 // same and no global property with this name contains a value. | 2808 // same and no global property with this name contains a value. |
| 2798 __ mov(eax, Factory::undefined_value()); | 2809 __ mov(eax, FACTORY->undefined_value()); |
| 2799 __ ret(0); | 2810 __ ret(0); |
| 2800 | 2811 |
| 2801 __ bind(&miss); | 2812 __ bind(&miss); |
| 2802 GenerateLoadMiss(masm(), Code::LOAD_IC); | 2813 GenerateLoadMiss(masm(), Code::LOAD_IC); |
| 2803 | 2814 |
| 2804 // Return the generated code. | 2815 // Return the generated code. |
| 2805 return GetCode(NONEXISTENT, Heap::empty_string()); | 2816 return GetCode(NONEXISTENT, HEAP->empty_string()); |
| 2806 } | 2817 } |
| 2807 | 2818 |
| 2808 | 2819 |
| 2809 MaybeObject* LoadStubCompiler::CompileLoadField(JSObject* object, | 2820 MaybeObject* LoadStubCompiler::CompileLoadField(JSObject* object, |
| 2810 JSObject* holder, | 2821 JSObject* holder, |
| 2811 int index, | 2822 int index, |
| 2812 String* name) { | 2823 String* name) { |
| 2813 // ----------- S t a t e ------------- | 2824 // ----------- S t a t e ------------- |
| 2814 // -- eax : receiver | 2825 // -- eax : receiver |
| 2815 // -- ecx : name | 2826 // -- ecx : name |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2932 // Get the value from the cell. | 2943 // Get the value from the cell. |
| 2933 if (Serializer::enabled()) { | 2944 if (Serializer::enabled()) { |
| 2934 __ mov(ebx, Immediate(Handle<JSGlobalPropertyCell>(cell))); | 2945 __ mov(ebx, Immediate(Handle<JSGlobalPropertyCell>(cell))); |
| 2935 __ mov(ebx, FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset)); | 2946 __ mov(ebx, FieldOperand(ebx, JSGlobalPropertyCell::kValueOffset)); |
| 2936 } else { | 2947 } else { |
| 2937 __ mov(ebx, Operand::Cell(Handle<JSGlobalPropertyCell>(cell))); | 2948 __ mov(ebx, Operand::Cell(Handle<JSGlobalPropertyCell>(cell))); |
| 2938 } | 2949 } |
| 2939 | 2950 |
| 2940 // Check for deleted property if property can actually be deleted. | 2951 // Check for deleted property if property can actually be deleted. |
| 2941 if (!is_dont_delete) { | 2952 if (!is_dont_delete) { |
| 2942 __ cmp(ebx, Factory::the_hole_value()); | 2953 __ cmp(ebx, FACTORY->the_hole_value()); |
| 2943 __ j(equal, &miss, not_taken); | 2954 __ j(equal, &miss, not_taken); |
| 2944 } else if (FLAG_debug_code) { | 2955 } else if (FLAG_debug_code) { |
| 2945 __ cmp(ebx, Factory::the_hole_value()); | 2956 __ cmp(ebx, FACTORY->the_hole_value()); |
| 2946 __ Check(not_equal, "DontDelete cells can't contain the hole"); | 2957 __ Check(not_equal, "DontDelete cells can't contain the hole"); |
| 2947 } | 2958 } |
| 2948 | 2959 |
| 2949 __ IncrementCounter(&Counters::named_load_global_stub, 1); | 2960 __ IncrementCounter(COUNTERS->named_load_global_stub(), 1); |
| 2950 __ mov(eax, ebx); | 2961 __ mov(eax, ebx); |
| 2951 __ ret(0); | 2962 __ ret(0); |
| 2952 | 2963 |
| 2953 __ bind(&miss); | 2964 __ bind(&miss); |
| 2954 __ IncrementCounter(&Counters::named_load_global_stub_miss, 1); | 2965 __ IncrementCounter(COUNTERS->named_load_global_stub_miss(), 1); |
| 2955 GenerateLoadMiss(masm(), Code::LOAD_IC); | 2966 GenerateLoadMiss(masm(), Code::LOAD_IC); |
| 2956 | 2967 |
| 2957 // Return the generated code. | 2968 // Return the generated code. |
| 2958 return GetCode(NORMAL, name); | 2969 return GetCode(NORMAL, name); |
| 2959 } | 2970 } |
| 2960 | 2971 |
| 2961 | 2972 |
| 2962 MaybeObject* KeyedLoadStubCompiler::CompileLoadField(String* name, | 2973 MaybeObject* KeyedLoadStubCompiler::CompileLoadField(String* name, |
| 2963 JSObject* receiver, | 2974 JSObject* receiver, |
| 2964 JSObject* holder, | 2975 JSObject* holder, |
| 2965 int index) { | 2976 int index) { |
| 2966 // ----------- S t a t e ------------- | 2977 // ----------- S t a t e ------------- |
| 2967 // -- eax : key | 2978 // -- eax : key |
| 2968 // -- edx : receiver | 2979 // -- edx : receiver |
| 2969 // -- esp[0] : return address | 2980 // -- esp[0] : return address |
| 2970 // ----------------------------------- | 2981 // ----------------------------------- |
| 2971 Label miss; | 2982 Label miss; |
| 2972 | 2983 |
| 2973 __ IncrementCounter(&Counters::keyed_load_field, 1); | 2984 __ IncrementCounter(COUNTERS->keyed_load_field(), 1); |
| 2974 | 2985 |
| 2975 // Check that the name has not changed. | 2986 // Check that the name has not changed. |
| 2976 __ cmp(Operand(eax), Immediate(Handle<String>(name))); | 2987 __ cmp(Operand(eax), Immediate(Handle<String>(name))); |
| 2977 __ j(not_equal, &miss, not_taken); | 2988 __ j(not_equal, &miss, not_taken); |
| 2978 | 2989 |
| 2979 GenerateLoadField(receiver, holder, edx, ebx, ecx, edi, index, name, &miss); | 2990 GenerateLoadField(receiver, holder, edx, ebx, ecx, edi, index, name, &miss); |
| 2980 | 2991 |
| 2981 __ bind(&miss); | 2992 __ bind(&miss); |
| 2982 __ DecrementCounter(&Counters::keyed_load_field, 1); | 2993 __ DecrementCounter(COUNTERS->keyed_load_field(), 1); |
| 2983 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); | 2994 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); |
| 2984 | 2995 |
| 2985 // Return the generated code. | 2996 // Return the generated code. |
| 2986 return GetCode(FIELD, name); | 2997 return GetCode(FIELD, name); |
| 2987 } | 2998 } |
| 2988 | 2999 |
| 2989 | 3000 |
| 2990 MaybeObject* KeyedLoadStubCompiler::CompileLoadCallback( | 3001 MaybeObject* KeyedLoadStubCompiler::CompileLoadCallback( |
| 2991 String* name, | 3002 String* name, |
| 2992 JSObject* receiver, | 3003 JSObject* receiver, |
| 2993 JSObject* holder, | 3004 JSObject* holder, |
| 2994 AccessorInfo* callback) { | 3005 AccessorInfo* callback) { |
| 2995 // ----------- S t a t e ------------- | 3006 // ----------- S t a t e ------------- |
| 2996 // -- eax : key | 3007 // -- eax : key |
| 2997 // -- edx : receiver | 3008 // -- edx : receiver |
| 2998 // -- esp[0] : return address | 3009 // -- esp[0] : return address |
| 2999 // ----------------------------------- | 3010 // ----------------------------------- |
| 3000 Label miss; | 3011 Label miss; |
| 3001 | 3012 |
| 3002 __ IncrementCounter(&Counters::keyed_load_callback, 1); | 3013 __ IncrementCounter(COUNTERS->keyed_load_callback(), 1); |
| 3003 | 3014 |
| 3004 // Check that the name has not changed. | 3015 // Check that the name has not changed. |
| 3005 __ cmp(Operand(eax), Immediate(Handle<String>(name))); | 3016 __ cmp(Operand(eax), Immediate(Handle<String>(name))); |
| 3006 __ j(not_equal, &miss, not_taken); | 3017 __ j(not_equal, &miss, not_taken); |
| 3007 | 3018 |
| 3008 MaybeObject* result = GenerateLoadCallback(receiver, holder, edx, eax, ebx, | 3019 MaybeObject* result = GenerateLoadCallback(receiver, holder, edx, eax, ebx, |
| 3009 ecx, edi, callback, name, &miss); | 3020 ecx, edi, callback, name, &miss); |
| 3010 if (result->IsFailure()) { | 3021 if (result->IsFailure()) { |
| 3011 miss.Unuse(); | 3022 miss.Unuse(); |
| 3012 return result; | 3023 return result; |
| 3013 } | 3024 } |
| 3014 | 3025 |
| 3015 __ bind(&miss); | 3026 __ bind(&miss); |
| 3016 | 3027 |
| 3017 __ DecrementCounter(&Counters::keyed_load_callback, 1); | 3028 __ DecrementCounter(COUNTERS->keyed_load_callback(), 1); |
| 3018 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); | 3029 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); |
| 3019 | 3030 |
| 3020 // Return the generated code. | 3031 // Return the generated code. |
| 3021 return GetCode(CALLBACKS, name); | 3032 return GetCode(CALLBACKS, name); |
| 3022 } | 3033 } |
| 3023 | 3034 |
| 3024 | 3035 |
| 3025 MaybeObject* KeyedLoadStubCompiler::CompileLoadConstant(String* name, | 3036 MaybeObject* KeyedLoadStubCompiler::CompileLoadConstant(String* name, |
| 3026 JSObject* receiver, | 3037 JSObject* receiver, |
| 3027 JSObject* holder, | 3038 JSObject* holder, |
| 3028 Object* value) { | 3039 Object* value) { |
| 3029 // ----------- S t a t e ------------- | 3040 // ----------- S t a t e ------------- |
| 3030 // -- eax : key | 3041 // -- eax : key |
| 3031 // -- edx : receiver | 3042 // -- edx : receiver |
| 3032 // -- esp[0] : return address | 3043 // -- esp[0] : return address |
| 3033 // ----------------------------------- | 3044 // ----------------------------------- |
| 3034 Label miss; | 3045 Label miss; |
| 3035 | 3046 |
| 3036 __ IncrementCounter(&Counters::keyed_load_constant_function, 1); | 3047 __ IncrementCounter(COUNTERS->keyed_load_constant_function(), 1); |
| 3037 | 3048 |
| 3038 // Check that the name has not changed. | 3049 // Check that the name has not changed. |
| 3039 __ cmp(Operand(eax), Immediate(Handle<String>(name))); | 3050 __ cmp(Operand(eax), Immediate(Handle<String>(name))); |
| 3040 __ j(not_equal, &miss, not_taken); | 3051 __ j(not_equal, &miss, not_taken); |
| 3041 | 3052 |
| 3042 GenerateLoadConstant(receiver, holder, edx, ebx, ecx, edi, | 3053 GenerateLoadConstant(receiver, holder, edx, ebx, ecx, edi, |
| 3043 value, name, &miss); | 3054 value, name, &miss); |
| 3044 __ bind(&miss); | 3055 __ bind(&miss); |
| 3045 __ DecrementCounter(&Counters::keyed_load_constant_function, 1); | 3056 __ DecrementCounter(COUNTERS->keyed_load_constant_function(), 1); |
| 3046 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); | 3057 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); |
| 3047 | 3058 |
| 3048 // Return the generated code. | 3059 // Return the generated code. |
| 3049 return GetCode(CONSTANT_FUNCTION, name); | 3060 return GetCode(CONSTANT_FUNCTION, name); |
| 3050 } | 3061 } |
| 3051 | 3062 |
| 3052 | 3063 |
| 3053 MaybeObject* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver, | 3064 MaybeObject* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver, |
| 3054 JSObject* holder, | 3065 JSObject* holder, |
| 3055 String* name) { | 3066 String* name) { |
| 3056 // ----------- S t a t e ------------- | 3067 // ----------- S t a t e ------------- |
| 3057 // -- eax : key | 3068 // -- eax : key |
| 3058 // -- edx : receiver | 3069 // -- edx : receiver |
| 3059 // -- esp[0] : return address | 3070 // -- esp[0] : return address |
| 3060 // ----------------------------------- | 3071 // ----------------------------------- |
| 3061 Label miss; | 3072 Label miss; |
| 3062 | 3073 |
| 3063 __ IncrementCounter(&Counters::keyed_load_interceptor, 1); | 3074 __ IncrementCounter(COUNTERS->keyed_load_interceptor(), 1); |
| 3064 | 3075 |
| 3065 // Check that the name has not changed. | 3076 // Check that the name has not changed. |
| 3066 __ cmp(Operand(eax), Immediate(Handle<String>(name))); | 3077 __ cmp(Operand(eax), Immediate(Handle<String>(name))); |
| 3067 __ j(not_equal, &miss, not_taken); | 3078 __ j(not_equal, &miss, not_taken); |
| 3068 | 3079 |
| 3069 LookupResult lookup; | 3080 LookupResult lookup; |
| 3070 LookupPostInterceptor(holder, name, &lookup); | 3081 LookupPostInterceptor(holder, name, &lookup); |
| 3071 GenerateLoadInterceptor(receiver, | 3082 GenerateLoadInterceptor(receiver, |
| 3072 holder, | 3083 holder, |
| 3073 &lookup, | 3084 &lookup, |
| 3074 edx, | 3085 edx, |
| 3075 eax, | 3086 eax, |
| 3076 ecx, | 3087 ecx, |
| 3077 ebx, | 3088 ebx, |
| 3078 edi, | 3089 edi, |
| 3079 name, | 3090 name, |
| 3080 &miss); | 3091 &miss); |
| 3081 __ bind(&miss); | 3092 __ bind(&miss); |
| 3082 __ DecrementCounter(&Counters::keyed_load_interceptor, 1); | 3093 __ DecrementCounter(COUNTERS->keyed_load_interceptor(), 1); |
| 3083 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); | 3094 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); |
| 3084 | 3095 |
| 3085 // Return the generated code. | 3096 // Return the generated code. |
| 3086 return GetCode(INTERCEPTOR, name); | 3097 return GetCode(INTERCEPTOR, name); |
| 3087 } | 3098 } |
| 3088 | 3099 |
| 3089 | 3100 |
| 3090 MaybeObject* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) { | 3101 MaybeObject* KeyedLoadStubCompiler::CompileLoadArrayLength(String* name) { |
| 3091 // ----------- S t a t e ------------- | 3102 // ----------- S t a t e ------------- |
| 3092 // -- eax : key | 3103 // -- eax : key |
| 3093 // -- edx : receiver | 3104 // -- edx : receiver |
| 3094 // -- esp[0] : return address | 3105 // -- esp[0] : return address |
| 3095 // ----------------------------------- | 3106 // ----------------------------------- |
| 3096 Label miss; | 3107 Label miss; |
| 3097 | 3108 |
| 3098 __ IncrementCounter(&Counters::keyed_load_array_length, 1); | 3109 __ IncrementCounter(COUNTERS->keyed_load_array_length(), 1); |
| 3099 | 3110 |
| 3100 // Check that the name has not changed. | 3111 // Check that the name has not changed. |
| 3101 __ cmp(Operand(eax), Immediate(Handle<String>(name))); | 3112 __ cmp(Operand(eax), Immediate(Handle<String>(name))); |
| 3102 __ j(not_equal, &miss, not_taken); | 3113 __ j(not_equal, &miss, not_taken); |
| 3103 | 3114 |
| 3104 GenerateLoadArrayLength(masm(), edx, ecx, &miss); | 3115 GenerateLoadArrayLength(masm(), edx, ecx, &miss); |
| 3105 __ bind(&miss); | 3116 __ bind(&miss); |
| 3106 __ DecrementCounter(&Counters::keyed_load_array_length, 1); | 3117 __ DecrementCounter(COUNTERS->keyed_load_array_length(), 1); |
| 3107 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); | 3118 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); |
| 3108 | 3119 |
| 3109 // Return the generated code. | 3120 // Return the generated code. |
| 3110 return GetCode(CALLBACKS, name); | 3121 return GetCode(CALLBACKS, name); |
| 3111 } | 3122 } |
| 3112 | 3123 |
| 3113 | 3124 |
| 3114 MaybeObject* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) { | 3125 MaybeObject* KeyedLoadStubCompiler::CompileLoadStringLength(String* name) { |
| 3115 // ----------- S t a t e ------------- | 3126 // ----------- S t a t e ------------- |
| 3116 // -- eax : key | 3127 // -- eax : key |
| 3117 // -- edx : receiver | 3128 // -- edx : receiver |
| 3118 // -- esp[0] : return address | 3129 // -- esp[0] : return address |
| 3119 // ----------------------------------- | 3130 // ----------------------------------- |
| 3120 Label miss; | 3131 Label miss; |
| 3121 | 3132 |
| 3122 __ IncrementCounter(&Counters::keyed_load_string_length, 1); | 3133 __ IncrementCounter(COUNTERS->keyed_load_string_length(), 1); |
| 3123 | 3134 |
| 3124 // Check that the name has not changed. | 3135 // Check that the name has not changed. |
| 3125 __ cmp(Operand(eax), Immediate(Handle<String>(name))); | 3136 __ cmp(Operand(eax), Immediate(Handle<String>(name))); |
| 3126 __ j(not_equal, &miss, not_taken); | 3137 __ j(not_equal, &miss, not_taken); |
| 3127 | 3138 |
| 3128 GenerateLoadStringLength(masm(), edx, ecx, ebx, &miss, true); | 3139 GenerateLoadStringLength(masm(), edx, ecx, ebx, &miss, true); |
| 3129 __ bind(&miss); | 3140 __ bind(&miss); |
| 3130 __ DecrementCounter(&Counters::keyed_load_string_length, 1); | 3141 __ DecrementCounter(COUNTERS->keyed_load_string_length(), 1); |
| 3131 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); | 3142 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); |
| 3132 | 3143 |
| 3133 // Return the generated code. | 3144 // Return the generated code. |
| 3134 return GetCode(CALLBACKS, name); | 3145 return GetCode(CALLBACKS, name); |
| 3135 } | 3146 } |
| 3136 | 3147 |
| 3137 | 3148 |
| 3138 MaybeObject* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) { | 3149 MaybeObject* KeyedLoadStubCompiler::CompileLoadFunctionPrototype(String* name) { |
| 3139 // ----------- S t a t e ------------- | 3150 // ----------- S t a t e ------------- |
| 3140 // -- eax : key | 3151 // -- eax : key |
| 3141 // -- edx : receiver | 3152 // -- edx : receiver |
| 3142 // -- esp[0] : return address | 3153 // -- esp[0] : return address |
| 3143 // ----------------------------------- | 3154 // ----------------------------------- |
| 3144 Label miss; | 3155 Label miss; |
| 3145 | 3156 |
| 3146 __ IncrementCounter(&Counters::keyed_load_function_prototype, 1); | 3157 __ IncrementCounter(COUNTERS->keyed_load_function_prototype(), 1); |
| 3147 | 3158 |
| 3148 // Check that the name has not changed. | 3159 // Check that the name has not changed. |
| 3149 __ cmp(Operand(eax), Immediate(Handle<String>(name))); | 3160 __ cmp(Operand(eax), Immediate(Handle<String>(name))); |
| 3150 __ j(not_equal, &miss, not_taken); | 3161 __ j(not_equal, &miss, not_taken); |
| 3151 | 3162 |
| 3152 GenerateLoadFunctionPrototype(masm(), edx, ecx, ebx, &miss); | 3163 GenerateLoadFunctionPrototype(masm(), edx, ecx, ebx, &miss); |
| 3153 __ bind(&miss); | 3164 __ bind(&miss); |
| 3154 __ DecrementCounter(&Counters::keyed_load_function_prototype, 1); | 3165 __ DecrementCounter(COUNTERS->keyed_load_function_prototype(), 1); |
| 3155 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); | 3166 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); |
| 3156 | 3167 |
| 3157 // Return the generated code. | 3168 // Return the generated code. |
| 3158 return GetCode(CALLBACKS, name); | 3169 return GetCode(CALLBACKS, name); |
| 3159 } | 3170 } |
| 3160 | 3171 |
| 3161 | 3172 |
| 3162 MaybeObject* KeyedLoadStubCompiler::CompileLoadSpecialized(JSObject* receiver) { | 3173 MaybeObject* KeyedLoadStubCompiler::CompileLoadSpecialized(JSObject* receiver) { |
| 3163 // ----------- S t a t e ------------- | 3174 // ----------- S t a t e ------------- |
| 3164 // -- eax : key | 3175 // -- eax : key |
| (...skipping 19 matching lines...) Expand all Loading... |
| 3184 __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset)); | 3195 __ mov(ecx, FieldOperand(edx, JSObject::kElementsOffset)); |
| 3185 __ AssertFastElements(ecx); | 3196 __ AssertFastElements(ecx); |
| 3186 | 3197 |
| 3187 // Check that the key is within bounds. | 3198 // Check that the key is within bounds. |
| 3188 __ cmp(eax, FieldOperand(ecx, FixedArray::kLengthOffset)); | 3199 __ cmp(eax, FieldOperand(ecx, FixedArray::kLengthOffset)); |
| 3189 __ j(above_equal, &miss, not_taken); | 3200 __ j(above_equal, &miss, not_taken); |
| 3190 | 3201 |
| 3191 // Load the result and make sure it's not the hole. | 3202 // Load the result and make sure it's not the hole. |
| 3192 __ mov(ebx, Operand(ecx, eax, times_2, | 3203 __ mov(ebx, Operand(ecx, eax, times_2, |
| 3193 FixedArray::kHeaderSize - kHeapObjectTag)); | 3204 FixedArray::kHeaderSize - kHeapObjectTag)); |
| 3194 __ cmp(ebx, Factory::the_hole_value()); | 3205 __ cmp(ebx, FACTORY->the_hole_value()); |
| 3195 __ j(equal, &miss, not_taken); | 3206 __ j(equal, &miss, not_taken); |
| 3196 __ mov(eax, ebx); | 3207 __ mov(eax, ebx); |
| 3197 __ ret(0); | 3208 __ ret(0); |
| 3198 | 3209 |
| 3199 __ bind(&miss); | 3210 __ bind(&miss); |
| 3200 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); | 3211 GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC); |
| 3201 | 3212 |
| 3202 // Return the generated code. | 3213 // Return the generated code. |
| 3203 return GetCode(NORMAL, NULL); | 3214 return GetCode(NORMAL, NULL); |
| 3204 } | 3215 } |
| 3205 | 3216 |
| 3206 | 3217 |
| 3207 // Specialized stub for constructing objects from functions which only have only | 3218 // Specialized stub for constructing objects from functions which only have only |
| 3208 // simple assignments of the form this.x = ...; in their body. | 3219 // simple assignments of the form this.x = ...; in their body. |
| 3209 MaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) { | 3220 MaybeObject* ConstructStubCompiler::CompileConstructStub(JSFunction* function) { |
| 3210 // ----------- S t a t e ------------- | 3221 // ----------- S t a t e ------------- |
| 3211 // -- eax : argc | 3222 // -- eax : argc |
| 3212 // -- edi : constructor | 3223 // -- edi : constructor |
| 3213 // -- esp[0] : return address | 3224 // -- esp[0] : return address |
| 3214 // -- esp[4] : last argument | 3225 // -- esp[4] : last argument |
| 3215 // ----------------------------------- | 3226 // ----------------------------------- |
| 3216 Label generic_stub_call; | 3227 Label generic_stub_call; |
| 3217 #ifdef ENABLE_DEBUGGER_SUPPORT | 3228 #ifdef ENABLE_DEBUGGER_SUPPORT |
| 3218 // Check to see whether there are any break points in the function code. If | 3229 // Check to see whether there are any break points in the function code. If |
| 3219 // there are jump to the generic constructor stub which calls the actual | 3230 // there are jump to the generic constructor stub which calls the actual |
| 3220 // code for the function thereby hitting the break points. | 3231 // code for the function thereby hitting the break points. |
| 3221 __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); | 3232 __ mov(ebx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset)); |
| 3222 __ mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kDebugInfoOffset)); | 3233 __ mov(ebx, FieldOperand(ebx, SharedFunctionInfo::kDebugInfoOffset)); |
| 3223 __ cmp(ebx, Factory::undefined_value()); | 3234 __ cmp(ebx, FACTORY->undefined_value()); |
| 3224 __ j(not_equal, &generic_stub_call, not_taken); | 3235 __ j(not_equal, &generic_stub_call, not_taken); |
| 3225 #endif | 3236 #endif |
| 3226 | 3237 |
| 3227 // Load the initial map and verify that it is in fact a map. | 3238 // Load the initial map and verify that it is in fact a map. |
| 3228 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset)); | 3239 __ mov(ebx, FieldOperand(edi, JSFunction::kPrototypeOrInitialMapOffset)); |
| 3229 // Will both indicate a NULL and a Smi. | 3240 // Will both indicate a NULL and a Smi. |
| 3230 __ test(ebx, Immediate(kSmiTagMask)); | 3241 __ test(ebx, Immediate(kSmiTagMask)); |
| 3231 __ j(zero, &generic_stub_call); | 3242 __ j(zero, &generic_stub_call); |
| 3232 __ CmpObjectType(ebx, MAP_TYPE, ecx); | 3243 __ CmpObjectType(ebx, MAP_TYPE, ecx); |
| 3233 __ j(not_equal, &generic_stub_call); | 3244 __ j(not_equal, &generic_stub_call); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 3250 edx, | 3261 edx, |
| 3251 ecx, | 3262 ecx, |
| 3252 no_reg, | 3263 no_reg, |
| 3253 &generic_stub_call, | 3264 &generic_stub_call, |
| 3254 NO_ALLOCATION_FLAGS); | 3265 NO_ALLOCATION_FLAGS); |
| 3255 | 3266 |
| 3256 // Allocated the JSObject, now initialize the fields and add the heap tag. | 3267 // Allocated the JSObject, now initialize the fields and add the heap tag. |
| 3257 // ebx: initial map | 3268 // ebx: initial map |
| 3258 // edx: JSObject (untagged) | 3269 // edx: JSObject (untagged) |
| 3259 __ mov(Operand(edx, JSObject::kMapOffset), ebx); | 3270 __ mov(Operand(edx, JSObject::kMapOffset), ebx); |
| 3260 __ mov(ebx, Factory::empty_fixed_array()); | 3271 __ mov(ebx, FACTORY->empty_fixed_array()); |
| 3261 __ mov(Operand(edx, JSObject::kPropertiesOffset), ebx); | 3272 __ mov(Operand(edx, JSObject::kPropertiesOffset), ebx); |
| 3262 __ mov(Operand(edx, JSObject::kElementsOffset), ebx); | 3273 __ mov(Operand(edx, JSObject::kElementsOffset), ebx); |
| 3263 | 3274 |
| 3264 // Push the allocated object to the stack. This is the object that will be | 3275 // Push the allocated object to the stack. This is the object that will be |
| 3265 // returned (after it is tagged). | 3276 // returned (after it is tagged). |
| 3266 __ push(edx); | 3277 __ push(edx); |
| 3267 | 3278 |
| 3268 // eax: argc | 3279 // eax: argc |
| 3269 // edx: JSObject (untagged) | 3280 // edx: JSObject (untagged) |
| 3270 // Load the address of the first in-object property into edx. | 3281 // Load the address of the first in-object property into edx. |
| 3271 __ lea(edx, Operand(edx, JSObject::kHeaderSize)); | 3282 __ lea(edx, Operand(edx, JSObject::kHeaderSize)); |
| 3272 // Calculate the location of the first argument. The stack contains the | 3283 // Calculate the location of the first argument. The stack contains the |
| 3273 // allocated object and the return address on top of the argc arguments. | 3284 // allocated object and the return address on top of the argc arguments. |
| 3274 __ lea(ecx, Operand(esp, eax, times_4, 1 * kPointerSize)); | 3285 __ lea(ecx, Operand(esp, eax, times_4, 1 * kPointerSize)); |
| 3275 | 3286 |
| 3276 // Use edi for holding undefined which is used in several places below. | 3287 // Use edi for holding undefined which is used in several places below. |
| 3277 __ mov(edi, Factory::undefined_value()); | 3288 __ mov(edi, FACTORY->undefined_value()); |
| 3278 | 3289 |
| 3279 // eax: argc | 3290 // eax: argc |
| 3280 // ecx: first argument | 3291 // ecx: first argument |
| 3281 // edx: first in-object property of the JSObject | 3292 // edx: first in-object property of the JSObject |
| 3282 // edi: undefined | 3293 // edi: undefined |
| 3283 // Fill the initialized properties with a constant value or a passed argument | 3294 // Fill the initialized properties with a constant value or a passed argument |
| 3284 // depending on the this.x = ...; assignment in the function. | 3295 // depending on the this.x = ...; assignment in the function. |
| 3285 SharedFunctionInfo* shared = function->shared(); | 3296 SharedFunctionInfo* shared = function->shared(); |
| 3286 for (int i = 0; i < shared->this_property_assignments_count(); i++) { | 3297 for (int i = 0; i < shared->this_property_assignments_count(); i++) { |
| 3287 if (shared->IsThisPropertyAssignmentArgument(i)) { | 3298 if (shared->IsThisPropertyAssignmentArgument(i)) { |
| 3288 // Check if the argument assigned to the property is actually passed. | 3299 // Check if the argument assigned to the property is actually passed. |
| 3289 // If argument is not passed the property is set to undefined, | 3300 // If argument is not passed the property is set to undefined, |
| 3290 // otherwise find it on the stack. | 3301 // otherwise find it on the stack. |
| 3291 int arg_number = shared->GetThisPropertyAssignmentArgument(i); | 3302 int arg_number = shared->GetThisPropertyAssignmentArgument(i); |
| 3292 __ mov(ebx, edi); | 3303 __ mov(ebx, edi); |
| 3293 __ cmp(eax, arg_number); | 3304 __ cmp(eax, arg_number); |
| 3294 if (CpuFeatures::IsSupported(CMOV)) { | 3305 if (Isolate::Current()->cpu_features()->IsSupported(CMOV)) { |
| 3295 CpuFeatures::Scope use_cmov(CMOV); | 3306 CpuFeatures::Scope use_cmov(CMOV); |
| 3296 __ cmov(above, ebx, Operand(ecx, arg_number * -kPointerSize)); | 3307 __ cmov(above, ebx, Operand(ecx, arg_number * -kPointerSize)); |
| 3297 } else { | 3308 } else { |
| 3298 Label not_passed; | 3309 Label not_passed; |
| 3299 __ j(below_equal, ¬_passed); | 3310 __ j(below_equal, ¬_passed); |
| 3300 __ mov(ebx, Operand(ecx, arg_number * -kPointerSize)); | 3311 __ mov(ebx, Operand(ecx, arg_number * -kPointerSize)); |
| 3301 __ bind(¬_passed); | 3312 __ bind(¬_passed); |
| 3302 } | 3313 } |
| 3303 // Store value in the property. | 3314 // Store value in the property. |
| 3304 __ mov(Operand(edx, i * kPointerSize), ebx); | 3315 __ mov(Operand(edx, i * kPointerSize), ebx); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 3319 | 3330 |
| 3320 // Move argc to ebx and retrieve and tag the JSObject to return. | 3331 // Move argc to ebx and retrieve and tag the JSObject to return. |
| 3321 __ mov(ebx, eax); | 3332 __ mov(ebx, eax); |
| 3322 __ pop(eax); | 3333 __ pop(eax); |
| 3323 __ or_(Operand(eax), Immediate(kHeapObjectTag)); | 3334 __ or_(Operand(eax), Immediate(kHeapObjectTag)); |
| 3324 | 3335 |
| 3325 // Remove caller arguments and receiver from the stack and return. | 3336 // Remove caller arguments and receiver from the stack and return. |
| 3326 __ pop(ecx); | 3337 __ pop(ecx); |
| 3327 __ lea(esp, Operand(esp, ebx, times_pointer_size, 1 * kPointerSize)); | 3338 __ lea(esp, Operand(esp, ebx, times_pointer_size, 1 * kPointerSize)); |
| 3328 __ push(ecx); | 3339 __ push(ecx); |
| 3329 __ IncrementCounter(&Counters::constructed_objects, 1); | 3340 __ IncrementCounter(COUNTERS->constructed_objects(), 1); |
| 3330 __ IncrementCounter(&Counters::constructed_objects_stub, 1); | 3341 __ IncrementCounter(COUNTERS->constructed_objects_stub(), 1); |
| 3331 __ ret(0); | 3342 __ ret(0); |
| 3332 | 3343 |
| 3333 // Jump to the generic stub in case the specialized code cannot handle the | 3344 // Jump to the generic stub in case the specialized code cannot handle the |
| 3334 // construction. | 3345 // construction. |
| 3335 __ bind(&generic_stub_call); | 3346 __ bind(&generic_stub_call); |
| 3336 Code* code = Builtins::builtin(Builtins::JSConstructStubGeneric); | 3347 Code* code = Isolate::Current()->builtins()->builtin( |
| 3348 Builtins::JSConstructStubGeneric); |
| 3337 Handle<Code> generic_construct_stub(code); | 3349 Handle<Code> generic_construct_stub(code); |
| 3338 __ jmp(generic_construct_stub, RelocInfo::CODE_TARGET); | 3350 __ jmp(generic_construct_stub, RelocInfo::CODE_TARGET); |
| 3339 | 3351 |
| 3340 // Return the generated code. | 3352 // Return the generated code. |
| 3341 return GetCode(); | 3353 return GetCode(); |
| 3342 } | 3354 } |
| 3343 | 3355 |
| 3344 | 3356 |
| 3345 MaybeObject* ExternalArrayStubCompiler::CompileKeyedLoadStub( | 3357 MaybeObject* ExternalArrayStubCompiler::CompileKeyedLoadStub( |
| 3346 JSObject*receiver, ExternalArrayType array_type, Code::Flags flags) { | 3358 JSObject*receiver, ExternalArrayType array_type, Code::Flags flags) { |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3467 | 3479 |
| 3468 // If we fail allocation of the HeapNumber, we still have a value on | 3480 // If we fail allocation of the HeapNumber, we still have a value on |
| 3469 // top of the FPU stack. Remove it. | 3481 // top of the FPU stack. Remove it. |
| 3470 __ bind(&failed_allocation); | 3482 __ bind(&failed_allocation); |
| 3471 __ ffree(); | 3483 __ ffree(); |
| 3472 __ fincstp(); | 3484 __ fincstp(); |
| 3473 // Fall through to slow case. | 3485 // Fall through to slow case. |
| 3474 | 3486 |
| 3475 // Slow case: Jump to runtime. | 3487 // Slow case: Jump to runtime. |
| 3476 __ bind(&slow); | 3488 __ bind(&slow); |
| 3477 __ IncrementCounter(&Counters::keyed_load_external_array_slow, 1); | 3489 __ IncrementCounter(COUNTERS->keyed_load_external_array_slow(), 1); |
| 3478 // ----------- S t a t e ------------- | 3490 // ----------- S t a t e ------------- |
| 3479 // -- eax : key | 3491 // -- eax : key |
| 3480 // -- edx : receiver | 3492 // -- edx : receiver |
| 3481 // -- esp[0] : return address | 3493 // -- esp[0] : return address |
| 3482 // ----------------------------------- | 3494 // ----------------------------------- |
| 3483 | 3495 |
| 3484 __ pop(ebx); | 3496 __ pop(ebx); |
| 3485 __ push(edx); // receiver | 3497 __ push(edx); // receiver |
| 3486 __ push(eax); // name | 3498 __ push(eax); // name |
| 3487 __ push(ebx); // return address | 3499 __ push(ebx); // return address |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3580 | 3592 |
| 3581 // TODO(danno): handle heap number -> pixel array conversion | 3593 // TODO(danno): handle heap number -> pixel array conversion |
| 3582 if (array_type != kExternalPixelArray) { | 3594 if (array_type != kExternalPixelArray) { |
| 3583 __ bind(&check_heap_number); | 3595 __ bind(&check_heap_number); |
| 3584 // eax: value | 3596 // eax: value |
| 3585 // edx: receiver | 3597 // edx: receiver |
| 3586 // ecx: key | 3598 // ecx: key |
| 3587 // edi: elements array | 3599 // edi: elements array |
| 3588 // ebx: untagged index | 3600 // ebx: untagged index |
| 3589 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), | 3601 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), |
| 3590 Immediate(Factory::heap_number_map())); | 3602 Immediate(FACTORY->heap_number_map())); |
| 3591 __ j(not_equal, &slow); | 3603 __ j(not_equal, &slow); |
| 3592 | 3604 |
| 3593 // The WebGL specification leaves the behavior of storing NaN and | 3605 // The WebGL specification leaves the behavior of storing NaN and |
| 3594 // +/-Infinity into integer arrays basically undefined. For more | 3606 // +/-Infinity into integer arrays basically undefined. For more |
| 3595 // reproducible behavior, convert these to zero. | 3607 // reproducible behavior, convert these to zero. |
| 3596 __ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset)); | 3608 __ mov(edi, FieldOperand(edi, ExternalArray::kExternalPointerOffset)); |
| 3597 // ebx: untagged index | 3609 // ebx: untagged index |
| 3598 // edi: base pointer of external storage | 3610 // edi: base pointer of external storage |
| 3599 if (array_type == kExternalFloatArray) { | 3611 if (array_type == kExternalFloatArray) { |
| 3600 __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); | 3612 __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
| 3601 __ fstp_s(Operand(edi, ebx, times_4, 0)); | 3613 __ fstp_s(Operand(edi, ebx, times_4, 0)); |
| 3602 __ ret(0); | 3614 __ ret(0); |
| 3603 } else { | 3615 } else { |
| 3604 // Perform float-to-int conversion with truncation (round-to-zero) | 3616 // Perform float-to-int conversion with truncation (round-to-zero) |
| 3605 // behavior. | 3617 // behavior. |
| 3606 | 3618 |
| 3607 // For the moment we make the slow call to the runtime on | 3619 // For the moment we make the slow call to the runtime on |
| 3608 // processors that don't support SSE2. The code in IntegerConvert | 3620 // processors that don't support SSE2. The code in IntegerConvert |
| 3609 // (code-stubs-ia32.cc) is roughly what is needed here though the | 3621 // (code-stubs-ia32.cc) is roughly what is needed here though the |
| 3610 // conversion failure case does not need to be handled. | 3622 // conversion failure case does not need to be handled. |
| 3611 if (CpuFeatures::IsSupported(SSE2)) { | 3623 if (Isolate::Current()->cpu_features()->IsSupported(SSE2)) { |
| 3612 if (array_type != kExternalIntArray && | 3624 if (array_type != kExternalIntArray && |
| 3613 array_type != kExternalUnsignedIntArray) { | 3625 array_type != kExternalUnsignedIntArray) { |
| 3614 ASSERT(CpuFeatures::IsSupported(SSE2)); | 3626 ASSERT(Isolate::Current()->cpu_features()->IsSupported(SSE2)); |
| 3615 CpuFeatures::Scope scope(SSE2); | 3627 CpuFeatures::Scope scope(SSE2); |
| 3616 __ cvttsd2si(ecx, FieldOperand(eax, HeapNumber::kValueOffset)); | 3628 __ cvttsd2si(ecx, FieldOperand(eax, HeapNumber::kValueOffset)); |
| 3617 // ecx: untagged integer value | 3629 // ecx: untagged integer value |
| 3618 switch (array_type) { | 3630 switch (array_type) { |
| 3619 case kExternalPixelArray: | 3631 case kExternalPixelArray: |
| 3620 { // Clamp the value to [0..255]. | 3632 { // Clamp the value to [0..255]. |
| 3621 NearLabel done; | 3633 NearLabel done; |
| 3622 __ test(ecx, Immediate(0xFFFFFF00)); | 3634 __ test(ecx, Immediate(0xFFFFFF00)); |
| 3623 __ j(zero, &done); | 3635 __ j(zero, &done); |
| 3624 __ setcc(negative, ecx); // 1 if negative, 0 if positive. | 3636 __ setcc(negative, ecx); // 1 if negative, 0 if positive. |
| 3625 __ dec_b(ecx); // 0 if negative, 255 if positive. | 3637 __ dec_b(ecx); // 0 if negative, 255 if positive. |
| 3626 __ bind(&done); | 3638 __ bind(&done); |
| 3627 } | 3639 } |
| 3628 __ mov_b(Operand(edi, ebx, times_1, 0), ecx); | 3640 __ mov_b(Operand(edi, ebx, times_1, 0), ecx); |
| 3629 case kExternalByteArray: | 3641 case kExternalByteArray: |
| 3630 case kExternalUnsignedByteArray: | 3642 case kExternalUnsignedByteArray: |
| 3631 __ mov_b(Operand(edi, ebx, times_1, 0), ecx); | 3643 __ mov_b(Operand(edi, ebx, times_1, 0), ecx); |
| 3632 break; | 3644 break; |
| 3633 case kExternalShortArray: | 3645 case kExternalShortArray: |
| 3634 case kExternalUnsignedShortArray: | 3646 case kExternalUnsignedShortArray: |
| 3635 __ mov_w(Operand(edi, ebx, times_2, 0), ecx); | 3647 __ mov_w(Operand(edi, ebx, times_2, 0), ecx); |
| 3636 break; | 3648 break; |
| 3637 default: | 3649 default: |
| 3638 UNREACHABLE(); | 3650 UNREACHABLE(); |
| 3639 break; | 3651 break; |
| 3640 } | 3652 } |
| 3641 } else { | 3653 } else { |
| 3642 if (CpuFeatures::IsSupported(SSE3)) { | 3654 if (Isolate::Current()->cpu_features()->IsSupported(SSE3)) { |
| 3643 CpuFeatures::Scope scope(SSE3); | 3655 CpuFeatures::Scope scope(SSE3); |
| 3644 // fisttp stores values as signed integers. To represent the | 3656 // fisttp stores values as signed integers. To represent the |
| 3645 // entire range of int and unsigned int arrays, store as a | 3657 // entire range of int and unsigned int arrays, store as a |
| 3646 // 64-bit int and discard the high 32 bits. | 3658 // 64-bit int and discard the high 32 bits. |
| 3647 // If the value is NaN or +/-infinity, the result is 0x80000000, | 3659 // If the value is NaN or +/-infinity, the result is 0x80000000, |
| 3648 // which is automatically zero when taken mod 2^n, n < 32. | 3660 // which is automatically zero when taken mod 2^n, n < 32. |
| 3649 __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); | 3661 __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset)); |
| 3650 __ sub(Operand(esp), Immediate(2 * kPointerSize)); | 3662 __ sub(Operand(esp), Immediate(2 * kPointerSize)); |
| 3651 __ fisttp_d(Operand(esp, 0)); | 3663 __ fisttp_d(Operand(esp, 0)); |
| 3652 __ pop(ecx); | 3664 __ pop(ecx); |
| 3653 __ add(Operand(esp), Immediate(kPointerSize)); | 3665 __ add(Operand(esp), Immediate(kPointerSize)); |
| 3654 } else { | 3666 } else { |
| 3655 ASSERT(CpuFeatures::IsSupported(SSE2)); | 3667 ASSERT(Isolate::Current()->cpu_features()->IsSupported(SSE2)); |
| 3656 CpuFeatures::Scope scope(SSE2); | 3668 CpuFeatures::Scope scope(SSE2); |
| 3657 // We can easily implement the correct rounding behavior for the | 3669 // We can easily implement the correct rounding behavior for the |
| 3658 // range [0, 2^31-1]. For the time being, to keep this code simple, | 3670 // range [0, 2^31-1]. For the time being, to keep this code simple, |
| 3659 // make the slow runtime call for values outside this range. | 3671 // make the slow runtime call for values outside this range. |
| 3660 // Note: we could do better for signed int arrays. | 3672 // Note: we could do better for signed int arrays. |
| 3661 __ movd(xmm0, FieldOperand(eax, HeapNumber::kValueOffset)); | 3673 __ movd(xmm0, FieldOperand(eax, HeapNumber::kValueOffset)); |
| 3662 // We will need the key if we have to make the slow runtime call. | 3674 // We will need the key if we have to make the slow runtime call. |
| 3663 __ push(ecx); | 3675 __ push(ecx); |
| 3664 __ LoadPowerOf2(xmm1, ecx, 31); | 3676 __ LoadPowerOf2(xmm1, ecx, 31); |
| 3665 __ pop(ecx); | 3677 __ pop(ecx); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3698 | 3710 |
| 3699 return GetCode(flags); | 3711 return GetCode(flags); |
| 3700 } | 3712 } |
| 3701 | 3713 |
| 3702 | 3714 |
| 3703 #undef __ | 3715 #undef __ |
| 3704 | 3716 |
| 3705 } } // namespace v8::internal | 3717 } } // namespace v8::internal |
| 3706 | 3718 |
| 3707 #endif // V8_TARGET_ARCH_IA32 | 3719 #endif // V8_TARGET_ARCH_IA32 |
| OLD | NEW |