Commit 7084bd25 authored by Toon Verwaest's avatar Toon Verwaest Committed by Commit Bot

[ic] Migrate StoreIC setter support to data driven handlers

Bug: v8:5561
Change-Id: Ieb44074280fa034b4f88e630e747211d73dedb6f
Reviewed-on: https://chromium-review.googlesource.com/753374Reviewed-by: 's avatarIgor Sheludko <ishell@chromium.org>
Commit-Queue: Toon Verwaest <verwaest@chromium.org>
Cr-Commit-Position: refs/heads/master@{#49184}
parent 84294418
......@@ -892,6 +892,7 @@ class RuntimeCallTimer final {
V(StoreIC_NonReceiver) \
V(StoreIC_Premonomorphic) \
V(StoreIC_SlowStub) \
V(StoreIC_StoreApiSetterOnPrototypeDH) \
V(StoreIC_StoreCallback) \
V(StoreIC_StoreFieldDH) \
V(StoreIC_StoreGlobalDH) \
......
This diff is collapsed.
......@@ -139,81 +139,6 @@ void PropertyHandlerCompiler::GenerateCheckPropertyCell(
__ b(ne, miss);
}
// Generate call to api function.
void PropertyHandlerCompiler::GenerateApiAccessorCall(
MacroAssembler* masm, const CallOptimization& optimization,
Handle<Map> receiver_map, Register receiver, Register scratch_in,
bool is_store, Register store_parameter, Register accessor_holder,
int accessor_index) {
DCHECK(accessor_holder != scratch_in);
DCHECK(receiver != scratch_in);
__ push(receiver);
// Write the arguments to stack frame.
if (is_store) {
DCHECK(receiver != store_parameter);
DCHECK(scratch_in != store_parameter);
__ push(store_parameter);
}
DCHECK(optimization.is_simple_api_call());
// Abi for CallApiCallbackStub.
Register callee = r0;
Register data = r4;
Register holder = r2;
Register api_function_address = r1;
// Put callee in place.
__ LoadAccessor(callee, accessor_holder, accessor_index,
is_store ? ACCESSOR_SETTER : ACCESSOR_GETTER);
// Put holder in place.
CallOptimization::HolderLookup holder_lookup;
optimization.LookupHolderOfExpectedType(receiver_map, &holder_lookup);
switch (holder_lookup) {
case CallOptimization::kHolderIsReceiver:
__ Move(holder, receiver);
break;
case CallOptimization::kHolderFound:
__ ldr(holder, FieldMemOperand(receiver, HeapObject::kMapOffset));
__ ldr(holder, FieldMemOperand(holder, Map::kPrototypeOffset));
break;
case CallOptimization::kHolderNotFound:
UNREACHABLE();
break;
}
Isolate* isolate = masm->isolate();
Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
// Put call data in place.
if (api_call_info->data()->IsUndefined(isolate)) {
__ LoadRoot(data, Heap::kUndefinedValueRootIndex);
} else {
if (optimization.is_constant_call()) {
__ ldr(data,
FieldMemOperand(callee, JSFunction::kSharedFunctionInfoOffset));
__ ldr(data,
FieldMemOperand(data, SharedFunctionInfo::kFunctionDataOffset));
__ ldr(data,
FieldMemOperand(data, FunctionTemplateInfo::kCallCodeOffset));
} else {
__ ldr(data,
FieldMemOperand(callee, FunctionTemplateInfo::kCallCodeOffset));
}
__ ldr(data, FieldMemOperand(data, CallHandlerInfo::kDataOffset));
}
// Put api_function_address in place.
Address function_address = v8::ToCData<Address>(api_call_info->callback());
ApiFunction fun(function_address);
ExternalReference::Type type = ExternalReference::DIRECT_API_CALL;
ExternalReference ref = ExternalReference(&fun, type, masm->isolate());
__ mov(api_function_address, Operand(ref));
// Jump to stub.
CallApiCallbackStub stub(isolate, is_store ? 1 : 0);
__ TailCallStub(&stub);
}
#undef __
#define __ ACCESS_MASM(masm())
......
......@@ -100,86 +100,6 @@ void PropertyHandlerCompiler::GenerateCheckPropertyCell(
__ JumpIfNotRoot(scratch, Heap::kTheHoleValueRootIndex, miss);
}
// Generate call to api function.
void PropertyHandlerCompiler::GenerateApiAccessorCall(
MacroAssembler* masm, const CallOptimization& optimization,
Handle<Map> receiver_map, Register receiver, Register scratch,
bool is_store, Register store_parameter, Register accessor_holder,
int accessor_index) {
DCHECK(!AreAliased(accessor_holder, scratch));
DCHECK(!AreAliased(receiver, scratch));
MacroAssembler::PushPopQueue queue(masm);
queue.Queue(receiver);
// Write the arguments to the stack frame.
if (is_store) {
DCHECK(!receiver.is(store_parameter));
DCHECK(!scratch.is(store_parameter));
queue.Queue(store_parameter);
}
queue.PushQueued();
DCHECK(optimization.is_simple_api_call());
// Abi for CallApiCallbackStub.
Register callee = x0;
Register data = x4;
Register holder = x2;
Register api_function_address = x1;
// Put callee in place.
__ LoadAccessor(callee, accessor_holder, accessor_index,
is_store ? ACCESSOR_SETTER : ACCESSOR_GETTER);
// Put holder in place.
CallOptimization::HolderLookup holder_lookup;
optimization.LookupHolderOfExpectedType(receiver_map, &holder_lookup);
switch (holder_lookup) {
case CallOptimization::kHolderIsReceiver:
__ Mov(holder, receiver);
break;
case CallOptimization::kHolderFound:
__ Ldr(holder, FieldMemOperand(receiver, HeapObject::kMapOffset));
__ Ldr(holder, FieldMemOperand(holder, Map::kPrototypeOffset));
break;
case CallOptimization::kHolderNotFound:
UNREACHABLE();
break;
}
Isolate* isolate = masm->isolate();
Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
// Put call data in place.
if (api_call_info->data()->IsUndefined(isolate)) {
__ LoadRoot(data, Heap::kUndefinedValueRootIndex);
} else {
if (optimization.is_constant_call()) {
__ Ldr(data,
FieldMemOperand(callee, JSFunction::kSharedFunctionInfoOffset));
__ Ldr(data,
FieldMemOperand(data, SharedFunctionInfo::kFunctionDataOffset));
__ Ldr(data,
FieldMemOperand(data, FunctionTemplateInfo::kCallCodeOffset));
} else {
__ Ldr(data,
FieldMemOperand(callee, FunctionTemplateInfo::kCallCodeOffset));
}
__ Ldr(data, FieldMemOperand(data, CallHandlerInfo::kDataOffset));
}
// Put api_function_address in place.
Address function_address = v8::ToCData<Address>(api_call_info->callback());
ApiFunction fun(function_address);
ExternalReference ref = ExternalReference(
&fun, ExternalReference::DIRECT_API_CALL, masm->isolate());
__ Mov(api_function_address, ref);
// Jump to stub.
CallApiCallbackStub stub(isolate, is_store ? 1 : 0);
__ TailCallStub(&stub);
}
void NamedStoreHandlerCompiler::GenerateStoreViaSetter(
MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder,
int accessor_index, int expected_arguments, Register scratch) {
......
......@@ -95,28 +95,6 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreViaSetter(
return GetCode(name);
}
Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
Handle<JSObject> object, Handle<Name> name,
const CallOptimization& call_optimization, Handle<Context> context,
int accessor_index, Handle<Code> slow_stub) {
if (V8_UNLIKELY(FLAG_runtime_stats)) {
GenerateTailCall(masm(), slow_stub);
}
Register holder = Frontend(name);
if (Descriptor::kPassLastArgsOnStack) {
__ LoadParameterFromStack<Descriptor>(value(), Descriptor::kValue);
}
Handle<WeakCell> cell = factory()->NewWeakCell(context);
__ GetWeakValue(JavaScriptFrame::context_register(), cell);
GenerateApiAccessorCall(masm(), call_optimization, handle(object->map()),
receiver(), scratch2(), true, value(), holder,
accessor_index);
return GetCode(name);
}
#undef __
} // namespace internal
......
......@@ -44,15 +44,6 @@ class PropertyHandlerCompiler : public PropertyAccessCompiler {
void DiscardVectorAndSlot();
// TODO(verwaest): Make non-static.
static void GenerateApiAccessorCall(MacroAssembler* masm,
const CallOptimization& optimization,
Handle<Map> receiver_map,
Register receiver, Register scratch,
bool is_store, Register store_parameter,
Register accessor_holder,
int accessor_index);
// Helper function used to check that the dictionary doesn't contain
// the property. This function may return false negatives, so miss_label
// must always call a backup property check that is complete.
......@@ -132,10 +123,6 @@ class NamedStoreHandlerCompiler : public PropertyHandlerCompiler {
Handle<Code> CompileStoreCallback(Handle<JSObject> object, Handle<Name> name,
Handle<AccessorInfo> callback,
LanguageMode language_mode);
Handle<Code> CompileStoreCallback(Handle<JSObject> object, Handle<Name> name,
const CallOptimization& call_optimization,
Handle<Context> context, int accessor_index,
Handle<Code> slow_stub);
Handle<Code> CompileStoreViaSetter(Handle<JSObject> object, Handle<Name> name,
int accessor_index,
int expected_arguments);
......
......@@ -37,7 +37,7 @@ Handle<Smi> LoadHandler::LoadField(Isolate* isolate, FieldIndex field_index) {
int config = KindBits::encode(kField) |
IsInobjectBits::encode(field_index.is_inobject()) |
IsDoubleBits::encode(field_index.is_double()) |
FieldOffsetBits::encode(field_index.offset());
FieldIndexBits::encode(field_index.index());
return handle(Smi::FromInt(config), isolate);
}
......@@ -126,12 +126,12 @@ Handle<Smi> LoadHandler::LoadIndexedString(Isolate* isolate,
}
Handle<Smi> StoreHandler::StoreGlobalProxy(Isolate* isolate) {
int config = KindBits::encode(kStoreGlobalProxy);
int config = KindBits::encode(kGlobalProxy);
return handle(Smi::FromInt(config), isolate);
}
Handle<Smi> StoreHandler::StoreNormal(Isolate* isolate) {
int config = KindBits::encode(kStoreNormal);
int config = KindBits::encode(kNormal);
return handle(Smi::FromInt(config), isolate);
}
......@@ -151,35 +151,35 @@ Handle<Smi> StoreHandler::StoreField(Isolate* isolate, Kind kind,
int descriptor, FieldIndex field_index,
Representation representation,
bool extend_storage) {
StoreHandler::FieldRepresentation field_rep;
FieldRepresentation field_rep;
switch (representation.kind()) {
case Representation::kSmi:
field_rep = StoreHandler::kSmi;
field_rep = kSmi;
break;
case Representation::kDouble:
field_rep = StoreHandler::kDouble;
field_rep = kDouble;
break;
case Representation::kHeapObject:
field_rep = StoreHandler::kHeapObject;
field_rep = kHeapObject;
break;
case Representation::kTagged:
field_rep = StoreHandler::kTagged;
field_rep = kTagged;
break;
default:
UNREACHABLE();
}
DCHECK(kind == kStoreField || kind == kTransitionToField ||
(kind == kStoreConstField && FLAG_track_constant_fields));
DCHECK(kind == kField || kind == kTransitionToField ||
(kind == kConstField && FLAG_track_constant_fields));
DCHECK_IMPLIES(extend_storage, kind == kTransitionToField);
DCHECK_IMPLIES(field_index.is_inobject(), !extend_storage);
int config = StoreHandler::KindBits::encode(kind) |
StoreHandler::ExtendStorageBits::encode(extend_storage) |
StoreHandler::IsInobjectBits::encode(field_index.is_inobject()) |
StoreHandler::FieldRepresentationBits::encode(field_rep) |
StoreHandler::DescriptorBits::encode(descriptor) |
StoreHandler::FieldOffsetBits::encode(field_index.offset());
int config = KindBits::encode(kind) |
ExtendStorageBits::encode(extend_storage) |
IsInobjectBits::encode(field_index.is_inobject()) |
FieldRepresentationBits::encode(field_rep) |
DescriptorBits::encode(descriptor) |
FieldIndexBits::encode(field_index.index());
return handle(Smi::FromInt(config), isolate);
}
......@@ -188,7 +188,7 @@ Handle<Smi> StoreHandler::StoreField(Isolate* isolate, int descriptor,
PropertyConstness constness,
Representation representation) {
DCHECK_IMPLIES(!FLAG_track_constant_fields, constness == kMutable);
Kind kind = constness == kMutable ? kStoreField : kStoreConstField;
Kind kind = constness == kMutable ? kField : kConstField;
return StoreField(isolate, kind, descriptor, field_index, representation,
false);
}
......@@ -204,9 +204,15 @@ Handle<Smi> StoreHandler::TransitionToField(Isolate* isolate, int descriptor,
Handle<Smi> StoreHandler::TransitionToConstant(Isolate* isolate,
int descriptor) {
DCHECK(!FLAG_track_constant_fields);
int config =
StoreHandler::KindBits::encode(StoreHandler::kTransitionToConstant) |
StoreHandler::DescriptorBits::encode(descriptor);
int config = KindBits::encode(kTransitionToConstant) |
DescriptorBits::encode(descriptor);
return handle(Smi::FromInt(config), isolate);
}
Handle<Smi> StoreHandler::StoreApiSetter(Isolate* isolate,
bool holder_is_receiver) {
int config = KindBits::encode(
holder_is_receiver ? kApiSetter : kApiSetterHolderIsPrototype);
return handle(Smi::FromInt(config), isolate);
}
......
......@@ -221,69 +221,38 @@ Handle<Object> StoreHandler::StoreElementTransition(
return isolate->factory()->NewTuple3(cell, stub, validity_cell, TENURED);
}
// static
Handle<Object> StoreHandler::StoreTransition(Isolate* isolate,
Handle<Map> receiver_map,
Handle<JSObject> holder,
Handle<HeapObject> transition,
Handle<Name> name) {
Handle<Smi> smi_handler;
Handle<WeakCell> transition_cell;
if (transition->IsMap()) {
Handle<Map> transition_map = Handle<Map>::cast(transition);
if (transition_map->is_dictionary_map()) {
smi_handler = StoreNormal(isolate);
} else {
int descriptor = transition_map->LastAdded();
Handle<DescriptorArray> descriptors(
transition_map->instance_descriptors());
PropertyDetails details = descriptors->GetDetails(descriptor);
Representation representation = details.representation();
DCHECK(!representation.IsNone());
// Declarative handlers don't support access checks.
DCHECK(!transition_map->is_access_check_needed());
DCHECK_EQ(kData, details.kind());
if (details.location() == kDescriptor) {
smi_handler = TransitionToConstant(isolate, descriptor);
} else {
DCHECK_EQ(kField, details.location());
bool extend_storage = Map::cast(transition_map->GetBackPointer())
->UnusedPropertyFields() == 0;
FieldIndex index =
FieldIndex::ForDescriptor(*transition_map, descriptor);
smi_handler = TransitionToField(isolate, descriptor, index,
representation, extend_storage);
}
}
// |holder| is either a receiver if the property is non-existent or
// one of the prototypes.
DCHECK(!holder.is_null());
bool is_nonexistent = holder->map() == transition_map->GetBackPointer();
if (is_nonexistent) holder = Handle<JSObject>::null();
transition_cell = Map::WeakCellForMap(transition_map);
} else {
DCHECK(transition->IsPropertyCell());
if (receiver_map->IsJSGlobalObjectMap()) {
// TODO(ishell): this must be handled by StoreGlobalIC once it's finished.
return StoreGlobal(isolate, Handle<PropertyCell>::cast(transition));
} else {
DCHECK(receiver_map->IsJSGlobalProxyMap());
smi_handler = StoreGlobalProxy(isolate);
transition_cell = isolate->factory()->NewWeakCell(transition);
}
Handle<Smi> StoreHandler::StoreTransition(Isolate* isolate,
Handle<Map> transition_map) {
int descriptor = transition_map->LastAdded();
Handle<DescriptorArray> descriptors(transition_map->instance_descriptors());
PropertyDetails details = descriptors->GetDetails(descriptor);
Representation representation = details.representation();
DCHECK(!representation.IsNone());
// Declarative handlers don't support access checks.
DCHECK(!transition_map->is_access_check_needed());
DCHECK_EQ(kData, details.kind());
if (details.location() == PropertyLocation::kDescriptor) {
return TransitionToConstant(isolate, descriptor);
}
DCHECK_EQ(PropertyLocation::kField, details.location());
bool extend_storage =
Map::cast(transition_map->GetBackPointer())->UnusedPropertyFields() == 0;
FieldIndex index = FieldIndex::ForDescriptor(*transition_map, descriptor);
return TransitionToField(isolate, descriptor, index, representation,
extend_storage);
}
// static
Handle<Object> StoreHandler::StoreThroughPrototype(
Isolate* isolate, Handle<Map> receiver_map, Handle<JSReceiver> holder,
Handle<Name> name, Handle<Smi> smi_handler, Handle<Object> data) {
int checks_count =
GetPrototypeCheckCount(isolate, receiver_map, holder, name);
DCHECK_LE(0, checks_count);
DCHECK(!receiver_map->IsJSGlobalObjectMap());
if (receiver_map->is_access_check_needed()) {
DCHECK(!receiver_map->is_dictionary_map());
......@@ -300,14 +269,13 @@ Handle<Object> StoreHandler::StoreTransition(Isolate* isolate,
Factory* factory = isolate->factory();
if (checks_count == 0) {
return factory->NewTuple3(transition_cell, smi_handler, validity_cell,
TENURED);
return factory->NewTuple3(data, smi_handler, validity_cell, TENURED);
}
Handle<FixedArray> handler_array(
factory->NewFixedArray(kFirstPrototypeIndex + checks_count, TENURED));
handler_array->set(kSmiHandlerIndex, *smi_handler);
handler_array->set(kValidityCellIndex, *validity_cell);
handler_array->set(kDataIndex, *transition_cell);
handler_array->set(kDataIndex, *data);
InitPrototypeChecks(isolate, receiver_map, holder, name, handler_array,
kFirstPrototypeIndex);
return handler_array;
......@@ -326,40 +294,10 @@ Handle<Object> StoreHandler::StoreProxy(Isolate* isolate,
Handle<JSReceiver> receiver,
Handle<Name> name) {
Handle<Smi> smi_handler = StoreProxy(isolate);
if (receiver.is_identical_to(proxy)) return smi_handler;
int checks_count = GetPrototypeCheckCount(isolate, receiver_map, proxy, name);
DCHECK_LE(0, checks_count);
if (receiver_map->is_access_check_needed()) {
DCHECK(!receiver_map->is_dictionary_map());
DCHECK_LE(1, checks_count); // For native context.
smi_handler = EnableAccessCheckOnReceiver(isolate, smi_handler);
}
Handle<Object> validity_cell =
Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate);
if (validity_cell.is_null()) {
DCHECK_EQ(0, checks_count);
validity_cell = handle(Smi::kZero, isolate);
}
Factory* factory = isolate->factory();
Handle<WeakCell> holder_cell = factory->NewWeakCell(proxy);
if (checks_count == 0) {
return factory->NewTuple3(holder_cell, smi_handler, validity_cell, TENURED);
}
Handle<FixedArray> handler_array(
factory->NewFixedArray(kFirstPrototypeIndex + checks_count, TENURED));
handler_array->set(kSmiHandlerIndex, *smi_handler);
handler_array->set(kValidityCellIndex, *validity_cell);
handler_array->set(kDataIndex, *holder_cell);
InitPrototypeChecks(isolate, receiver_map, proxy, name, handler_array,
kFirstPrototypeIndex);
return handler_array;
Handle<WeakCell> holder_cell = isolate->factory()->NewWeakCell(proxy);
return StoreThroughPrototype(isolate, receiver_map, proxy, name, smi_handler,
holder_cell);
}
Object* StoreHandler::ValidHandlerOrNull(Object* raw_handler, Name* name,
......
......@@ -64,11 +64,10 @@ class LoadHandler {
};
class IsDoubleBits : public BitField<bool, IsInobjectBits::kNext, 1> {};
// +1 here is to cover all possible JSObject header sizes.
class FieldOffsetBits
: public BitField<unsigned, IsDoubleBits::kNext,
kDescriptorIndexBitCount + 1 + kPointerSizeLog2> {};
class FieldIndexBits : public BitField<unsigned, IsDoubleBits::kNext,
kDescriptorIndexBitCount + 1> {};
// Make sure we don't overflow the smi.
STATIC_ASSERT(FieldOffsetBits::kNext <= kSmiValueSize);
STATIC_ASSERT(FieldIndexBits::kNext <= kSmiValueSize);
//
// Encoding when KindBits contains kElement or kIndexedString.
......@@ -195,30 +194,32 @@ class LoadHandler {
class StoreHandler {
public:
enum Kind {
kStoreElement,
kStoreField,
kStoreConstField,
kElement,
kField,
kConstField,
// TODO(ishell): remove once constant field tracking is done.
kTransitionToConstant = kStoreConstField,
kTransitionToConstant = kConstField,
kTransitionToField,
kStoreGlobalProxy,
kStoreNormal,
kApiSetter,
kApiSetterHolderIsPrototype,
kGlobalProxy,
kNormal,
kProxy,
kKindsNumber // Keep last
};
class KindBits : public BitField<Kind, 0, 3> {};
class KindBits : public BitField<Kind, 0, 4> {};
enum FieldRepresentation { kSmi, kDouble, kHeapObject, kTagged };
static inline bool IsHandler(Object* maybe_handler);
// Applicable to kStoreGlobalProxy, kProxy kinds.
// Applicable to kGlobalProxy, kProxy kinds.
// Defines whether access rights check should be done on receiver object.
class DoAccessCheckOnReceiverBits
: public BitField<bool, KindBits::kNext, 1> {};
// Applicable to kStoreField, kTransitionToField and kTransitionToConstant
// Applicable to kField, kTransitionToField and kTransitionToConstant
// kinds.
// Index of a value entry in the descriptor array.
......@@ -233,18 +234,18 @@ class StoreHandler {
STATIC_ASSERT(DescriptorBits::kNext <= kSmiValueSize);
//
// Encoding when KindBits contains kStoreField or kTransitionToField.
// Encoding when KindBits contains kField or kTransitionToField.
//
class ExtendStorageBits : public BitField<bool, DescriptorBits::kNext, 1> {};
class IsInobjectBits : public BitField<bool, ExtendStorageBits::kNext, 1> {};
class FieldRepresentationBits
: public BitField<FieldRepresentation, IsInobjectBits::kNext, 2> {};
// +1 here is to cover all possible JSObject header sizes.
class FieldOffsetBits
class FieldIndexBits
: public BitField<unsigned, FieldRepresentationBits::kNext,
kDescriptorIndexBitCount + 1 + kPointerSizeLog2> {};
kDescriptorIndexBitCount + 1> {};
// Make sure we don't overflow the smi.
STATIC_ASSERT(FieldOffsetBits::kNext <= kSmiValueSize);
STATIC_ASSERT(FieldIndexBits::kNext <= kSmiValueSize);
// The layout of an Tuple3 handler representing a transitioning store
// when prototype chain checks do not include non-existing lookups or access
......@@ -270,11 +271,16 @@ class StoreHandler {
PropertyConstness constness,
Representation representation);
static Handle<Object> StoreTransition(Isolate* isolate,
Handle<Map> receiver_map,
Handle<JSObject> holder,
Handle<HeapObject> transition,
Handle<Name> name);
static Handle<Smi> StoreTransition(Isolate* isolate,
Handle<Map> transition_map);
// Creates a Smi-handler for calling a native setter on a fast object.
static inline Handle<Smi> StoreApiSetter(Isolate* isolate,
bool holder_is_receiver);
static Handle<Object> StoreThroughPrototype(
Isolate* isolate, Handle<Map> receiver_map, Handle<JSReceiver> holder,
Handle<Name> name, Handle<Smi> smi_handler, Handle<Object> data);
static Handle<Object> StoreElementTransition(Isolate* isolate,
Handle<Map> receiver_map,
......
......@@ -83,87 +83,6 @@ void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
__ DecrementCounter(counters->negative_lookups_miss(), 1);
}
// Generate call to api function.
// This function uses push() to generate smaller, faster code than
// the version above. It is an optimization that should will be removed
// when api call ICs are generated in hydrogen.
void PropertyHandlerCompiler::GenerateApiAccessorCall(
MacroAssembler* masm, const CallOptimization& optimization,
Handle<Map> receiver_map, Register receiver, Register scratch,
bool is_store, Register store_parameter, Register accessor_holder,
int accessor_index) {
DCHECK(accessor_holder != scratch);
// Copy return value.
__ pop(scratch);
if (is_store) {
// Discard stack arguments.
__ add(esp, Immediate(StoreWithVectorDescriptor::kStackArgumentsCount *
kPointerSize));
}
// Write the receiver and arguments to stack frame.
__ push(receiver);
if (is_store) {
DCHECK(!AreAliased(receiver, scratch, store_parameter));
__ push(store_parameter);
}
__ push(scratch);
// Stack now matches JSFunction abi.
DCHECK(optimization.is_simple_api_call());
// Abi for CallApiCallbackStub.
Register callee = edi;
Register data = ebx;
Register holder = ecx;
Register api_function_address = edx;
scratch = no_reg;
// Put callee in place.
__ LoadAccessor(callee, accessor_holder, accessor_index,
is_store ? ACCESSOR_SETTER : ACCESSOR_GETTER);
// Put holder in place.
CallOptimization::HolderLookup holder_lookup;
optimization.LookupHolderOfExpectedType(receiver_map, &holder_lookup);
switch (holder_lookup) {
case CallOptimization::kHolderIsReceiver:
__ Move(holder, receiver);
break;
case CallOptimization::kHolderFound:
__ mov(holder, FieldOperand(receiver, HeapObject::kMapOffset));
__ mov(holder, FieldOperand(holder, Map::kPrototypeOffset));
break;
case CallOptimization::kHolderNotFound:
UNREACHABLE();
break;
}
Isolate* isolate = masm->isolate();
Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
// Put call data in place.
if (api_call_info->data()->IsUndefined(isolate)) {
__ mov(data, Immediate(isolate->factory()->undefined_value()));
} else {
if (optimization.is_constant_call()) {
__ mov(data, FieldOperand(callee, JSFunction::kSharedFunctionInfoOffset));
__ mov(data, FieldOperand(data, SharedFunctionInfo::kFunctionDataOffset));
__ mov(data, FieldOperand(data, FunctionTemplateInfo::kCallCodeOffset));
} else {
__ mov(data, FieldOperand(callee, FunctionTemplateInfo::kCallCodeOffset));
}
__ mov(data, FieldOperand(data, CallHandlerInfo::kDataOffset));
}
// Put api_function_address in place.
Address function_address = v8::ToCData<Address>(api_call_info->callback());
__ mov(api_function_address, Immediate(function_address));
// Jump to stub.
CallApiCallbackStub stub(isolate, is_store ? 1 : 0);
__ TailCallStub(&stub);
}
// Generate code to check that a global property cell is empty. Create
// the property cell at compilation time if no cell exists for the
// property.
......
......@@ -1433,9 +1433,20 @@ Handle<Object> StoreIC::GetMapIndependentHandler(LookupIterator* lookup) {
if (store_target->IsJSGlobalObject()) {
TRACE_HANDLER_STATS(isolate(), StoreIC_StoreGlobalTransitionDH);
Handle<Object> handler = StoreHandler::StoreTransition(
isolate(), receiver_map(), store_target, lookup->transition_cell(),
lookup->name());
if (receiver_map()->IsJSGlobalObject()) {
DCHECK(IsStoreGlobalIC());
DCHECK_EQ(*lookup->GetReceiver(), *holder);
DCHECK_EQ(*store_target, *holder);
return StoreHandler::StoreGlobal(isolate(),
lookup->transition_cell());
}
Handle<Smi> smi_handler = StoreHandler::StoreGlobalProxy(isolate());
Handle<WeakCell> cell =
isolate()->factory()->NewWeakCell(lookup->transition_cell());
Handle<Object> handler = StoreHandler::StoreThroughPrototype(
isolate(), receiver_map(), store_target, lookup->name(),
smi_handler, cell);
return handler;
}
// Currently not handled by CompileStoreTransition.
......@@ -1447,9 +1458,19 @@ Handle<Object> StoreIC::GetMapIndependentHandler(LookupIterator* lookup) {
DCHECK(lookup->IsCacheableTransition());
Handle<Map> transition = lookup->transition_map();
TRACE_HANDLER_STATS(isolate(), StoreIC_StoreTransitionDH);
Handle<Object> handler = StoreHandler::StoreTransition(
isolate(), receiver_map(), holder, transition, lookup->name());
Handle<Smi> smi_handler;
if (transition->is_dictionary_map()) {
TRACE_HANDLER_STATS(isolate(), StoreIC_StoreNormalDH);
smi_handler = StoreHandler::StoreNormal(isolate());
} else {
TRACE_HANDLER_STATS(isolate(), StoreIC_StoreTransitionDH);
smi_handler = StoreHandler::StoreTransition(isolate(), transition);
}
Handle<WeakCell> cell = Map::WeakCellForMap(transition);
Handle<Object> handler = StoreHandler::StoreThroughPrototype(
isolate(), receiver_map(), holder, lookup->name(), smi_handler, cell);
TransitionsAccessor(receiver_map())
.UpdateHandler(*lookup->name(), *handler);
return handler;
......@@ -1508,7 +1529,26 @@ Handle<Object> StoreIC::GetMapIndependentHandler(LookupIterator* lookup) {
CallOptimization call_optimization(setter);
if (call_optimization.is_simple_api_call()) {
if (call_optimization.IsCompatibleReceiver(receiver, holder)) {
break; // Custom-compiled handler.
CallOptimization::HolderLookup holder_lookup;
call_optimization.LookupHolderOfExpectedType(receiver_map(),
&holder_lookup);
Handle<Smi> smi_handler = StoreHandler::StoreApiSetter(
isolate(),
holder_lookup == CallOptimization::kHolderIsReceiver);
Handle<Context> context(
call_optimization.GetAccessorContext(holder->map()));
Handle<WeakCell> context_cell =
isolate()->factory()->NewWeakCell(context);
Handle<WeakCell> data_cell = isolate()->factory()->NewWeakCell(
call_optimization.api_call_info());
Handle<Tuple2> data = isolate()->factory()->NewTuple2(
context_cell, data_cell, TENURED);
TRACE_HANDLER_STATS(isolate(), StoreIC_StoreApiSetterOnPrototypeDH);
return StoreHandler::StoreThroughPrototype(
isolate(), receiver_map(), holder, lookup->name(), smi_handler,
data);
}
TRACE_GENERIC_IC("incompatible receiver");
TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
......@@ -1615,15 +1655,7 @@ Handle<Code> StoreIC::CompileHandler(LookupIterator* lookup) {
DCHECK(setter->IsJSFunction() || setter->IsFunctionTemplateInfo());
CallOptimization call_optimization(setter);
NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
if (call_optimization.is_simple_api_call()) {
DCHECK(call_optimization.IsCompatibleReceiver(receiver, holder));
TRACE_HANDLER_STATS(isolate(), StoreIC_StoreCallback);
Handle<Code> code = compiler.CompileStoreCallback(
receiver, lookup->name(), call_optimization,
handle(call_optimization.GetAccessorContext(holder->map())),
lookup->GetAccessorIndex(), slow_stub());
return code;
}
DCHECK(!call_optimization.is_simple_api_call());
TRACE_HANDLER_STATS(isolate(), StoreIC_StoreViaSetter);
int expected_arguments =
JSFunction::cast(*setter)->shared()->internal_formal_parameter_count();
......
......@@ -134,80 +134,6 @@ void PropertyHandlerCompiler::GenerateCheckPropertyCell(
__ Branch(miss, ne, scratch, Operand(at));
}
// Generate call to api function.
void PropertyHandlerCompiler::GenerateApiAccessorCall(
MacroAssembler* masm, const CallOptimization& optimization,
Handle<Map> receiver_map, Register receiver, Register scratch_in,
bool is_store, Register store_parameter, Register accessor_holder,
int accessor_index) {
DCHECK(accessor_holder != scratch_in);
DCHECK(receiver != scratch_in);
__ push(receiver);
// Write the arguments to stack frame.
if (is_store) {
DCHECK(receiver != store_parameter);
DCHECK(scratch_in != store_parameter);
__ push(store_parameter);
}
DCHECK(optimization.is_simple_api_call());
// Abi for CallApiCallbackStub.
Register callee = a0;
Register data = t0;
Register holder = a2;
Register api_function_address = a1;
// Put callee in place.
__ LoadAccessor(callee, accessor_holder, accessor_index,
is_store ? ACCESSOR_SETTER : ACCESSOR_GETTER);
// Put holder in place.
CallOptimization::HolderLookup holder_lookup;
optimization.LookupHolderOfExpectedType(receiver_map, &holder_lookup);
switch (holder_lookup) {
case CallOptimization::kHolderIsReceiver:
__ Move(holder, receiver);
break;
case CallOptimization::kHolderFound:
__ lw(holder, FieldMemOperand(receiver, HeapObject::kMapOffset));
__ lw(holder, FieldMemOperand(holder, Map::kPrototypeOffset));
break;
case CallOptimization::kHolderNotFound:
UNREACHABLE();
break;
}
Isolate* isolate = masm->isolate();
Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
// Put call data in place.
if (api_call_info->data()->IsUndefined(isolate)) {
__ LoadRoot(data, Heap::kUndefinedValueRootIndex);
} else {
if (optimization.is_constant_call()) {
__ lw(data,
FieldMemOperand(callee, JSFunction::kSharedFunctionInfoOffset));
__ lw(data,
FieldMemOperand(data, SharedFunctionInfo::kFunctionDataOffset));
__ lw(data, FieldMemOperand(data, FunctionTemplateInfo::kCallCodeOffset));
} else {
__ lw(data,
FieldMemOperand(callee, FunctionTemplateInfo::kCallCodeOffset));
}
__ lw(data, FieldMemOperand(data, CallHandlerInfo::kDataOffset));
}
// Put api_function_address in place.
Address function_address = v8::ToCData<Address>(api_call_info->callback());
ApiFunction fun(function_address);
ExternalReference::Type type = ExternalReference::DIRECT_API_CALL;
ExternalReference ref = ExternalReference(&fun, type, masm->isolate());
__ li(api_function_address, Operand(ref));
// Jump to stub.
CallApiCallbackStub stub(isolate, is_store ? 1 : 0);
__ TailCallStub(&stub);
}
#undef __
#define __ ACCESS_MASM(masm())
......
......@@ -134,80 +134,6 @@ void PropertyHandlerCompiler::GenerateCheckPropertyCell(
__ Branch(miss, ne, scratch, Operand(at));
}
// Generate call to api function.
void PropertyHandlerCompiler::GenerateApiAccessorCall(
MacroAssembler* masm, const CallOptimization& optimization,
Handle<Map> receiver_map, Register receiver, Register scratch_in,
bool is_store, Register store_parameter, Register accessor_holder,
int accessor_index) {
DCHECK(accessor_holder != scratch_in);
DCHECK(receiver != scratch_in);
__ push(receiver);
// Write the arguments to stack frame.
if (is_store) {
DCHECK(receiver != store_parameter);
DCHECK(scratch_in != store_parameter);
__ push(store_parameter);
}
DCHECK(optimization.is_simple_api_call());
// Abi for CallApiCallbackStub.
Register callee = a0;
Register data = a4;
Register holder = a2;
Register api_function_address = a1;
// Put callee in place.
__ LoadAccessor(callee, accessor_holder, accessor_index,
is_store ? ACCESSOR_SETTER : ACCESSOR_GETTER);
// Put holder in place.
CallOptimization::HolderLookup holder_lookup;
optimization.LookupHolderOfExpectedType(receiver_map, &holder_lookup);
switch (holder_lookup) {
case CallOptimization::kHolderIsReceiver:
__ Move(holder, receiver);
break;
case CallOptimization::kHolderFound:
__ Ld(holder, FieldMemOperand(receiver, HeapObject::kMapOffset));
__ Ld(holder, FieldMemOperand(holder, Map::kPrototypeOffset));
break;
case CallOptimization::kHolderNotFound:
UNREACHABLE();
break;
}
Isolate* isolate = masm->isolate();
Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
// Put call data in place.
if (api_call_info->data()->IsUndefined(isolate)) {
__ LoadRoot(data, Heap::kUndefinedValueRootIndex);
} else {
if (optimization.is_constant_call()) {
__ Ld(data,
FieldMemOperand(callee, JSFunction::kSharedFunctionInfoOffset));
__ Ld(data,
FieldMemOperand(data, SharedFunctionInfo::kFunctionDataOffset));
__ Ld(data, FieldMemOperand(data, FunctionTemplateInfo::kCallCodeOffset));
} else {
__ Ld(data,
FieldMemOperand(callee, FunctionTemplateInfo::kCallCodeOffset));
}
__ Ld(data, FieldMemOperand(data, CallHandlerInfo::kDataOffset));
}
// Put api_function_address in place.
Address function_address = v8::ToCData<Address>(api_call_info->callback());
ApiFunction fun(function_address);
ExternalReference::Type type = ExternalReference::DIRECT_API_CALL;
ExternalReference ref = ExternalReference(&fun, type, masm->isolate());
__ li(api_function_address, Operand(ref));
// Jump to stub.
CallApiCallbackStub stub(isolate, is_store ? 1 : 0);
__ TailCallStub(&stub);
}
#undef __
#define __ ACCESS_MASM(masm())
......
......@@ -138,81 +138,6 @@ void PropertyHandlerCompiler::GenerateCheckPropertyCell(
}
// Generate call to api function.
void PropertyHandlerCompiler::GenerateApiAccessorCall(
MacroAssembler* masm, const CallOptimization& optimization,
Handle<Map> receiver_map, Register receiver, Register scratch_in,
bool is_store, Register store_parameter, Register accessor_holder,
int accessor_index) {
DCHECK(accessor_holder != scratch_in);
DCHECK(receiver != scratch_in);
__ push(receiver);
// Write the arguments to stack frame.
if (is_store) {
DCHECK(receiver != store_parameter);
DCHECK(scratch_in != store_parameter);
__ push(store_parameter);
}
DCHECK(optimization.is_simple_api_call());
// Abi for CallApiCallbackStub.
Register callee = r3;
Register data = r7;
Register holder = r5;
Register api_function_address = r4;
// Put callee in place.
__ LoadAccessor(callee, accessor_holder, accessor_index,
is_store ? ACCESSOR_SETTER : ACCESSOR_GETTER);
// Put holder in place.
CallOptimization::HolderLookup holder_lookup;
optimization.LookupHolderOfExpectedType(receiver_map, &holder_lookup);
switch (holder_lookup) {
case CallOptimization::kHolderIsReceiver:
__ Move(holder, receiver);
break;
case CallOptimization::kHolderFound:
__ LoadP(holder, FieldMemOperand(receiver, HeapObject::kMapOffset));
__ LoadP(holder, FieldMemOperand(holder, Map::kPrototypeOffset));
break;
case CallOptimization::kHolderNotFound:
UNREACHABLE();
break;
}
Isolate* isolate = masm->isolate();
Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
// Put call data in place.
if (api_call_info->data()->IsUndefined(isolate)) {
__ LoadRoot(data, Heap::kUndefinedValueRootIndex);
} else {
if (optimization.is_constant_call()) {
__ LoadP(data,
FieldMemOperand(callee, JSFunction::kSharedFunctionInfoOffset));
__ LoadP(data,
FieldMemOperand(data, SharedFunctionInfo::kFunctionDataOffset));
__ LoadP(data,
FieldMemOperand(data, FunctionTemplateInfo::kCallCodeOffset));
} else {
__ LoadP(data,
FieldMemOperand(callee, FunctionTemplateInfo::kCallCodeOffset));
}
__ LoadP(data, FieldMemOperand(data, CallHandlerInfo::kDataOffset));
}
// Put api_function_address in place.
Address function_address = v8::ToCData<Address>(api_call_info->callback());
ApiFunction fun(function_address);
ExternalReference::Type type = ExternalReference::DIRECT_API_CALL;
ExternalReference ref = ExternalReference(&fun, type, masm->isolate());
__ mov(api_function_address, Operand(ref));
// Jump to stub.
CallApiCallbackStub stub(isolate, is_store ? 1 : 0);
__ TailCallStub(&stub);
}
#undef __
#define __ ACCESS_MASM(masm())
......
......@@ -132,81 +132,6 @@ void PropertyHandlerCompiler::GenerateCheckPropertyCell(
__ bne(miss);
}
// Generate call to api function.
void PropertyHandlerCompiler::GenerateApiAccessorCall(
MacroAssembler* masm, const CallOptimization& optimization,
Handle<Map> receiver_map, Register receiver, Register scratch_in,
bool is_store, Register store_parameter, Register accessor_holder,
int accessor_index) {
DCHECK(accessor_holder != scratch_in);
DCHECK(receiver != scratch_in);
__ Push(receiver);
// Write the arguments to stack frame.
if (is_store) {
DCHECK(receiver != store_parameter);
DCHECK(scratch_in != store_parameter);
__ Push(store_parameter);
}
DCHECK(optimization.is_simple_api_call());
// Abi for CallApiCallbackStub.
Register callee = r2;
Register data = r6;
Register holder = r4;
Register api_function_address = r3;
// Put callee in place.
__ LoadAccessor(callee, accessor_holder, accessor_index,
is_store ? ACCESSOR_SETTER : ACCESSOR_GETTER);
// Put holder in place.
CallOptimization::HolderLookup holder_lookup;
optimization.LookupHolderOfExpectedType(receiver_map, &holder_lookup);
switch (holder_lookup) {
case CallOptimization::kHolderIsReceiver:
__ Move(holder, receiver);
break;
case CallOptimization::kHolderFound:
__ LoadP(holder, FieldMemOperand(receiver, HeapObject::kMapOffset));
__ LoadP(holder, FieldMemOperand(holder, Map::kPrototypeOffset));
break;
case CallOptimization::kHolderNotFound:
UNREACHABLE();
break;
}
Isolate* isolate = masm->isolate();
Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
// Put call data in place.
if (api_call_info->data()->IsUndefined(isolate)) {
__ LoadRoot(data, Heap::kUndefinedValueRootIndex);
} else {
if (optimization.is_constant_call()) {
__ LoadP(data,
FieldMemOperand(callee, JSFunction::kSharedFunctionInfoOffset));
__ LoadP(data,
FieldMemOperand(data, SharedFunctionInfo::kFunctionDataOffset));
__ LoadP(data,
FieldMemOperand(data, FunctionTemplateInfo::kCallCodeOffset));
} else {
__ LoadP(data,
FieldMemOperand(callee, FunctionTemplateInfo::kCallCodeOffset));
}
__ LoadP(data, FieldMemOperand(data, CallHandlerInfo::kDataOffset));
}
// Put api_function_address in place.
Address function_address = v8::ToCData<Address>(api_call_info->callback());
ApiFunction fun(function_address);
ExternalReference::Type type = ExternalReference::DIRECT_API_CALL;
ExternalReference ref = ExternalReference(&fun, type, masm->isolate());
__ mov(api_function_address, Operand(ref));
// Jump to stub.
CallApiCallbackStub stub(isolate, is_store ? 1 : 0);
__ TailCallStub(&stub);
}
#undef __
#define __ ACCESS_MASM(masm())
......
......@@ -84,84 +84,6 @@ void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
__ DecrementCounter(counters->negative_lookups_miss(), 1);
}
// Generate call to api function.
void PropertyHandlerCompiler::GenerateApiAccessorCall(
MacroAssembler* masm, const CallOptimization& optimization,
Handle<Map> receiver_map, Register receiver, Register scratch,
bool is_store, Register store_parameter, Register accessor_holder,
int accessor_index) {
DCHECK(accessor_holder != scratch);
DCHECK(optimization.is_simple_api_call());
__ PopReturnAddressTo(scratch);
// receiver
__ Push(receiver);
// Write the arguments to stack frame.
if (is_store) {
DCHECK(receiver != store_parameter);
DCHECK(scratch != store_parameter);
__ Push(store_parameter);
}
__ PushReturnAddressFrom(scratch);
// Stack now matches JSFunction abi.
// Abi for CallApiCallbackStub.
Register callee = rdi;
Register data = rbx;
Register holder = rcx;
Register api_function_address = rdx;
scratch = no_reg;
// Put callee in place.
__ LoadAccessor(callee, accessor_holder, accessor_index,
is_store ? ACCESSOR_SETTER : ACCESSOR_GETTER);
// Put holder in place.
CallOptimization::HolderLookup holder_lookup;
optimization.LookupHolderOfExpectedType(receiver_map, &holder_lookup);
switch (holder_lookup) {
case CallOptimization::kHolderIsReceiver:
__ Move(holder, receiver);
break;
case CallOptimization::kHolderFound:
__ movp(holder, FieldOperand(receiver, HeapObject::kMapOffset));
__ movp(holder, FieldOperand(holder, Map::kPrototypeOffset));
break;
case CallOptimization::kHolderNotFound:
UNREACHABLE();
break;
}
Isolate* isolate = masm->isolate();
Handle<CallHandlerInfo> api_call_info = optimization.api_call_info();
// Put call data in place.
if (api_call_info->data()->IsUndefined(isolate)) {
__ LoadRoot(data, Heap::kUndefinedValueRootIndex);
} else {
if (optimization.is_constant_call()) {
__ movp(data,
FieldOperand(callee, JSFunction::kSharedFunctionInfoOffset));
__ movp(data,
FieldOperand(data, SharedFunctionInfo::kFunctionDataOffset));
__ movp(data, FieldOperand(data, FunctionTemplateInfo::kCallCodeOffset));
} else {
__ movp(data,
FieldOperand(callee, FunctionTemplateInfo::kCallCodeOffset));
}
__ movp(data, FieldOperand(data, CallHandlerInfo::kDataOffset));
}
// Put api_function_address in place.
Address function_address = v8::ToCData<Address>(api_call_info->callback());
__ Move(api_function_address, function_address,
RelocInfo::EXTERNAL_REFERENCE);
// Jump to stub.
CallApiCallbackStub stub(isolate, is_store ? 1 : 0);
__ TailCallStub(&stub);
}
void PropertyHandlerCompiler::GenerateCheckPropertyCell(
MacroAssembler* masm, Handle<JSGlobalObject> global, Handle<Name> name,
Register scratch, Label* miss) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment