Chromium Code Reviews| Index: src/code-stub-assembler.cc |
| diff --git a/src/code-stub-assembler.cc b/src/code-stub-assembler.cc |
| index 323c05d17e737cbbfdc0e5acfb1dc6625743b867..a6dc02cd7fc2b0f0309ec057aec336c3a8f0bd14 100644 |
| --- a/src/code-stub-assembler.cc |
| +++ b/src/code-stub-assembler.cc |
| @@ -5509,145 +5509,148 @@ void CodeStubAssembler::HandleLoadICHandlerCase( |
| // for the encoding format. |
| Bind(&if_smi_handler); |
| { |
| - Variable var_double_value(this, MachineRepresentation::kFloat64); |
|
Igor Sheludko
2016/11/14 18:08:54
This whole piece of code was moved to HandleLoadIC
|
| - Label rebox_double(this, &var_double_value); |
| + HandleLoadICSmiHandlerCase(p, var_holder.value(), var_smi_handler.value(), |
| + miss, support_elements); |
| + } |
| - Node* holder = var_holder.value(); |
| - Node* handler_word = SmiUntag(var_smi_handler.value()); |
| - Node* handler_kind = DecodeWord<LoadHandler::KindBits>(handler_word); |
| - if (support_elements == kSupportElements) { |
| - Label property(this); |
| - GotoUnless( |
| - WordEqual(handler_kind, IntPtrConstant(LoadHandler::kForElements)), |
| - &property); |
| - |
| - Comment("element_load"); |
| - Node* intptr_index = TryToIntptr(p->name, miss); |
| - Node* elements = LoadElements(holder); |
| - Node* is_jsarray_condition = |
| - IsSetWord<LoadHandler::IsJsArrayBits>(handler_word); |
| - Node* elements_kind = |
| - DecodeWord<LoadHandler::ElementsKindBits>(handler_word); |
| - Label if_hole(this), unimplemented_elements_kind(this); |
| - Label* out_of_bounds = miss; |
| - EmitElementLoad(holder, elements, elements_kind, intptr_index, |
| - is_jsarray_condition, &if_hole, &rebox_double, |
| - &var_double_value, &unimplemented_elements_kind, |
| - out_of_bounds, miss); |
| - |
| - Bind(&unimplemented_elements_kind); |
| - { |
| - // Smi handlers should only be installed for supported elements kinds. |
| - // Crash if we get here. |
| - DebugBreak(); |
| - Goto(miss); |
| - } |
| + Bind(&try_proto_handler); |
| + { |
| + GotoIf(IsCodeMap(LoadMap(handler)), &call_handler); |
| + HandleLoadICProtoHandler(p, handler, &var_holder, &var_smi_handler, |
| + &if_smi_handler, miss); |
| + } |
| - Bind(&if_hole); |
| - { |
| - Comment("convert hole"); |
| - GotoUnless(IsSetWord<LoadHandler::ConvertHoleBits>(handler_word), miss); |
| - Node* protector_cell = LoadRoot(Heap::kArrayProtectorRootIndex); |
| - DCHECK(isolate()->heap()->array_protector()->IsPropertyCell()); |
| - GotoUnless( |
| - WordEqual( |
| - LoadObjectField(protector_cell, PropertyCell::kValueOffset), |
| - SmiConstant(Smi::FromInt(Isolate::kArrayProtectorValid))), |
| - miss); |
| - Return(UndefinedConstant()); |
| - } |
| + Bind(&call_handler); |
| + { |
| + typedef LoadWithVectorDescriptor Descriptor; |
| + TailCallStub(Descriptor(isolate()), handler, p->context, |
| + Arg(Descriptor::kReceiver, p->receiver), |
| + Arg(Descriptor::kName, p->name), |
| + Arg(Descriptor::kSlot, p->slot), |
| + Arg(Descriptor::kVector, p->vector)); |
| + } |
| +} |
| - Bind(&property); |
| - Comment("property_load"); |
| - } |
| +void CodeStubAssembler::HandleLoadICSmiHandlerCase( |
| + const LoadICParameters* p, Node* holder, Node* smi_handler, Label* miss, |
| + ElementSupport support_elements) { |
| + Variable var_double_value(this, MachineRepresentation::kFloat64); |
| + Label rebox_double(this, &var_double_value); |
| - Label constant(this), field(this); |
| - Branch(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kForFields)), |
| - &field, &constant); |
| + Node* handler_word = SmiUntag(smi_handler); |
| + Node* handler_kind = DecodeWord<LoadHandler::KindBits>(handler_word); |
| + if (support_elements == kSupportElements) { |
| + Label property(this); |
| + GotoUnless( |
| + WordEqual(handler_kind, IntPtrConstant(LoadHandler::kForElements)), |
| + &property); |
| - Bind(&field); |
| + Comment("element_load"); |
| + Node* intptr_index = TryToIntptr(p->name, miss); |
| + Node* elements = LoadElements(holder); |
| + Node* is_jsarray_condition = |
| + IsSetWord<LoadHandler::IsJsArrayBits>(handler_word); |
| + Node* elements_kind = |
| + DecodeWord<LoadHandler::ElementsKindBits>(handler_word); |
| + Label if_hole(this), unimplemented_elements_kind(this); |
| + Label* out_of_bounds = miss; |
| + EmitElementLoad(holder, elements, elements_kind, intptr_index, |
| + is_jsarray_condition, &if_hole, &rebox_double, |
| + &var_double_value, &unimplemented_elements_kind, |
| + out_of_bounds, miss); |
| + |
| + Bind(&unimplemented_elements_kind); |
| { |
| - Comment("field_load"); |
| - Node* offset = DecodeWord<LoadHandler::FieldOffsetBits>(handler_word); |
| + // Smi handlers should only be installed for supported elements kinds. |
| + // Crash if we get here. |
| + DebugBreak(); |
| + Goto(miss); |
| + } |
| - Label inobject(this), out_of_object(this); |
| - Branch(IsSetWord<LoadHandler::IsInobjectBits>(handler_word), &inobject, |
| - &out_of_object); |
| + Bind(&if_hole); |
| + { |
| + Comment("convert hole"); |
| + GotoUnless(IsSetWord<LoadHandler::ConvertHoleBits>(handler_word), miss); |
| + Node* protector_cell = LoadRoot(Heap::kArrayProtectorRootIndex); |
| + DCHECK(isolate()->heap()->array_protector()->IsPropertyCell()); |
| + GotoUnless( |
| + WordEqual(LoadObjectField(protector_cell, PropertyCell::kValueOffset), |
| + SmiConstant(Smi::FromInt(Isolate::kArrayProtectorValid))), |
| + miss); |
| + Return(UndefinedConstant()); |
| + } |
| - Bind(&inobject); |
| - { |
| - Label is_double(this); |
| - GotoIf(IsSetWord<LoadHandler::IsDoubleBits>(handler_word), &is_double); |
| - Return(LoadObjectField(holder, offset)); |
| + Bind(&property); |
| + Comment("property_load"); |
| + } |
| - Bind(&is_double); |
| - if (FLAG_unbox_double_fields) { |
| - var_double_value.Bind( |
| - LoadObjectField(holder, offset, MachineType::Float64())); |
| - } else { |
| - Node* mutable_heap_number = LoadObjectField(holder, offset); |
| - var_double_value.Bind(LoadHeapNumberValue(mutable_heap_number)); |
| - } |
| - Goto(&rebox_double); |
| - } |
| + Label constant(this), field(this); |
| + Branch(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kForFields)), |
| + &field, &constant); |
| - Bind(&out_of_object); |
| - { |
| - Label is_double(this); |
| - Node* properties = LoadProperties(holder); |
| - Node* value = LoadObjectField(properties, offset); |
| - GotoIf(IsSetWord<LoadHandler::IsDoubleBits>(handler_word), &is_double); |
| - Return(value); |
| + Bind(&field); |
| + { |
| + Comment("field_load"); |
| + Node* offset = DecodeWord<LoadHandler::FieldOffsetBits>(handler_word); |
| - Bind(&is_double); |
| - var_double_value.Bind(LoadHeapNumberValue(value)); |
| - Goto(&rebox_double); |
| - } |
| + Label inobject(this), out_of_object(this); |
| + Branch(IsSetWord<LoadHandler::IsInobjectBits>(handler_word), &inobject, |
| + &out_of_object); |
| - Bind(&rebox_double); |
| - Return(AllocateHeapNumberWithValue(var_double_value.value())); |
| + Bind(&inobject); |
| + { |
| + Label is_double(this); |
| + GotoIf(IsSetWord<LoadHandler::IsDoubleBits>(handler_word), &is_double); |
| + Return(LoadObjectField(holder, offset)); |
| + |
| + Bind(&is_double); |
| + if (FLAG_unbox_double_fields) { |
| + var_double_value.Bind( |
| + LoadObjectField(holder, offset, MachineType::Float64())); |
| + } else { |
| + Node* mutable_heap_number = LoadObjectField(holder, offset); |
| + var_double_value.Bind(LoadHeapNumberValue(mutable_heap_number)); |
| + } |
| + Goto(&rebox_double); |
| } |
| - Bind(&constant); |
| + Bind(&out_of_object); |
| { |
| - Comment("constant_load"); |
| - Node* descriptors = LoadMapDescriptors(LoadMap(holder)); |
| - Node* descriptor = |
| - DecodeWord<LoadHandler::DescriptorValueIndexBits>(handler_word); |
| -#if defined(DEBUG) |
|
Igor Sheludko
2016/11/14 18:08:54
I only removed this #ifdef.
|
| - CSA_ASSERT( |
| - this, UintPtrLessThan(descriptor, |
| - LoadAndUntagFixedArrayBaseLength(descriptors))); |
| -#endif |
| - Node* value = |
| - LoadFixedArrayElement(descriptors, descriptor, 0, INTPTR_PARAMETERS); |
| - |
| - Label if_accessor_info(this); |
| - GotoIf(IsSetWord<LoadHandler::IsAccessorInfoBits>(handler_word), |
| - &if_accessor_info); |
| + Label is_double(this); |
| + Node* properties = LoadProperties(holder); |
| + Node* value = LoadObjectField(properties, offset); |
| + GotoIf(IsSetWord<LoadHandler::IsDoubleBits>(handler_word), &is_double); |
| Return(value); |
| - Bind(&if_accessor_info); |
| - Callable callable = CodeFactory::ApiGetter(isolate()); |
| - TailCallStub(callable, p->context, p->receiver, holder, value); |
| + Bind(&is_double); |
| + var_double_value.Bind(LoadHeapNumberValue(value)); |
| + Goto(&rebox_double); |
| } |
| - } |
| - Bind(&try_proto_handler); |
| - { |
| - GotoIf(IsCodeMap(LoadMap(handler)), &call_handler); |
| - HandleLoadICProtoHandler(p, handler, &var_holder, &var_smi_handler, |
| - &if_smi_handler, miss); |
| + Bind(&rebox_double); |
| + Return(AllocateHeapNumberWithValue(var_double_value.value())); |
| } |
| - Bind(&call_handler); |
| + Bind(&constant); |
| { |
| - typedef LoadWithVectorDescriptor Descriptor; |
| - TailCallStub(Descriptor(isolate()), handler, p->context, |
| - Arg(Descriptor::kReceiver, p->receiver), |
| - Arg(Descriptor::kName, p->name), |
| - Arg(Descriptor::kSlot, p->slot), |
| - Arg(Descriptor::kVector, p->vector)); |
| + Comment("constant_load"); |
| + Node* descriptors = LoadMapDescriptors(LoadMap(holder)); |
| + Node* descriptor = |
| + DecodeWord<LoadHandler::DescriptorValueIndexBits>(handler_word); |
| + CSA_ASSERT(this, |
| + UintPtrLessThan(descriptor, |
| + LoadAndUntagFixedArrayBaseLength(descriptors))); |
| + Node* value = |
| + LoadFixedArrayElement(descriptors, descriptor, 0, INTPTR_PARAMETERS); |
| + |
| + Label if_accessor_info(this); |
| + GotoIf(IsSetWord<LoadHandler::IsAccessorInfoBits>(handler_word), |
| + &if_accessor_info); |
| + Return(value); |
| + |
| + Bind(&if_accessor_info); |
| + Callable callable = CodeFactory::ApiGetter(isolate()); |
| + TailCallStub(callable, p->context, p->receiver, holder, value); |
| } |
| } |
| @@ -5717,67 +5720,74 @@ void CodeStubAssembler::HandleLoadICProtoHandler( |
| Bind(&array_handler); |
| { |
| - Node* length = SmiUntag(maybe_holder_cell); |
| - |
| - Variable start_index(this, MachineType::PointerRepresentation()); |
|
Igor Sheludko
2016/11/14 18:08:54
This code block now returns a holder.
|
| - start_index.Bind(IntPtrConstant(LoadHandler::kFirstPrototypeIndex)); |
| + Node* handler_length = SmiUntag(maybe_holder_cell); |
| + Node* holder = EmitLoadICProtoArrayCheck(p, handler, handler_length, |
| + handler_flags, miss); |
| + var_holder->Bind(holder); |
| + var_smi_handler->Bind(smi_handler); |
| + Goto(if_smi_handler); |
| + } |
| +} |
| - Label can_access(this); |
| - GotoUnless( |
| - IsSetWord<LoadHandler::DoAccessCheckOnReceiverBits>(handler_flags), |
| - &can_access); |
| - { |
| - // Skip this entry of a handler. |
| - start_index.Bind(IntPtrConstant(LoadHandler::kFirstPrototypeIndex + 1)); |
| - |
| - int offset = |
| - FixedArray::OffsetOfElementAt(LoadHandler::kFirstPrototypeIndex); |
| - Node* expected_native_context = |
| - LoadWeakCellValue(LoadObjectField(handler, offset), miss); |
| - CSA_ASSERT(this, IsNativeContext(expected_native_context)); |
| - |
| - Node* native_context = LoadNativeContext(p->context); |
| - GotoIf(WordEqual(expected_native_context, native_context), &can_access); |
| - // If the receiver is not a JSGlobalProxy then we miss. |
| - GotoUnless(IsJSGlobalProxy(p->receiver), miss); |
| - // For JSGlobalProxy receiver try to compare security tokens of current |
| - // and expected native contexts. |
| - Node* expected_token = LoadContextElement(expected_native_context, |
| - Context::SECURITY_TOKEN_INDEX); |
| - Node* current_token = |
| - LoadContextElement(native_context, Context::SECURITY_TOKEN_INDEX); |
| - Branch(WordEqual(expected_token, current_token), &can_access, miss); |
| - } |
| - Bind(&can_access); |
| +Node* CodeStubAssembler::EmitLoadICProtoArrayCheck(const LoadICParameters* p, |
| + Node* handler, |
| + Node* handler_length, |
| + Node* handler_flags, |
| + Label* miss) { |
| + Variable start_index(this, MachineType::PointerRepresentation()); |
| + start_index.Bind(IntPtrConstant(LoadHandler::kFirstPrototypeIndex)); |
| - BuildFastLoop(MachineType::PointerRepresentation(), start_index.value(), |
| - length, |
| - [this, p, handler, miss](CodeStubAssembler*, Node* current) { |
| - Node* prototype_cell = LoadFixedArrayElement( |
| - handler, current, 0, INTPTR_PARAMETERS); |
| - CheckPrototype(prototype_cell, p->name, miss); |
| - }, |
| - 1, IndexAdvanceMode::kPost); |
| + Label can_access(this); |
| + GotoUnless(IsSetWord<LoadHandler::DoAccessCheckOnReceiverBits>(handler_flags), |
| + &can_access); |
| + { |
| + // Skip this entry of a handler. |
| + start_index.Bind(IntPtrConstant(LoadHandler::kFirstPrototypeIndex + 1)); |
| - Node* maybe_holder_cell = LoadFixedArrayElement( |
| - handler, IntPtrConstant(LoadHandler::kHolderCellIndex), 0, |
| - INTPTR_PARAMETERS); |
| - Label load_existent(this); |
| - GotoIf(WordNotEqual(maybe_holder_cell, NullConstant()), &load_existent); |
| - // This is a handler for a load of a non-existent value. |
| - Return(UndefinedConstant()); |
| + int offset = |
| + FixedArray::OffsetOfElementAt(LoadHandler::kFirstPrototypeIndex); |
| + Node* expected_native_context = |
| + LoadWeakCellValue(LoadObjectField(handler, offset), miss); |
| + CSA_ASSERT(this, IsNativeContext(expected_native_context)); |
| - Bind(&load_existent); |
| - Node* holder = LoadWeakCellValue(maybe_holder_cell); |
| - // The |holder| is guaranteed to be alive at this point since we passed |
| - // the receiver map check, the validity cell check and the prototype chain |
| - // check. |
| - CSA_ASSERT(this, WordNotEqual(holder, IntPtrConstant(0))); |
| + Node* native_context = LoadNativeContext(p->context); |
| + GotoIf(WordEqual(expected_native_context, native_context), &can_access); |
| + // If the receiver is not a JSGlobalProxy then we miss. |
| + GotoUnless(IsJSGlobalProxy(p->receiver), miss); |
| + // For JSGlobalProxy receiver try to compare security tokens of current |
| + // and expected native contexts. |
| + Node* expected_token = LoadContextElement(expected_native_context, |
| + Context::SECURITY_TOKEN_INDEX); |
| + Node* current_token = |
| + LoadContextElement(native_context, Context::SECURITY_TOKEN_INDEX); |
| + Branch(WordEqual(expected_token, current_token), &can_access, miss); |
| + } |
| + Bind(&can_access); |
| - var_holder->Bind(holder); |
| - var_smi_handler->Bind(smi_handler); |
| - Goto(if_smi_handler); |
| - } |
| + BuildFastLoop( |
| + MachineType::PointerRepresentation(), start_index.value(), handler_length, |
| + [this, p, handler, miss](CodeStubAssembler*, Node* current) { |
| + Node* prototype_cell = |
| + LoadFixedArrayElement(handler, current, 0, INTPTR_PARAMETERS); |
| + CheckPrototype(prototype_cell, p->name, miss); |
| + }, |
| + 1, IndexAdvanceMode::kPost); |
| + |
| + Node* maybe_holder_cell = LoadFixedArrayElement( |
| + handler, IntPtrConstant(LoadHandler::kHolderCellIndex), 0, |
| + INTPTR_PARAMETERS); |
| + Label load_existent(this); |
| + GotoIf(WordNotEqual(maybe_holder_cell, NullConstant()), &load_existent); |
| + // This is a handler for a load of a non-existent value. |
| + Return(UndefinedConstant()); |
| + |
| + Bind(&load_existent); |
| + Node* holder = LoadWeakCellValue(maybe_holder_cell); |
| + // The |holder| is guaranteed to be alive at this point since we passed |
| + // the receiver map check, the validity cell check and the prototype chain |
| + // check. |
| + CSA_ASSERT(this, WordNotEqual(holder, IntPtrConstant(0))); |
| + return holder; |
| } |
| void CodeStubAssembler::CheckPrototype(Node* prototype_cell, Node* name, |