| OLD | NEW |
| 1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/ic/handler-compiler.h" | 5 #include "src/ic/handler-compiler.h" |
| 6 | 6 |
| 7 #include "src/field-type.h" | 7 #include "src/field-type.h" |
| 8 #include "src/ic/call-optimization.h" | 8 #include "src/ic/call-optimization.h" |
| 9 #include "src/ic/handler-configuration.h" | 9 #include "src/ic/handler-configuration.h" |
| 10 #include "src/ic/ic-inl.h" | 10 #include "src/ic/ic-inl.h" |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 122 Handle<Name> name, | 122 Handle<Name> name, |
| 123 Label* miss, | 123 Label* miss, |
| 124 ReturnHolder return_what) { | 124 ReturnHolder return_what) { |
| 125 return CheckPrototypes(object_reg, this->name(), scratch1(), scratch2(), name, | 125 return CheckPrototypes(object_reg, this->name(), scratch1(), scratch2(), name, |
| 126 miss, SKIP_RECEIVER, return_what); | 126 miss, SKIP_RECEIVER, return_what); |
| 127 } | 127 } |
| 128 | 128 |
| 129 | 129 |
| 130 Register PropertyHandlerCompiler::Frontend(Handle<Name> name) { | 130 Register PropertyHandlerCompiler::Frontend(Handle<Name> name) { |
| 131 Label miss; | 131 Label miss; |
| 132 if (IC::ICUseVector(kind())) { | 132 if (IC::ShouldPushPopSlotAndVector(kind())) { |
| 133 PushVectorAndSlot(); | 133 PushVectorAndSlot(); |
| 134 } | 134 } |
| 135 Register reg = FrontendHeader(receiver(), name, &miss, RETURN_HOLDER); | 135 Register reg = FrontendHeader(receiver(), name, &miss, RETURN_HOLDER); |
| 136 FrontendFooter(name, &miss); | 136 FrontendFooter(name, &miss); |
| 137 // The footer consumes the vector and slot from the stack if miss occurs. | 137 // The footer consumes the vector and slot from the stack if miss occurs. |
| 138 if (IC::ICUseVector(kind())) { | 138 if (IC::ShouldPushPopSlotAndVector(kind())) { |
| 139 DiscardVectorAndSlot(); | 139 DiscardVectorAndSlot(); |
| 140 } | 140 } |
| 141 return reg; | 141 return reg; |
| 142 } | 142 } |
| 143 | 143 |
| 144 | 144 |
| 145 void PropertyHandlerCompiler::NonexistentFrontendHeader(Handle<Name> name, | 145 void PropertyHandlerCompiler::NonexistentFrontendHeader(Handle<Name> name, |
| 146 Label* miss, | 146 Label* miss, |
| 147 Register scratch1, | 147 Register scratch1, |
| 148 Register scratch2) { | 148 Register scratch2) { |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 202 __ Move(receiver(), reg); | 202 __ Move(receiver(), reg); |
| 203 LoadConstantStub stub(isolate(), constant_index); | 203 LoadConstantStub stub(isolate(), constant_index); |
| 204 GenerateTailCall(masm(), stub.GetCode()); | 204 GenerateTailCall(masm(), stub.GetCode()); |
| 205 return GetCode(kind(), name); | 205 return GetCode(kind(), name); |
| 206 } | 206 } |
| 207 | 207 |
| 208 | 208 |
| 209 Handle<Code> NamedLoadHandlerCompiler::CompileLoadNonexistent( | 209 Handle<Code> NamedLoadHandlerCompiler::CompileLoadNonexistent( |
| 210 Handle<Name> name) { | 210 Handle<Name> name) { |
| 211 Label miss; | 211 Label miss; |
| 212 if (IC::ICUseVector(kind())) { | 212 if (IC::ShouldPushPopSlotAndVector(kind())) { |
| 213 DCHECK(kind() == Code::LOAD_IC); | 213 DCHECK(kind() == Code::LOAD_IC); |
| 214 PushVectorAndSlot(); | 214 PushVectorAndSlot(); |
| 215 } | 215 } |
| 216 NonexistentFrontendHeader(name, &miss, scratch2(), scratch3()); | 216 NonexistentFrontendHeader(name, &miss, scratch2(), scratch3()); |
| 217 if (IC::ICUseVector(kind())) { | 217 if (IC::ShouldPushPopSlotAndVector(kind())) { |
| 218 DiscardVectorAndSlot(); | 218 DiscardVectorAndSlot(); |
| 219 } | 219 } |
| 220 GenerateLoadConstant(isolate()->factory()->undefined_value()); | 220 GenerateLoadConstant(isolate()->factory()->undefined_value()); |
| 221 FrontendFooter(name, &miss); | 221 FrontendFooter(name, &miss); |
| 222 return GetCode(kind(), name); | 222 return GetCode(kind(), name); |
| 223 } | 223 } |
| 224 | 224 |
| 225 Handle<Code> NamedLoadHandlerCompiler::CompileLoadCallback( | 225 Handle<Code> NamedLoadHandlerCompiler::CompileLoadCallback( |
| 226 Handle<Name> name, Handle<AccessorInfo> callback, Handle<Code> slow_stub) { | 226 Handle<Name> name, Handle<AccessorInfo> callback, Handle<Code> slow_stub) { |
| 227 if (FLAG_runtime_call_stats) { | 227 if (FLAG_runtime_call_stats) { |
| (...skipping 12 matching lines...) Expand all Loading... |
| 240 GenerateTailCall(masm(), slow_stub); | 240 GenerateTailCall(masm(), slow_stub); |
| 241 } | 241 } |
| 242 Register holder = Frontend(name); | 242 Register holder = Frontend(name); |
| 243 GenerateApiAccessorCall(masm(), call_optimization, map(), receiver(), | 243 GenerateApiAccessorCall(masm(), call_optimization, map(), receiver(), |
| 244 scratch2(), false, no_reg, holder, accessor_index); | 244 scratch2(), false, no_reg, holder, accessor_index); |
| 245 return GetCode(kind(), name); | 245 return GetCode(kind(), name); |
| 246 } | 246 } |
| 247 | 247 |
| 248 | 248 |
| 249 void NamedLoadHandlerCompiler::InterceptorVectorSlotPush(Register holder_reg) { | 249 void NamedLoadHandlerCompiler::InterceptorVectorSlotPush(Register holder_reg) { |
| 250 if (IC::ICUseVector(kind())) { | 250 if (IC::ShouldPushPopSlotAndVector(kind())) { |
| 251 if (holder_reg.is(receiver())) { | 251 if (holder_reg.is(receiver())) { |
| 252 PushVectorAndSlot(); | 252 PushVectorAndSlot(); |
| 253 } else { | 253 } else { |
| 254 DCHECK(holder_reg.is(scratch1())); | 254 DCHECK(holder_reg.is(scratch1())); |
| 255 PushVectorAndSlot(scratch2(), scratch3()); | 255 PushVectorAndSlot(scratch2(), scratch3()); |
| 256 } | 256 } |
| 257 } | 257 } |
| 258 } | 258 } |
| 259 | 259 |
| 260 | 260 |
| 261 void NamedLoadHandlerCompiler::InterceptorVectorSlotPop(Register holder_reg, | 261 void NamedLoadHandlerCompiler::InterceptorVectorSlotPop(Register holder_reg, |
| 262 PopMode mode) { | 262 PopMode mode) { |
| 263 if (IC::ICUseVector(kind())) { | 263 if (IC::ShouldPushPopSlotAndVector(kind())) { |
| 264 if (mode == DISCARD) { | 264 if (mode == DISCARD) { |
| 265 DiscardVectorAndSlot(); | 265 DiscardVectorAndSlot(); |
| 266 } else { | 266 } else { |
| 267 if (holder_reg.is(receiver())) { | 267 if (holder_reg.is(receiver())) { |
| 268 PopVectorAndSlot(); | 268 PopVectorAndSlot(); |
| 269 } else { | 269 } else { |
| 270 DCHECK(holder_reg.is(scratch1())); | 270 DCHECK(holder_reg.is(scratch1())); |
| 271 PopVectorAndSlot(scratch2(), scratch3()); | 271 PopVectorAndSlot(scratch2(), scratch3()); |
| 272 } | 272 } |
| 273 } | 273 } |
| (...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 431 expected_arguments, scratch2()); | 431 expected_arguments, scratch2()); |
| 432 return GetCode(kind(), name); | 432 return GetCode(kind(), name); |
| 433 } | 433 } |
| 434 | 434 |
| 435 | 435 |
| 436 // TODO(verwaest): Cleanup. holder() is actually the receiver. | 436 // TODO(verwaest): Cleanup. holder() is actually the receiver. |
| 437 Handle<Code> NamedStoreHandlerCompiler::CompileStoreTransition( | 437 Handle<Code> NamedStoreHandlerCompiler::CompileStoreTransition( |
| 438 Handle<Map> transition, Handle<Name> name) { | 438 Handle<Map> transition, Handle<Name> name) { |
| 439 Label miss; | 439 Label miss; |
| 440 | 440 |
| 441 bool vector_and_slot_on_stack = | 441 // Ensure that the StoreTransitionStub we are going to call has the same |
| 442 StoreTransitionDescriptor::PassVectorAndSlotOnStack(); | 442 // number of stack arguments. This means that we don't have to adapt them |
| 443 if (vector_and_slot_on_stack) { | 443 // if we decide to call the transition or miss stub. |
| 444 // Speculatively prepare for calling StoreTransitionStub by converting | 444 STATIC_ASSERT(StoreWithVectorDescriptor::kStackArgumentsCount == |
| 445 // StoreWithVectorDescriptor arguments to StoreTransitionDescriptor | 445 StoreTransitionDescriptor::kStackArgumentsCount); |
| 446 // arguments. | 446 STATIC_ASSERT(StoreWithVectorDescriptor::kStackArgumentsCount == 0 || |
| 447 PopReturnAddress(this->name()); | 447 StoreWithVectorDescriptor::kStackArgumentsCount == 3); |
| 448 PushVectorAndSlot(); | 448 STATIC_ASSERT(StoreWithVectorDescriptor::kParameterCount - |
| 449 PushReturnAddress(this->name()); | 449 StoreWithVectorDescriptor::kValue == |
| 450 } else { | 450 StoreTransitionDescriptor::kParameterCount - |
| 451 StoreTransitionDescriptor::kValue); |
| 452 STATIC_ASSERT(StoreWithVectorDescriptor::kParameterCount - |
| 453 StoreWithVectorDescriptor::kSlot == |
| 454 StoreTransitionDescriptor::kParameterCount - |
| 455 StoreTransitionDescriptor::kSlot); |
| 456 STATIC_ASSERT(StoreWithVectorDescriptor::kParameterCount - |
| 457 StoreWithVectorDescriptor::kVector == |
| 458 StoreTransitionDescriptor::kParameterCount - |
| 459 StoreTransitionDescriptor::kVector); |
| 460 |
| 461 bool need_save_restore = IC::ShouldPushPopSlotAndVector(kind()); |
| 462 if (need_save_restore) { |
| 451 PushVectorAndSlot(); | 463 PushVectorAndSlot(); |
| 452 } | 464 } |
| 453 | 465 |
| 454 // Check that we are allowed to write this. | 466 // Check that we are allowed to write this. |
| 455 bool is_nonexistent = holder()->map() == transition->GetBackPointer(); | 467 bool is_nonexistent = holder()->map() == transition->GetBackPointer(); |
| 456 if (is_nonexistent) { | 468 if (is_nonexistent) { |
| 457 // Find the top object. | 469 // Find the top object. |
| 458 Handle<JSObject> last; | 470 Handle<JSObject> last; |
| 459 PrototypeIterator::WhereToEnd end = | 471 PrototypeIterator::WhereToEnd end = |
| 460 name->IsPrivate() ? PrototypeIterator::END_AT_NON_HIDDEN | 472 name->IsPrivate() ? PrototypeIterator::END_AT_NON_HIDDEN |
| (...skipping 19 matching lines...) Expand all Loading... |
| 480 // Stub is never generated for objects that require access checks. | 492 // Stub is never generated for objects that require access checks. |
| 481 DCHECK(!transition->is_access_check_needed()); | 493 DCHECK(!transition->is_access_check_needed()); |
| 482 | 494 |
| 483 // Call to respective StoreTransitionStub. | 495 // Call to respective StoreTransitionStub. |
| 484 Register map_reg = StoreTransitionDescriptor::MapRegister(); | 496 Register map_reg = StoreTransitionDescriptor::MapRegister(); |
| 485 | 497 |
| 486 if (details.type() == DATA_CONSTANT) { | 498 if (details.type() == DATA_CONSTANT) { |
| 487 DCHECK(descriptors->GetValue(descriptor)->IsJSFunction()); | 499 DCHECK(descriptors->GetValue(descriptor)->IsJSFunction()); |
| 488 GenerateRestoreMap(transition, map_reg, scratch1(), &miss); | 500 GenerateRestoreMap(transition, map_reg, scratch1(), &miss); |
| 489 GenerateConstantCheck(map_reg, descriptor, value(), scratch1(), &miss); | 501 GenerateConstantCheck(map_reg, descriptor, value(), scratch1(), &miss); |
| 490 if (!vector_and_slot_on_stack) { | 502 if (need_save_restore) { |
| 491 PopVectorAndSlot(); | 503 PopVectorAndSlot(); |
| 492 } | 504 } |
| 493 GenerateRestoreName(name); | 505 GenerateRestoreName(name); |
| 494 StoreTransitionStub stub(isolate()); | 506 StoreTransitionStub stub(isolate()); |
| 495 GenerateTailCall(masm(), stub.GetCode()); | 507 GenerateTailCall(masm(), stub.GetCode()); |
| 496 | 508 |
| 497 } else { | 509 } else { |
| 498 if (representation.IsHeapObject()) { | 510 if (representation.IsHeapObject()) { |
| 499 GenerateFieldTypeChecks(descriptors->GetFieldType(descriptor), value(), | 511 GenerateFieldTypeChecks(descriptors->GetFieldType(descriptor), value(), |
| 500 &miss); | 512 &miss); |
| 501 } | 513 } |
| 502 StoreTransitionStub::StoreMode store_mode = | 514 StoreTransitionStub::StoreMode store_mode = |
| 503 Map::cast(transition->GetBackPointer())->unused_property_fields() == 0 | 515 Map::cast(transition->GetBackPointer())->unused_property_fields() == 0 |
| 504 ? StoreTransitionStub::ExtendStorageAndStoreMapAndValue | 516 ? StoreTransitionStub::ExtendStorageAndStoreMapAndValue |
| 505 : StoreTransitionStub::StoreMapAndValue; | 517 : StoreTransitionStub::StoreMapAndValue; |
| 506 GenerateRestoreMap(transition, map_reg, scratch1(), &miss); | 518 GenerateRestoreMap(transition, map_reg, scratch1(), &miss); |
| 507 if (!vector_and_slot_on_stack) { | 519 if (need_save_restore) { |
| 508 PopVectorAndSlot(); | 520 PopVectorAndSlot(); |
| 509 } | 521 } |
| 510 GenerateRestoreName(name); | 522 GenerateRestoreName(name); |
| 511 StoreTransitionStub stub(isolate(), | 523 StoreTransitionStub stub(isolate(), |
| 512 FieldIndex::ForDescriptor(*transition, descriptor), | 524 FieldIndex::ForDescriptor(*transition, descriptor), |
| 513 representation, store_mode); | 525 representation, store_mode); |
| 514 GenerateTailCall(masm(), stub.GetCode()); | 526 GenerateTailCall(masm(), stub.GetCode()); |
| 515 } | 527 } |
| 516 | 528 |
| 517 __ bind(&miss); | 529 __ bind(&miss); |
| 518 if (vector_and_slot_on_stack) { | 530 if (need_save_restore) { |
| 519 // Prepare for calling miss builtin with StoreWithVectorDescriptor. | |
| 520 PopReturnAddress(this->name()); | |
| 521 PopVectorAndSlot(); | |
| 522 PushReturnAddress(this->name()); | |
| 523 } else { | |
| 524 PopVectorAndSlot(); | 531 PopVectorAndSlot(); |
| 525 } | 532 } |
| 526 GenerateRestoreName(name); | 533 GenerateRestoreName(name); |
| 527 TailCallBuiltin(masm(), MissBuiltin(kind())); | 534 TailCallBuiltin(masm(), MissBuiltin(kind())); |
| 528 | 535 |
| 529 return GetCode(kind(), name); | 536 return GetCode(kind(), name); |
| 530 } | 537 } |
| 531 | 538 |
| 532 bool NamedStoreHandlerCompiler::RequiresFieldTypeChecks( | 539 bool NamedStoreHandlerCompiler::RequiresFieldTypeChecks( |
| 533 FieldType* field_type) const { | 540 FieldType* field_type) const { |
| 534 return field_type->IsClass(); | 541 return field_type->IsClass(); |
| 535 } | 542 } |
| 536 | 543 |
| 537 | 544 |
| 538 Handle<Code> NamedStoreHandlerCompiler::CompileStoreField(LookupIterator* it) { | 545 Handle<Code> NamedStoreHandlerCompiler::CompileStoreField(LookupIterator* it) { |
| 539 Label miss; | 546 Label miss; |
| 540 DCHECK(it->representation().IsHeapObject()); | 547 DCHECK(it->representation().IsHeapObject()); |
| 541 | 548 |
| 542 FieldType* field_type = *it->GetFieldType(); | 549 FieldType* field_type = *it->GetFieldType(); |
| 543 bool need_save_restore = false; | 550 bool need_save_restore = false; |
| 544 if (RequiresFieldTypeChecks(field_type)) { | 551 if (RequiresFieldTypeChecks(field_type)) { |
| 545 need_save_restore = IC::ICUseVector(kind()); | 552 need_save_restore = IC::ShouldPushPopSlotAndVector(kind()); |
| 546 if (need_save_restore) PushVectorAndSlot(); | 553 if (need_save_restore) PushVectorAndSlot(); |
| 547 GenerateFieldTypeChecks(field_type, value(), &miss); | 554 GenerateFieldTypeChecks(field_type, value(), &miss); |
| 548 if (need_save_restore) PopVectorAndSlot(); | 555 if (need_save_restore) PopVectorAndSlot(); |
| 549 } | 556 } |
| 550 | 557 |
| 551 StoreFieldStub stub(isolate(), it->GetFieldIndex(), it->representation()); | 558 StoreFieldStub stub(isolate(), it->GetFieldIndex(), it->representation()); |
| 552 GenerateTailCall(masm(), stub.GetCode()); | 559 GenerateTailCall(masm(), stub.GetCode()); |
| 553 | 560 |
| 554 __ bind(&miss); | 561 __ bind(&miss); |
| 555 if (need_save_restore) PopVectorAndSlot(); | 562 if (need_save_restore) PopVectorAndSlot(); |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 642 } | 649 } |
| 643 | 650 |
| 644 void ElementHandlerCompiler::CompileElementHandlers( | 651 void ElementHandlerCompiler::CompileElementHandlers( |
| 645 MapHandleList* receiver_maps, List<Handle<Object>>* handlers) { | 652 MapHandleList* receiver_maps, List<Handle<Object>>* handlers) { |
| 646 for (int i = 0; i < receiver_maps->length(); ++i) { | 653 for (int i = 0; i < receiver_maps->length(); ++i) { |
| 647 handlers->Add(GetKeyedLoadHandler(receiver_maps->at(i), isolate())); | 654 handlers->Add(GetKeyedLoadHandler(receiver_maps->at(i), isolate())); |
| 648 } | 655 } |
| 649 } | 656 } |
| 650 } // namespace internal | 657 } // namespace internal |
| 651 } // namespace v8 | 658 } // namespace v8 |
| OLD | NEW |