summaryrefslogtreecommitdiff
path: root/deps/v8/src/ic
diff options
context:
space:
mode:
authorMichaël Zasso <targos@protonmail.com>2017-06-06 10:28:14 +0200
committerMichaël Zasso <targos@protonmail.com>2017-06-07 10:33:31 +0200
commit3dc8c3bed4cf3a77607edbb0b015e33f8b60fc09 (patch)
tree9dee56e142638b34f1eccbd0ad88c3bce5377c29 /deps/v8/src/ic
parent91a1bbe3055a660194ca4d403795aa0c03e9d056 (diff)
downloadandroid-node-v8-3dc8c3bed4cf3a77607edbb0b015e33f8b60fc09.tar.gz
android-node-v8-3dc8c3bed4cf3a77607edbb0b015e33f8b60fc09.tar.bz2
android-node-v8-3dc8c3bed4cf3a77607edbb0b015e33f8b60fc09.zip
deps: update V8 to 5.9.211.32
PR-URL: https://github.com/nodejs/node/pull/13263 Reviewed-By: Gibson Fahnestock <gibfahn@gmail.com> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Franziska Hinkelmann <franziska.hinkelmann@gmail.com> Reviewed-By: Myles Borins <myles.borins@gmail.com>
Diffstat (limited to 'deps/v8/src/ic')
-rw-r--r--deps/v8/src/ic/access-compiler.cc29
-rw-r--r--deps/v8/src/ic/access-compiler.h11
-rw-r--r--deps/v8/src/ic/accessor-assembler.cc1272
-rw-r--r--deps/v8/src/ic/accessor-assembler.h43
-rw-r--r--deps/v8/src/ic/arm/access-compiler-arm.cc2
-rw-r--r--deps/v8/src/ic/arm/handler-compiler-arm.cc197
-rw-r--r--deps/v8/src/ic/arm/ic-arm.cc2
-rw-r--r--deps/v8/src/ic/arm64/access-compiler-arm64.cc1
-rw-r--r--deps/v8/src/ic/arm64/handler-compiler-arm64.cc190
-rw-r--r--deps/v8/src/ic/arm64/ic-arm64.cc4
-rw-r--r--deps/v8/src/ic/binary-op-assembler.cc827
-rw-r--r--deps/v8/src/ic/binary-op-assembler.h45
-rw-r--r--deps/v8/src/ic/handler-compiler.cc289
-rw-r--r--deps/v8/src/ic/handler-compiler.h92
-rw-r--r--deps/v8/src/ic/handler-configuration-inl.h118
-rw-r--r--deps/v8/src/ic/handler-configuration.h131
-rw-r--r--deps/v8/src/ic/ia32/handler-compiler-ia32.cc198
-rw-r--r--deps/v8/src/ic/ic-inl.h36
-rw-r--r--deps/v8/src/ic/ic.cc1202
-rw-r--r--deps/v8/src/ic/ic.h81
-rw-r--r--deps/v8/src/ic/keyed-store-generic.cc228
-rw-r--r--deps/v8/src/ic/keyed-store-generic.h6
-rw-r--r--deps/v8/src/ic/mips/handler-compiler-mips.cc193
-rw-r--r--deps/v8/src/ic/mips64/handler-compiler-mips64.cc193
-rw-r--r--deps/v8/src/ic/ppc/handler-compiler-ppc.cc194
-rw-r--r--deps/v8/src/ic/s390/handler-compiler-s390.cc188
-rw-r--r--deps/v8/src/ic/stub-cache.cc6
-rw-r--r--deps/v8/src/ic/x64/handler-compiler-x64.cc207
-rw-r--r--deps/v8/src/ic/x87/handler-compiler-x87.cc199
29 files changed, 2706 insertions, 3478 deletions
diff --git a/deps/v8/src/ic/access-compiler.cc b/deps/v8/src/ic/access-compiler.cc
index d210ea8c71..d06028030c 100644
--- a/deps/v8/src/ic/access-compiler.cc
+++ b/deps/v8/src/ic/access-compiler.cc
@@ -3,39 +3,12 @@
// found in the LICENSE file.
#include "src/ic/access-compiler.h"
+#include "src/assembler-inl.h"
#include "src/objects-inl.h"
namespace v8 {
namespace internal {
-
-Handle<Code> PropertyAccessCompiler::GetCodeWithFlags(Code::Flags flags,
- const char* name) {
- // Create code object in the heap.
- CodeDesc desc;
- masm()->GetCode(&desc);
- Handle<Code> code = factory()->NewCode(desc, flags, masm()->CodeObject());
- if (code->IsCodeStubOrIC()) code->set_stub_key(CodeStub::NoCacheKey());
-#ifdef ENABLE_DISASSEMBLER
- if (FLAG_print_code_stubs) {
- CodeTracer::Scope trace_scope(isolate()->GetCodeTracer());
- OFStream os(trace_scope.file());
- code->Disassemble(name, os);
- }
-#endif
- return code;
-}
-
-
-Handle<Code> PropertyAccessCompiler::GetCodeWithFlags(Code::Flags flags,
- Handle<Name> name) {
- return (FLAG_print_code_stubs && !name.is_null() && name->IsString())
- ? GetCodeWithFlags(flags,
- Handle<String>::cast(name)->ToCString().get())
- : GetCodeWithFlags(flags, NULL);
-}
-
-
void PropertyAccessCompiler::TailCallBuiltin(MacroAssembler* masm,
Builtins::Name name) {
Handle<Code> code(masm->isolate()->builtins()->builtin(name));
diff --git a/deps/v8/src/ic/access-compiler.h b/deps/v8/src/ic/access-compiler.h
index 3d488e82ea..b91aa43aea 100644
--- a/deps/v8/src/ic/access-compiler.h
+++ b/deps/v8/src/ic/access-compiler.h
@@ -34,11 +34,9 @@ class PropertyAccessCompiler BASE_EMBEDDED {
static void TailCallBuiltin(MacroAssembler* masm, Builtins::Name name);
protected:
- PropertyAccessCompiler(Isolate* isolate, Code::Kind kind,
- CacheHolderFlag cache_holder)
+ PropertyAccessCompiler(Isolate* isolate, Code::Kind kind)
: registers_(GetCallingConvention(isolate, kind)),
kind_(kind),
- cache_holder_(cache_holder),
isolate_(isolate),
masm_(isolate, NULL, 256, CodeObjectRequired::kYes) {
// TODO(yangguo): remove this once we can serialize IC stubs.
@@ -46,10 +44,8 @@ class PropertyAccessCompiler BASE_EMBEDDED {
}
Code::Kind kind() const { return kind_; }
- CacheHolderFlag cache_holder() const { return cache_holder_; }
MacroAssembler* masm() { return &masm_; }
Isolate* isolate() const { return isolate_; }
- Heap* heap() const { return isolate()->heap(); }
Factory* factory() const { return isolate()->factory(); }
Register receiver() const { return registers_[0]; }
@@ -63,16 +59,11 @@ class PropertyAccessCompiler BASE_EMBEDDED {
static void GenerateTailCall(MacroAssembler* masm, Handle<Code> code);
- Handle<Code> GetCodeWithFlags(Code::Flags flags, const char* name);
- Handle<Code> GetCodeWithFlags(Code::Flags flags, Handle<Name> name);
-
private:
static Register* GetCallingConvention(Isolate* isolate, Code::Kind kind);
static void InitializePlatformSpecific(AccessCompilerData* data);
Code::Kind kind_;
- CacheHolderFlag cache_holder_;
-
Isolate* isolate_;
MacroAssembler masm_;
// Ensure that MacroAssembler has a reasonable size.
diff --git a/deps/v8/src/ic/accessor-assembler.cc b/deps/v8/src/ic/accessor-assembler.cc
index d3379ab6d2..eb3971c54f 100644
--- a/deps/v8/src/ic/accessor-assembler.cc
+++ b/deps/v8/src/ic/accessor-assembler.cc
@@ -8,6 +8,7 @@
#include "src/code-stubs.h"
#include "src/counters.h"
#include "src/ic/handler-configuration.h"
+#include "src/ic/ic.h"
#include "src/ic/stub-cache.h"
#include "src/objects-inl.h"
@@ -57,32 +58,55 @@ void AccessorAssembler::HandlePolymorphicCase(Node* receiver_map,
Node* feedback, Label* if_handler,
Variable* var_handler,
Label* if_miss,
- int unroll_count) {
+ int min_feedback_capacity) {
Comment("HandlePolymorphicCase");
DCHECK_EQ(MachineRepresentation::kTagged, var_handler->rep());
+ // Deferred so the unrolled case can omit frame construction in bytecode
+ // handler.
+ Label loop(this, Label::kDeferred);
+
// Iterate {feedback} array.
const int kEntrySize = 2;
- for (int i = 0; i < unroll_count; i++) {
+ // Loading feedback's length is delayed until we need it when looking past
+ // the first {min_feedback_capacity} (map, handler) pairs.
+ Node* length = nullptr;
+ CSA_ASSERT(this, SmiGreaterThanOrEqual(
+ LoadFixedArrayBaseLength(feedback),
+ SmiConstant(min_feedback_capacity * kEntrySize)));
+
+ const int kUnrolledIterations = IC::kMaxPolymorphicMapCount;
+ for (int i = 0; i < kUnrolledIterations; i++) {
+ int map_index = i * kEntrySize;
+ int handler_index = i * kEntrySize + 1;
+
+ if (i >= min_feedback_capacity) {
+ if (length == nullptr) length = LoadFixedArrayBaseLength(feedback);
+ GotoIf(SmiGreaterThanOrEqual(SmiConstant(handler_index), length),
+ if_miss);
+ }
+
Label next_entry(this);
Node* cached_map =
- LoadWeakCellValue(LoadFixedArrayElement(feedback, i * kEntrySize));
+ LoadWeakCellValue(LoadFixedArrayElement(feedback, map_index));
GotoIf(WordNotEqual(receiver_map, cached_map), &next_entry);
// Found, now call handler.
- Node* handler = LoadFixedArrayElement(feedback, i * kEntrySize + 1);
+ Node* handler = LoadFixedArrayElement(feedback, handler_index);
var_handler->Bind(handler);
Goto(if_handler);
- Bind(&next_entry);
+ BIND(&next_entry);
}
+ Goto(&loop);
- // Loop from {unroll_count}*kEntrySize to {length}.
- Node* init = IntPtrConstant(unroll_count * kEntrySize);
- Node* length = LoadAndUntagFixedArrayBaseLength(feedback);
+ // Loop from {kUnrolledIterations}*kEntrySize to {length}.
+ BIND(&loop);
+ Node* start_index = IntPtrConstant(kUnrolledIterations * kEntrySize);
+ Node* end_index = LoadAndUntagFixedArrayBaseLength(feedback);
BuildFastLoop(
- init, length,
+ start_index, end_index,
[this, receiver_map, feedback, if_handler, var_handler](Node* index) {
Node* cached_map =
LoadWeakCellValue(LoadFixedArrayElement(feedback, index));
@@ -95,103 +119,106 @@ void AccessorAssembler::HandlePolymorphicCase(Node* receiver_map,
var_handler->Bind(handler);
Goto(if_handler);
- Bind(&next_entry);
+ BIND(&next_entry);
},
kEntrySize, INTPTR_PARAMETERS, IndexAdvanceMode::kPost);
// The loop falls through if no handler was found.
Goto(if_miss);
}
-void AccessorAssembler::HandleKeyedStorePolymorphicCase(
- Node* receiver_map, Node* feedback, Label* if_handler,
- Variable* var_handler, Label* if_transition_handler,
- Variable* var_transition_map_cell, Label* if_miss) {
- DCHECK_EQ(MachineRepresentation::kTagged, var_handler->rep());
- DCHECK_EQ(MachineRepresentation::kTagged, var_transition_map_cell->rep());
-
- const int kEntrySize = 3;
-
- Node* init = IntPtrConstant(0);
- Node* length = LoadAndUntagFixedArrayBaseLength(feedback);
- BuildFastLoop(init, length,
- [this, receiver_map, feedback, if_handler, var_handler,
- if_transition_handler, var_transition_map_cell](Node* index) {
- Node* cached_map =
- LoadWeakCellValue(LoadFixedArrayElement(feedback, index));
- Label next_entry(this);
- GotoIf(WordNotEqual(receiver_map, cached_map), &next_entry);
-
- Node* maybe_transition_map_cell =
- LoadFixedArrayElement(feedback, index, kPointerSize);
-
- var_handler->Bind(
- LoadFixedArrayElement(feedback, index, 2 * kPointerSize));
- GotoIf(WordEqual(maybe_transition_map_cell,
- LoadRoot(Heap::kUndefinedValueRootIndex)),
- if_handler);
- var_transition_map_cell->Bind(maybe_transition_map_cell);
- Goto(if_transition_handler);
-
- Bind(&next_entry);
- },
- kEntrySize, INTPTR_PARAMETERS, IndexAdvanceMode::kPost);
- // The loop falls through if no handler was found.
- Goto(if_miss);
-}
-
void AccessorAssembler::HandleLoadICHandlerCase(
const LoadICParameters* p, Node* handler, Label* miss,
- ElementSupport support_elements) {
+ ExitPoint* exit_point, ElementSupport support_elements) {
Comment("have_handler");
- ExitPoint direct_exit(this);
- Variable var_holder(this, MachineRepresentation::kTagged);
- var_holder.Bind(p->receiver);
- Variable var_smi_handler(this, MachineRepresentation::kTagged);
- var_smi_handler.Bind(handler);
+ VARIABLE(var_holder, MachineRepresentation::kTagged, p->receiver);
+ VARIABLE(var_smi_handler, MachineRepresentation::kTagged, handler);
Variable* vars[] = {&var_holder, &var_smi_handler};
Label if_smi_handler(this, 2, vars);
- Label try_proto_handler(this), call_handler(this);
+ Label try_proto_handler(this, Label::kDeferred),
+ call_handler(this, Label::kDeferred);
Branch(TaggedIsSmi(handler), &if_smi_handler, &try_proto_handler);
// |handler| is a Smi, encoding what to do. See SmiHandler methods
// for the encoding format.
- Bind(&if_smi_handler);
+ BIND(&if_smi_handler);
{
HandleLoadICSmiHandlerCase(p, var_holder.value(), var_smi_handler.value(),
- miss, &direct_exit, support_elements);
+ miss, exit_point, false, support_elements);
}
- Bind(&try_proto_handler);
+ BIND(&try_proto_handler);
{
GotoIf(IsCodeMap(LoadMap(handler)), &call_handler);
HandleLoadICProtoHandlerCase(p, handler, &var_holder, &var_smi_handler,
- &if_smi_handler, miss, &direct_exit, false);
+ &if_smi_handler, miss, exit_point, false);
}
- Bind(&call_handler);
+ BIND(&call_handler);
{
typedef LoadWithVectorDescriptor Descriptor;
- TailCallStub(Descriptor(isolate()), handler, p->context, p->receiver,
- p->name, p->slot, p->vector);
+ exit_point->ReturnCallStub(Descriptor(isolate()), handler, p->context,
+ p->receiver, p->name, p->slot, p->vector);
+ }
+}
+
+void AccessorAssembler::HandleLoadField(Node* holder, Node* handler_word,
+ Variable* var_double_value,
+ Label* rebox_double,
+ ExitPoint* exit_point) {
+ Comment("field_load");
+ Node* offset = DecodeWord<LoadHandler::FieldOffsetBits>(handler_word);
+
+ Label inobject(this), out_of_object(this);
+ Branch(IsSetWord<LoadHandler::IsInobjectBits>(handler_word), &inobject,
+ &out_of_object);
+
+ BIND(&inobject);
+ {
+ Label is_double(this);
+ GotoIf(IsSetWord<LoadHandler::IsDoubleBits>(handler_word), &is_double);
+ exit_point->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(&out_of_object);
+ {
+ Label is_double(this);
+ Node* properties = LoadProperties(holder);
+ Node* value = LoadObjectField(properties, offset);
+ GotoIf(IsSetWord<LoadHandler::IsDoubleBits>(handler_word), &is_double);
+ exit_point->Return(value);
+
+ BIND(&is_double);
+ var_double_value->Bind(LoadHeapNumberValue(value));
+ Goto(rebox_double);
}
}
void AccessorAssembler::HandleLoadICSmiHandlerCase(
const LoadICParameters* p, Node* holder, Node* smi_handler, Label* miss,
- ExitPoint* exit_point, ElementSupport support_elements) {
- Variable var_double_value(this, MachineRepresentation::kFloat64);
+ ExitPoint* exit_point, bool throw_reference_error_if_nonexistent,
+ ElementSupport support_elements) {
+ VARIABLE(var_double_value, MachineRepresentation::kFloat64);
Label rebox_double(this, &var_double_value);
Node* handler_word = SmiUntag(smi_handler);
Node* handler_kind = DecodeWord<LoadHandler::KindBits>(handler_word);
if (support_elements == kSupportElements) {
Label property(this);
- GotoIfNot(
- WordEqual(handler_kind, IntPtrConstant(LoadHandler::kForElements)),
- &property);
+ GotoIfNot(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kElement)),
+ &property);
Comment("element_load");
Node* intptr_index = TryToIntptr(p->name, miss);
@@ -207,7 +234,7 @@ void AccessorAssembler::HandleLoadICSmiHandlerCase(
&var_double_value, &unimplemented_elements_kind,
out_of_bounds, miss, exit_point);
- Bind(&unimplemented_elements_kind);
+ BIND(&unimplemented_elements_kind);
{
// Smi handlers should only be installed for supported elements kinds.
// Crash if we get here.
@@ -215,7 +242,7 @@ void AccessorAssembler::HandleLoadICSmiHandlerCase(
Goto(miss);
}
- Bind(&if_hole);
+ BIND(&if_hole);
{
Comment("convert hole");
GotoIfNot(IsSetWord<LoadHandler::ConvertHoleBits>(handler_word), miss);
@@ -228,78 +255,136 @@ void AccessorAssembler::HandleLoadICSmiHandlerCase(
exit_point->Return(UndefinedConstant());
}
- Bind(&property);
+ BIND(&property);
Comment("property_load");
}
- Label constant(this), field(this);
- Branch(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kForFields)),
- &field, &constant);
+ Label constant(this), field(this), normal(this, Label::kDeferred),
+ interceptor(this, Label::kDeferred), nonexistent(this),
+ accessor(this, Label::kDeferred), global(this, Label::kDeferred);
+ GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kField)), &field);
- Bind(&field);
- {
- Comment("field_load");
- Node* offset = DecodeWord<LoadHandler::FieldOffsetBits>(handler_word);
+ GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kConstant)),
+ &constant);
- Label inobject(this), out_of_object(this);
- Branch(IsSetWord<LoadHandler::IsInobjectBits>(handler_word), &inobject,
- &out_of_object);
+ GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kNonExistent)),
+ &nonexistent);
- Bind(&inobject);
- {
- Label is_double(this);
- GotoIf(IsSetWord<LoadHandler::IsDoubleBits>(handler_word), &is_double);
- exit_point->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);
- }
+ GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kNormal)),
+ &normal);
- 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);
- exit_point->Return(value);
+ GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kAccessor)),
+ &accessor);
- Bind(&is_double);
- var_double_value.Bind(LoadHeapNumberValue(value));
- Goto(&rebox_double);
- }
+ Branch(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kGlobal)), &global,
+ &interceptor);
- Bind(&rebox_double);
- exit_point->Return(AllocateHeapNumberWithValue(var_double_value.value()));
+ BIND(&field);
+ HandleLoadField(holder, handler_word, &var_double_value, &rebox_double,
+ exit_point);
+
+ BIND(&nonexistent);
+ // This is a handler for a load of a non-existent value.
+ if (throw_reference_error_if_nonexistent) {
+ exit_point->ReturnCallRuntime(Runtime::kThrowReferenceError, p->context,
+ p->name);
+ } else {
+ exit_point->Return(UndefinedConstant());
}
- Bind(&constant);
+ BIND(&constant);
{
Comment("constant_load");
Node* descriptors = LoadMapDescriptors(LoadMap(holder));
- Node* descriptor =
- DecodeWord<LoadHandler::DescriptorValueIndexBits>(handler_word);
+ Node* descriptor = DecodeWord<LoadHandler::DescriptorBits>(handler_word);
+ Node* scaled_descriptor =
+ IntPtrMul(descriptor, IntPtrConstant(DescriptorArray::kEntrySize));
+ Node* value_index =
+ IntPtrAdd(scaled_descriptor,
+ IntPtrConstant(DescriptorArray::kFirstIndex +
+ DescriptorArray::kEntryValueIndex));
CSA_ASSERT(this,
UintPtrLessThan(descriptor,
LoadAndUntagFixedArrayBaseLength(descriptors)));
- Node* value = LoadFixedArrayElement(descriptors, descriptor);
+ Node* value = LoadFixedArrayElement(descriptors, value_index);
- Label if_accessor_info(this);
+ Label if_accessor_info(this, Label::kDeferred);
GotoIf(IsSetWord<LoadHandler::IsAccessorInfoBits>(handler_word),
&if_accessor_info);
exit_point->Return(value);
- Bind(&if_accessor_info);
+ BIND(&if_accessor_info);
Callable callable = CodeFactory::ApiGetter(isolate());
exit_point->ReturnCallStub(callable, p->context, p->receiver, holder,
value);
}
+
+ BIND(&normal);
+ {
+ Comment("load_normal");
+ Node* properties = LoadProperties(holder);
+ VARIABLE(var_name_index, MachineType::PointerRepresentation());
+ Label found(this, &var_name_index);
+ NameDictionaryLookup<NameDictionary>(properties, p->name, &found,
+ &var_name_index, miss);
+ BIND(&found);
+ {
+ VARIABLE(var_details, MachineRepresentation::kWord32);
+ VARIABLE(var_value, MachineRepresentation::kTagged);
+ LoadPropertyFromNameDictionary(properties, var_name_index.value(),
+ &var_details, &var_value);
+ Node* value = CallGetterIfAccessor(var_value.value(), var_details.value(),
+ p->context, p->receiver, miss);
+ exit_point->Return(value);
+ }
+ }
+
+ BIND(&accessor);
+ {
+ Comment("accessor_load");
+ Node* descriptors = LoadMapDescriptors(LoadMap(holder));
+ Node* descriptor = DecodeWord<LoadHandler::DescriptorBits>(handler_word);
+ Node* scaled_descriptor =
+ IntPtrMul(descriptor, IntPtrConstant(DescriptorArray::kEntrySize));
+ Node* value_index =
+ IntPtrAdd(scaled_descriptor,
+ IntPtrConstant(DescriptorArray::kFirstIndex +
+ DescriptorArray::kEntryValueIndex));
+ CSA_ASSERT(this,
+ UintPtrLessThan(descriptor,
+ LoadAndUntagFixedArrayBaseLength(descriptors)));
+ Node* accessor_pair = LoadFixedArrayElement(descriptors, value_index);
+ CSA_ASSERT(this, IsAccessorPair(accessor_pair));
+ Node* getter = LoadObjectField(accessor_pair, AccessorPair::kGetterOffset);
+ CSA_ASSERT(this, Word32BinaryNot(IsTheHole(getter)));
+
+ Callable callable = CodeFactory::Call(isolate());
+ exit_point->Return(CallJS(callable, p->context, getter, p->receiver));
+ }
+
+ BIND(&global);
+ {
+ CSA_ASSERT(this, IsPropertyCell(holder));
+ // Ensure the property cell doesn't contain the hole.
+ Node* value = LoadObjectField(holder, PropertyCell::kValueOffset);
+ Node* details =
+ LoadAndUntagToWord32ObjectField(holder, PropertyCell::kDetailsOffset);
+ GotoIf(IsTheHole(value), miss);
+
+ exit_point->Return(
+ CallGetterIfAccessor(value, details, p->context, p->receiver, miss));
+ }
+
+ BIND(&interceptor);
+ {
+ Comment("load_interceptor");
+ exit_point->ReturnCallRuntime(Runtime::kLoadPropertyWithInterceptor,
+ p->context, p->name, p->receiver, holder,
+ p->slot, p->vector);
+ }
+
+ BIND(&rebox_double);
+ exit_point->Return(AllocateHeapNumberWithValue(var_double_value.value()));
}
void AccessorAssembler::HandleLoadICProtoHandlerCase(
@@ -328,53 +413,64 @@ void AccessorAssembler::HandleLoadICProtoHandlerCase(
miss);
Goto(&validity_cell_check_done);
- Bind(&validity_cell_check_done);
+ BIND(&validity_cell_check_done);
Node* smi_handler = LoadObjectField(handler, LoadHandler::kSmiHandlerOffset);
CSA_ASSERT(this, TaggedIsSmi(smi_handler));
Node* handler_flags = SmiUntag(smi_handler);
Label check_prototypes(this);
- GotoIfNot(
- IsSetWord<LoadHandler::DoNegativeLookupOnReceiverBits>(handler_flags),
- &check_prototypes);
+ GotoIfNot(IsSetWord<LoadHandler::LookupOnReceiverBits>(handler_flags),
+ &check_prototypes);
{
CSA_ASSERT(this, Word32BinaryNot(
HasInstanceType(p->receiver, JS_GLOBAL_OBJECT_TYPE)));
- // We have a dictionary receiver, do a negative lookup check.
- NameDictionaryNegativeLookup(p->receiver, p->name, miss);
- Goto(&check_prototypes);
+ Node* properties = LoadProperties(p->receiver);
+ VARIABLE(var_name_index, MachineType::PointerRepresentation());
+ Label found(this, &var_name_index);
+ NameDictionaryLookup<NameDictionary>(properties, p->name, &found,
+ &var_name_index, &check_prototypes);
+ BIND(&found);
+ {
+ VARIABLE(var_details, MachineRepresentation::kWord32);
+ VARIABLE(var_value, MachineRepresentation::kTagged);
+ LoadPropertyFromNameDictionary(properties, var_name_index.value(),
+ &var_details, &var_value);
+ Node* value = CallGetterIfAccessor(var_value.value(), var_details.value(),
+ p->context, p->receiver, miss);
+ exit_point->Return(value);
+ }
}
- Bind(&check_prototypes);
+ BIND(&check_prototypes);
Node* maybe_holder_cell =
LoadObjectField(handler, LoadHandler::kHolderCellOffset);
Label array_handler(this), tuple_handler(this);
Branch(TaggedIsSmi(maybe_holder_cell), &array_handler, &tuple_handler);
- Bind(&tuple_handler);
+ BIND(&tuple_handler);
{
- Label load_existent(this);
- GotoIf(WordNotEqual(maybe_holder_cell, NullConstant()), &load_existent);
- // This is a handler for a load of a non-existent value.
- if (throw_reference_error_if_nonexistent) {
- exit_point->ReturnCallRuntime(Runtime::kThrowReferenceError, p->context,
- p->name);
- } else {
- exit_point->Return(UndefinedConstant());
- }
+ Label load_from_cached_holder(this), done(this);
+
+ Branch(WordEqual(maybe_holder_cell, NullConstant()), &done,
+ &load_from_cached_holder);
+
+ BIND(&load_from_cached_holder);
+ {
+ // For regular holders, having passed the receiver map check and the
+ // validity cell check implies that |holder| is alive. However, for
+ // global object receivers, the |maybe_holder_cell| may be cleared.
+ Node* holder = LoadWeakCellValue(maybe_holder_cell, miss);
- Bind(&load_existent);
- Node* holder = LoadWeakCellValue(maybe_holder_cell);
- // The |holder| is guaranteed to be alive at this point since we passed
- // both the receiver map check and the validity cell check.
- CSA_ASSERT(this, WordNotEqual(holder, IntPtrConstant(0)));
+ var_holder->Bind(holder);
+ Goto(&done);
+ }
- var_holder->Bind(holder);
+ BIND(&done);
var_smi_handler->Bind(smi_handler);
Goto(if_smi_handler);
}
- Bind(&array_handler);
+ BIND(&array_handler);
{
exit_point->ReturnCallStub(
CodeFactory::LoadICProtoArray(isolate(),
@@ -383,11 +479,12 @@ void AccessorAssembler::HandleLoadICProtoHandlerCase(
}
}
-Node* AccessorAssembler::EmitLoadICProtoArrayCheck(
- const LoadICParameters* p, Node* handler, Node* handler_length,
- Node* handler_flags, Label* miss,
- bool throw_reference_error_if_nonexistent) {
- Variable start_index(this, MachineType::PointerRepresentation());
+Node* AccessorAssembler::EmitLoadICProtoArrayCheck(const LoadICParameters* p,
+ Node* handler,
+ Node* handler_length,
+ Node* handler_flags,
+ Label* miss) {
+ VARIABLE(start_index, MachineType::PointerRepresentation());
start_index.Bind(IntPtrConstant(LoadHandler::kFirstPrototypeIndex));
Label can_access(this);
@@ -415,7 +512,7 @@ Node* AccessorAssembler::EmitLoadICProtoArrayCheck(
LoadContextElement(native_context, Context::SECURITY_TOKEN_INDEX);
Branch(WordEqual(expected_token, current_token), &can_access, miss);
}
- Bind(&can_access);
+ BIND(&can_access);
BuildFastLoop(start_index.value(), handler_length,
[this, p, handler, miss](Node* current) {
@@ -427,22 +524,21 @@ Node* AccessorAssembler::EmitLoadICProtoArrayCheck(
Node* maybe_holder_cell =
LoadFixedArrayElement(handler, LoadHandler::kHolderCellIndex);
- Label load_existent(this);
- GotoIf(WordNotEqual(maybe_holder_cell, NullConstant()), &load_existent);
- // This is a handler for a load of a non-existent value.
- if (throw_reference_error_if_nonexistent) {
- TailCallRuntime(Runtime::kThrowReferenceError, p->context, p->name);
- } else {
- Return(UndefinedConstant());
+
+ VARIABLE(var_holder, MachineRepresentation::kTagged, p->receiver);
+ Label done(this);
+ GotoIf(WordEqual(maybe_holder_cell, NullConstant()), &done);
+
+ {
+ // For regular holders, having passed the receiver map check and the
+ // validity cell check implies that |holder| is alive. However, for
+ // global object receivers, the |maybe_holder_cell| may be cleared.
+ var_holder.Bind(LoadWeakCellValue(maybe_holder_cell, miss));
+ Goto(&done);
}
- 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;
+ BIND(&done);
+ return var_holder.value();
}
void AccessorAssembler::HandleLoadGlobalICHandlerCase(
@@ -451,64 +547,164 @@ void AccessorAssembler::HandleLoadGlobalICHandlerCase(
LoadICParameters p = *pp;
DCHECK_NULL(p.receiver);
Node* native_context = LoadNativeContext(p.context);
- p.receiver = LoadContextElement(native_context, Context::EXTENSION_INDEX);
+ p.receiver = LoadContextElement(native_context, Context::GLOBAL_PROXY_INDEX);
- Variable var_holder(this, MachineRepresentation::kTagged);
- Variable var_smi_handler(this, MachineRepresentation::kTagged);
+ VARIABLE(var_holder, MachineRepresentation::kTagged,
+ LoadContextElement(native_context, Context::EXTENSION_INDEX));
+ VARIABLE(var_smi_handler, MachineRepresentation::kTagged);
Label if_smi_handler(this);
+
HandleLoadICProtoHandlerCase(&p, handler, &var_holder, &var_smi_handler,
&if_smi_handler, miss, exit_point,
throw_reference_error_if_nonexistent);
- Bind(&if_smi_handler);
- HandleLoadICSmiHandlerCase(&p, var_holder.value(), var_smi_handler.value(),
- miss, exit_point, kOnlyProperties);
+ BIND(&if_smi_handler);
+ HandleLoadICSmiHandlerCase(
+ &p, var_holder.value(), var_smi_handler.value(), miss, exit_point,
+ throw_reference_error_if_nonexistent, kOnlyProperties);
+}
+
+void AccessorAssembler::JumpIfDataProperty(Node* details, Label* writable,
+ Label* readonly) {
+ // Accessor properties never have the READ_ONLY attribute set.
+ GotoIf(IsSetWord32(details, PropertyDetails::kAttributesReadOnlyMask),
+ readonly);
+ Node* kind = DecodeWord32<PropertyDetails::KindField>(details);
+ GotoIf(Word32Equal(kind, Int32Constant(kData)), writable);
+ // Fall through if it's an accessor property.
}
void AccessorAssembler::HandleStoreICHandlerCase(
const StoreICParameters* p, Node* handler, Label* miss,
ElementSupport support_elements) {
Label if_smi_handler(this), if_nonsmi_handler(this);
- Label if_proto_handler(this), if_element_handler(this), call_handler(this);
+ Label if_proto_handler(this), if_element_handler(this), call_handler(this),
+ store_global(this);
Branch(TaggedIsSmi(handler), &if_smi_handler, &if_nonsmi_handler);
// |handler| is a Smi, encoding what to do. See SmiHandler methods
// for the encoding format.
- Bind(&if_smi_handler);
+ BIND(&if_smi_handler);
{
Node* holder = p->receiver;
Node* handler_word = SmiUntag(handler);
+ Label if_fast_smi(this), slow(this);
+ GotoIfNot(
+ WordEqual(handler_word, IntPtrConstant(StoreHandler::kStoreNormal)),
+ &if_fast_smi);
+
+ Node* properties = LoadProperties(holder);
+
+ VARIABLE(var_name_index, MachineType::PointerRepresentation());
+ Label dictionary_found(this, &var_name_index);
+ NameDictionaryLookup<NameDictionary>(properties, p->name, &dictionary_found,
+ &var_name_index, miss);
+ BIND(&dictionary_found);
+ {
+ Node* details = LoadDetailsByKeyIndex<NameDictionary>(
+ properties, var_name_index.value());
+ // Check that the property is a writable data property (no accessor).
+ const int kTypeAndReadOnlyMask = PropertyDetails::KindField::kMask |
+ PropertyDetails::kAttributesReadOnlyMask;
+ STATIC_ASSERT(kData == 0);
+ GotoIf(IsSetWord32(details, kTypeAndReadOnlyMask), miss);
+
+ StoreValueByKeyIndex<NameDictionary>(properties, var_name_index.value(),
+ p->value);
+ Return(p->value);
+ }
+
+ BIND(&if_fast_smi);
// Handle non-transitioning field stores.
HandleStoreICSmiHandlerCase(handler_word, holder, p->value, nullptr, miss);
}
- Bind(&if_nonsmi_handler);
+ BIND(&if_nonsmi_handler);
{
Node* handler_map = LoadMap(handler);
if (support_elements == kSupportElements) {
GotoIf(IsTuple2Map(handler_map), &if_element_handler);
}
+ GotoIf(IsWeakCellMap(handler_map), &store_global);
Branch(IsCodeMap(handler_map), &call_handler, &if_proto_handler);
}
if (support_elements == kSupportElements) {
- Bind(&if_element_handler);
+ BIND(&if_element_handler);
{ HandleStoreICElementHandlerCase(p, handler, miss); }
}
- Bind(&if_proto_handler);
- {
- HandleStoreICProtoHandler(p, handler, miss);
- }
+ BIND(&if_proto_handler);
+ { HandleStoreICProtoHandler(p, handler, miss, support_elements); }
// |handler| is a heap object. Must be code, call it.
- Bind(&call_handler);
+ BIND(&call_handler);
{
StoreWithVectorDescriptor descriptor(isolate());
TailCallStub(descriptor, handler, p->context, p->receiver, p->name,
p->value, p->slot, p->vector);
}
+
+ BIND(&store_global);
+ {
+ Node* cell = LoadWeakCellValue(handler, miss);
+ CSA_ASSERT(this, IsPropertyCell(cell));
+
+ // Load the payload of the global parameter cell. A hole indicates that
+ // the cell has been invalidated and that the store must be handled by the
+ // runtime.
+ Node* cell_contents = LoadObjectField(cell, PropertyCell::kValueOffset);
+ Node* details =
+ LoadAndUntagToWord32ObjectField(cell, PropertyCell::kDetailsOffset);
+ Node* type = DecodeWord32<PropertyDetails::PropertyCellTypeField>(details);
+
+ Label constant(this), store(this), not_smi(this);
+
+ GotoIf(
+ Word32Equal(
+ type, Int32Constant(static_cast<int>(PropertyCellType::kConstant))),
+ &constant);
+
+ GotoIf(IsTheHole(cell_contents), miss);
+
+ GotoIf(
+ Word32Equal(
+ type, Int32Constant(static_cast<int>(PropertyCellType::kMutable))),
+ &store);
+ CSA_ASSERT(this,
+ Word32Or(Word32Equal(type,
+ Int32Constant(static_cast<int>(
+ PropertyCellType::kConstantType))),
+ Word32Equal(type,
+ Int32Constant(static_cast<int>(
+ PropertyCellType::kUndefined)))));
+
+ GotoIfNot(TaggedIsSmi(cell_contents), &not_smi);
+ GotoIfNot(TaggedIsSmi(p->value), miss);
+ Goto(&store);
+
+ BIND(&not_smi);
+ {
+ GotoIf(TaggedIsSmi(p->value), miss);
+ Node* expected_map = LoadMap(cell_contents);
+ Node* map = LoadMap(p->value);
+ GotoIfNot(WordEqual(expected_map, map), miss);
+ Goto(&store);
+ }
+
+ BIND(&store);
+ {
+ StoreObjectField(cell, PropertyCell::kValueOffset, p->value);
+ Return(p->value);
+ }
+
+ BIND(&constant);
+ {
+ GotoIfNot(WordEqual(cell_contents, p->value), miss);
+ Return(p->value);
+ }
+ }
}
void AccessorAssembler::HandleStoreICElementHandlerCase(
@@ -528,8 +724,9 @@ void AccessorAssembler::HandleStoreICElementHandlerCase(
p->value, p->slot, p->vector);
}
-void AccessorAssembler::HandleStoreICProtoHandler(const StoreICParameters* p,
- Node* handler, Label* miss) {
+void AccessorAssembler::HandleStoreICProtoHandler(
+ const StoreICParameters* p, Node* handler, Label* miss,
+ ElementSupport support_elements) {
// IC dispatchers rely on these assumptions to be held.
STATIC_ASSERT(FixedArray::kLengthOffset ==
StoreHandler::kTransitionCellOffset);
@@ -550,25 +747,25 @@ void AccessorAssembler::HandleStoreICProtoHandler(const StoreICParameters* p,
miss);
Goto(&validity_cell_check_done);
- Bind(&validity_cell_check_done);
- Node* smi_handler = LoadObjectField(handler, StoreHandler::kSmiHandlerOffset);
- CSA_ASSERT(this, TaggedIsSmi(smi_handler));
+ BIND(&validity_cell_check_done);
+ Node* smi_or_code = LoadObjectField(handler, StoreHandler::kSmiHandlerOffset);
Node* maybe_transition_cell =
LoadObjectField(handler, StoreHandler::kTransitionCellOffset);
Label array_handler(this), tuple_handler(this);
Branch(TaggedIsSmi(maybe_transition_cell), &array_handler, &tuple_handler);
- Variable var_transition(this, MachineRepresentation::kTagged);
- Label if_transition(this), if_transition_to_constant(this);
- Bind(&tuple_handler);
+ VARIABLE(var_transition, MachineRepresentation::kTagged);
+ Label if_transition(this), if_transition_to_constant(this),
+ if_store_normal(this);
+ BIND(&tuple_handler);
{
Node* transition = LoadWeakCellValue(maybe_transition_cell, miss);
var_transition.Bind(transition);
Goto(&if_transition);
}
- Bind(&array_handler);
+ BIND(&array_handler);
{
Node* length = SmiUntag(maybe_transition_cell);
BuildFastLoop(IntPtrConstant(StoreHandler::kFirstPrototypeIndex), length,
@@ -586,15 +783,34 @@ void AccessorAssembler::HandleStoreICProtoHandler(const StoreICParameters* p,
Goto(&if_transition);
}
- Bind(&if_transition);
+ BIND(&if_transition);
{
Node* holder = p->receiver;
Node* transition = var_transition.value();
- Node* handler_word = SmiUntag(smi_handler);
- GotoIf(IsSetWord32<Map::Deprecated>(LoadMapBitField3(transition)), miss);
+ GotoIf(IsDeprecatedMap(transition), miss);
+
+ if (support_elements == kSupportElements) {
+ Label if_smi_handler(this);
+
+ GotoIf(TaggedIsSmi(smi_or_code), &if_smi_handler);
+ Node* code_handler = smi_or_code;
+ CSA_ASSERT(this, IsCodeMap(LoadMap(code_handler)));
+
+ StoreTransitionDescriptor descriptor(isolate());
+ TailCallStub(descriptor, code_handler, p->context, p->receiver, p->name,
+ transition, p->value, p->slot, p->vector);
+
+ BIND(&if_smi_handler);
+ }
+
+ Node* smi_handler = smi_or_code;
+ CSA_ASSERT(this, TaggedIsSmi(smi_handler));
+ Node* handler_word = SmiUntag(smi_handler);
Node* handler_kind = DecodeWord<StoreHandler::KindBits>(handler_word);
+ GotoIf(WordEqual(handler_kind, IntPtrConstant(StoreHandler::kStoreNormal)),
+ &if_store_normal);
GotoIf(WordEqual(handler_kind,
IntPtrConstant(StoreHandler::kTransitionToConstant)),
&if_transition_to_constant);
@@ -603,19 +819,64 @@ void AccessorAssembler::HandleStoreICProtoHandler(const StoreICParameters* p,
HandleStoreICSmiHandlerCase(handler_word, holder, p->value, transition,
miss);
- Bind(&if_transition_to_constant);
+ BIND(&if_transition_to_constant);
{
// Check that constant matches value.
- Node* value_index_in_descriptor =
- DecodeWord<StoreHandler::DescriptorValueIndexBits>(handler_word);
+ Node* descriptor = DecodeWord<StoreHandler::DescriptorBits>(handler_word);
+ Node* scaled_descriptor =
+ IntPtrMul(descriptor, IntPtrConstant(DescriptorArray::kEntrySize));
+ Node* value_index =
+ IntPtrAdd(scaled_descriptor,
+ IntPtrConstant(DescriptorArray::kFirstIndex +
+ DescriptorArray::kEntryValueIndex));
Node* descriptors = LoadMapDescriptors(transition);
- Node* constant =
- LoadFixedArrayElement(descriptors, value_index_in_descriptor);
+ CSA_ASSERT(
+ this,
+ UintPtrLessThan(descriptor,
+ LoadAndUntagFixedArrayBaseLength(descriptors)));
+
+ Node* constant = LoadFixedArrayElement(descriptors, value_index);
GotoIf(WordNotEqual(p->value, constant), miss);
StoreMap(p->receiver, transition);
Return(p->value);
}
+
+ BIND(&if_store_normal);
+ {
+ Node* properties = LoadProperties(p->receiver);
+
+ VARIABLE(var_name_index, MachineType::PointerRepresentation());
+ Label found(this, &var_name_index), not_found(this);
+ NameDictionaryLookup<NameDictionary>(properties, p->name, &found,
+ &var_name_index, &not_found);
+ BIND(&found);
+ {
+ Node* details = LoadDetailsByKeyIndex<NameDictionary>(
+ properties, var_name_index.value());
+ // Check that the property is a writable data property (no accessor).
+ const int kTypeAndReadOnlyMask =
+ PropertyDetails::KindField::kMask |
+ PropertyDetails::kAttributesReadOnlyMask;
+ STATIC_ASSERT(kData == 0);
+ GotoIf(IsSetWord32(details, kTypeAndReadOnlyMask), miss);
+
+ StoreValueByKeyIndex<NameDictionary>(properties, var_name_index.value(),
+ p->value);
+ Return(p->value);
+ }
+
+ BIND(&not_found);
+ {
+ Label slow(this);
+ Add<NameDictionary>(properties, p->name, p->value, &slow);
+ Return(p->value);
+
+ BIND(&slow);
+ TailCallRuntime(Runtime::kAddDictionaryProperty, p->context,
+ p->receiver, p->name, p->value);
+ }
+ }
}
}
@@ -667,21 +928,21 @@ void AccessorAssembler::HandleStoreICSmiHandlerCase(Node* handler_word,
IntPtrConstant(StoreHandler::kSmi)));
Goto(&if_smi_field);
- Bind(&if_tagged_field);
+ BIND(&if_tagged_field);
{
Comment("store tagged field");
HandleStoreFieldAndReturn(handler_word, holder, Representation::Tagged(),
value, transition, miss);
}
- Bind(&if_double_field);
+ BIND(&if_double_field);
{
Comment("store double field");
HandleStoreFieldAndReturn(handler_word, holder, Representation::Double(),
value, transition, miss);
}
- Bind(&if_heap_object_field);
+ BIND(&if_heap_object_field);
{
Comment("store heap object field");
HandleStoreFieldAndReturn(handler_word, holder,
@@ -689,7 +950,7 @@ void AccessorAssembler::HandleStoreICSmiHandlerCase(Node* handler_word,
miss);
}
- Bind(&if_smi_field);
+ BIND(&if_smi_field);
{
Comment("store smi field");
HandleStoreFieldAndReturn(handler_word, holder, Representation::Smi(),
@@ -710,7 +971,7 @@ void AccessorAssembler::HandleStoreFieldAndReturn(Node* handler_word,
Branch(IsSetWord<StoreHandler::IsInobjectBits>(handler_word), &if_inobject,
&if_out_of_object);
- Bind(&if_inobject);
+ BIND(&if_inobject);
{
StoreNamedField(handler_word, holder, true, representation, prepared_value,
transition_to_field, miss);
@@ -720,7 +981,7 @@ void AccessorAssembler::HandleStoreFieldAndReturn(Node* handler_word,
Return(value);
}
- Bind(&if_out_of_object);
+ BIND(&if_out_of_object);
{
if (transition_to_field) {
Label storage_extended(this);
@@ -731,7 +992,7 @@ void AccessorAssembler::HandleStoreFieldAndReturn(Node* handler_word,
Comment("] Extend storage");
Goto(&storage_extended);
- Bind(&storage_extended);
+ BIND(&storage_extended);
}
StoreNamedField(handler_word, holder, false, representation, prepared_value,
@@ -761,12 +1022,19 @@ Node* AccessorAssembler::PrepareValueForStore(Node* handler_word, Node* holder,
IntPtrConstant(StoreHandler::kStoreConstField)),
&done);
}
- Node* value_index_in_descriptor =
- DecodeWord<StoreHandler::DescriptorValueIndexBits>(handler_word);
+ Node* descriptor = DecodeWord<StoreHandler::DescriptorBits>(handler_word);
+ Node* scaled_descriptor =
+ IntPtrMul(descriptor, IntPtrConstant(DescriptorArray::kEntrySize));
+ Node* value_index =
+ IntPtrAdd(scaled_descriptor,
+ IntPtrConstant(DescriptorArray::kFirstIndex +
+ DescriptorArray::kEntryValueIndex));
Node* descriptors =
LoadMapDescriptors(transition ? transition : LoadMap(holder));
- Node* maybe_field_type =
- LoadFixedArrayElement(descriptors, value_index_in_descriptor);
+ CSA_ASSERT(this,
+ UintPtrLessThan(descriptor,
+ LoadAndUntagFixedArrayBaseLength(descriptors)));
+ Node* maybe_field_type = LoadFixedArrayElement(descriptors, value_index);
GotoIf(TaggedIsSmi(maybe_field_type), &done);
// Check that value type matches the field type.
@@ -774,7 +1042,7 @@ Node* AccessorAssembler::PrepareValueForStore(Node* handler_word, Node* holder,
Node* field_type = LoadWeakCellValue(maybe_field_type, bailout);
Branch(WordEqual(LoadMap(value), field_type), &done, bailout);
}
- Bind(&done);
+ BIND(&done);
} else if (representation.IsSmi()) {
GotoIfNot(TaggedIsSmi(value), bailout);
@@ -786,11 +1054,12 @@ Node* AccessorAssembler::PrepareValueForStore(Node* handler_word, Node* holder,
}
void AccessorAssembler::ExtendPropertiesBackingStore(Node* object) {
- Node* properties = LoadProperties(object);
- Node* length = LoadFixedArrayBaseLength(properties);
-
ParameterMode mode = OptimalParameterMode();
- length = TaggedToParameter(length, mode);
+
+ Node* properties = LoadProperties(object);
+ Node* length = (mode == INTPTR_PARAMETERS)
+ ? LoadAndUntagFixedArrayBaseLength(properties)
+ : LoadFixedArrayBaseLength(properties);
Node* delta = IntPtrOrSmiConstant(JSObject::kFieldsAdded, mode);
Node* new_capacity = IntPtrOrSmiAdd(length, delta, mode);
@@ -866,7 +1135,7 @@ void AccessorAssembler::StoreNamedField(Node* handler_word, Node* object,
}
Goto(&done);
}
- Bind(&done);
+ BIND(&done);
}
// Do the store.
@@ -885,7 +1154,7 @@ void AccessorAssembler::EmitFastElementsBoundsCheck(Node* object,
Node* intptr_index,
Node* is_jsarray_condition,
Label* miss) {
- Variable var_length(this, MachineType::PointerRepresentation());
+ VARIABLE(var_length, MachineType::PointerRepresentation());
Comment("Fast elements bounds check");
Label if_array(this), length_loaded(this, &var_length);
GotoIf(is_jsarray_condition, &if_array);
@@ -893,12 +1162,12 @@ void AccessorAssembler::EmitFastElementsBoundsCheck(Node* object,
var_length.Bind(SmiUntag(LoadFixedArrayBaseLength(elements)));
Goto(&length_loaded);
}
- Bind(&if_array);
+ BIND(&if_array);
{
var_length.Bind(SmiUntag(LoadJSArrayLength(object)));
Goto(&length_loaded);
}
- Bind(&length_loaded);
+ BIND(&length_loaded);
GotoIfNot(UintPtrLessThan(intptr_index, var_length.value()), miss);
}
@@ -935,13 +1204,13 @@ void AccessorAssembler::EmitElementLoad(
Switch(elements_kind, unimplemented_elements_kind, kinds, labels,
arraysize(kinds));
- Bind(&if_fast_packed);
+ BIND(&if_fast_packed);
{
Comment("fast packed elements");
exit_point->Return(LoadFixedArrayElement(elements, intptr_index));
}
- Bind(&if_fast_holey);
+ BIND(&if_fast_holey);
{
Comment("fast holey elements");
Node* element = LoadFixedArrayElement(elements, intptr_index);
@@ -949,7 +1218,7 @@ void AccessorAssembler::EmitElementLoad(
exit_point->Return(element);
}
- Bind(&if_fast_double);
+ BIND(&if_fast_double);
{
Comment("packed double elements");
var_double_value->Bind(LoadFixedDoubleArrayElement(elements, intptr_index,
@@ -957,7 +1226,7 @@ void AccessorAssembler::EmitElementLoad(
Goto(rebox_double);
}
- Bind(&if_fast_holey_double);
+ BIND(&if_fast_holey_double);
{
Comment("holey double elements");
Node* value = LoadFixedDoubleArrayElement(elements, intptr_index,
@@ -967,7 +1236,7 @@ void AccessorAssembler::EmitElementLoad(
Goto(rebox_double);
}
- Bind(&if_nonfast);
+ BIND(&if_nonfast);
{
STATIC_ASSERT(LAST_ELEMENTS_KIND == LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND);
GotoIf(Int32GreaterThanOrEqual(
@@ -979,15 +1248,15 @@ void AccessorAssembler::EmitElementLoad(
Goto(unimplemented_elements_kind);
}
- Bind(&if_dictionary);
+ BIND(&if_dictionary);
{
Comment("dictionary elements");
GotoIf(IntPtrLessThan(intptr_index, IntPtrConstant(0)), out_of_bounds);
- Variable var_entry(this, MachineType::PointerRepresentation());
+ VARIABLE(var_entry, MachineType::PointerRepresentation());
Label if_found(this);
NumberDictionaryLookup<SeededNumberDictionary>(
elements, intptr_index, &if_found, &var_entry, if_hole);
- Bind(&if_found);
+ BIND(&if_found);
// Check that the value is a data property.
Node* index = EntryToIndex<SeededNumberDictionary>(var_entry.value());
Node* details =
@@ -1000,7 +1269,7 @@ void AccessorAssembler::EmitElementLoad(
LoadValueByKeyIndex<SeededNumberDictionary>(elements, index));
}
- Bind(&if_typed_array);
+ BIND(&if_typed_array);
{
Comment("typed elements");
// Check if buffer has been neutered.
@@ -1039,47 +1308,47 @@ void AccessorAssembler::EmitElementLoad(
DCHECK_EQ(kTypedElementsKindCount, arraysize(elements_kind_labels));
Switch(elements_kind, miss, elements_kinds, elements_kind_labels,
kTypedElementsKindCount);
- Bind(&uint8_elements);
+ BIND(&uint8_elements);
{
Comment("UINT8_ELEMENTS"); // Handles UINT8_CLAMPED_ELEMENTS too.
Node* element = Load(MachineType::Uint8(), backing_store, intptr_index);
exit_point->Return(SmiFromWord32(element));
}
- Bind(&int8_elements);
+ BIND(&int8_elements);
{
Comment("INT8_ELEMENTS");
Node* element = Load(MachineType::Int8(), backing_store, intptr_index);
exit_point->Return(SmiFromWord32(element));
}
- Bind(&uint16_elements);
+ BIND(&uint16_elements);
{
Comment("UINT16_ELEMENTS");
Node* index = WordShl(intptr_index, IntPtrConstant(1));
Node* element = Load(MachineType::Uint16(), backing_store, index);
exit_point->Return(SmiFromWord32(element));
}
- Bind(&int16_elements);
+ BIND(&int16_elements);
{
Comment("INT16_ELEMENTS");
Node* index = WordShl(intptr_index, IntPtrConstant(1));
Node* element = Load(MachineType::Int16(), backing_store, index);
exit_point->Return(SmiFromWord32(element));
}
- Bind(&uint32_elements);
+ BIND(&uint32_elements);
{
Comment("UINT32_ELEMENTS");
Node* index = WordShl(intptr_index, IntPtrConstant(2));
Node* element = Load(MachineType::Uint32(), backing_store, index);
exit_point->Return(ChangeUint32ToTagged(element));
}
- Bind(&int32_elements);
+ BIND(&int32_elements);
{
Comment("INT32_ELEMENTS");
Node* index = WordShl(intptr_index, IntPtrConstant(2));
Node* element = Load(MachineType::Int32(), backing_store, index);
exit_point->Return(ChangeInt32ToTagged(element));
}
- Bind(&float32_elements);
+ BIND(&float32_elements);
{
Comment("FLOAT32_ELEMENTS");
Node* index = WordShl(intptr_index, IntPtrConstant(2));
@@ -1087,7 +1356,7 @@ void AccessorAssembler::EmitElementLoad(
var_double_value->Bind(ChangeFloat32ToFloat64(element));
Goto(rebox_double);
}
- Bind(&float64_elements);
+ BIND(&float64_elements);
{
Comment("FLOAT64_ELEMENTS");
Node* index = WordShl(intptr_index, IntPtrConstant(3));
@@ -1106,26 +1375,25 @@ void AccessorAssembler::CheckPrototype(Node* prototype_cell, Node* name,
Label if_property_cell(this), if_dictionary_object(this);
// |maybe_prototype| is either a PropertyCell or a slow-mode prototype.
- Branch(WordEqual(LoadMap(maybe_prototype),
- LoadRoot(Heap::kGlobalPropertyCellMapRootIndex)),
- &if_property_cell, &if_dictionary_object);
+ Branch(IsPropertyCell(maybe_prototype), &if_property_cell,
+ &if_dictionary_object);
- Bind(&if_dictionary_object);
+ BIND(&if_dictionary_object);
{
CSA_ASSERT(this, IsDictionaryMap(LoadMap(maybe_prototype)));
NameDictionaryNegativeLookup(maybe_prototype, name, miss);
Goto(&done);
}
- Bind(&if_property_cell);
+ BIND(&if_property_cell);
{
// Ensure the property cell still contains the hole.
Node* value = LoadObjectField(maybe_prototype, PropertyCell::kValueOffset);
- GotoIf(WordNotEqual(value, LoadRoot(Heap::kTheHoleValueRootIndex)), miss);
+ GotoIfNot(IsTheHole(value), miss);
Goto(&done);
}
- Bind(&done);
+ BIND(&done);
}
void AccessorAssembler::NameDictionaryNegativeLookup(Node* object, Node* name,
@@ -1133,11 +1401,11 @@ void AccessorAssembler::NameDictionaryNegativeLookup(Node* object, Node* name,
CSA_ASSERT(this, IsDictionaryMap(LoadMap(object)));
Node* properties = LoadProperties(object);
// Ensure the property does not exist in a dictionary-mode object.
- Variable var_name_index(this, MachineType::PointerRepresentation());
+ VARIABLE(var_name_index, MachineType::PointerRepresentation());
Label done(this);
NameDictionaryLookup<NameDictionary>(properties, name, miss, &var_name_index,
&done);
- Bind(&done);
+ BIND(&done);
}
void AccessorAssembler::GenericElementLoad(Node* receiver, Node* receiver_map,
@@ -1157,7 +1425,7 @@ void AccessorAssembler::GenericElementLoad(Node* receiver, Node* receiver_map,
Node* elements_kind = LoadMapElementsKind(receiver_map);
Node* is_jsarray_condition =
Word32Equal(instance_type, Int32Constant(JS_ARRAY_TYPE));
- Variable var_double_value(this, MachineRepresentation::kFloat64);
+ VARIABLE(var_double_value, MachineRepresentation::kFloat64);
Label rebox_double(this, &var_double_value);
// Unimplemented elements kinds fall back to a runtime call.
@@ -1168,10 +1436,10 @@ void AccessorAssembler::GenericElementLoad(Node* receiver, Node* receiver_map,
&var_double_value, unimplemented_elements_kind, &if_oob, slow,
&direct_exit);
- Bind(&rebox_double);
+ BIND(&rebox_double);
Return(AllocateHeapNumberWithValue(var_double_value.value()));
- Bind(&if_oob);
+ BIND(&if_oob);
{
Comment("out of bounds");
// Negative keys can't take the fast OOB path.
@@ -1180,13 +1448,13 @@ void AccessorAssembler::GenericElementLoad(Node* receiver, Node* receiver_map,
Goto(&if_element_hole);
}
- Bind(&if_element_hole);
+ BIND(&if_element_hole);
{
Comment("found the hole");
Label return_undefined(this);
BranchIfPrototypesHaveNoElements(receiver_map, &return_undefined, slow);
- Bind(&return_undefined);
+ BIND(&return_undefined);
Return(UndefinedConstant());
}
}
@@ -1194,12 +1462,15 @@ void AccessorAssembler::GenericElementLoad(Node* receiver, Node* receiver_map,
void AccessorAssembler::GenericPropertyLoad(Node* receiver, Node* receiver_map,
Node* instance_type, Node* key,
const LoadICParameters* p,
- Label* slow) {
+ Label* slow,
+ UseStubCache use_stub_cache) {
+ ExitPoint direct_exit(this);
+
Comment("key is unique name");
Label if_found_on_receiver(this), if_property_dictionary(this),
lookup_prototype_chain(this);
- Variable var_details(this, MachineRepresentation::kWord32);
- Variable var_value(this, MachineRepresentation::kTagged);
+ VARIABLE(var_details, MachineRepresentation::kWord32);
+ VARIABLE(var_value, MachineRepresentation::kTagged);
// Receivers requiring non-standard accesses (interceptors, access
// checks, strings and string wrappers, proxies) are handled in the runtime.
@@ -1219,11 +1490,13 @@ void AccessorAssembler::GenericPropertyLoad(Node* receiver, Node* receiver_map,
Node* descriptors = LoadMapDescriptors(receiver_map);
Label if_descriptor_found(this), stub_cache(this);
- Variable var_name_index(this, MachineType::PointerRepresentation());
+ VARIABLE(var_name_index, MachineType::PointerRepresentation());
+ Label* notfound =
+ use_stub_cache == kUseStubCache ? &stub_cache : &lookup_prototype_chain;
DescriptorLookup(key, descriptors, bitfield3, &if_descriptor_found,
- &var_name_index, &stub_cache);
+ &var_name_index, notfound);
- Bind(&if_descriptor_found);
+ BIND(&if_descriptor_found);
{
LoadPropertyFromFastObject(receiver, receiver_map, descriptors,
var_name_index.value(), &var_details,
@@ -1231,17 +1504,17 @@ void AccessorAssembler::GenericPropertyLoad(Node* receiver, Node* receiver_map,
Goto(&if_found_on_receiver);
}
- Bind(&stub_cache);
- {
+ if (use_stub_cache == kUseStubCache) {
+ BIND(&stub_cache);
Comment("stub cache probe for fast property load");
- Variable var_handler(this, MachineRepresentation::kTagged);
+ VARIABLE(var_handler, MachineRepresentation::kTagged);
Label found_handler(this, &var_handler), stub_cache_miss(this);
TryProbeStubCache(isolate()->load_stub_cache(), receiver, key,
&found_handler, &var_handler, &stub_cache_miss);
- Bind(&found_handler);
- { HandleLoadICHandlerCase(p, var_handler.value(), slow); }
+ BIND(&found_handler);
+ { HandleLoadICHandlerCase(p, var_handler.value(), slow, &direct_exit); }
- Bind(&stub_cache_miss);
+ BIND(&stub_cache_miss);
{
// TODO(jkummerow): Check if the property exists on the prototype
// chain. If it doesn't, then there's no point in missing.
@@ -1251,18 +1524,18 @@ void AccessorAssembler::GenericPropertyLoad(Node* receiver, Node* receiver_map,
}
}
- Bind(&if_property_dictionary);
+ BIND(&if_property_dictionary);
{
Comment("dictionary property load");
// We checked for LAST_CUSTOM_ELEMENTS_RECEIVER before, which rules out
// seeing global objects here (which would need special handling).
- Variable var_name_index(this, MachineType::PointerRepresentation());
+ VARIABLE(var_name_index, MachineType::PointerRepresentation());
Label dictionary_found(this, &var_name_index);
NameDictionaryLookup<NameDictionary>(properties, key, &dictionary_found,
&var_name_index,
&lookup_prototype_chain);
- Bind(&dictionary_found);
+ BIND(&dictionary_found);
{
LoadPropertyFromNameDictionary(properties, var_name_index.value(),
&var_details, &var_value);
@@ -1270,7 +1543,7 @@ void AccessorAssembler::GenericPropertyLoad(Node* receiver, Node* receiver_map,
}
}
- Bind(&if_found_on_receiver);
+ BIND(&if_found_on_receiver);
{
Node* value = CallGetterIfAccessor(var_value.value(), var_details.value(),
p->context, receiver, slow);
@@ -1278,10 +1551,10 @@ void AccessorAssembler::GenericPropertyLoad(Node* receiver, Node* receiver_map,
Return(value);
}
- Bind(&lookup_prototype_chain);
+ BIND(&lookup_prototype_chain);
{
- Variable var_holder_map(this, MachineRepresentation::kTagged);
- Variable var_holder_instance_type(this, MachineRepresentation::kWord32);
+ VARIABLE(var_holder_map, MachineRepresentation::kTagged);
+ VARIABLE(var_holder_instance_type, MachineRepresentation::kWord32);
Label return_undefined(this);
Variable* merged_variables[] = {&var_holder_map, &var_holder_instance_type};
Label loop(this, arraysize(merged_variables), merged_variables);
@@ -1291,7 +1564,7 @@ void AccessorAssembler::GenericPropertyLoad(Node* receiver, Node* receiver_map,
// Private symbols must not be looked up on the prototype chain.
GotoIf(IsPrivateSymbol(key), &return_undefined);
Goto(&loop);
- Bind(&loop);
+ BIND(&loop);
{
// Bailout if it can be an integer indexed exotic case.
GotoIf(Word32Equal(var_holder_instance_type.value(),
@@ -1310,17 +1583,17 @@ void AccessorAssembler::GenericPropertyLoad(Node* receiver, Node* receiver_map,
// This trampoline and the next are required to appease Turbofan's
// variable merging.
- Bind(&next_proto);
+ BIND(&next_proto);
Goto(&loop);
- Bind(&goto_slow);
+ BIND(&goto_slow);
Goto(slow);
- Bind(&return_value);
+ BIND(&return_value);
Return(var_value.value());
}
- Bind(&return_undefined);
+ BIND(&return_undefined);
Return(UndefinedConstant());
}
}
@@ -1430,7 +1703,7 @@ void AccessorAssembler::TryProbeStubCache(StubCache* stub_cache, Node* receiver,
TryProbeStubCacheTable(stub_cache, kPrimary, primary_offset, name,
receiver_map, if_handler, var_handler, &try_secondary);
- Bind(&try_secondary);
+ BIND(&try_secondary);
{
// Probe the secondary table.
Node* secondary_offset = StubCacheSecondaryOffset(name, primary_offset);
@@ -1438,7 +1711,7 @@ void AccessorAssembler::TryProbeStubCache(StubCache* stub_cache, Node* receiver,
receiver_map, if_handler, var_handler, &miss);
}
- Bind(&miss);
+ BIND(&miss);
{
IncrementCounter(counters->megamorphic_stub_cache_misses(), 1);
Goto(if_miss);
@@ -1447,44 +1720,189 @@ void AccessorAssembler::TryProbeStubCache(StubCache* stub_cache, Node* receiver,
//////////////////// Entry points into private implementation (one per stub).
+void AccessorAssembler::LoadIC_BytecodeHandler(const LoadICParameters* p,
+ ExitPoint* exit_point) {
+ // Must be kept in sync with LoadIC.
+
+ // This function is hand-tuned to omit frame construction for common cases,
+ // e.g.: monomorphic field and constant loads through smi handlers.
+ // Polymorphic ICs with a hit in the first two entries also omit frames.
+ // TODO(jgruber): Frame omission is fragile and can be affected by minor
+ // changes in control flow and logic. We currently have no way of ensuring
+ // that no frame is constructed, so it's easy to break this optimization by
+ // accident.
+ Label stub_call(this, Label::kDeferred), miss(this, Label::kDeferred);
+
+ // Inlined fast path.
+ {
+ Comment("LoadIC_BytecodeHandler_fast");
+
+ Node* recv_map = LoadReceiverMap(p->receiver);
+ GotoIf(IsDeprecatedMap(recv_map), &miss);
+
+ VARIABLE(var_handler, MachineRepresentation::kTagged);
+ Label try_polymorphic(this), if_handler(this, &var_handler);
+
+ Node* feedback =
+ TryMonomorphicCase(p->slot, p->vector, recv_map, &if_handler,
+ &var_handler, &try_polymorphic);
+
+ BIND(&if_handler);
+ HandleLoadICHandlerCase(p, var_handler.value(), &miss, exit_point);
+
+ BIND(&try_polymorphic);
+ {
+ GotoIfNot(WordEqual(LoadMap(feedback), FixedArrayMapConstant()),
+ &stub_call);
+ HandlePolymorphicCase(recv_map, feedback, &if_handler, &var_handler,
+ &miss, 2);
+ }
+ }
+
+ BIND(&stub_call);
+ {
+ Comment("LoadIC_BytecodeHandler_noninlined");
+
+ // Call into the stub that implements the non-inlined parts of LoadIC.
+ Callable ic = CodeFactory::LoadICInOptimizedCode_Noninlined(isolate());
+ Node* code_target = HeapConstant(ic.code());
+ exit_point->ReturnCallStub(ic.descriptor(), code_target, p->context,
+ p->receiver, p->name, p->slot, p->vector);
+ }
+
+ BIND(&miss);
+ {
+ Comment("LoadIC_BytecodeHandler_miss");
+
+ exit_point->ReturnCallRuntime(Runtime::kLoadIC_Miss, p->context,
+ p->receiver, p->name, p->slot, p->vector);
+ }
+}
+
void AccessorAssembler::LoadIC(const LoadICParameters* p) {
- Variable var_handler(this, MachineRepresentation::kTagged);
- // TODO(ishell): defer blocks when it works.
- Label if_handler(this, &var_handler), try_polymorphic(this),
- try_megamorphic(this /*, Label::kDeferred*/),
- miss(this /*, Label::kDeferred*/);
+ // Must be kept in sync with LoadIC_BytecodeHandler.
+
+ ExitPoint direct_exit(this);
+
+ VARIABLE(var_handler, MachineRepresentation::kTagged);
+ Label if_handler(this, &var_handler), non_inlined(this, Label::kDeferred),
+ try_polymorphic(this), miss(this, Label::kDeferred);
Node* receiver_map = LoadReceiverMap(p->receiver);
- GotoIf(IsSetWord32<Map::Deprecated>(LoadMapBitField3(receiver_map)), &miss);
+ GotoIf(IsDeprecatedMap(receiver_map), &miss);
// Check monomorphic case.
Node* feedback =
TryMonomorphicCase(p->slot, p->vector, receiver_map, &if_handler,
&var_handler, &try_polymorphic);
- Bind(&if_handler);
- { HandleLoadICHandlerCase(p, var_handler.value(), &miss); }
+ BIND(&if_handler);
+ HandleLoadICHandlerCase(p, var_handler.value(), &miss, &direct_exit);
- Bind(&try_polymorphic);
+ BIND(&try_polymorphic);
{
// Check polymorphic case.
Comment("LoadIC_try_polymorphic");
GotoIfNot(WordEqual(LoadMap(feedback), FixedArrayMapConstant()),
- &try_megamorphic);
+ &non_inlined);
HandlePolymorphicCase(receiver_map, feedback, &if_handler, &var_handler,
&miss, 2);
}
- Bind(&try_megamorphic);
+ BIND(&non_inlined);
+ LoadIC_Noninlined(p, receiver_map, feedback, &var_handler, &if_handler, &miss,
+ &direct_exit);
+
+ BIND(&miss);
+ direct_exit.ReturnCallRuntime(Runtime::kLoadIC_Miss, p->context, p->receiver,
+ p->name, p->slot, p->vector);
+}
+
+void AccessorAssembler::LoadIC_Noninlined(const LoadICParameters* p,
+ Node* receiver_map, Node* feedback,
+ Variable* var_handler,
+ Label* if_handler, Label* miss,
+ ExitPoint* exit_point) {
+ Label try_uninitialized(this, Label::kDeferred);
+
+ // Neither deprecated map nor monomorphic. These cases are handled in the
+ // bytecode handler.
+ CSA_ASSERT(this, Word32BinaryNot(IsDeprecatedMap(receiver_map)));
+ CSA_ASSERT(this,
+ WordNotEqual(receiver_map, LoadWeakCellValueUnchecked(feedback)));
+ CSA_ASSERT(this, WordNotEqual(LoadMap(feedback), FixedArrayMapConstant()));
+ DCHECK_EQ(MachineRepresentation::kTagged, var_handler->rep());
+
{
// Check megamorphic case.
GotoIfNot(WordEqual(feedback, LoadRoot(Heap::kmegamorphic_symbolRootIndex)),
- &miss);
+ &try_uninitialized);
TryProbeStubCache(isolate()->load_stub_cache(), p->receiver, p->name,
- &if_handler, &var_handler, &miss);
+ if_handler, var_handler, miss);
+ }
+
+ BIND(&try_uninitialized);
+ {
+ // Check uninitialized case.
+ GotoIfNot(
+ WordEqual(feedback, LoadRoot(Heap::kuninitialized_symbolRootIndex)),
+ miss);
+ exit_point->ReturnCallStub(CodeFactory::LoadIC_Uninitialized(isolate()),
+ p->context, p->receiver, p->name, p->slot,
+ p->vector);
+ }
+}
+
+void AccessorAssembler::LoadIC_Uninitialized(const LoadICParameters* p) {
+ Label miss(this);
+ Node* receiver = p->receiver;
+ GotoIf(TaggedIsSmi(receiver), &miss);
+ Node* receiver_map = LoadMap(receiver);
+ Node* instance_type = LoadMapInstanceType(receiver_map);
+
+ // Optimistically write the state transition to the vector.
+ StoreFixedArrayElement(p->vector, p->slot,
+ LoadRoot(Heap::kpremonomorphic_symbolRootIndex),
+ SKIP_WRITE_BARRIER, 0, SMI_PARAMETERS);
+
+ Label not_function_prototype(this);
+ GotoIf(Word32NotEqual(instance_type, Int32Constant(JS_FUNCTION_TYPE)),
+ &not_function_prototype);
+ GotoIfNot(WordEqual(p->name, LoadRoot(Heap::kprototype_stringRootIndex)),
+ &not_function_prototype);
+ Node* bit_field = LoadMapBitField(receiver_map);
+ GotoIf(IsSetWord32(bit_field, 1 << Map::kHasNonInstancePrototype),
+ &not_function_prototype);
+ // Function.prototype load.
+ {
+ // TODO(jkummerow): Unify with LoadIC_FunctionPrototype builtin
+ // (when we have a shared CSA base class for all builtins).
+ Node* proto_or_map =
+ LoadObjectField(receiver, JSFunction::kPrototypeOrInitialMapOffset);
+ GotoIf(IsTheHole(proto_or_map), &miss);
+
+ VARIABLE(var_result, MachineRepresentation::kTagged, proto_or_map);
+ Label done(this, &var_result);
+ GotoIfNot(IsMap(proto_or_map), &done);
+
+ var_result.Bind(LoadMapPrototype(proto_or_map));
+ Goto(&done);
+
+ BIND(&done);
+ Return(var_result.value());
}
- Bind(&miss);
+ BIND(&not_function_prototype);
+
+ GenericPropertyLoad(receiver, receiver_map, instance_type, p->name, p, &miss,
+ kDontUseStubCache);
+
+ BIND(&miss);
{
+ // Undo the optimistic state transition.
+ StoreFixedArrayElement(p->vector, p->slot,
+ LoadRoot(Heap::kuninitialized_symbolRootIndex),
+ SKIP_WRITE_BARRIER, 0, SMI_PARAMETERS);
+
TailCallRuntime(Runtime::kLoadIC_Miss, p->context, p->receiver, p->name,
p->slot, p->vector);
}
@@ -1504,14 +1922,14 @@ void AccessorAssembler::LoadICProtoArray(
Node* handler_length = LoadAndUntagFixedArrayBaseLength(handler);
- Node* holder =
- EmitLoadICProtoArrayCheck(p, handler, handler_length, handler_flags,
- &miss, throw_reference_error_if_nonexistent);
+ Node* holder = EmitLoadICProtoArrayCheck(p, handler, handler_length,
+ handler_flags, &miss);
HandleLoadICSmiHandlerCase(p, holder, smi_handler, &miss, &direct_exit,
+ throw_reference_error_if_nonexistent,
kOnlyProperties);
- Bind(&miss);
+ BIND(&miss);
{
TailCallRuntime(Runtime::kLoadIC_Miss, p->context, p->receiver, p->name,
p->slot, p->vector);
@@ -1528,40 +1946,56 @@ void AccessorAssembler::LoadGlobalIC_TryPropertyCellCase(
// Load value or try handler case if the {weak_cell} is cleared.
Node* property_cell = LoadWeakCellValue(weak_cell, try_handler);
- CSA_ASSERT(this, HasInstanceType(property_cell, PROPERTY_CELL_TYPE));
+ CSA_ASSERT(this, IsPropertyCell(property_cell));
Node* value = LoadObjectField(property_cell, PropertyCell::kValueOffset);
GotoIf(WordEqual(value, TheHoleConstant()), miss);
exit_point->Return(value);
}
-void AccessorAssembler::LoadGlobalIC_TryHandlerCase(const LoadICParameters* p,
+void AccessorAssembler::LoadGlobalIC_TryHandlerCase(const LoadICParameters* pp,
TypeofMode typeof_mode,
ExitPoint* exit_point,
Label* miss) {
Comment("LoadGlobalIC_TryHandlerCase");
- Label call_handler(this);
+ Label call_handler(this), non_smi(this);
Node* handler =
- LoadFixedArrayElement(p->vector, p->slot, kPointerSize, SMI_PARAMETERS);
- CSA_ASSERT(this, Word32BinaryNot(TaggedIsSmi(handler)));
+ LoadFixedArrayElement(pp->vector, pp->slot, kPointerSize, SMI_PARAMETERS);
GotoIf(WordEqual(handler, LoadRoot(Heap::kuninitialized_symbolRootIndex)),
miss);
- GotoIf(IsCodeMap(LoadMap(handler)), &call_handler);
+
+ GotoIfNot(TaggedIsSmi(handler), &non_smi);
bool throw_reference_error_if_nonexistent = typeof_mode == NOT_INSIDE_TYPEOF;
- HandleLoadGlobalICHandlerCase(p, handler, miss, exit_point,
+
+ {
+ LoadICParameters p = *pp;
+ DCHECK_NULL(p.receiver);
+ Node* native_context = LoadNativeContext(p.context);
+ p.receiver =
+ LoadContextElement(native_context, Context::GLOBAL_PROXY_INDEX);
+ Node* holder = LoadContextElement(native_context, Context::EXTENSION_INDEX);
+ HandleLoadICSmiHandlerCase(&p, holder, handler, miss, exit_point,
+ throw_reference_error_if_nonexistent,
+ kOnlyProperties);
+ }
+
+ BIND(&non_smi);
+ GotoIf(IsCodeMap(LoadMap(handler)), &call_handler);
+
+ HandleLoadGlobalICHandlerCase(pp, handler, miss, exit_point,
throw_reference_error_if_nonexistent);
- Bind(&call_handler);
+ BIND(&call_handler);
{
LoadWithVectorDescriptor descriptor(isolate());
- Node* native_context = LoadNativeContext(p->context);
+ Node* native_context = LoadNativeContext(pp->context);
Node* receiver =
- LoadContextElement(native_context, Context::EXTENSION_INDEX);
- exit_point->ReturnCallStub(descriptor, handler, p->context, receiver,
- p->name, p->slot, p->vector);
+ LoadContextElement(native_context, Context::GLOBAL_PROXY_INDEX);
+ exit_point->ReturnCallStub(descriptor, handler, pp->context, receiver,
+ pp->name, pp->slot, pp->vector);
}
}
@@ -1575,38 +2009,44 @@ void AccessorAssembler::LoadGlobalIC_MissCase(const LoadICParameters* p,
void AccessorAssembler::LoadGlobalIC(const LoadICParameters* p,
TypeofMode typeof_mode) {
+ // Must be kept in sync with Interpreter::BuildLoadGlobal.
+
ExitPoint direct_exit(this);
Label try_handler(this), miss(this);
LoadGlobalIC_TryPropertyCellCase(p->vector, p->slot, &direct_exit,
&try_handler, &miss);
- Bind(&try_handler);
+ BIND(&try_handler);
LoadGlobalIC_TryHandlerCase(p, typeof_mode, &direct_exit, &miss);
- Bind(&miss);
+ BIND(&miss);
LoadGlobalIC_MissCase(p, &direct_exit);
}
void AccessorAssembler::KeyedLoadIC(const LoadICParameters* p) {
- Variable var_handler(this, MachineRepresentation::kTagged);
- // TODO(ishell): defer blocks when it works.
- Label if_handler(this, &var_handler), try_polymorphic(this),
- try_megamorphic(this /*, Label::kDeferred*/),
- try_polymorphic_name(this /*, Label::kDeferred*/),
- miss(this /*, Label::kDeferred*/);
+ ExitPoint direct_exit(this);
+
+ VARIABLE(var_handler, MachineRepresentation::kTagged);
+ Label if_handler(this, &var_handler), try_polymorphic(this, Label::kDeferred),
+ try_megamorphic(this, Label::kDeferred),
+ try_polymorphic_name(this, Label::kDeferred),
+ miss(this, Label::kDeferred);
Node* receiver_map = LoadReceiverMap(p->receiver);
- GotoIf(IsSetWord32<Map::Deprecated>(LoadMapBitField3(receiver_map)), &miss);
+ GotoIf(IsDeprecatedMap(receiver_map), &miss);
// Check monomorphic case.
Node* feedback =
TryMonomorphicCase(p->slot, p->vector, receiver_map, &if_handler,
&var_handler, &try_polymorphic);
- Bind(&if_handler);
- { HandleLoadICHandlerCase(p, var_handler.value(), &miss, kSupportElements); }
+ BIND(&if_handler);
+ {
+ HandleLoadICHandlerCase(p, var_handler.value(), &miss, &direct_exit,
+ kSupportElements);
+ }
- Bind(&try_polymorphic);
+ BIND(&try_polymorphic);
{
// Check polymorphic case.
Comment("KeyedLoadIC_try_polymorphic");
@@ -1616,7 +2056,7 @@ void AccessorAssembler::KeyedLoadIC(const LoadICParameters* p) {
&miss, 2);
}
- Bind(&try_megamorphic);
+ BIND(&try_megamorphic);
{
// Check megamorphic case.
Comment("KeyedLoadIC_try_megamorphic");
@@ -1626,21 +2066,19 @@ void AccessorAssembler::KeyedLoadIC(const LoadICParameters* p) {
TailCallStub(CodeFactory::KeyedLoadIC_Megamorphic(isolate()), p->context,
p->receiver, p->name, p->slot, p->vector);
}
- Bind(&try_polymorphic_name);
+ BIND(&try_polymorphic_name);
{
// We might have a name in feedback, and a fixed array in the next slot.
Comment("KeyedLoadIC_try_polymorphic_name");
GotoIfNot(WordEqual(feedback, p->name), &miss);
// If the name comparison succeeded, we know we have a fixed array with
// at least one map/handler pair.
- Node* offset = ElementOffsetFromIndex(
- p->slot, FAST_HOLEY_ELEMENTS, SMI_PARAMETERS,
- FixedArray::kHeaderSize + kPointerSize - kHeapObjectTag);
- Node* array = Load(MachineType::AnyTagged(), p->vector, offset);
+ Node* array =
+ LoadFixedArrayElement(p->vector, p->slot, kPointerSize, SMI_PARAMETERS);
HandlePolymorphicCase(receiver_map, array, &if_handler, &var_handler, &miss,
1);
}
- Bind(&miss);
+ BIND(&miss);
{
Comment("KeyedLoadIC_miss");
TailCallRuntime(Runtime::kKeyedLoadIC_Miss, p->context, p->receiver,
@@ -1649,8 +2087,8 @@ void AccessorAssembler::KeyedLoadIC(const LoadICParameters* p) {
}
void AccessorAssembler::KeyedLoadICGeneric(const LoadICParameters* p) {
- Variable var_index(this, MachineType::PointerRepresentation());
- Variable var_unique(this, MachineRepresentation::kTagged);
+ VARIABLE(var_index, MachineType::PointerRepresentation());
+ VARIABLE(var_unique, MachineRepresentation::kTagged);
var_unique.Bind(p->name); // Dummy initialization.
Label if_index(this), if_unique_name(this), slow(this);
@@ -1662,19 +2100,19 @@ void AccessorAssembler::KeyedLoadICGeneric(const LoadICParameters* p) {
TryToName(p->name, &if_index, &var_index, &if_unique_name, &var_unique,
&slow);
- Bind(&if_index);
+ BIND(&if_index);
{
GenericElementLoad(receiver, receiver_map, instance_type, var_index.value(),
&slow);
}
- Bind(&if_unique_name);
+ BIND(&if_unique_name);
{
GenericPropertyLoad(receiver, receiver_map, instance_type,
var_unique.value(), p, &slow);
}
- Bind(&slow);
+ BIND(&slow);
{
Comment("KeyedLoadGeneric_slow");
IncrementCounter(isolate()->counters()->ic_keyed_load_generic_slow(), 1);
@@ -1684,27 +2122,27 @@ void AccessorAssembler::KeyedLoadICGeneric(const LoadICParameters* p) {
}
}
-void AccessorAssembler::StoreIC(const StoreICParameters* p) {
- Variable var_handler(this, MachineRepresentation::kTagged);
- // TODO(ishell): defer blocks when it works.
- Label if_handler(this, &var_handler), try_polymorphic(this),
- try_megamorphic(this /*, Label::kDeferred*/),
- miss(this /*, Label::kDeferred*/);
+void AccessorAssembler::StoreIC(const StoreICParameters* p,
+ LanguageMode language_mode) {
+ VARIABLE(var_handler, MachineRepresentation::kTagged);
+ Label if_handler(this, &var_handler), try_polymorphic(this, Label::kDeferred),
+ try_megamorphic(this, Label::kDeferred),
+ try_uninitialized(this, Label::kDeferred), miss(this, Label::kDeferred);
Node* receiver_map = LoadReceiverMap(p->receiver);
- GotoIf(IsSetWord32<Map::Deprecated>(LoadMapBitField3(receiver_map)), &miss);
+ GotoIf(IsDeprecatedMap(receiver_map), &miss);
// Check monomorphic case.
Node* feedback =
TryMonomorphicCase(p->slot, p->vector, receiver_map, &if_handler,
&var_handler, &try_polymorphic);
- Bind(&if_handler);
+ BIND(&if_handler);
{
Comment("StoreIC_if_handler");
HandleStoreICHandlerCase(p, var_handler.value(), &miss);
}
- Bind(&try_polymorphic);
+ BIND(&try_polymorphic);
{
// Check polymorphic case.
Comment("StoreIC_try_polymorphic");
@@ -1715,16 +2153,26 @@ void AccessorAssembler::StoreIC(const StoreICParameters* p) {
&miss, 2);
}
- Bind(&try_megamorphic);
+ BIND(&try_megamorphic);
{
// Check megamorphic case.
GotoIfNot(WordEqual(feedback, LoadRoot(Heap::kmegamorphic_symbolRootIndex)),
- &miss);
+ &try_uninitialized);
TryProbeStubCache(isolate()->store_stub_cache(), p->receiver, p->name,
&if_handler, &var_handler, &miss);
}
- Bind(&miss);
+ BIND(&try_uninitialized);
+ {
+ // Check uninitialized case.
+ GotoIfNot(
+ WordEqual(feedback, LoadRoot(Heap::kuninitialized_symbolRootIndex)),
+ &miss);
+ TailCallStub(CodeFactory::StoreIC_Uninitialized(isolate(), language_mode),
+ p->context, p->receiver, p->name, p->value, p->slot,
+ p->vector);
+ }
+ BIND(&miss);
{
TailCallRuntime(Runtime::kStoreIC_Miss, p->context, p->value, p->slot,
p->vector, p->receiver, p->name);
@@ -1733,80 +2181,40 @@ void AccessorAssembler::StoreIC(const StoreICParameters* p) {
void AccessorAssembler::KeyedStoreIC(const StoreICParameters* p,
LanguageMode language_mode) {
- // TODO(ishell): defer blocks when it works.
- Label miss(this /*, Label::kDeferred*/);
+ Label miss(this, Label::kDeferred);
{
- Variable var_handler(this, MachineRepresentation::kTagged);
+ VARIABLE(var_handler, MachineRepresentation::kTagged);
- // TODO(ishell): defer blocks when it works.
- Label if_handler(this, &var_handler), try_polymorphic(this),
- try_megamorphic(this /*, Label::kDeferred*/),
- try_polymorphic_name(this /*, Label::kDeferred*/);
+ Label if_handler(this, &var_handler),
+ try_polymorphic(this, Label::kDeferred),
+ try_megamorphic(this, Label::kDeferred),
+ try_polymorphic_name(this, Label::kDeferred);
Node* receiver_map = LoadReceiverMap(p->receiver);
- GotoIf(IsSetWord32<Map::Deprecated>(LoadMapBitField3(receiver_map)), &miss);
+ GotoIf(IsDeprecatedMap(receiver_map), &miss);
// Check monomorphic case.
Node* feedback =
TryMonomorphicCase(p->slot, p->vector, receiver_map, &if_handler,
&var_handler, &try_polymorphic);
- Bind(&if_handler);
+ BIND(&if_handler);
{
Comment("KeyedStoreIC_if_handler");
HandleStoreICHandlerCase(p, var_handler.value(), &miss, kSupportElements);
}
- Bind(&try_polymorphic);
+ BIND(&try_polymorphic);
{
// CheckPolymorphic case.
Comment("KeyedStoreIC_try_polymorphic");
GotoIfNot(
WordEqual(LoadMap(feedback), LoadRoot(Heap::kFixedArrayMapRootIndex)),
&try_megamorphic);
- Label if_transition_handler(this);
- Variable var_transition_map_cell(this, MachineRepresentation::kTagged);
- HandleKeyedStorePolymorphicCase(receiver_map, feedback, &if_handler,
- &var_handler, &if_transition_handler,
- &var_transition_map_cell, &miss);
- Bind(&if_transition_handler);
- Comment("KeyedStoreIC_polymorphic_transition");
- {
- Node* handler = var_handler.value();
-
- Label call_handler(this);
- Variable var_code_handler(this, MachineRepresentation::kTagged);
- var_code_handler.Bind(handler);
- GotoIfNot(IsTuple2Map(LoadMap(handler)), &call_handler);
- {
- CSA_ASSERT(this, IsTuple2Map(LoadMap(handler)));
-
- // Check validity cell.
- Node* validity_cell = LoadObjectField(handler, Tuple2::kValue1Offset);
- Node* cell_value = LoadObjectField(validity_cell, Cell::kValueOffset);
- GotoIf(
- WordNotEqual(cell_value, SmiConstant(Map::kPrototypeChainValid)),
- &miss);
-
- var_code_handler.Bind(
- LoadObjectField(handler, Tuple2::kValue2Offset));
- Goto(&call_handler);
- }
-
- Bind(&call_handler);
- {
- Node* code_handler = var_code_handler.value();
- CSA_ASSERT(this, IsCodeMap(LoadMap(code_handler)));
-
- Node* transition_map =
- LoadWeakCellValue(var_transition_map_cell.value(), &miss);
- StoreTransitionDescriptor descriptor(isolate());
- TailCallStub(descriptor, code_handler, p->context, p->receiver,
- p->name, transition_map, p->value, p->slot, p->vector);
- }
- }
+ HandlePolymorphicCase(receiver_map, feedback, &if_handler, &var_handler,
+ &miss, 2);
}
- Bind(&try_megamorphic);
+ BIND(&try_megamorphic);
{
// Check megamorphic case.
Comment("KeyedStoreIC_try_megamorphic");
@@ -1818,22 +2226,20 @@ void AccessorAssembler::KeyedStoreIC(const StoreICParameters* p,
p->context, p->receiver, p->name, p->value, p->slot, p->vector);
}
- Bind(&try_polymorphic_name);
+ BIND(&try_polymorphic_name);
{
// We might have a name in feedback, and a fixed array in the next slot.
Comment("KeyedStoreIC_try_polymorphic_name");
GotoIfNot(WordEqual(feedback, p->name), &miss);
// If the name comparison succeeded, we know we have a FixedArray with
// at least one map/handler pair.
- Node* offset = ElementOffsetFromIndex(
- p->slot, FAST_HOLEY_ELEMENTS, SMI_PARAMETERS,
- FixedArray::kHeaderSize + kPointerSize - kHeapObjectTag);
- Node* array = Load(MachineType::AnyTagged(), p->vector, offset);
+ Node* array = LoadFixedArrayElement(p->vector, p->slot, kPointerSize,
+ SMI_PARAMETERS);
HandlePolymorphicCase(receiver_map, array, &if_handler, &var_handler,
&miss, 1);
}
}
- Bind(&miss);
+ BIND(&miss);
{
Comment("KeyedStoreIC_miss");
TailCallRuntime(Runtime::kKeyedStoreIC_Miss, p->context, p->value, p->slot,
@@ -1856,6 +2262,47 @@ void AccessorAssembler::GenerateLoadIC() {
LoadIC(&p);
}
+void AccessorAssembler::GenerateLoadIC_Noninlined() {
+ typedef LoadWithVectorDescriptor Descriptor;
+
+ Node* receiver = Parameter(Descriptor::kReceiver);
+ Node* name = Parameter(Descriptor::kName);
+ Node* slot = Parameter(Descriptor::kSlot);
+ Node* vector = Parameter(Descriptor::kVector);
+ Node* context = Parameter(Descriptor::kContext);
+
+ ExitPoint direct_exit(this);
+ VARIABLE(var_handler, MachineRepresentation::kTagged);
+ Label if_handler(this, &var_handler), miss(this, Label::kDeferred);
+
+ Node* receiver_map = LoadReceiverMap(receiver);
+ Node* feedback = LoadFixedArrayElement(vector, slot, 0, SMI_PARAMETERS);
+
+ LoadICParameters p(context, receiver, name, slot, vector);
+ LoadIC_Noninlined(&p, receiver_map, feedback, &var_handler, &if_handler,
+ &miss, &direct_exit);
+
+ BIND(&if_handler);
+ HandleLoadICHandlerCase(&p, var_handler.value(), &miss, &direct_exit);
+
+ BIND(&miss);
+ direct_exit.ReturnCallRuntime(Runtime::kLoadIC_Miss, context, receiver, name,
+ slot, vector);
+}
+
+void AccessorAssembler::GenerateLoadIC_Uninitialized() {
+ typedef LoadWithVectorDescriptor Descriptor;
+
+ Node* receiver = Parameter(Descriptor::kReceiver);
+ Node* name = Parameter(Descriptor::kName);
+ Node* slot = Parameter(Descriptor::kSlot);
+ Node* vector = Parameter(Descriptor::kVector);
+ Node* context = Parameter(Descriptor::kContext);
+
+ LoadICParameters p(context, receiver, name, slot, vector);
+ LoadIC_Uninitialized(&p);
+}
+
void AccessorAssembler::GenerateLoadICTrampoline() {
typedef LoadDescriptor Descriptor;
@@ -1865,8 +2312,8 @@ void AccessorAssembler::GenerateLoadICTrampoline() {
Node* context = Parameter(Descriptor::kContext);
Node* vector = LoadFeedbackVectorForStub();
- LoadICParameters p(context, receiver, name, slot, vector);
- LoadIC(&p);
+ Callable callable = CodeFactory::LoadICInOptimizedCode(isolate());
+ TailCallStub(callable, context, receiver, name, slot, vector);
}
void AccessorAssembler::GenerateLoadICProtoArray(
@@ -1896,8 +2343,16 @@ void AccessorAssembler::GenerateLoadField() {
ExitPoint direct_exit(this);
- HandleLoadICSmiHandlerCase(&p, receiver, Parameter(Descriptor::kSmiHandler),
- nullptr, &direct_exit, kOnlyProperties);
+ VARIABLE(var_double_value, MachineRepresentation::kFloat64);
+ Label rebox_double(this, &var_double_value);
+
+ Node* smi_handler = Parameter(Descriptor::kSmiHandler);
+ Node* handler_word = SmiUntag(smi_handler);
+ HandleLoadField(receiver, handler_word, &var_double_value, &rebox_double,
+ &direct_exit);
+
+ BIND(&rebox_double);
+ Return(AllocateHeapNumberWithValue(var_double_value.value()));
}
void AccessorAssembler::GenerateLoadGlobalIC(TypeofMode typeof_mode) {
@@ -1920,8 +2375,9 @@ void AccessorAssembler::GenerateLoadGlobalICTrampoline(TypeofMode typeof_mode) {
Node* context = Parameter(Descriptor::kContext);
Node* vector = LoadFeedbackVectorForStub();
- LoadICParameters p(context, nullptr, name, slot, vector);
- LoadGlobalIC(&p, typeof_mode);
+ Callable callable =
+ CodeFactory::LoadGlobalICInOptimizedCode(isolate(), typeof_mode);
+ TailCallStub(callable, context, name, slot, vector);
}
void AccessorAssembler::GenerateKeyedLoadIC() {
@@ -1946,8 +2402,8 @@ void AccessorAssembler::GenerateKeyedLoadICTrampoline() {
Node* context = Parameter(Descriptor::kContext);
Node* vector = LoadFeedbackVectorForStub();
- LoadICParameters p(context, receiver, name, slot, vector);
- KeyedLoadIC(&p);
+ Callable callable = CodeFactory::KeyedLoadICInOptimizedCode(isolate());
+ TailCallStub(callable, context, receiver, name, slot, vector);
}
void AccessorAssembler::GenerateKeyedLoadIC_Megamorphic() {
@@ -1963,7 +2419,7 @@ void AccessorAssembler::GenerateKeyedLoadIC_Megamorphic() {
KeyedLoadICGeneric(&p);
}
-void AccessorAssembler::GenerateStoreIC() {
+void AccessorAssembler::GenerateStoreIC(LanguageMode language_mode) {
typedef StoreWithVectorDescriptor Descriptor;
Node* receiver = Parameter(Descriptor::kReceiver);
@@ -1974,10 +2430,10 @@ void AccessorAssembler::GenerateStoreIC() {
Node* context = Parameter(Descriptor::kContext);
StoreICParameters p(context, receiver, name, value, slot, vector);
- StoreIC(&p);
+ StoreIC(&p, language_mode);
}
-void AccessorAssembler::GenerateStoreICTrampoline() {
+void AccessorAssembler::GenerateStoreICTrampoline(LanguageMode language_mode) {
typedef StoreDescriptor Descriptor;
Node* receiver = Parameter(Descriptor::kReceiver);
@@ -1987,8 +2443,9 @@ void AccessorAssembler::GenerateStoreICTrampoline() {
Node* context = Parameter(Descriptor::kContext);
Node* vector = LoadFeedbackVectorForStub();
- StoreICParameters p(context, receiver, name, value, slot, vector);
- StoreIC(&p);
+ Callable callable =
+ CodeFactory::StoreICInOptimizedCode(isolate(), language_mode);
+ TailCallStub(callable, context, receiver, name, value, slot, vector);
}
void AccessorAssembler::GenerateKeyedStoreIC(LanguageMode language_mode) {
@@ -2016,8 +2473,9 @@ void AccessorAssembler::GenerateKeyedStoreICTrampoline(
Node* context = Parameter(Descriptor::kContext);
Node* vector = LoadFeedbackVectorForStub();
- StoreICParameters p(context, receiver, name, value, slot, vector);
- KeyedStoreIC(&p, language_mode);
+ Callable callable =
+ CodeFactory::KeyedStoreICInOptimizedCode(isolate(), language_mode);
+ TailCallStub(callable, context, receiver, name, value, slot, vector);
}
} // namespace internal
diff --git a/deps/v8/src/ic/accessor-assembler.h b/deps/v8/src/ic/accessor-assembler.h
index 9bc2873f85..f2cafdb128 100644
--- a/deps/v8/src/ic/accessor-assembler.h
+++ b/deps/v8/src/ic/accessor-assembler.h
@@ -24,13 +24,15 @@ class AccessorAssembler : public CodeStubAssembler {
: CodeStubAssembler(state) {}
void GenerateLoadIC();
+ void GenerateLoadIC_Noninlined();
+ void GenerateLoadIC_Uninitialized();
void GenerateLoadField();
void GenerateLoadICTrampoline();
void GenerateKeyedLoadIC();
void GenerateKeyedLoadICTrampoline();
void GenerateKeyedLoadIC_Megamorphic();
- void GenerateStoreIC();
- void GenerateStoreICTrampoline();
+ void GenerateStoreIC(LanguageMode language_mode);
+ void GenerateStoreICTrampoline(LanguageMode language_mode);
void GenerateLoadICProtoArray(bool throw_reference_error_if_nonexistent);
@@ -75,6 +77,10 @@ class AccessorAssembler : public CodeStubAssembler {
ExitPoint* exit_point, Label* miss);
void LoadGlobalIC_MissCase(const LoadICParameters* p, ExitPoint* exit_point);
+ // Specialized LoadIC for inlined bytecode handler, hand-tuned to omit frame
+ // construction on common paths.
+ void LoadIC_BytecodeHandler(const LoadICParameters* p, ExitPoint* exit_point);
+
protected:
struct StoreICParameters : public LoadICParameters {
StoreICParameters(Node* context, Node* receiver, Node* name, Node* value,
@@ -88,17 +94,25 @@ class AccessorAssembler : public CodeStubAssembler {
void HandleStoreICHandlerCase(
const StoreICParameters* p, Node* handler, Label* miss,
ElementSupport support_elements = kOnlyProperties);
+ void JumpIfDataProperty(Node* details, Label* writable, Label* readonly);
private:
// Stub generation entry points.
+ // LoadIC contains the full LoadIC logic, while LoadIC_Noninlined contains
+ // logic not inlined into Ignition bytecode handlers.
void LoadIC(const LoadICParameters* p);
+ void LoadIC_Noninlined(const LoadICParameters* p, Node* receiver_map,
+ Node* feedback, Variable* var_handler,
+ Label* if_handler, Label* miss, ExitPoint* exit_point);
+
+ void LoadIC_Uninitialized(const LoadICParameters* p);
void LoadICProtoArray(const LoadICParameters* p, Node* handler,
bool throw_reference_error_if_nonexistent);
void LoadGlobalIC(const LoadICParameters* p, TypeofMode typeof_mode);
void KeyedLoadIC(const LoadICParameters* p);
void KeyedLoadICGeneric(const LoadICParameters* p);
- void StoreIC(const StoreICParameters* p);
+ void StoreIC(const StoreICParameters* p, LanguageMode language_mode);
void KeyedStoreIC(const StoreICParameters* p, LanguageMode language_mode);
// IC dispatcher behavior.
@@ -109,22 +123,18 @@ class AccessorAssembler : public CodeStubAssembler {
Label* if_miss);
void HandlePolymorphicCase(Node* receiver_map, Node* feedback,
Label* if_handler, Variable* var_handler,
- Label* if_miss, int unroll_count);
- void HandleKeyedStorePolymorphicCase(Node* receiver_map, Node* feedback,
- Label* if_handler, Variable* var_handler,
- Label* if_transition_handler,
- Variable* var_transition_map_cell,
- Label* if_miss);
+ Label* if_miss, int min_feedback_capacity);
// LoadIC implementation.
void HandleLoadICHandlerCase(
const LoadICParameters* p, Node* handler, Label* miss,
- ElementSupport support_elements = kOnlyProperties);
+ ExitPoint* exit_point, ElementSupport support_elements = kOnlyProperties);
void HandleLoadICSmiHandlerCase(const LoadICParameters* p, Node* holder,
Node* smi_handler, Label* miss,
ExitPoint* exit_point,
+ bool throw_reference_error_if_nonexistent,
ElementSupport support_elements);
void HandleLoadICProtoHandlerCase(const LoadICParameters* p, Node* handler,
@@ -134,10 +144,13 @@ class AccessorAssembler : public CodeStubAssembler {
ExitPoint* exit_point,
bool throw_reference_error_if_nonexistent);
+ void HandleLoadField(Node* holder, Node* handler_word,
+ Variable* var_double_value, Label* rebox_double,
+ ExitPoint* exit_point);
+
Node* EmitLoadICProtoArrayCheck(const LoadICParameters* p, Node* handler,
Node* handler_length, Node* handler_flags,
- Label* miss,
- bool throw_reference_error_if_nonexistent);
+ Label* miss);
// LoadGlobalIC implementation.
@@ -151,7 +164,7 @@ class AccessorAssembler : public CodeStubAssembler {
Node* handler, Label* miss);
void HandleStoreICProtoHandler(const StoreICParameters* p, Node* handler,
- Label* miss);
+ Label* miss, ElementSupport support_elements);
// If |transition| is nullptr then the normal field store is generated or
// transitioning store otherwise.
void HandleStoreICSmiHandlerCase(Node* handler_word, Node* holder,
@@ -167,9 +180,11 @@ class AccessorAssembler : public CodeStubAssembler {
void GenericElementLoad(Node* receiver, Node* receiver_map,
Node* instance_type, Node* index, Label* slow);
+ enum UseStubCache { kUseStubCache, kDontUseStubCache };
void GenericPropertyLoad(Node* receiver, Node* receiver_map,
Node* instance_type, Node* key,
- const LoadICParameters* p, Label* slow);
+ const LoadICParameters* p, Label* slow,
+ UseStubCache use_stub_cache = kUseStubCache);
// Low-level helpers.
diff --git a/deps/v8/src/ic/arm/access-compiler-arm.cc b/deps/v8/src/ic/arm/access-compiler-arm.cc
index e501cdcc8b..627c06c858 100644
--- a/deps/v8/src/ic/arm/access-compiler-arm.cc
+++ b/deps/v8/src/ic/arm/access-compiler-arm.cc
@@ -6,6 +6,8 @@
#include "src/ic/access-compiler.h"
+#include "src/objects-inl.h"
+
namespace v8 {
namespace internal {
diff --git a/deps/v8/src/ic/arm/handler-compiler-arm.cc b/deps/v8/src/ic/arm/handler-compiler-arm.cc
index ebef63ca66..dd99a21219 100644
--- a/deps/v8/src/ic/arm/handler-compiler-arm.cc
+++ b/deps/v8/src/ic/arm/handler-compiler-arm.cc
@@ -7,6 +7,7 @@
#include "src/ic/handler-compiler.h"
#include "src/api-arguments.h"
+#include "src/assembler-inl.h"
#include "src/field-type.h"
#include "src/ic/call-optimization.h"
#include "src/ic/ic.h"
@@ -17,43 +18,13 @@ namespace internal {
#define __ ACCESS_MASM(masm)
-
-void NamedLoadHandlerCompiler::GenerateLoadViaGetter(
- MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder,
- int accessor_index, int expected_arguments, Register scratch) {
- // ----------- S t a t e -------------
- // -- r0 : receiver
- // -- r2 : name
- // -- lr : return address
- // -----------------------------------
+void NamedLoadHandlerCompiler::GenerateLoadViaGetterForDeopt(
+ MacroAssembler* masm) {
{
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
-
- // Save context register
- __ push(cp);
-
- if (accessor_index >= 0) {
- DCHECK(!holder.is(scratch));
- DCHECK(!receiver.is(scratch));
- // Call the JavaScript getter with the receiver on the stack.
- if (map->IsJSGlobalObjectMap()) {
- // Swap in the global receiver.
- __ ldr(scratch,
- FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
- receiver = scratch;
- }
- __ push(receiver);
- __ LoadAccessor(r1, holder, accessor_index, ACCESSOR_GETTER);
- __ mov(r0, Operand(0));
- __ Call(masm->isolate()->builtins()->CallFunction(
- ConvertReceiverMode::kNotNullOrUndefined),
- RelocInfo::CODE_TARGET);
- } else {
- // If we generate a global code snippet for deoptimization only, remember
- // the place to continue after deoptimization.
- masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
- }
-
+ // If we generate a global code snippet for deoptimization only, remember
+ // the place to continue after deoptimization.
+ masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
// Restore context register.
__ pop(cp);
}
@@ -199,24 +170,6 @@ void PropertyHandlerCompiler::GenerateCheckPropertyCell(
__ b(ne, miss);
}
-static void CompileCallLoadPropertyWithInterceptor(
- MacroAssembler* masm, Register receiver, Register holder, Register name,
- Handle<JSObject> holder_obj, Runtime::FunctionId id) {
- DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength ==
- Runtime::FunctionForId(id)->nargs);
-
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
- __ push(name);
- __ push(receiver);
- __ push(holder);
-
- __ CallRuntime(id);
-}
-
-
// Generate call to api function.
void PropertyHandlerCompiler::GenerateApiAccessorCall(
MacroAssembler* masm, const CallOptimization& optimization,
@@ -288,13 +241,6 @@ void PropertyHandlerCompiler::GenerateApiAccessorCall(
__ ldr(data, FieldMemOperand(data, CallHandlerInfo::kDataOffset));
}
- if (api_call_info->fast_handler()->IsCode()) {
- // Just tail call into the fast handler if present.
- __ Jump(handle(Code::cast(api_call_info->fast_handler())),
- RelocInfo::CODE_TARGET);
- return;
- }
-
// Put api_function_address in place.
Address function_address = v8::ToCData<Address>(api_call_info->callback());
ApiFunction fun(function_address);
@@ -347,8 +293,7 @@ void PropertyHandlerCompiler::GenerateAccessCheck(
Register PropertyHandlerCompiler::CheckPrototypes(
Register object_reg, Register holder_reg, Register scratch1,
- Register scratch2, Handle<Name> name, Label* miss,
- ReturnHolder return_what) {
+ Register scratch2, Handle<Name> name, Label* miss) {
Handle<Map> receiver_map = map();
// Make sure there's no overlap between holder and object registers.
@@ -413,15 +358,14 @@ Register PropertyHandlerCompiler::CheckPrototypes(
// Log the check depth.
LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
- bool return_holder = return_what == RETURN_HOLDER;
- if (return_holder && depth != 0) {
+ if (depth != 0) {
Handle<WeakCell> weak_cell =
Map::GetOrCreatePrototypeWeakCell(current, isolate());
__ LoadWeakValue(reg, weak_cell, miss);
}
// Return the register containing the holder.
- return return_holder ? reg : no_reg;
+ return reg;
}
@@ -430,10 +374,8 @@ void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
Label success;
__ b(&success);
__ bind(miss);
- if (IC::ICUseVector(kind())) {
- DCHECK(kind() == Code::LOAD_IC);
- PopVectorAndSlot();
- }
+ DCHECK(kind() == Code::LOAD_IC);
+ PopVectorAndSlot();
TailCallBuiltin(masm(), MissBuiltin(kind()));
__ bind(&success);
}
@@ -445,92 +387,12 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
Label success;
__ b(&success);
GenerateRestoreName(miss, name);
- if (IC::ICUseVector(kind())) PopVectorAndSlot();
+ PopVectorAndSlot();
TailCallBuiltin(masm(), MissBuiltin(kind()));
__ bind(&success);
}
}
-void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
- LookupIterator* it, Register holder_reg) {
- DCHECK(holder()->HasNamedInterceptor());
- DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
-
- // Compile the interceptor call, followed by inline code to load the
- // property from further up the prototype chain if the call fails.
- // Check that the maps haven't changed.
- DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
-
- // Preserve the receiver register explicitly whenever it is different from the
- // holder and it is needed should the interceptor return without any result.
- // The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD
- // case might cause a miss during the prototype check.
- bool must_perform_prototype_check =
- !holder().is_identical_to(it->GetHolder<JSObject>());
- bool must_preserve_receiver_reg =
- !receiver().is(holder_reg) &&
- (it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check);
-
- // Save necessary data before invoking an interceptor.
- // Requires a frame to make GC aware of pushed pointers.
- {
- FrameAndConstantPoolScope frame_scope(masm(), StackFrame::INTERNAL);
- if (must_preserve_receiver_reg) {
- __ Push(receiver(), holder_reg, this->name());
- } else {
- __ Push(holder_reg, this->name());
- }
- InterceptorVectorSlotPush(holder_reg);
- // Invoke an interceptor. Note: map checks from receiver to
- // interceptor's holder has been compiled before (see a caller
- // of this method.)
- CompileCallLoadPropertyWithInterceptor(
- masm(), receiver(), holder_reg, this->name(), holder(),
- Runtime::kLoadPropertyWithInterceptorOnly);
-
- // Check if interceptor provided a value for property. If it's
- // the case, return immediately.
- Label interceptor_failed;
- __ LoadRoot(scratch1(), Heap::kNoInterceptorResultSentinelRootIndex);
- __ cmp(r0, scratch1());
- __ b(eq, &interceptor_failed);
- frame_scope.GenerateLeaveFrame();
- __ Ret();
-
- __ bind(&interceptor_failed);
- InterceptorVectorSlotPop(holder_reg);
- __ pop(this->name());
- __ pop(holder_reg);
- if (must_preserve_receiver_reg) {
- __ pop(receiver());
- }
- // Leave the internal frame.
- }
-
- GenerateLoadPostInterceptor(it, holder_reg);
-}
-
-
-void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
- // Call the runtime system to load the interceptor.
- DCHECK(holder()->HasNamedInterceptor());
- DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
-
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
- __ Push(name(), receiver(), holder_reg);
- // See NamedLoadHandlerCompiler::InterceptorVectorSlotPop() for details.
- if (holder_reg.is(receiver())) {
- __ Push(slot(), vector());
- } else {
- __ Push(scratch3(), scratch2()); // slot, vector
- }
-
- __ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor);
-}
-
void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() {
STATIC_ASSERT(!StoreWithVectorDescriptor::kPassLastArgsOnStack);
}
@@ -569,41 +431,6 @@ Register NamedStoreHandlerCompiler::value() {
}
-Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
- Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) {
- Label miss;
- if (IC::ICUseVector(kind())) {
- PushVectorAndSlot();
- }
- FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING);
-
- // Get the value from the cell.
- Register result = StoreDescriptor::ValueRegister();
- Handle<WeakCell> weak_cell = factory()->NewWeakCell(cell);
- __ LoadWeakValue(result, weak_cell, &miss);
- __ ldr(result, FieldMemOperand(result, PropertyCell::kValueOffset));
-
- // Check for deleted property if property can actually be deleted.
- if (is_configurable) {
- __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
- __ cmp(result, ip);
- __ b(eq, &miss);
- }
-
- Counters* counters = isolate()->counters();
- __ IncrementCounter(counters->ic_named_load_global_stub(), 1, r1, r3);
- if (IC::ICUseVector(kind())) {
- DiscardVectorAndSlot();
- }
- __ Ret();
-
- FrontendFooter(name, &miss);
-
- // Return the generated code.
- return GetCode(kind(), name);
-}
-
-
#undef __
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/ic/arm/ic-arm.cc b/deps/v8/src/ic/arm/ic-arm.cc
index b749027ebe..5cf9dc46ae 100644
--- a/deps/v8/src/ic/arm/ic-arm.cc
+++ b/deps/v8/src/ic/arm/ic-arm.cc
@@ -4,9 +4,11 @@
#if V8_TARGET_ARCH_ARM
+#include "src/assembler-inl.h"
#include "src/codegen.h"
#include "src/ic/ic.h"
#include "src/ic/stub-cache.h"
+#include "src/objects-inl.h"
namespace v8 {
namespace internal {
diff --git a/deps/v8/src/ic/arm64/access-compiler-arm64.cc b/deps/v8/src/ic/arm64/access-compiler-arm64.cc
index 8cbb5278ea..1b58e5c697 100644
--- a/deps/v8/src/ic/arm64/access-compiler-arm64.cc
+++ b/deps/v8/src/ic/arm64/access-compiler-arm64.cc
@@ -5,6 +5,7 @@
#if V8_TARGET_ARCH_ARM64
#include "src/ic/access-compiler.h"
+#include "src/objects-inl.h"
namespace v8 {
namespace internal {
diff --git a/deps/v8/src/ic/arm64/handler-compiler-arm64.cc b/deps/v8/src/ic/arm64/handler-compiler-arm64.cc
index b7dc58974f..68bd393cab 100644
--- a/deps/v8/src/ic/arm64/handler-compiler-arm64.cc
+++ b/deps/v8/src/ic/arm64/handler-compiler-arm64.cc
@@ -7,6 +7,8 @@
#include "src/ic/handler-compiler.h"
#include "src/api-arguments.h"
+#include "src/arm64/assembler-arm64-inl.h"
+#include "src/arm64/macro-assembler-arm64-inl.h"
#include "src/field-type.h"
#include "src/ic/call-optimization.h"
#include "src/ic/ic.h"
@@ -99,22 +101,6 @@ void PropertyHandlerCompiler::GenerateCheckPropertyCell(
__ JumpIfNotRoot(scratch, Heap::kTheHoleValueRootIndex, miss);
}
-static void CompileCallLoadPropertyWithInterceptor(
- MacroAssembler* masm, Register receiver, Register holder, Register name,
- Handle<JSObject> holder_obj, Runtime::FunctionId id) {
- DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength ==
- Runtime::FunctionForId(id)->nargs);
-
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
- __ Push(name, receiver, holder);
-
- __ CallRuntime(id);
-}
-
-
// Generate call to api function.
void PropertyHandlerCompiler::GenerateApiAccessorCall(
MacroAssembler* masm, const CallOptimization& optimization,
@@ -190,13 +176,6 @@ void PropertyHandlerCompiler::GenerateApiAccessorCall(
__ Ldr(data, FieldMemOperand(data, CallHandlerInfo::kDataOffset));
}
- if (api_call_info->fast_handler()->IsCode()) {
- // Just tail call into the fast handler if present.
- __ Jump(handle(Code::cast(api_call_info->fast_handler())),
- RelocInfo::CODE_TARGET);
- return;
- }
-
// Put api_function_address in place.
Address function_address = v8::ToCData<Address>(api_call_info->callback());
ApiFunction fun(function_address);
@@ -258,38 +237,13 @@ void NamedStoreHandlerCompiler::GenerateStoreViaSetter(
__ Ret();
}
-
-void NamedLoadHandlerCompiler::GenerateLoadViaGetter(
- MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder,
- int accessor_index, int expected_arguments, Register scratch) {
+void NamedLoadHandlerCompiler::GenerateLoadViaGetterForDeopt(
+ MacroAssembler* masm) {
{
FrameScope scope(masm, StackFrame::INTERNAL);
-
- // Save context register
- __ Push(cp);
-
- if (accessor_index >= 0) {
- DCHECK(!AreAliased(holder, scratch));
- DCHECK(!AreAliased(receiver, scratch));
- // Call the JavaScript getter with the receiver on the stack.
- if (map->IsJSGlobalObjectMap()) {
- // Swap in the global receiver.
- __ Ldr(scratch,
- FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
- receiver = scratch;
- }
- __ Push(receiver);
- __ LoadAccessor(x1, holder, accessor_index, ACCESSOR_GETTER);
- __ Mov(x0, 0);
- __ Call(masm->isolate()->builtins()->CallFunction(
- ConvertReceiverMode::kNotNullOrUndefined),
- RelocInfo::CODE_TARGET);
- } else {
- // If we generate a global code snippet for deoptimization only, remember
- // the place to continue after deoptimization.
- masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
- }
-
+ // If we generate a global code snippet for deoptimization only, remember
+ // the place to continue after deoptimization.
+ masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
// Restore context register.
__ Pop(cp);
}
@@ -300,39 +254,6 @@ void NamedLoadHandlerCompiler::GenerateLoadViaGetter(
#define __ ACCESS_MASM(masm())
-Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
- Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) {
- Label miss;
- if (IC::ICUseVector(kind())) {
- PushVectorAndSlot();
- }
- FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING);
-
- // Get the value from the cell.
- Register result = StoreDescriptor::ValueRegister();
- Handle<WeakCell> weak_cell = factory()->NewWeakCell(cell);
- __ LoadWeakValue(result, weak_cell, &miss);
- __ Ldr(result, FieldMemOperand(result, PropertyCell::kValueOffset));
-
- // Check for deleted property if property can actually be deleted.
- if (is_configurable) {
- __ JumpIfRoot(result, Heap::kTheHoleValueRootIndex, &miss);
- }
-
- Counters* counters = isolate()->counters();
- __ IncrementCounter(counters->ic_named_load_global_stub(), 1, x1, x3);
- if (IC::ICUseVector(kind())) {
- DiscardVectorAndSlot();
- }
- __ Ret();
-
- FrontendFooter(name, &miss);
-
- // Return the generated code.
- return GetCode(kind(), name);
-}
-
-
Register NamedStoreHandlerCompiler::value() {
return StoreDescriptor::ValueRegister();
}
@@ -373,8 +294,7 @@ void PropertyHandlerCompiler::GenerateAccessCheck(
Register PropertyHandlerCompiler::CheckPrototypes(
Register object_reg, Register holder_reg, Register scratch1,
- Register scratch2, Handle<Name> name, Label* miss,
- ReturnHolder return_what) {
+ Register scratch2, Handle<Name> name, Label* miss) {
Handle<Map> receiver_map = map();
// object_reg and holder_reg registers can alias.
@@ -439,15 +359,14 @@ Register PropertyHandlerCompiler::CheckPrototypes(
// Log the check depth.
LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
- bool return_holder = return_what == RETURN_HOLDER;
- if (return_holder && depth != 0) {
+ if (depth != 0) {
Handle<WeakCell> weak_cell =
Map::GetOrCreatePrototypeWeakCell(current, isolate());
__ LoadWeakValue(reg, weak_cell, miss);
}
// Return the register containing the holder.
- return return_holder ? reg : no_reg;
+ return reg;
}
@@ -457,10 +376,8 @@ void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
__ B(&success);
__ Bind(miss);
- if (IC::ICUseVector(kind())) {
- DCHECK(kind() == Code::LOAD_IC);
- PopVectorAndSlot();
- }
+ DCHECK(kind() == Code::LOAD_IC);
+ PopVectorAndSlot();
TailCallBuiltin(masm(), MissBuiltin(kind()));
__ Bind(&success);
@@ -474,94 +391,13 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
__ B(&success);
GenerateRestoreName(miss, name);
- if (IC::ICUseVector(kind())) PopVectorAndSlot();
+ PopVectorAndSlot();
TailCallBuiltin(masm(), MissBuiltin(kind()));
__ Bind(&success);
}
}
-void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
- LookupIterator* it, Register holder_reg) {
- DCHECK(!AreAliased(receiver(), this->name(), scratch1(), scratch2(),
- scratch3()));
- DCHECK(holder()->HasNamedInterceptor());
- DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
-
- // Compile the interceptor call, followed by inline code to load the
- // property from further up the prototype chain if the call fails.
- // Check that the maps haven't changed.
- DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
-
- // Preserve the receiver register explicitly whenever it is different from the
- // holder and it is needed should the interceptor return without any result.
- // The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD
- // case might cause a miss during the prototype check.
- bool must_perform_prototype_check =
- !holder().is_identical_to(it->GetHolder<JSObject>());
- bool must_preserve_receiver_reg =
- !receiver().is(holder_reg) &&
- (it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check);
-
- // Save necessary data before invoking an interceptor.
- // Requires a frame to make GC aware of pushed pointers.
- {
- FrameScope frame_scope(masm(), StackFrame::INTERNAL);
- if (must_preserve_receiver_reg) {
- __ Push(receiver(), holder_reg, this->name());
- } else {
- __ Push(holder_reg, this->name());
- }
- InterceptorVectorSlotPush(holder_reg);
- // Invoke an interceptor. Note: map checks from receiver to
- // interceptor's holder has been compiled before (see a caller
- // of this method.)
- CompileCallLoadPropertyWithInterceptor(
- masm(), receiver(), holder_reg, this->name(), holder(),
- Runtime::kLoadPropertyWithInterceptorOnly);
-
- // Check if interceptor provided a value for property. If it's
- // the case, return immediately.
- Label interceptor_failed;
- __ JumpIfRoot(x0, Heap::kNoInterceptorResultSentinelRootIndex,
- &interceptor_failed);
- frame_scope.GenerateLeaveFrame();
- __ Ret();
-
- __ Bind(&interceptor_failed);
- InterceptorVectorSlotPop(holder_reg);
- if (must_preserve_receiver_reg) {
- __ Pop(this->name(), holder_reg, receiver());
- } else {
- __ Pop(this->name(), holder_reg);
- }
- // Leave the internal frame.
- }
-
- GenerateLoadPostInterceptor(it, holder_reg);
-}
-
-
-void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
- // Call the runtime system to load the interceptor.
- DCHECK(holder()->HasNamedInterceptor());
- DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
-
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
- __ Push(name(), receiver(), holder_reg);
- // See NamedLoadHandlerCompiler::InterceptorVectorSlotPop() for details.
- if (holder_reg.is(receiver())) {
- __ Push(slot(), vector());
- } else {
- __ Push(scratch3(), scratch2()); // slot, vector
- }
-
- __ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor);
-}
-
void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() {
STATIC_ASSERT(!StoreWithVectorDescriptor::kPassLastArgsOnStack);
}
diff --git a/deps/v8/src/ic/arm64/ic-arm64.cc b/deps/v8/src/ic/arm64/ic-arm64.cc
index 8c7d4f2241..f77bb8af5b 100644
--- a/deps/v8/src/ic/arm64/ic-arm64.cc
+++ b/deps/v8/src/ic/arm64/ic-arm64.cc
@@ -4,9 +4,11 @@
#if V8_TARGET_ARCH_ARM64
+#include "src/arm64/assembler-arm64-inl.h"
#include "src/codegen.h"
#include "src/ic/ic.h"
#include "src/ic/stub-cache.h"
+#include "src/objects-inl.h"
namespace v8 {
namespace internal {
@@ -69,7 +71,7 @@ void PatchInlinedSmiCode(Isolate* isolate, Address address,
// to
// tb(!n)z test_reg, #0, <target>
Instruction* to_patch = info.SmiCheck();
- PatchingAssembler patcher(isolate, to_patch, 1);
+ PatchingAssembler patcher(isolate, reinterpret_cast<byte*>(to_patch), 1);
DCHECK(to_patch->IsTestBranch());
DCHECK(to_patch->ImmTestBranchBit5() == 0);
DCHECK(to_patch->ImmTestBranchBit40() == 0);
diff --git a/deps/v8/src/ic/binary-op-assembler.cc b/deps/v8/src/ic/binary-op-assembler.cc
new file mode 100644
index 0000000000..29df4bf082
--- /dev/null
+++ b/deps/v8/src/ic/binary-op-assembler.cc
@@ -0,0 +1,827 @@
+// Copyright 2016 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/ic/binary-op-assembler.h"
+
+#include "src/globals.h"
+
+namespace v8 {
+namespace internal {
+
+using compiler::Node;
+
+Node* BinaryOpAssembler::Generate_AddWithFeedback(Node* context, Node* lhs,
+ Node* rhs, Node* slot_id,
+ Node* feedback_vector) {
+ // Shared entry for floating point addition.
+ Label do_fadd(this), if_lhsisnotnumber(this, Label::kDeferred),
+ check_rhsisoddball(this, Label::kDeferred),
+ call_with_oddball_feedback(this), call_with_any_feedback(this),
+ call_add_stub(this), end(this);
+ VARIABLE(var_fadd_lhs, MachineRepresentation::kFloat64);
+ VARIABLE(var_fadd_rhs, MachineRepresentation::kFloat64);
+ VARIABLE(var_type_feedback, MachineRepresentation::kTaggedSigned);
+ VARIABLE(var_result, MachineRepresentation::kTagged);
+
+ // Check if the {lhs} is a Smi or a HeapObject.
+ Label if_lhsissmi(this), if_lhsisnotsmi(this);
+ Branch(TaggedIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi);
+
+ BIND(&if_lhsissmi);
+ {
+ // Check if the {rhs} is also a Smi.
+ Label if_rhsissmi(this), if_rhsisnotsmi(this);
+ Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi);
+
+ BIND(&if_rhsissmi);
+ {
+ // Try fast Smi addition first.
+ Node* pair = IntPtrAddWithOverflow(BitcastTaggedToWord(lhs),
+ BitcastTaggedToWord(rhs));
+ Node* overflow = Projection(1, pair);
+
+ // Check if the Smi additon overflowed.
+ Label if_overflow(this), if_notoverflow(this);
+ Branch(overflow, &if_overflow, &if_notoverflow);
+
+ BIND(&if_overflow);
+ {
+ var_fadd_lhs.Bind(SmiToFloat64(lhs));
+ var_fadd_rhs.Bind(SmiToFloat64(rhs));
+ Goto(&do_fadd);
+ }
+
+ BIND(&if_notoverflow);
+ {
+ var_type_feedback.Bind(
+ SmiConstant(BinaryOperationFeedback::kSignedSmall));
+ var_result.Bind(BitcastWordToTaggedSigned(Projection(0, pair)));
+ Goto(&end);
+ }
+ }
+
+ BIND(&if_rhsisnotsmi);
+ {
+ // Load the map of {rhs}.
+ Node* rhs_map = LoadMap(rhs);
+
+ // Check if the {rhs} is a HeapNumber.
+ GotoIfNot(IsHeapNumberMap(rhs_map), &check_rhsisoddball);
+
+ var_fadd_lhs.Bind(SmiToFloat64(lhs));
+ var_fadd_rhs.Bind(LoadHeapNumberValue(rhs));
+ Goto(&do_fadd);
+ }
+ }
+
+ BIND(&if_lhsisnotsmi);
+ {
+ // Load the map of {lhs}.
+ Node* lhs_map = LoadMap(lhs);
+
+ // Check if {lhs} is a HeapNumber.
+ GotoIfNot(IsHeapNumberMap(lhs_map), &if_lhsisnotnumber);
+
+ // Check if the {rhs} is Smi.
+ Label if_rhsissmi(this), if_rhsisnotsmi(this);
+ Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi);
+
+ BIND(&if_rhsissmi);
+ {
+ var_fadd_lhs.Bind(LoadHeapNumberValue(lhs));
+ var_fadd_rhs.Bind(SmiToFloat64(rhs));
+ Goto(&do_fadd);
+ }
+
+ BIND(&if_rhsisnotsmi);
+ {
+ // Load the map of {rhs}.
+ Node* rhs_map = LoadMap(rhs);
+
+ // Check if the {rhs} is a HeapNumber.
+ GotoIfNot(IsHeapNumberMap(rhs_map), &check_rhsisoddball);
+
+ var_fadd_lhs.Bind(LoadHeapNumberValue(lhs));
+ var_fadd_rhs.Bind(LoadHeapNumberValue(rhs));
+ Goto(&do_fadd);
+ }
+ }
+
+ BIND(&do_fadd);
+ {
+ var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kNumber));
+ Node* value = Float64Add(var_fadd_lhs.value(), var_fadd_rhs.value());
+ Node* result = AllocateHeapNumberWithValue(value);
+ var_result.Bind(result);
+ Goto(&end);
+ }
+
+ BIND(&if_lhsisnotnumber);
+ {
+ // No checks on rhs are done yet. We just know lhs is not a number or Smi.
+ Label if_lhsisoddball(this), if_lhsisnotoddball(this);
+ Node* lhs_instance_type = LoadInstanceType(lhs);
+ Node* lhs_is_oddball =
+ Word32Equal(lhs_instance_type, Int32Constant(ODDBALL_TYPE));
+ Branch(lhs_is_oddball, &if_lhsisoddball, &if_lhsisnotoddball);
+
+ BIND(&if_lhsisoddball);
+ {
+ GotoIf(TaggedIsSmi(rhs), &call_with_oddball_feedback);
+
+ // Load the map of the {rhs}.
+ Node* rhs_map = LoadMap(rhs);
+
+ // Check if {rhs} is a HeapNumber.
+ Branch(IsHeapNumberMap(rhs_map), &call_with_oddball_feedback,
+ &check_rhsisoddball);
+ }
+
+ BIND(&if_lhsisnotoddball);
+ {
+ // Exit unless {lhs} is a string
+ GotoIfNot(IsStringInstanceType(lhs_instance_type),
+ &call_with_any_feedback);
+
+ // Check if the {rhs} is a smi, and exit the string check early if it is.
+ GotoIf(TaggedIsSmi(rhs), &call_with_any_feedback);
+
+ Node* rhs_instance_type = LoadInstanceType(rhs);
+
+ // Exit unless {rhs} is a string. Since {lhs} is a string we no longer
+ // need an Oddball check.
+ GotoIfNot(IsStringInstanceType(rhs_instance_type),
+ &call_with_any_feedback);
+
+ var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kString));
+ Callable callable =
+ CodeFactory::StringAdd(isolate(), STRING_ADD_CHECK_NONE, NOT_TENURED);
+ var_result.Bind(CallStub(callable, context, lhs, rhs));
+
+ Goto(&end);
+ }
+ }
+
+ BIND(&check_rhsisoddball);
+ {
+ // Check if rhs is an oddball. At this point we know lhs is either a
+ // Smi or number or oddball and rhs is not a number or Smi.
+ Node* rhs_instance_type = LoadInstanceType(rhs);
+ Node* rhs_is_oddball =
+ Word32Equal(rhs_instance_type, Int32Constant(ODDBALL_TYPE));
+ Branch(rhs_is_oddball, &call_with_oddball_feedback,
+ &call_with_any_feedback);
+ }
+
+ BIND(&call_with_oddball_feedback);
+ {
+ var_type_feedback.Bind(
+ SmiConstant(BinaryOperationFeedback::kNumberOrOddball));
+ Goto(&call_add_stub);
+ }
+
+ BIND(&call_with_any_feedback);
+ {
+ var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kAny));
+ Goto(&call_add_stub);
+ }
+
+ BIND(&call_add_stub);
+ {
+ Callable callable = CodeFactory::Add(isolate());
+ var_result.Bind(CallStub(callable, context, lhs, rhs));
+ Goto(&end);
+ }
+
+ BIND(&end);
+ UpdateFeedback(var_type_feedback.value(), feedback_vector, slot_id);
+ return var_result.value();
+}
+
+Node* BinaryOpAssembler::Generate_SubtractWithFeedback(Node* context, Node* lhs,
+ Node* rhs, Node* slot_id,
+ Node* feedback_vector) {
+ // Shared entry for floating point subtraction.
+ Label do_fsub(this), end(this), call_subtract_stub(this),
+ if_lhsisnotnumber(this), check_rhsisoddball(this),
+ call_with_any_feedback(this);
+ VARIABLE(var_fsub_lhs, MachineRepresentation::kFloat64);
+ VARIABLE(var_fsub_rhs, MachineRepresentation::kFloat64);
+ VARIABLE(var_type_feedback, MachineRepresentation::kTaggedSigned);
+ VARIABLE(var_result, MachineRepresentation::kTagged);
+
+ // Check if the {lhs} is a Smi or a HeapObject.
+ Label if_lhsissmi(this), if_lhsisnotsmi(this);
+ Branch(TaggedIsSmi(lhs), &if_lhsissmi, &if_lhsisnotsmi);
+
+ BIND(&if_lhsissmi);
+ {
+ // Check if the {rhs} is also a Smi.
+ Label if_rhsissmi(this), if_rhsisnotsmi(this);
+ Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi);
+
+ BIND(&if_rhsissmi);
+ {
+ // Try a fast Smi subtraction first.
+ Node* pair = IntPtrSubWithOverflow(BitcastTaggedToWord(lhs),
+ BitcastTaggedToWord(rhs));
+ Node* overflow = Projection(1, pair);
+
+ // Check if the Smi subtraction overflowed.
+ Label if_overflow(this), if_notoverflow(this);
+ Branch(overflow, &if_overflow, &if_notoverflow);
+
+ BIND(&if_overflow);
+ {
+ // lhs, rhs - smi and result - number. combined - number.
+ // The result doesn't fit into Smi range.
+ var_fsub_lhs.Bind(SmiToFloat64(lhs));
+ var_fsub_rhs.Bind(SmiToFloat64(rhs));
+ Goto(&do_fsub);
+ }
+
+ BIND(&if_notoverflow);
+ // lhs, rhs, result smi. combined - smi.
+ var_type_feedback.Bind(
+ SmiConstant(BinaryOperationFeedback::kSignedSmall));
+ var_result.Bind(BitcastWordToTaggedSigned(Projection(0, pair)));
+ Goto(&end);
+ }
+
+ BIND(&if_rhsisnotsmi);
+ {
+ // Load the map of the {rhs}.
+ Node* rhs_map = LoadMap(rhs);
+
+ // Check if {rhs} is a HeapNumber.
+ GotoIfNot(IsHeapNumberMap(rhs_map), &check_rhsisoddball);
+
+ // Perform a floating point subtraction.
+ var_fsub_lhs.Bind(SmiToFloat64(lhs));
+ var_fsub_rhs.Bind(LoadHeapNumberValue(rhs));
+ Goto(&do_fsub);
+ }
+ }
+
+ BIND(&if_lhsisnotsmi);
+ {
+ // Load the map of the {lhs}.
+ Node* lhs_map = LoadMap(lhs);
+
+ // Check if the {lhs} is a HeapNumber.
+ GotoIfNot(IsHeapNumberMap(lhs_map), &if_lhsisnotnumber);
+
+ // Check if the {rhs} is a Smi.
+ Label if_rhsissmi(this), if_rhsisnotsmi(this);
+ Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi);
+
+ BIND(&if_rhsissmi);
+ {
+ // Perform a floating point subtraction.
+ var_fsub_lhs.Bind(LoadHeapNumberValue(lhs));
+ var_fsub_rhs.Bind(SmiToFloat64(rhs));
+ Goto(&do_fsub);
+ }
+
+ BIND(&if_rhsisnotsmi);
+ {
+ // Load the map of the {rhs}.
+ Node* rhs_map = LoadMap(rhs);
+
+ // Check if the {rhs} is a HeapNumber.
+ GotoIfNot(IsHeapNumberMap(rhs_map), &check_rhsisoddball);
+
+ // Perform a floating point subtraction.
+ var_fsub_lhs.Bind(LoadHeapNumberValue(lhs));
+ var_fsub_rhs.Bind(LoadHeapNumberValue(rhs));
+ Goto(&do_fsub);
+ }
+ }
+
+ BIND(&do_fsub);
+ {
+ var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kNumber));
+ Node* lhs_value = var_fsub_lhs.value();
+ Node* rhs_value = var_fsub_rhs.value();
+ Node* value = Float64Sub(lhs_value, rhs_value);
+ var_result.Bind(AllocateHeapNumberWithValue(value));
+ Goto(&end);
+ }
+
+ BIND(&if_lhsisnotnumber);
+ {
+ // No checks on rhs are done yet. We just know lhs is not a number or Smi.
+ // Check if lhs is an oddball.
+ Node* lhs_instance_type = LoadInstanceType(lhs);
+ Node* lhs_is_oddball =
+ Word32Equal(lhs_instance_type, Int32Constant(ODDBALL_TYPE));
+ GotoIfNot(lhs_is_oddball, &call_with_any_feedback);
+
+ Label if_rhsissmi(this), if_rhsisnotsmi(this);
+ Branch(TaggedIsSmi(rhs), &if_rhsissmi, &if_rhsisnotsmi);
+
+ BIND(&if_rhsissmi);
+ {
+ var_type_feedback.Bind(
+ SmiConstant(BinaryOperationFeedback::kNumberOrOddball));
+ Goto(&call_subtract_stub);
+ }
+
+ BIND(&if_rhsisnotsmi);
+ {
+ // Load the map of the {rhs}.
+ Node* rhs_map = LoadMap(rhs);
+
+ // Check if {rhs} is a HeapNumber.
+ GotoIfNot(IsHeapNumberMap(rhs_map), &check_rhsisoddball);
+
+ var_type_feedback.Bind(
+ SmiConstant(BinaryOperationFeedback::kNumberOrOddball));
+ Goto(&call_subtract_stub);
+ }
+ }
+
+ BIND(&check_rhsisoddball);
+ {
+ // Check if rhs is an oddball. At this point we know lhs is either a
+ // Smi or number or oddball and rhs is not a number or Smi.
+ Node* rhs_instance_type = LoadInstanceType(rhs);
+ Node* rhs_is_oddball =
+ Word32Equal(rhs_instance_type, Int32Constant(ODDBALL_TYPE));
+ GotoIfNot(rhs_is_oddball, &call_with_any_feedback);
+
+ var_type_feedback.Bind(
+ SmiConstant(BinaryOperationFeedback::kNumberOrOddball));
+ Goto(&call_subtract_stub);
+ }
+
+ BIND(&call_with_any_feedback);
+ {
+ var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kAny));
+ Goto(&call_subtract_stub);
+ }
+
+ BIND(&call_subtract_stub);
+ {
+ Callable callable = CodeFactory::Subtract(isolate());
+ var_result.Bind(CallStub(callable, context, lhs, rhs));
+ Goto(&end);
+ }
+
+ BIND(&end);
+ UpdateFeedback(var_type_feedback.value(), feedback_vector, slot_id);
+ return var_result.value();
+}
+
+Node* BinaryOpAssembler::Generate_MultiplyWithFeedback(Node* context, Node* lhs,
+ Node* rhs, Node* slot_id,
+ Node* feedback_vector) {
+ // Shared entry point for floating point multiplication.
+ Label do_fmul(this), if_lhsisnotnumber(this, Label::kDeferred),
+ check_rhsisoddball(this, Label::kDeferred),
+ call_with_oddball_feedback(this), call_with_any_feedback(this),
+ call_multiply_stub(this), end(this);
+ VARIABLE(var_lhs_float64, MachineRepresentation::kFloat64);
+ VARIABLE(var_rhs_float64, MachineRepresentation::kFloat64);
+ VARIABLE(var_result, MachineRepresentation::kTagged);
+ VARIABLE(var_type_feedback, MachineRepresentation::kTaggedSigned);
+
+ Label lhs_is_smi(this), lhs_is_not_smi(this);
+ Branch(TaggedIsSmi(lhs), &lhs_is_smi, &lhs_is_not_smi);
+
+ BIND(&lhs_is_smi);
+ {
+ Label rhs_is_smi(this), rhs_is_not_smi(this);
+ Branch(TaggedIsSmi(rhs), &rhs_is_smi, &rhs_is_not_smi);
+
+ BIND(&rhs_is_smi);
+ {
+ // Both {lhs} and {rhs} are Smis. The result is not necessarily a smi,
+ // in case of overflow.
+ var_result.Bind(SmiMul(lhs, rhs));
+ var_type_feedback.Bind(
+ SelectSmiConstant(TaggedIsSmi(var_result.value()),
+ BinaryOperationFeedback::kSignedSmall,
+ BinaryOperationFeedback::kNumber));
+ Goto(&end);
+ }
+
+ BIND(&rhs_is_not_smi);
+ {
+ Node* rhs_map = LoadMap(rhs);
+
+ // Check if {rhs} is a HeapNumber.
+ GotoIfNot(IsHeapNumberMap(rhs_map), &check_rhsisoddball);
+
+ // Convert {lhs} to a double and multiply it with the value of {rhs}.
+ var_lhs_float64.Bind(SmiToFloat64(lhs));
+ var_rhs_float64.Bind(LoadHeapNumberValue(rhs));
+ Goto(&do_fmul);
+ }
+ }
+
+ BIND(&lhs_is_not_smi);
+ {
+ Node* lhs_map = LoadMap(lhs);
+
+ // Check if {lhs} is a HeapNumber.
+ GotoIfNot(IsHeapNumberMap(lhs_map), &if_lhsisnotnumber);
+
+ // Check if {rhs} is a Smi.
+ Label rhs_is_smi(this), rhs_is_not_smi(this);
+ Branch(TaggedIsSmi(rhs), &rhs_is_smi, &rhs_is_not_smi);
+
+ BIND(&rhs_is_smi);
+ {
+ // Convert {rhs} to a double and multiply it with the value of {lhs}.
+ var_lhs_float64.Bind(LoadHeapNumberValue(lhs));
+ var_rhs_float64.Bind(SmiToFloat64(rhs));
+ Goto(&do_fmul);
+ }
+
+ BIND(&rhs_is_not_smi);
+ {
+ Node* rhs_map = LoadMap(rhs);
+
+ // Check if {rhs} is a HeapNumber.
+ GotoIfNot(IsHeapNumberMap(rhs_map), &check_rhsisoddball);
+
+ // Both {lhs} and {rhs} are HeapNumbers. Load their values and
+ // multiply them.
+ var_lhs_float64.Bind(LoadHeapNumberValue(lhs));
+ var_rhs_float64.Bind(LoadHeapNumberValue(rhs));
+ Goto(&do_fmul);
+ }
+ }
+
+ BIND(&do_fmul);
+ {
+ var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kNumber));
+ Node* value = Float64Mul(var_lhs_float64.value(), var_rhs_float64.value());
+ Node* result = AllocateHeapNumberWithValue(value);
+ var_result.Bind(result);
+ Goto(&end);
+ }
+
+ BIND(&if_lhsisnotnumber);
+ {
+ // No checks on rhs are done yet. We just know lhs is not a number or Smi.
+ // Check if lhs is an oddball.
+ Node* lhs_instance_type = LoadInstanceType(lhs);
+ Node* lhs_is_oddball =
+ Word32Equal(lhs_instance_type, Int32Constant(ODDBALL_TYPE));
+ GotoIfNot(lhs_is_oddball, &call_with_any_feedback);
+
+ GotoIf(TaggedIsSmi(rhs), &call_with_oddball_feedback);
+
+ // Load the map of the {rhs}.
+ Node* rhs_map = LoadMap(rhs);
+
+ // Check if {rhs} is a HeapNumber.
+ Branch(IsHeapNumberMap(rhs_map), &call_with_oddball_feedback,
+ &check_rhsisoddball);
+ }
+
+ BIND(&check_rhsisoddball);
+ {
+ // Check if rhs is an oddball. At this point we know lhs is either a
+ // Smi or number or oddball and rhs is not a number or Smi.
+ Node* rhs_instance_type = LoadInstanceType(rhs);
+ Node* rhs_is_oddball =
+ Word32Equal(rhs_instance_type, Int32Constant(ODDBALL_TYPE));
+ Branch(rhs_is_oddball, &call_with_oddball_feedback,
+ &call_with_any_feedback);
+ }
+
+ BIND(&call_with_oddball_feedback);
+ {
+ var_type_feedback.Bind(
+ SmiConstant(BinaryOperationFeedback::kNumberOrOddball));
+ Goto(&call_multiply_stub);
+ }
+
+ BIND(&call_with_any_feedback);
+ {
+ var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kAny));
+ Goto(&call_multiply_stub);
+ }
+
+ BIND(&call_multiply_stub);
+ {
+ Callable callable = CodeFactory::Multiply(isolate());
+ var_result.Bind(CallStub(callable, context, lhs, rhs));
+ Goto(&end);
+ }
+
+ BIND(&end);
+ UpdateFeedback(var_type_feedback.value(), feedback_vector, slot_id);
+ return var_result.value();
+}
+
+Node* BinaryOpAssembler::Generate_DivideWithFeedback(Node* context,
+ Node* dividend,
+ Node* divisor,
+ Node* slot_id,
+ Node* feedback_vector) {
+ // Shared entry point for floating point division.
+ Label do_fdiv(this), dividend_is_not_number(this, Label::kDeferred),
+ check_divisor_for_oddball(this, Label::kDeferred),
+ call_with_oddball_feedback(this), call_with_any_feedback(this),
+ call_divide_stub(this), end(this);
+ VARIABLE(var_dividend_float64, MachineRepresentation::kFloat64);
+ VARIABLE(var_divisor_float64, MachineRepresentation::kFloat64);
+ VARIABLE(var_result, MachineRepresentation::kTagged);
+ VARIABLE(var_type_feedback, MachineRepresentation::kTaggedSigned);
+
+ Label dividend_is_smi(this), dividend_is_not_smi(this);
+ Branch(TaggedIsSmi(dividend), &dividend_is_smi, &dividend_is_not_smi);
+
+ BIND(&dividend_is_smi);
+ {
+ Label divisor_is_smi(this), divisor_is_not_smi(this);
+ Branch(TaggedIsSmi(divisor), &divisor_is_smi, &divisor_is_not_smi);
+
+ BIND(&divisor_is_smi);
+ {
+ Label bailout(this);
+
+ // Try to perform Smi division if possible.
+ var_result.Bind(TrySmiDiv(dividend, divisor, &bailout));
+ var_type_feedback.Bind(
+ SmiConstant(BinaryOperationFeedback::kSignedSmall));
+ Goto(&end);
+
+ // Bailout: convert {dividend} and {divisor} to double and do double
+ // division.
+ BIND(&bailout);
+ {
+ var_dividend_float64.Bind(SmiToFloat64(dividend));
+ var_divisor_float64.Bind(SmiToFloat64(divisor));
+ Goto(&do_fdiv);
+ }
+ }
+
+ BIND(&divisor_is_not_smi);
+ {
+ Node* divisor_map = LoadMap(divisor);
+
+ // Check if {divisor} is a HeapNumber.
+ GotoIfNot(IsHeapNumberMap(divisor_map), &check_divisor_for_oddball);
+
+ // Convert {dividend} to a double and divide it with the value of
+ // {divisor}.
+ var_dividend_float64.Bind(SmiToFloat64(dividend));
+ var_divisor_float64.Bind(LoadHeapNumberValue(divisor));
+ Goto(&do_fdiv);
+ }
+
+ BIND(&dividend_is_not_smi);
+ {
+ Node* dividend_map = LoadMap(dividend);
+
+ // Check if {dividend} is a HeapNumber.
+ GotoIfNot(IsHeapNumberMap(dividend_map), &dividend_is_not_number);
+
+ // Check if {divisor} is a Smi.
+ Label divisor_is_smi(this), divisor_is_not_smi(this);
+ Branch(TaggedIsSmi(divisor), &divisor_is_smi, &divisor_is_not_smi);
+
+ BIND(&divisor_is_smi);
+ {
+ // Convert {divisor} to a double and use it for a floating point
+ // division.
+ var_dividend_float64.Bind(LoadHeapNumberValue(dividend));
+ var_divisor_float64.Bind(SmiToFloat64(divisor));
+ Goto(&do_fdiv);
+ }
+
+ BIND(&divisor_is_not_smi);
+ {
+ Node* divisor_map = LoadMap(divisor);
+
+ // Check if {divisor} is a HeapNumber.
+ GotoIfNot(IsHeapNumberMap(divisor_map), &check_divisor_for_oddball);
+
+ // Both {dividend} and {divisor} are HeapNumbers. Load their values
+ // and divide them.
+ var_dividend_float64.Bind(LoadHeapNumberValue(dividend));
+ var_divisor_float64.Bind(LoadHeapNumberValue(divisor));
+ Goto(&do_fdiv);
+ }
+ }
+ }
+
+ BIND(&do_fdiv);
+ {
+ var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kNumber));
+ Node* value =
+ Float64Div(var_dividend_float64.value(), var_divisor_float64.value());
+ var_result.Bind(AllocateHeapNumberWithValue(value));
+ Goto(&end);
+ }
+
+ BIND(&dividend_is_not_number);
+ {
+ // We just know dividend is not a number or Smi. No checks on divisor yet.
+ // Check if dividend is an oddball.
+ Node* dividend_instance_type = LoadInstanceType(dividend);
+ Node* dividend_is_oddball =
+ Word32Equal(dividend_instance_type, Int32Constant(ODDBALL_TYPE));
+ GotoIfNot(dividend_is_oddball, &call_with_any_feedback);
+
+ GotoIf(TaggedIsSmi(divisor), &call_with_oddball_feedback);
+
+ // Load the map of the {divisor}.
+ Node* divisor_map = LoadMap(divisor);
+
+ // Check if {divisor} is a HeapNumber.
+ Branch(IsHeapNumberMap(divisor_map), &call_with_oddball_feedback,
+ &check_divisor_for_oddball);
+ }
+
+ BIND(&check_divisor_for_oddball);
+ {
+ // Check if divisor is an oddball. At this point we know dividend is either
+ // a Smi or number or oddball and divisor is not a number or Smi.
+ Node* divisor_instance_type = LoadInstanceType(divisor);
+ Node* divisor_is_oddball =
+ Word32Equal(divisor_instance_type, Int32Constant(ODDBALL_TYPE));
+ Branch(divisor_is_oddball, &call_with_oddball_feedback,
+ &call_with_any_feedback);
+ }
+
+ BIND(&call_with_oddball_feedback);
+ {
+ var_type_feedback.Bind(
+ SmiConstant(BinaryOperationFeedback::kNumberOrOddball));
+ Goto(&call_divide_stub);
+ }
+
+ BIND(&call_with_any_feedback);
+ {
+ var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kAny));
+ Goto(&call_divide_stub);
+ }
+
+ BIND(&call_divide_stub);
+ {
+ Callable callable = CodeFactory::Divide(isolate());
+ var_result.Bind(CallStub(callable, context, dividend, divisor));
+ Goto(&end);
+ }
+
+ BIND(&end);
+ UpdateFeedback(var_type_feedback.value(), feedback_vector, slot_id);
+ return var_result.value();
+}
+
+Node* BinaryOpAssembler::Generate_ModulusWithFeedback(Node* context,
+ Node* dividend,
+ Node* divisor,
+ Node* slot_id,
+ Node* feedback_vector) {
+ // Shared entry point for floating point division.
+ Label do_fmod(this), dividend_is_not_number(this, Label::kDeferred),
+ check_divisor_for_oddball(this, Label::kDeferred),
+ call_with_oddball_feedback(this), call_with_any_feedback(this),
+ call_modulus_stub(this), end(this);
+ VARIABLE(var_dividend_float64, MachineRepresentation::kFloat64);
+ VARIABLE(var_divisor_float64, MachineRepresentation::kFloat64);
+ VARIABLE(var_result, MachineRepresentation::kTagged);
+ VARIABLE(var_type_feedback, MachineRepresentation::kTaggedSigned);
+
+ Label dividend_is_smi(this), dividend_is_not_smi(this);
+ Branch(TaggedIsSmi(dividend), &dividend_is_smi, &dividend_is_not_smi);
+
+ BIND(&dividend_is_smi);
+ {
+ Label divisor_is_smi(this), divisor_is_not_smi(this);
+ Branch(TaggedIsSmi(divisor), &divisor_is_smi, &divisor_is_not_smi);
+
+ BIND(&divisor_is_smi);
+ {
+ var_result.Bind(SmiMod(dividend, divisor));
+ var_type_feedback.Bind(
+ SelectSmiConstant(TaggedIsSmi(var_result.value()),
+ BinaryOperationFeedback::kSignedSmall,
+ BinaryOperationFeedback::kNumber));
+ Goto(&end);
+ }
+
+ BIND(&divisor_is_not_smi);
+ {
+ Node* divisor_map = LoadMap(divisor);
+
+ // Check if {divisor} is a HeapNumber.
+ GotoIfNot(IsHeapNumberMap(divisor_map), &check_divisor_for_oddball);
+
+ // Convert {dividend} to a double and divide it with the value of
+ // {divisor}.
+ var_dividend_float64.Bind(SmiToFloat64(dividend));
+ var_divisor_float64.Bind(LoadHeapNumberValue(divisor));
+ Goto(&do_fmod);
+ }
+ }
+
+ BIND(&dividend_is_not_smi);
+ {
+ Node* dividend_map = LoadMap(dividend);
+
+ // Check if {dividend} is a HeapNumber.
+ GotoIfNot(IsHeapNumberMap(dividend_map), &dividend_is_not_number);
+
+ // Check if {divisor} is a Smi.
+ Label divisor_is_smi(this), divisor_is_not_smi(this);
+ Branch(TaggedIsSmi(divisor), &divisor_is_smi, &divisor_is_not_smi);
+
+ BIND(&divisor_is_smi);
+ {
+ // Convert {divisor} to a double and use it for a floating point
+ // division.
+ var_dividend_float64.Bind(LoadHeapNumberValue(dividend));
+ var_divisor_float64.Bind(SmiToFloat64(divisor));
+ Goto(&do_fmod);
+ }
+
+ BIND(&divisor_is_not_smi);
+ {
+ Node* divisor_map = LoadMap(divisor);
+
+ // Check if {divisor} is a HeapNumber.
+ GotoIfNot(IsHeapNumberMap(divisor_map), &check_divisor_for_oddball);
+
+ // Both {dividend} and {divisor} are HeapNumbers. Load their values
+ // and divide them.
+ var_dividend_float64.Bind(LoadHeapNumberValue(dividend));
+ var_divisor_float64.Bind(LoadHeapNumberValue(divisor));
+ Goto(&do_fmod);
+ }
+ }
+
+ BIND(&do_fmod);
+ {
+ var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kNumber));
+ Node* value =
+ Float64Mod(var_dividend_float64.value(), var_divisor_float64.value());
+ var_result.Bind(AllocateHeapNumberWithValue(value));
+ Goto(&end);
+ }
+
+ BIND(&dividend_is_not_number);
+ {
+ // No checks on divisor yet. We just know dividend is not a number or Smi.
+ // Check if dividend is an oddball.
+ Node* dividend_instance_type = LoadInstanceType(dividend);
+ Node* dividend_is_oddball =
+ Word32Equal(dividend_instance_type, Int32Constant(ODDBALL_TYPE));
+ GotoIfNot(dividend_is_oddball, &call_with_any_feedback);
+
+ GotoIf(TaggedIsSmi(divisor), &call_with_oddball_feedback);
+
+ // Load the map of the {divisor}.
+ Node* divisor_map = LoadMap(divisor);
+
+ // Check if {divisor} is a HeapNumber.
+ Branch(IsHeapNumberMap(divisor_map), &call_with_oddball_feedback,
+ &check_divisor_for_oddball);
+ }
+
+ BIND(&check_divisor_for_oddball);
+ {
+ // Check if divisor is an oddball. At this point we know dividend is either
+ // a Smi or number or oddball and divisor is not a number or Smi.
+ Node* divisor_instance_type = LoadInstanceType(divisor);
+ Node* divisor_is_oddball =
+ Word32Equal(divisor_instance_type, Int32Constant(ODDBALL_TYPE));
+ Branch(divisor_is_oddball, &call_with_oddball_feedback,
+ &call_with_any_feedback);
+ }
+
+ BIND(&call_with_oddball_feedback);
+ {
+ var_type_feedback.Bind(
+ SmiConstant(BinaryOperationFeedback::kNumberOrOddball));
+ Goto(&call_modulus_stub);
+ }
+
+ BIND(&call_with_any_feedback);
+ {
+ var_type_feedback.Bind(SmiConstant(BinaryOperationFeedback::kAny));
+ Goto(&call_modulus_stub);
+ }
+
+ BIND(&call_modulus_stub);
+ {
+ Callable callable = CodeFactory::Modulus(isolate());
+ var_result.Bind(CallStub(callable, context, dividend, divisor));
+ Goto(&end);
+ }
+
+ BIND(&end);
+ UpdateFeedback(var_type_feedback.value(), feedback_vector, slot_id);
+ return var_result.value();
+}
+
+} // namespace internal
+} // namespace v8
diff --git a/deps/v8/src/ic/binary-op-assembler.h b/deps/v8/src/ic/binary-op-assembler.h
new file mode 100644
index 0000000000..849dfc29dc
--- /dev/null
+++ b/deps/v8/src/ic/binary-op-assembler.h
@@ -0,0 +1,45 @@
+// Copyright 2017 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef V8_SRC_IC_BINARY_OP_ASSEMBLER_H_
+#define V8_SRC_IC_BINARY_OP_ASSEMBLER_H_
+
+#include "src/code-stub-assembler.h"
+
+namespace v8 {
+namespace internal {
+
+namespace compiler {
+class CodeAssemblerState;
+}
+
+class BinaryOpAssembler : public CodeStubAssembler {
+ public:
+ typedef compiler::Node Node;
+
+ explicit BinaryOpAssembler(compiler::CodeAssemblerState* state)
+ : CodeStubAssembler(state) {}
+
+ Node* Generate_AddWithFeedback(Node* context, Node* lhs, Node* rhs,
+ Node* slot_id, Node* feedback_vector);
+
+ Node* Generate_SubtractWithFeedback(Node* context, Node* lhs, Node* rhs,
+ Node* slot_id, Node* feedback_vector);
+
+ Node* Generate_MultiplyWithFeedback(Node* context, Node* lhs, Node* rhs,
+ Node* slot_id, Node* feedback_vector);
+
+ Node* Generate_DivideWithFeedback(Node* context, Node* dividend,
+ Node* divisor, Node* slot_id,
+ Node* feedback_vector);
+
+ Node* Generate_ModulusWithFeedback(Node* context, Node* dividend,
+ Node* divisor, Node* slot_id,
+ Node* feedback_vector);
+};
+
+} // namespace internal
+} // namespace v8
+
+#endif // V8_SRC_IC_BINARY_OP_ASSEMBLER_H_
diff --git a/deps/v8/src/ic/handler-compiler.cc b/deps/v8/src/ic/handler-compiler.cc
index 6a9734d5eb..69ba39768a 100644
--- a/deps/v8/src/ic/handler-compiler.cc
+++ b/deps/v8/src/ic/handler-compiler.cc
@@ -4,6 +4,7 @@
#include "src/ic/handler-compiler.h"
+#include "src/assembler-inl.h"
#include "src/field-type.h"
#include "src/ic/call-optimization.h"
#include "src/ic/handler-configuration-inl.h"
@@ -16,9 +17,8 @@ namespace internal {
Handle<Code> PropertyHandlerCompiler::Find(Handle<Name> name,
Handle<Map> stub_holder,
- Code::Kind kind,
- CacheHolderFlag cache_holder) {
- Code::Flags flags = Code::ComputeHandlerFlags(kind, cache_holder);
+ Code::Kind kind) {
+ Code::Flags flags = Code::ComputeHandlerFlags(kind);
Code* code = stub_holder->LookupInCodeCache(*name, flags);
if (code == nullptr) return Handle<Code>();
return handle(code);
@@ -26,10 +26,27 @@ Handle<Code> PropertyHandlerCompiler::Find(Handle<Name> name,
Handle<Code> PropertyHandlerCompiler::GetCode(Code::Kind kind,
Handle<Name> name) {
- Code::Flags flags = Code::ComputeHandlerFlags(kind, cache_holder());
- Handle<Code> code = GetCodeWithFlags(flags, name);
+ Code::Flags flags = Code::ComputeHandlerFlags(kind);
+
+ // Create code object in the heap.
+ CodeDesc desc;
+ masm()->GetCode(&desc);
+ Handle<Code> code = factory()->NewCode(desc, flags, masm()->CodeObject());
+ if (code->IsCodeStubOrIC()) code->set_stub_key(CodeStub::NoCacheKey());
+#ifdef ENABLE_DISASSEMBLER
+ if (FLAG_print_code_stubs) {
+ char* raw_name = !name.is_null() && name->IsString()
+ ? String::cast(*name)->ToCString().get()
+ : nullptr;
+ CodeTracer::Scope trace_scope(isolate()->GetCodeTracer());
+ OFStream os(trace_scope.file());
+ code->Disassemble(raw_name, os);
+ }
+#endif
+
PROFILE(isolate(), CodeCreateEvent(CodeEventListener::HANDLER_TAG,
AbstractCode::cast(*code), *name));
+
#ifdef DEBUG
code->VerifyEmbeddedObjects();
#endif
@@ -39,11 +56,9 @@ Handle<Code> PropertyHandlerCompiler::GetCode(Code::Kind kind,
#define __ ACCESS_MASM(masm())
-
Register NamedLoadHandlerCompiler::FrontendHeader(Register object_reg,
Handle<Name> name,
- Label* miss,
- ReturnHolder return_what) {
+ Label* miss) {
if (map()->IsPrimitiveMap() || map()->IsJSGlobalProxyMap()) {
// If the receiver is a global proxy and if we get to this point then
// the compile-time (current) native context has access to global proxy's
@@ -60,7 +75,7 @@ Register NamedLoadHandlerCompiler::FrontendHeader(Register object_reg,
// Check that the maps starting from the prototype haven't changed.
return CheckPrototypes(object_reg, scratch1(), scratch2(), scratch3(), name,
- miss, return_what);
+ miss);
}
@@ -68,8 +83,7 @@ Register NamedLoadHandlerCompiler::FrontendHeader(Register object_reg,
// miss.
Register NamedStoreHandlerCompiler::FrontendHeader(Register object_reg,
Handle<Name> name,
- Label* miss,
- ReturnHolder return_what) {
+ Label* miss) {
if (map()->IsJSGlobalProxyMap()) {
Handle<Context> native_context = isolate()->native_context();
Handle<WeakCell> weak_cell(native_context->self_weak_cell(), isolate());
@@ -77,7 +91,7 @@ Register NamedStoreHandlerCompiler::FrontendHeader(Register object_reg,
}
return CheckPrototypes(object_reg, this->name(), scratch1(), scratch2(), name,
- miss, return_what);
+ miss);
}
@@ -86,7 +100,7 @@ Register PropertyHandlerCompiler::Frontend(Handle<Name> name) {
if (IC::ShouldPushPopSlotAndVector(kind())) {
PushVectorAndSlot();
}
- Register reg = FrontendHeader(receiver(), name, &miss, RETURN_HOLDER);
+ Register reg = FrontendHeader(receiver(), name, &miss);
FrontendFooter(name, &miss);
// The footer consumes the vector and slot from the stack if miss occurs.
if (IC::ShouldPushPopSlotAndVector(kind())) {
@@ -96,16 +110,6 @@ Register PropertyHandlerCompiler::Frontend(Handle<Name> name) {
}
Handle<Code> NamedLoadHandlerCompiler::CompileLoadCallback(
- Handle<Name> name, Handle<AccessorInfo> callback, Handle<Code> slow_stub) {
- if (V8_UNLIKELY(FLAG_runtime_stats)) {
- GenerateTailCall(masm(), slow_stub);
- }
- Register reg = Frontend(name);
- GenerateLoadCallback(reg, callback);
- return GetCode(kind(), name);
-}
-
-Handle<Code> NamedLoadHandlerCompiler::CompileLoadCallback(
Handle<Name> name, const CallOptimization& call_optimization,
int accessor_index, Handle<Code> slow_stub) {
DCHECK(call_optimization.is_simple_api_call());
@@ -118,199 +122,6 @@ Handle<Code> NamedLoadHandlerCompiler::CompileLoadCallback(
return GetCode(kind(), name);
}
-
-void NamedLoadHandlerCompiler::InterceptorVectorSlotPush(Register holder_reg) {
- if (IC::ShouldPushPopSlotAndVector(kind())) {
- if (holder_reg.is(receiver())) {
- PushVectorAndSlot();
- } else {
- DCHECK(holder_reg.is(scratch1()));
- PushVectorAndSlot(scratch2(), scratch3());
- }
- }
-}
-
-
-void NamedLoadHandlerCompiler::InterceptorVectorSlotPop(Register holder_reg,
- PopMode mode) {
- if (IC::ShouldPushPopSlotAndVector(kind())) {
- if (mode == DISCARD) {
- DiscardVectorAndSlot();
- } else {
- if (holder_reg.is(receiver())) {
- PopVectorAndSlot();
- } else {
- DCHECK(holder_reg.is(scratch1()));
- PopVectorAndSlot(scratch2(), scratch3());
- }
- }
- }
-}
-
-
-Handle<Code> NamedLoadHandlerCompiler::CompileLoadInterceptor(
- LookupIterator* it) {
- // So far the most popular follow ups for interceptor loads are DATA and
- // AccessorInfo, so inline only them. Other cases may be added
- // later.
- bool inline_followup = false;
- switch (it->state()) {
- case LookupIterator::TRANSITION:
- UNREACHABLE();
- case LookupIterator::ACCESS_CHECK:
- case LookupIterator::INTERCEPTOR:
- case LookupIterator::JSPROXY:
- case LookupIterator::NOT_FOUND:
- case LookupIterator::INTEGER_INDEXED_EXOTIC:
- break;
- case LookupIterator::DATA: {
- PropertyDetails details = it->property_details();
- inline_followup = details.kind() == kData &&
- details.location() == kField &&
- !it->is_dictionary_holder();
- break;
- }
- case LookupIterator::ACCESSOR: {
- Handle<Object> accessors = it->GetAccessors();
- if (accessors->IsAccessorInfo()) {
- Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors);
- inline_followup =
- info->getter() != NULL &&
- AccessorInfo::IsCompatibleReceiverMap(isolate(), info, map());
- } else if (accessors->IsAccessorPair()) {
- Handle<JSObject> property_holder(it->GetHolder<JSObject>());
- Handle<Object> getter(Handle<AccessorPair>::cast(accessors)->getter(),
- isolate());
- if (!(getter->IsJSFunction() || getter->IsFunctionTemplateInfo())) {
- break;
- }
- if (!property_holder->HasFastProperties()) break;
- CallOptimization call_optimization(getter);
- Handle<Map> receiver_map = map();
- inline_followup = call_optimization.is_simple_api_call() &&
- call_optimization.IsCompatibleReceiverMap(
- receiver_map, property_holder);
- }
- }
- }
-
- Label miss;
- InterceptorVectorSlotPush(receiver());
- bool lost_holder_register = false;
- auto holder_orig = holder();
- // non masking interceptors must check the entire chain, so temporarily reset
- // the holder to be that last element for the FrontendHeader call.
- if (holder()->GetNamedInterceptor()->non_masking()) {
- DCHECK(!inline_followup);
- JSObject* last = *holder();
- PrototypeIterator iter(isolate(), last);
- while (!iter.IsAtEnd()) {
- lost_holder_register = true;
- // Casting to JSObject is fine here. The LookupIterator makes sure to
- // look behind non-masking interceptors during the original lookup, and
- // we wouldn't try to compile a handler if there was a Proxy anywhere.
- last = iter.GetCurrent<JSObject>();
- iter.Advance();
- }
- auto last_handle = handle(last);
- set_holder(last_handle);
- }
- Register reg = FrontendHeader(receiver(), it->name(), &miss, RETURN_HOLDER);
- // Reset the holder so further calculations are correct.
- set_holder(holder_orig);
- if (lost_holder_register) {
- if (*it->GetReceiver() == *holder()) {
- reg = receiver();
- } else {
- // Reload lost holder register.
- auto cell = isolate()->factory()->NewWeakCell(holder());
- __ LoadWeakValue(reg, cell, &miss);
- }
- }
- FrontendFooter(it->name(), &miss);
- InterceptorVectorSlotPop(reg);
- if (inline_followup) {
- // TODO(368): Compile in the whole chain: all the interceptors in
- // prototypes and ultimate answer.
- GenerateLoadInterceptorWithFollowup(it, reg);
- } else {
- GenerateLoadInterceptor(reg);
- }
- return GetCode(kind(), it->name());
-}
-
-void NamedLoadHandlerCompiler::GenerateLoadCallback(
- Register reg, Handle<AccessorInfo> callback) {
- DCHECK(receiver().is(ApiGetterDescriptor::ReceiverRegister()));
- __ Move(ApiGetterDescriptor::HolderRegister(), reg);
- // The callback is alive if this instruction is executed,
- // so the weak cell is not cleared and points to data.
- Handle<WeakCell> cell = isolate()->factory()->NewWeakCell(callback);
- __ GetWeakValue(ApiGetterDescriptor::CallbackRegister(), cell);
-
- CallApiGetterStub stub(isolate());
- __ TailCallStub(&stub);
-}
-
-void NamedLoadHandlerCompiler::GenerateLoadPostInterceptor(
- LookupIterator* it, Register interceptor_reg) {
- Handle<JSObject> real_named_property_holder(it->GetHolder<JSObject>());
-
- Handle<Map> holder_map(holder()->map());
- set_map(holder_map);
- set_holder(real_named_property_holder);
-
- Label miss;
- InterceptorVectorSlotPush(interceptor_reg);
- Register reg =
- FrontendHeader(interceptor_reg, it->name(), &miss, RETURN_HOLDER);
- FrontendFooter(it->name(), &miss);
- // We discard the vector and slot now because we don't miss below this point.
- InterceptorVectorSlotPop(reg, DISCARD);
-
- switch (it->state()) {
- case LookupIterator::ACCESS_CHECK:
- case LookupIterator::INTERCEPTOR:
- case LookupIterator::JSPROXY:
- case LookupIterator::NOT_FOUND:
- case LookupIterator::INTEGER_INDEXED_EXOTIC:
- case LookupIterator::TRANSITION:
- UNREACHABLE();
- case LookupIterator::DATA: {
- DCHECK_EQ(kData, it->property_details().kind());
- DCHECK_EQ(kField, it->property_details().location());
- __ Move(LoadFieldDescriptor::ReceiverRegister(), reg);
- Handle<Object> smi_handler =
- LoadIC::SimpleFieldLoad(isolate(), it->GetFieldIndex());
- __ Move(LoadFieldDescriptor::SmiHandlerRegister(), smi_handler);
- GenerateTailCall(masm(), isolate()->builtins()->LoadField());
- break;
- }
- case LookupIterator::ACCESSOR:
- if (it->GetAccessors()->IsAccessorInfo()) {
- Handle<AccessorInfo> info =
- Handle<AccessorInfo>::cast(it->GetAccessors());
- DCHECK_NOT_NULL(info->getter());
- GenerateLoadCallback(reg, info);
- } else {
- Handle<Object> function = handle(
- AccessorPair::cast(*it->GetAccessors())->getter(), isolate());
- CallOptimization call_optimization(function);
- GenerateApiAccessorCall(masm(), call_optimization, holder_map,
- receiver(), scratch2(), false, no_reg, reg,
- it->GetAccessorIndex());
- }
- }
-}
-
-Handle<Code> NamedLoadHandlerCompiler::CompileLoadViaGetter(
- Handle<Name> name, int accessor_index, int expected_arguments) {
- Register holder = Frontend(name);
- GenerateLoadViaGetter(masm(), map(), receiver(), holder, accessor_index,
- expected_arguments, scratch2());
- return GetCode(kind(), name);
-}
-
Handle<Code> NamedStoreHandlerCompiler::CompileStoreViaSetter(
Handle<JSObject> object, Handle<Name> name, int accessor_index,
int expected_arguments) {
@@ -341,51 +152,5 @@ Handle<Code> NamedStoreHandlerCompiler::CompileStoreCallback(
#undef __
-// static
-Handle<Object> ElementHandlerCompiler::GetKeyedLoadHandler(
- Handle<Map> receiver_map, Isolate* isolate) {
- if (receiver_map->has_indexed_interceptor() &&
- !receiver_map->GetIndexedInterceptor()->getter()->IsUndefined(isolate) &&
- !receiver_map->GetIndexedInterceptor()->non_masking()) {
- TRACE_HANDLER_STATS(isolate, KeyedLoadIC_LoadIndexedInterceptorStub);
- return LoadIndexedInterceptorStub(isolate).GetCode();
- }
- if (receiver_map->IsStringMap()) {
- TRACE_HANDLER_STATS(isolate, KeyedLoadIC_LoadIndexedStringStub);
- return isolate->builtins()->KeyedLoadIC_IndexedString();
- }
- InstanceType instance_type = receiver_map->instance_type();
- if (instance_type < FIRST_JS_RECEIVER_TYPE) {
- TRACE_HANDLER_STATS(isolate, KeyedLoadIC_SlowStub);
- return isolate->builtins()->KeyedLoadIC_Slow();
- }
-
- ElementsKind elements_kind = receiver_map->elements_kind();
- if (IsSloppyArgumentsElements(elements_kind)) {
- TRACE_HANDLER_STATS(isolate, KeyedLoadIC_KeyedLoadSloppyArgumentsStub);
- return KeyedLoadSloppyArgumentsStub(isolate).GetCode();
- }
- bool is_js_array = instance_type == JS_ARRAY_TYPE;
- if (elements_kind == DICTIONARY_ELEMENTS) {
- TRACE_HANDLER_STATS(isolate, KeyedLoadIC_LoadElementDH);
- return LoadHandler::LoadElement(isolate, elements_kind, false, is_js_array);
- }
- DCHECK(IsFastElementsKind(elements_kind) ||
- IsFixedTypedArrayElementsKind(elements_kind));
- // TODO(jkummerow): Use IsHoleyElementsKind(elements_kind).
- bool convert_hole_to_undefined =
- is_js_array && elements_kind == FAST_HOLEY_ELEMENTS &&
- *receiver_map == isolate->get_initial_js_array_map(elements_kind);
- TRACE_HANDLER_STATS(isolate, KeyedLoadIC_LoadElementDH);
- return LoadHandler::LoadElement(isolate, elements_kind,
- convert_hole_to_undefined, is_js_array);
-}
-
-void ElementHandlerCompiler::CompileElementHandlers(
- MapHandleList* receiver_maps, List<Handle<Object>>* handlers) {
- for (int i = 0; i < receiver_maps->length(); ++i) {
- handlers->Add(GetKeyedLoadHandler(receiver_maps->at(i), isolate()));
- }
-}
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/ic/handler-compiler.h b/deps/v8/src/ic/handler-compiler.h
index a37375abfb..4eb1b464c3 100644
--- a/deps/v8/src/ic/handler-compiler.h
+++ b/deps/v8/src/ic/handler-compiler.h
@@ -13,24 +13,19 @@ namespace internal {
class CallOptimization;
-enum ReturnHolder { RETURN_HOLDER, DONT_RETURN_ANYTHING };
-
class PropertyHandlerCompiler : public PropertyAccessCompiler {
public:
- static Handle<Code> Find(Handle<Name> name, Handle<Map> map, Code::Kind kind,
- CacheHolderFlag cache_holder);
+ static Handle<Code> Find(Handle<Name> name, Handle<Map> map, Code::Kind kind);
protected:
PropertyHandlerCompiler(Isolate* isolate, Code::Kind kind, Handle<Map> map,
- Handle<JSObject> holder, CacheHolderFlag cache_holder)
- : PropertyAccessCompiler(isolate, kind, cache_holder),
- map_(map),
- holder_(holder) {}
+ Handle<JSObject> holder)
+ : PropertyAccessCompiler(isolate, kind), map_(map), holder_(holder) {}
virtual ~PropertyHandlerCompiler() {}
virtual Register FrontendHeader(Register object_reg, Handle<Name> name,
- Label* miss, ReturnHolder return_what) {
+ Label* miss) {
UNREACHABLE();
return receiver();
}
@@ -104,13 +99,10 @@ class PropertyHandlerCompiler : public PropertyAccessCompiler {
// holder_reg.
Register CheckPrototypes(Register object_reg, Register holder_reg,
Register scratch1, Register scratch2,
- Handle<Name> name, Label* miss,
- ReturnHolder return_what);
+ Handle<Name> name, Label* miss);
Handle<Code> GetCode(Code::Kind kind, Handle<Name> name);
- void set_holder(Handle<JSObject> holder) { holder_ = holder; }
Handle<Map> map() const { return map_; }
- void set_map(Handle<Map> map) { map_ = map; }
Handle<JSObject> holder() const { return holder_; }
private:
@@ -122,70 +114,24 @@ class PropertyHandlerCompiler : public PropertyAccessCompiler {
class NamedLoadHandlerCompiler : public PropertyHandlerCompiler {
public:
NamedLoadHandlerCompiler(Isolate* isolate, Handle<Map> map,
- Handle<JSObject> holder,
- CacheHolderFlag cache_holder)
- : PropertyHandlerCompiler(isolate, Code::LOAD_IC, map, holder,
- cache_holder) {}
+ Handle<JSObject> holder)
+ : PropertyHandlerCompiler(isolate, Code::LOAD_IC, map, holder) {}
virtual ~NamedLoadHandlerCompiler() {}
Handle<Code> CompileLoadCallback(Handle<Name> name,
- Handle<AccessorInfo> callback,
- Handle<Code> slow_stub);
-
- Handle<Code> CompileLoadCallback(Handle<Name> name,
const CallOptimization& call_optimization,
int accessor_index, Handle<Code> slow_stub);
- // The LookupIterator is used to perform a lookup behind the interceptor. If
- // the iterator points to a LookupIterator::PROPERTY, its access will be
- // inlined.
- Handle<Code> CompileLoadInterceptor(LookupIterator* it);
-
- Handle<Code> CompileLoadViaGetter(Handle<Name> name, int accessor_index,
- int expected_arguments);
-
- Handle<Code> CompileLoadGlobal(Handle<PropertyCell> cell, Handle<Name> name,
- bool is_configurable);
-
- static void GenerateLoadViaGetter(MacroAssembler* masm, Handle<Map> map,
- Register receiver, Register holder,
- int accessor_index, int expected_arguments,
- Register scratch);
-
- static void GenerateLoadViaGetterForDeopt(MacroAssembler* masm) {
- GenerateLoadViaGetter(masm, Handle<Map>::null(), no_reg, no_reg, -1, -1,
- no_reg);
- }
-
- // These constants describe the structure of the interceptor arguments on the
- // stack. The arguments are pushed by the (platform-specific)
- // PushInterceptorArguments and read by LoadPropertyWithInterceptorOnly and
- // LoadWithInterceptor.
- static const int kInterceptorArgsNameIndex = 0;
- static const int kInterceptorArgsThisIndex = 1;
- static const int kInterceptorArgsHolderIndex = 2;
- static const int kInterceptorArgsLength = 3;
+ static void GenerateLoadViaGetterForDeopt(MacroAssembler* masm);
protected:
virtual Register FrontendHeader(Register object_reg, Handle<Name> name,
- Label* miss, ReturnHolder return_what);
+ Label* miss);
virtual void FrontendFooter(Handle<Name> name, Label* miss);
private:
- void GenerateLoadCallback(Register reg, Handle<AccessorInfo> callback);
-
- // Helper emits no code if vector-ics are disabled.
- void InterceptorVectorSlotPush(Register holder_reg);
- enum PopMode { POP, DISCARD };
- void InterceptorVectorSlotPop(Register holder_reg, PopMode mode = POP);
-
- void GenerateLoadInterceptor(Register holder_reg);
- void GenerateLoadInterceptorWithFollowup(LookupIterator* it,
- Register holder_reg);
- void GenerateLoadPostInterceptor(LookupIterator* it, Register reg);
-
Register scratch3() { return registers_[4]; }
};
@@ -197,8 +143,7 @@ class NamedStoreHandlerCompiler : public PropertyHandlerCompiler {
explicit NamedStoreHandlerCompiler(Isolate* isolate, Handle<Map> map,
Handle<JSObject> holder)
- : PropertyHandlerCompiler(isolate, Code::STORE_IC, map, holder,
- kCacheOnReceiver) {
+ : PropertyHandlerCompiler(isolate, Code::STORE_IC, map, holder) {
#ifdef DEBUG
if (Descriptor::kPassLastArgsOnStack) {
ZapStackArgumentsRegisterAliases();
@@ -232,7 +177,7 @@ class NamedStoreHandlerCompiler : public PropertyHandlerCompiler {
protected:
virtual Register FrontendHeader(Register object_reg, Handle<Name> name,
- Label* miss, ReturnHolder return_what);
+ Label* miss);
virtual void FrontendFooter(Handle<Name> name, Label* miss);
void GenerateRestoreName(Label* label, Handle<Name> name);
@@ -241,21 +186,6 @@ class NamedStoreHandlerCompiler : public PropertyHandlerCompiler {
static Register value();
};
-
-class ElementHandlerCompiler : public PropertyHandlerCompiler {
- public:
- explicit ElementHandlerCompiler(Isolate* isolate)
- : PropertyHandlerCompiler(isolate, Code::KEYED_LOAD_IC,
- Handle<Map>::null(), Handle<JSObject>::null(),
- kCacheOnReceiver) {}
-
- virtual ~ElementHandlerCompiler() {}
-
- static Handle<Object> GetKeyedLoadHandler(Handle<Map> receiver_map,
- Isolate* isolate);
- void CompileElementHandlers(MapHandleList* receiver_maps,
- List<Handle<Object>>* handlers);
-};
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/ic/handler-configuration-inl.h b/deps/v8/src/ic/handler-configuration-inl.h
index 437c5288fb..2b9dc04b5a 100644
--- a/deps/v8/src/ic/handler-configuration-inl.h
+++ b/deps/v8/src/ic/handler-configuration-inl.h
@@ -13,76 +13,94 @@
namespace v8 {
namespace internal {
-Handle<Object> LoadHandler::LoadField(Isolate* isolate,
- FieldIndex field_index) {
- int config = KindBits::encode(kForFields) |
+Handle<Smi> LoadHandler::LoadNormal(Isolate* isolate) {
+ int config = KindBits::encode(kNormal);
+ return handle(Smi::FromInt(config), isolate);
+}
+
+Handle<Smi> LoadHandler::LoadGlobal(Isolate* isolate) {
+ int config = KindBits::encode(kGlobal);
+ return handle(Smi::FromInt(config), isolate);
+}
+
+Handle<Smi> LoadHandler::LoadInterceptor(Isolate* isolate) {
+ int config = KindBits::encode(kInterceptor);
+ return handle(Smi::FromInt(config), isolate);
+}
+
+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());
return handle(Smi::FromInt(config), isolate);
}
-Handle<Object> LoadHandler::LoadConstant(Isolate* isolate, int descriptor) {
- int config = KindBits::encode(kForConstants) |
- IsAccessorInfoBits::encode(false) |
- DescriptorValueIndexBits::encode(
- DescriptorArray::ToValueIndex(descriptor));
+Handle<Smi> LoadHandler::LoadConstant(Isolate* isolate, int descriptor) {
+ int config = KindBits::encode(kConstant) | IsAccessorInfoBits::encode(false) |
+ DescriptorBits::encode(descriptor);
+ return handle(Smi::FromInt(config), isolate);
+}
+
+Handle<Smi> LoadHandler::LoadAccessor(Isolate* isolate, int descriptor) {
+ int config = KindBits::encode(kAccessor) | IsAccessorInfoBits::encode(false) |
+ DescriptorBits::encode(descriptor);
return handle(Smi::FromInt(config), isolate);
}
-Handle<Object> LoadHandler::LoadApiGetter(Isolate* isolate, int descriptor) {
- int config = KindBits::encode(kForConstants) |
- IsAccessorInfoBits::encode(true) |
- DescriptorValueIndexBits::encode(
- DescriptorArray::ToValueIndex(descriptor));
+Handle<Smi> LoadHandler::LoadApiGetter(Isolate* isolate, int descriptor) {
+ int config = KindBits::encode(kConstant) | IsAccessorInfoBits::encode(true) |
+ DescriptorBits::encode(descriptor);
return handle(Smi::FromInt(config), isolate);
}
-Handle<Object> LoadHandler::EnableAccessCheckOnReceiver(
- Isolate* isolate, Handle<Object> smi_handler) {
- int config = Smi::cast(*smi_handler)->value();
+Handle<Smi> LoadHandler::EnableAccessCheckOnReceiver(Isolate* isolate,
+ Handle<Smi> smi_handler) {
+ int config = smi_handler->value();
#ifdef DEBUG
Kind kind = KindBits::decode(config);
- DCHECK_NE(kForElements, kind);
+ DCHECK_NE(kElement, kind);
#endif
config = DoAccessCheckOnReceiverBits::update(config, true);
return handle(Smi::FromInt(config), isolate);
}
-Handle<Object> LoadHandler::EnableNegativeLookupOnReceiver(
- Isolate* isolate, Handle<Object> smi_handler) {
- int config = Smi::cast(*smi_handler)->value();
+Handle<Smi> LoadHandler::EnableLookupOnReceiver(Isolate* isolate,
+ Handle<Smi> smi_handler) {
+ int config = smi_handler->value();
#ifdef DEBUG
Kind kind = KindBits::decode(config);
- DCHECK_NE(kForElements, kind);
+ DCHECK_NE(kElement, kind);
#endif
- config = DoNegativeLookupOnReceiverBits::update(config, true);
+ config = LookupOnReceiverBits::update(config, true);
return handle(Smi::FromInt(config), isolate);
}
-Handle<Object> LoadHandler::LoadNonExistent(
- Isolate* isolate, bool do_negative_lookup_on_receiver) {
- int config =
- KindBits::encode(kForNonExistent) |
- DoNegativeLookupOnReceiverBits::encode(do_negative_lookup_on_receiver);
+Handle<Smi> LoadHandler::LoadNonExistent(Isolate* isolate) {
+ int config = KindBits::encode(kNonExistent);
return handle(Smi::FromInt(config), isolate);
}
-Handle<Object> LoadHandler::LoadElement(Isolate* isolate,
- ElementsKind elements_kind,
- bool convert_hole_to_undefined,
- bool is_js_array) {
- int config = KindBits::encode(kForElements) |
+Handle<Smi> LoadHandler::LoadElement(Isolate* isolate,
+ ElementsKind elements_kind,
+ bool convert_hole_to_undefined,
+ bool is_js_array) {
+ int config = KindBits::encode(kElement) |
ElementsKindBits::encode(elements_kind) |
ConvertHoleBits::encode(convert_hole_to_undefined) |
IsJsArrayBits::encode(is_js_array);
return handle(Smi::FromInt(config), isolate);
}
-Handle<Object> StoreHandler::StoreField(Isolate* isolate, Kind kind,
- int descriptor, FieldIndex field_index,
- Representation representation,
- bool extend_storage) {
+Handle<Smi> StoreHandler::StoreNormal(Isolate* isolate) {
+ int config = KindBits::encode(kStoreNormal);
+ return handle(Smi::FromInt(config), isolate);
+}
+
+Handle<Smi> StoreHandler::StoreField(Isolate* isolate, Kind kind,
+ int descriptor, FieldIndex field_index,
+ Representation representation,
+ bool extend_storage) {
StoreHandler::FieldRepresentation field_rep;
switch (representation.kind()) {
case Representation::kSmi:
@@ -99,9 +117,8 @@ Handle<Object> StoreHandler::StoreField(Isolate* isolate, Kind kind,
break;
default:
UNREACHABLE();
- return Handle<Object>::null();
+ return Handle<Smi>::null();
}
- int value_index = DescriptorArray::ToValueIndex(descriptor);
DCHECK(kind == kStoreField || kind == kTransitionToField ||
(kind == kStoreConstField && FLAG_track_constant_fields));
@@ -112,36 +129,35 @@ Handle<Object> StoreHandler::StoreField(Isolate* isolate, Kind kind,
StoreHandler::ExtendStorageBits::encode(extend_storage) |
StoreHandler::IsInobjectBits::encode(field_index.is_inobject()) |
StoreHandler::FieldRepresentationBits::encode(field_rep) |
- StoreHandler::DescriptorValueIndexBits::encode(value_index) |
+ StoreHandler::DescriptorBits::encode(descriptor) |
StoreHandler::FieldOffsetBits::encode(field_index.offset());
return handle(Smi::FromInt(config), isolate);
}
-Handle<Object> StoreHandler::StoreField(Isolate* isolate, int descriptor,
- FieldIndex field_index,
- PropertyConstness constness,
- Representation representation) {
+Handle<Smi> StoreHandler::StoreField(Isolate* isolate, int descriptor,
+ FieldIndex field_index,
+ PropertyConstness constness,
+ Representation representation) {
DCHECK_IMPLIES(!FLAG_track_constant_fields, constness == kMutable);
Kind kind = constness == kMutable ? kStoreField : kStoreConstField;
return StoreField(isolate, kind, descriptor, field_index, representation,
false);
}
-Handle<Object> StoreHandler::TransitionToField(Isolate* isolate, int descriptor,
- FieldIndex field_index,
- Representation representation,
- bool extend_storage) {
+Handle<Smi> StoreHandler::TransitionToField(Isolate* isolate, int descriptor,
+ FieldIndex field_index,
+ Representation representation,
+ bool extend_storage) {
return StoreField(isolate, kTransitionToField, descriptor, field_index,
representation, extend_storage);
}
-Handle<Object> StoreHandler::TransitionToConstant(Isolate* isolate,
- int descriptor) {
+Handle<Smi> StoreHandler::TransitionToConstant(Isolate* isolate,
+ int descriptor) {
DCHECK(!FLAG_track_constant_fields);
- int value_index = DescriptorArray::ToValueIndex(descriptor);
int config =
StoreHandler::KindBits::encode(StoreHandler::kTransitionToConstant) |
- StoreHandler::DescriptorValueIndexBits::encode(value_index);
+ StoreHandler::DescriptorBits::encode(descriptor);
return handle(Smi::FromInt(config), isolate);
}
diff --git a/deps/v8/src/ic/handler-configuration.h b/deps/v8/src/ic/handler-configuration.h
index 539d448008..ab117d5c9b 100644
--- a/deps/v8/src/ic/handler-configuration.h
+++ b/deps/v8/src/ic/handler-configuration.h
@@ -16,19 +16,28 @@ namespace internal {
// A set of bit fields representing Smi handlers for loads.
class LoadHandler {
public:
- enum Kind { kForElements, kForFields, kForConstants, kForNonExistent };
- class KindBits : public BitField<Kind, 0, 2> {};
+ enum Kind {
+ kElement,
+ kNormal,
+ kGlobal,
+ kField,
+ kConstant,
+ kAccessor,
+ kInterceptor,
+ kNonExistent
+ };
+ class KindBits : public BitField<Kind, 0, 3> {};
// Defines whether access rights check should be done on receiver object.
- // Applicable to kForFields, kForConstants and kForNonExistent kinds only when
- // loading value from prototype chain. Ignored when loading from holder.
+ // Applicable to named property kinds only when loading value from prototype
+ // chain. Ignored when loading from holder.
class DoAccessCheckOnReceiverBits
: public BitField<bool, KindBits::kNext, 1> {};
- // Defines whether negative lookup check should be done on receiver object.
- // Applicable to kForFields, kForConstants and kForNonExistent kinds only when
- // loading value from prototype chain. Ignored when loading from holder.
- class DoNegativeLookupOnReceiverBits
+ // Defines whether a lookup should be done on receiver object before
+ // proceeding to the prototype chain. Applicable to named property kinds only
+ // when loading value from prototype chain. Ignored when loading from holder.
+ class LookupOnReceiverBits
: public BitField<bool, DoAccessCheckOnReceiverBits::kNext, 1> {};
//
@@ -36,20 +45,18 @@ class LoadHandler {
//
class IsAccessorInfoBits
- : public BitField<bool, DoNegativeLookupOnReceiverBits::kNext, 1> {};
+ : public BitField<bool, LookupOnReceiverBits::kNext, 1> {};
// Index of a value entry in the descriptor array.
- // +2 here is because each descriptor entry occupies 3 slots in array.
- class DescriptorValueIndexBits
- : public BitField<unsigned, IsAccessorInfoBits::kNext,
- kDescriptorIndexBitCount + 2> {};
+ class DescriptorBits : public BitField<unsigned, IsAccessorInfoBits::kNext,
+ kDescriptorIndexBitCount> {};
// Make sure we don't overflow the smi.
- STATIC_ASSERT(DescriptorValueIndexBits::kNext <= kSmiValueSize);
+ STATIC_ASSERT(DescriptorBits::kNext <= kSmiValueSize);
//
- // Encoding when KindBits contains kForFields.
+ // Encoding when KindBits contains kField.
//
- class IsInobjectBits
- : public BitField<bool, DoNegativeLookupOnReceiverBits::kNext, 1> {};
+ class IsInobjectBits : public BitField<bool, LookupOnReceiverBits::kNext, 1> {
+ };
class IsDoubleBits : public BitField<bool, IsInobjectBits::kNext, 1> {};
// +1 here is to cover all possible JSObject header sizes.
class FieldOffsetBits
@@ -59,7 +66,7 @@ class LoadHandler {
STATIC_ASSERT(FieldOffsetBits::kNext <= kSmiValueSize);
//
- // Encoding when KindBits contains kForElements.
+ // Encoding when KindBits contains kElement.
//
class IsJsArrayBits : public BitField<bool, KindBits::kNext, 1> {};
class ConvertHoleBits : public BitField<bool, IsJsArrayBits::kNext, 1> {};
@@ -83,36 +90,47 @@ class LoadHandler {
static const int kHolderCellIndex = 2;
static const int kFirstPrototypeIndex = 3;
+ // Creates a Smi-handler for loading a property from a slow object.
+ static inline Handle<Smi> LoadNormal(Isolate* isolate);
+
+ // Creates a Smi-handler for loading a property from a global object.
+ static inline Handle<Smi> LoadGlobal(Isolate* isolate);
+
+ // Creates a Smi-handler for loading a property from an object with an
+ // interceptor.
+ static inline Handle<Smi> LoadInterceptor(Isolate* isolate);
+
// Creates a Smi-handler for loading a field from fast object.
- static inline Handle<Object> LoadField(Isolate* isolate,
- FieldIndex field_index);
+ static inline Handle<Smi> LoadField(Isolate* isolate, FieldIndex field_index);
// Creates a Smi-handler for loading a constant from fast object.
- static inline Handle<Object> LoadConstant(Isolate* isolate, int descriptor);
+ static inline Handle<Smi> LoadConstant(Isolate* isolate, int descriptor);
+
+ // Creates a Smi-handler for calling a getter on a fast object.
+ static inline Handle<Smi> LoadAccessor(Isolate* isolate, int descriptor);
// Creates a Smi-handler for loading an Api getter property from fast object.
- static inline Handle<Object> LoadApiGetter(Isolate* isolate, int descriptor);
+ static inline Handle<Smi> LoadApiGetter(Isolate* isolate, int descriptor);
// Sets DoAccessCheckOnReceiverBits in given Smi-handler. The receiver
// check is a part of a prototype chain check.
- static inline Handle<Object> EnableAccessCheckOnReceiver(
- Isolate* isolate, Handle<Object> smi_handler);
+ static inline Handle<Smi> EnableAccessCheckOnReceiver(
+ Isolate* isolate, Handle<Smi> smi_handler);
- // Sets DoNegativeLookupOnReceiverBits in given Smi-handler. The receiver
+ // Sets LookupOnReceiverBits in given Smi-handler. The receiver
// check is a part of a prototype chain check.
- static inline Handle<Object> EnableNegativeLookupOnReceiver(
- Isolate* isolate, Handle<Object> smi_handler);
+ static inline Handle<Smi> EnableLookupOnReceiver(Isolate* isolate,
+ Handle<Smi> smi_handler);
// Creates a Smi-handler for loading a non-existent property. Works only as
// a part of prototype chain check.
- static inline Handle<Object> LoadNonExistent(
- Isolate* isolate, bool do_negative_lookup_on_receiver);
+ static inline Handle<Smi> LoadNonExistent(Isolate* isolate);
// Creates a Smi-handler for loading an element.
- static inline Handle<Object> LoadElement(Isolate* isolate,
- ElementsKind elements_kind,
- bool convert_hole_to_undefined,
- bool is_js_array);
+ static inline Handle<Smi> LoadElement(Isolate* isolate,
+ ElementsKind elements_kind,
+ bool convert_hole_to_undefined,
+ bool is_js_array);
};
// A set of bit fields representing Smi handlers for stores.
@@ -122,11 +140,12 @@ class StoreHandler {
kStoreElement,
kStoreField,
kStoreConstField,
+ kStoreNormal,
kTransitionToField,
// TODO(ishell): remove once constant field tracking is done.
kTransitionToConstant = kStoreConstField
};
- class KindBits : public BitField<Kind, 0, 2> {};
+ class KindBits : public BitField<Kind, 0, 3> {};
enum FieldRepresentation { kSmi, kDouble, kHeapObject, kTagged };
@@ -134,22 +153,19 @@ class StoreHandler {
// kinds.
// Index of a value entry in the descriptor array.
- // +2 here is because each descriptor entry occupies 3 slots in array.
- class DescriptorValueIndexBits
- : public BitField<unsigned, KindBits::kNext,
- kDescriptorIndexBitCount + 2> {};
+ class DescriptorBits
+ : public BitField<unsigned, KindBits::kNext, kDescriptorIndexBitCount> {};
//
// Encoding when KindBits contains kTransitionToConstant.
//
// Make sure we don't overflow the smi.
- STATIC_ASSERT(DescriptorValueIndexBits::kNext <= kSmiValueSize);
+ STATIC_ASSERT(DescriptorBits::kNext <= kSmiValueSize);
//
// Encoding when KindBits contains kStoreField or kTransitionToField.
//
- class ExtendStorageBits
- : public BitField<bool, DescriptorValueIndexBits::kNext, 1> {};
+ class ExtendStorageBits : public BitField<bool, DescriptorBits::kNext, 1> {};
class IsInobjectBits : public BitField<bool, ExtendStorageBits::kNext, 1> {};
class FieldRepresentationBits
: public BitField<FieldRepresentation, IsInobjectBits::kNext, 2> {};
@@ -175,29 +191,30 @@ class StoreHandler {
static const int kFirstPrototypeIndex = 3;
// Creates a Smi-handler for storing a field to fast object.
- static inline Handle<Object> StoreField(Isolate* isolate, int descriptor,
- FieldIndex field_index,
- PropertyConstness constness,
- Representation representation);
+ static inline Handle<Smi> StoreField(Isolate* isolate, int descriptor,
+ FieldIndex field_index,
+ PropertyConstness constness,
+ Representation representation);
+
+ // Creates a Smi-handler for storing a property to a slow object.
+ static inline Handle<Smi> StoreNormal(Isolate* isolate);
// Creates a Smi-handler for transitioning store to a field.
- static inline Handle<Object> TransitionToField(Isolate* isolate,
- int descriptor,
- FieldIndex field_index,
- Representation representation,
- bool extend_storage);
+ static inline Handle<Smi> TransitionToField(Isolate* isolate, int descriptor,
+ FieldIndex field_index,
+ Representation representation,
+ bool extend_storage);
// Creates a Smi-handler for transitioning store to a constant field (in this
// case the only thing that needs to be done is an update of a map).
- static inline Handle<Object> TransitionToConstant(Isolate* isolate,
- int descriptor);
+ static inline Handle<Smi> TransitionToConstant(Isolate* isolate,
+ int descriptor);
private:
- static inline Handle<Object> StoreField(Isolate* isolate, Kind kind,
- int descriptor,
- FieldIndex field_index,
- Representation representation,
- bool extend_storage);
+ static inline Handle<Smi> StoreField(Isolate* isolate, Kind kind,
+ int descriptor, FieldIndex field_index,
+ Representation representation,
+ bool extend_storage);
};
} // namespace internal
diff --git a/deps/v8/src/ic/ia32/handler-compiler-ia32.cc b/deps/v8/src/ic/ia32/handler-compiler-ia32.cc
index f0f8faddde..324dc10d03 100644
--- a/deps/v8/src/ic/ia32/handler-compiler-ia32.cc
+++ b/deps/v8/src/ic/ia32/handler-compiler-ia32.cc
@@ -17,37 +17,13 @@ namespace internal {
#define __ ACCESS_MASM(masm)
-
-void NamedLoadHandlerCompiler::GenerateLoadViaGetter(
- MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder,
- int accessor_index, int expected_arguments, Register scratch) {
+void NamedLoadHandlerCompiler::GenerateLoadViaGetterForDeopt(
+ MacroAssembler* masm) {
{
FrameScope scope(masm, StackFrame::INTERNAL);
-
- // Save context register
- __ push(esi);
-
- if (accessor_index >= 0) {
- DCHECK(!holder.is(scratch));
- DCHECK(!receiver.is(scratch));
- // Call the JavaScript getter with the receiver on the stack.
- if (map->IsJSGlobalObjectMap()) {
- // Swap in the global receiver.
- __ mov(scratch,
- FieldOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
- receiver = scratch;
- }
- __ push(receiver);
- __ LoadAccessor(edi, holder, accessor_index, ACCESSOR_GETTER);
- __ Set(eax, 0);
- __ Call(masm->isolate()->builtins()->CallFunction(
- ConvertReceiverMode::kNotNullOrUndefined),
- RelocInfo::CODE_TARGET);
- } else {
- // If we generate a global code snippet for deoptimization only, remember
- // the place to continue after deoptimization.
- masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
- }
+ // If we generate a global code snippet for deoptimization only, remember
+ // the place to continue after deoptimization.
+ masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
// Restore context register.
__ pop(esi);
@@ -201,12 +177,6 @@ void PropertyHandlerCompiler::GenerateApiAccessorCall(
__ mov(data, FieldOperand(data, CallHandlerInfo::kDataOffset));
}
- if (api_call_info->fast_handler()->IsCode()) {
- // Just tail call into the code.
- __ Jump(handle(Code::cast(api_call_info->fast_handler())),
- RelocInfo::CODE_TARGET);
- return;
- }
// Put api_function_address in place.
Address function_address = v8::ToCData<Address>(api_call_info->callback());
__ mov(api_function_address, Immediate(function_address));
@@ -293,23 +263,6 @@ void NamedStoreHandlerCompiler::GenerateStoreViaSetter(
}
}
-static void CompileCallLoadPropertyWithInterceptor(
- MacroAssembler* masm, Register receiver, Register holder, Register name,
- Handle<JSObject> holder_obj, Runtime::FunctionId id) {
- DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength ==
- Runtime::FunctionForId(id)->nargs);
-
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
- __ push(name);
- __ push(receiver);
- __ push(holder);
-
- __ CallRuntime(id);
-}
-
#undef __
#define __ ACCESS_MASM(masm())
@@ -347,8 +300,7 @@ void PropertyHandlerCompiler::GenerateAccessCheck(
Register PropertyHandlerCompiler::CheckPrototypes(
Register object_reg, Register holder_reg, Register scratch1,
- Register scratch2, Handle<Name> name, Label* miss,
- ReturnHolder return_what) {
+ Register scratch2, Handle<Name> name, Label* miss) {
Handle<Map> receiver_map = map();
// Make sure there's no overlap between holder and object registers.
@@ -413,15 +365,14 @@ Register PropertyHandlerCompiler::CheckPrototypes(
// Log the check depth.
LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
- bool return_holder = return_what == RETURN_HOLDER;
- if (return_holder && depth != 0) {
+ if (depth != 0) {
Handle<WeakCell> weak_cell =
Map::GetOrCreatePrototypeWeakCell(current, isolate());
__ LoadWeakValue(reg, weak_cell, miss);
}
// Return the register containing the holder.
- return return_holder ? reg : no_reg;
+ return reg;
}
@@ -451,102 +402,6 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
}
}
-void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
- LookupIterator* it, Register holder_reg) {
- DCHECK(holder()->HasNamedInterceptor());
- DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
-
- // Compile the interceptor call, followed by inline code to load the
- // property from further up the prototype chain if the call fails.
- // Check that the maps haven't changed.
- DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
-
- // Preserve the receiver register explicitly whenever it is different from the
- // holder and it is needed should the interceptor return without any result.
- // The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD
- // case might cause a miss during the prototype check.
- bool must_perform_prototype_check =
- !holder().is_identical_to(it->GetHolder<JSObject>());
- bool must_preserve_receiver_reg =
- !receiver().is(holder_reg) &&
- (it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check);
-
- // Save necessary data before invoking an interceptor.
- // Requires a frame to make GC aware of pushed pointers.
- {
- FrameScope frame_scope(masm(), StackFrame::INTERNAL);
-
- if (must_preserve_receiver_reg) {
- __ push(receiver());
- }
- __ push(holder_reg);
- __ push(this->name());
- InterceptorVectorSlotPush(holder_reg);
- // Invoke an interceptor. Note: map checks from receiver to
- // interceptor's holder has been compiled before (see a caller
- // of this method.)
- CompileCallLoadPropertyWithInterceptor(
- masm(), receiver(), holder_reg, this->name(), holder(),
- Runtime::kLoadPropertyWithInterceptorOnly);
-
- // Check if interceptor provided a value for property. If it's
- // the case, return immediately.
- Label interceptor_failed;
- __ cmp(eax, factory()->no_interceptor_result_sentinel());
- __ j(equal, &interceptor_failed);
- frame_scope.GenerateLeaveFrame();
- __ ret(0);
-
- // Clobber registers when generating debug-code to provoke errors.
- __ bind(&interceptor_failed);
- if (FLAG_debug_code) {
- __ mov(receiver(), Immediate(bit_cast<int32_t>(kZapValue)));
- __ mov(holder_reg, Immediate(bit_cast<int32_t>(kZapValue)));
- __ mov(this->name(), Immediate(bit_cast<int32_t>(kZapValue)));
- }
-
- InterceptorVectorSlotPop(holder_reg);
- __ pop(this->name());
- __ pop(holder_reg);
- if (must_preserve_receiver_reg) {
- __ pop(receiver());
- }
-
- // Leave the internal frame.
- }
-
- GenerateLoadPostInterceptor(it, holder_reg);
-}
-
-
-void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
- DCHECK(holder()->HasNamedInterceptor());
- DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
- // Call the runtime system to load the interceptor.
-
- // Stack:
- // return address
-
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
- __ push(receiver());
- __ push(holder_reg);
- // See NamedLoadHandlerCompiler::InterceptorVectorSlotPop() for details.
- if (holder_reg.is(receiver())) {
- __ push(slot());
- __ push(vector());
- } else {
- __ push(scratch3()); // slot
- __ push(scratch2()); // vector
- }
- __ push(Operand(esp, 4 * kPointerSize)); // return address
- __ mov(Operand(esp, 5 * kPointerSize), name());
-
- __ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor);
-}
-
void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() {
// Zap register aliases of the arguments passed on the stack to ensure they
// are properly loaded by the handler (debug-only).
@@ -595,43 +450,6 @@ Register NamedStoreHandlerCompiler::value() {
}
-Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
- Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) {
- Label miss;
- if (IC::ShouldPushPopSlotAndVector(kind())) {
- PushVectorAndSlot();
- }
- FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING);
- // Get the value from the cell.
- Register result = StoreDescriptor::ValueRegister();
- Handle<WeakCell> weak_cell = factory()->NewWeakCell(cell);
- __ LoadWeakValue(result, weak_cell, &miss);
- __ mov(result, FieldOperand(result, PropertyCell::kValueOffset));
-
- // Check for deleted property if property can actually be deleted.
- if (is_configurable) {
- __ cmp(result, factory()->the_hole_value());
- __ j(equal, &miss);
- } else if (FLAG_debug_code) {
- __ cmp(result, factory()->the_hole_value());
- __ Check(not_equal, kDontDeleteCellsCannotContainTheHole);
- }
-
- Counters* counters = isolate()->counters();
- __ IncrementCounter(counters->ic_named_load_global_stub(), 1);
- // The code above already loads the result into the return register.
- if (IC::ShouldPushPopSlotAndVector(kind())) {
- DiscardVectorAndSlot();
- }
- __ ret(0);
-
- FrontendFooter(name, &miss);
-
- // Return the generated code.
- return GetCode(kind(), name);
-}
-
-
#undef __
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/ic/ic-inl.h b/deps/v8/src/ic/ic-inl.h
index aacb69091e..8ac3bd99da 100644
--- a/deps/v8/src/ic/ic-inl.h
+++ b/deps/v8/src/ic/ic-inl.h
@@ -86,44 +86,10 @@ Code* IC::target() const {
bool IC::IsHandler(Object* object) {
return (object->IsSmi() && (object != nullptr)) || object->IsTuple2() ||
- object->IsTuple3() || object->IsFixedArray() ||
+ object->IsTuple3() || object->IsFixedArray() || object->IsWeakCell() ||
(object->IsCode() && Code::cast(object)->is_handler());
}
-Handle<Map> IC::GetHandlerCacheHolder(Handle<Map> receiver_map,
- bool receiver_is_holder, Isolate* isolate,
- CacheHolderFlag* flag) {
- if (receiver_is_holder) {
- *flag = kCacheOnReceiver;
- return receiver_map;
- }
- Handle<JSFunction> builtin_ctor;
- if (Map::GetConstructorFunction(receiver_map, isolate->native_context())
- .ToHandle(&builtin_ctor)) {
- *flag = kCacheOnPrototypeReceiverIsPrimitive;
- return handle(HeapObject::cast(builtin_ctor->instance_prototype())->map());
- }
- *flag = receiver_map->is_dictionary_map()
- ? kCacheOnPrototypeReceiverIsDictionary
- : kCacheOnPrototype;
- // Callers must ensure that the prototype is non-null.
- return handle(JSObject::cast(receiver_map->prototype())->map());
-}
-
-
-Handle<Map> IC::GetICCacheHolder(Handle<Map> map, Isolate* isolate,
- CacheHolderFlag* flag) {
- Handle<JSFunction> builtin_ctor;
- if (Map::GetConstructorFunction(map, isolate->native_context())
- .ToHandle(&builtin_ctor)) {
- *flag = kCacheOnPrototype;
- return handle(builtin_ctor->initial_map());
- }
- *flag = kCacheOnReceiver;
- return map;
-}
-
-
bool IC::AddressIsDeoptimizedCode() const {
return AddressIsDeoptimizedCode(isolate(), address());
}
diff --git a/deps/v8/src/ic/ic.cc b/deps/v8/src/ic/ic.cc
index f11f94a770..b3b0eb4c84 100644
--- a/deps/v8/src/ic/ic.cc
+++ b/deps/v8/src/ic/ic.cc
@@ -4,8 +4,6 @@
#include "src/ic/ic.h"
-#include <iostream>
-
#include "src/accessors.h"
#include "src/api-arguments-inl.h"
#include "src/api.h"
@@ -70,7 +68,6 @@ const char* GetTransitionMarkModifier(KeyedAccessStoreMode mode) {
void IC::TraceIC(const char* type, Handle<Object> name) {
if (FLAG_ic_stats) {
if (AddressIsDeoptimizedCode()) return;
- DCHECK(UseVector());
State new_state = nexus()->StateFromFeedback();
TraceIC(type, name, state(), new_state);
}
@@ -228,7 +225,6 @@ IC::IC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus)
pc_address_ = StackFrame::ResolveReturnAddressLocation(pc_address);
if (nexus) {
kind_ = nexus->kind();
- DCHECK(UseVector());
state_ = nexus->StateFromFeedback();
extra_ic_state_ = kNoExtraICState;
} else {
@@ -244,7 +240,6 @@ IC::IC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus)
UNREACHABLE();
kind_ = FeedbackSlotKind::kInvalid;
}
- DCHECK(!UseVector());
state_ = StateFromCode(target);
extra_ic_state_ = target->extra_ic_state();
}
@@ -316,8 +311,7 @@ static void LookupForRead(LookupIterator* it) {
break;
}
case LookupIterator::ACCESS_CHECK:
- // PropertyHandlerCompiler::CheckPrototypes() knows how to emit
- // access checks for global proxies.
+ // ICs know how to perform access checks on global proxies.
if (it->GetHolder<JSObject>()->IsJSGlobalProxy() && it->HasAccess()) {
break;
}
@@ -333,7 +327,6 @@ static void LookupForRead(LookupIterator* it) {
bool IC::ShouldRecomputeHandler(Handle<String> name) {
if (!RecomputeHandlerForName(name)) return false;
- DCHECK(UseVector());
maybe_handler_ = nexus()->FindHandlerForMap(receiver_map());
// This is a contextual access, always just update the handler and stay
@@ -362,7 +355,6 @@ bool IC::RecomputeHandlerForName(Handle<Object> name) {
if (is_keyed()) {
// Determine whether the failure is due to a name failure.
if (!name->IsName()) return false;
- DCHECK(UseVector());
Name* stub_name = nexus()->FindFirstName();
if (*name != stub_name) return false;
}
@@ -442,6 +434,16 @@ void IC::OnFeedbackChanged(Isolate* isolate, JSFunction* host_function) {
TypeFeedbackInfo* info = TypeFeedbackInfo::cast(host->type_feedback_info());
info->change_own_type_change_checksum();
host->set_profiler_ticks(0);
+ } else if (host_function->IsInterpreted()) {
+ if (FLAG_trace_opt_verbose) {
+ if (host_function->shared()->profiler_ticks() != 0) {
+ PrintF("[resetting ticks for ");
+ host_function->PrintName();
+ PrintF(" due from %d due to IC change]\n",
+ host_function->shared()->profiler_ticks());
+ }
+ }
+ host_function->shared()->set_profiler_ticks(0);
}
isolate->runtime_profiler()->NotifyICChanged();
// TODO(2029): When an optimized function is patched, it would
@@ -452,8 +454,9 @@ void IC::OnFeedbackChanged(Isolate* isolate, JSFunction* host_function) {
void IC::PostPatching(Address address, Code* target, Code* old_target) {
// Type vector based ICs update these statistics at a different time because
// they don't always patch on state change.
- // TODO(ishell): DCHECK
- if (ICUseVector(target->kind())) return;
+ DCHECK(target->kind() == Code::BINARY_OP_IC ||
+ target->kind() == Code::COMPARE_IC ||
+ target->kind() == Code::TO_BOOLEAN_IC);
DCHECK(old_target->is_inline_cache_stub());
DCHECK(target->is_inline_cache_stub());
@@ -518,20 +521,11 @@ static bool MigrateDeprecated(Handle<Object> object) {
}
void IC::ConfigureVectorState(IC::State new_state, Handle<Object> key) {
- DCHECK(UseVector());
if (new_state == PREMONOMORPHIC) {
nexus()->ConfigurePremonomorphic();
} else if (new_state == MEGAMORPHIC) {
- if (IsLoadIC() || IsStoreIC() || IsStoreOwnIC()) {
- nexus()->ConfigureMegamorphic();
- } else if (IsKeyedLoadIC()) {
- KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>();
- nexus->ConfigureMegamorphicKeyed(key->IsName() ? PROPERTY : ELEMENT);
- } else {
- DCHECK(IsKeyedStoreIC());
- KeyedStoreICNexus* nexus = casted_nexus<KeyedStoreICNexus>();
- nexus->ConfigureMegamorphicKeyed(key->IsName() ? PROPERTY : ELEMENT);
- }
+ DCHECK_IMPLIES(!is_keyed(), key->IsName());
+ nexus()->ConfigureMegamorphic(key->IsName() ? PROPERTY : ELEMENT);
} else {
UNREACHABLE();
}
@@ -542,49 +536,13 @@ void IC::ConfigureVectorState(IC::State new_state, Handle<Object> key) {
void IC::ConfigureVectorState(Handle<Name> name, Handle<Map> map,
Handle<Object> handler) {
- DCHECK(UseVector());
- switch (kind_) {
- case FeedbackSlotKind::kLoadProperty: {
- LoadICNexus* nexus = casted_nexus<LoadICNexus>();
- nexus->ConfigureMonomorphic(map, handler);
- break;
- }
- case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
- case FeedbackSlotKind::kLoadGlobalInsideTypeof: {
- LoadGlobalICNexus* nexus = casted_nexus<LoadGlobalICNexus>();
- nexus->ConfigureHandlerMode(handler);
- break;
- }
- case FeedbackSlotKind::kLoadKeyed: {
- KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>();
- nexus->ConfigureMonomorphic(name, map, handler);
- break;
- }
- case FeedbackSlotKind::kStoreNamedSloppy:
- case FeedbackSlotKind::kStoreNamedStrict:
- case FeedbackSlotKind::kStoreOwnNamed: {
- StoreICNexus* nexus = casted_nexus<StoreICNexus>();
- nexus->ConfigureMonomorphic(map, handler);
- break;
- }
- case FeedbackSlotKind::kStoreKeyedSloppy:
- case FeedbackSlotKind::kStoreKeyedStrict: {
- KeyedStoreICNexus* nexus = casted_nexus<KeyedStoreICNexus>();
- nexus->ConfigureMonomorphic(name, map, handler);
- break;
- }
- case FeedbackSlotKind::kCall:
- case FeedbackSlotKind::kBinaryOp:
- case FeedbackSlotKind::kCompareOp:
- case FeedbackSlotKind::kToBoolean:
- case FeedbackSlotKind::kCreateClosure:
- case FeedbackSlotKind::kLiteral:
- case FeedbackSlotKind::kGeneral:
- case FeedbackSlotKind::kStoreDataPropertyInLiteral:
- case FeedbackSlotKind::kInvalid:
- case FeedbackSlotKind::kKindsNumber:
- UNREACHABLE();
- break;
+ if (IsLoadGlobalIC()) {
+ LoadGlobalICNexus* nexus = casted_nexus<LoadGlobalICNexus>();
+ nexus->ConfigureHandlerMode(handler);
+ } else {
+ // Non-keyed ICs don't track the name explicitly.
+ if (!is_keyed()) name = Handle<Name>::null();
+ nexus()->ConfigureMonomorphic(name, map, handler);
}
vector_set_ = true;
@@ -593,64 +551,15 @@ void IC::ConfigureVectorState(Handle<Name> name, Handle<Map> map,
void IC::ConfigureVectorState(Handle<Name> name, MapHandleList* maps,
List<Handle<Object>>* handlers) {
- DCHECK(UseVector());
- switch (kind_) {
- case FeedbackSlotKind::kLoadProperty: {
- LoadICNexus* nexus = casted_nexus<LoadICNexus>();
- nexus->ConfigurePolymorphic(maps, handlers);
- break;
- }
- case FeedbackSlotKind::kLoadKeyed: {
- KeyedLoadICNexus* nexus = casted_nexus<KeyedLoadICNexus>();
- nexus->ConfigurePolymorphic(name, maps, handlers);
- break;
- }
- case FeedbackSlotKind::kStoreNamedSloppy:
- case FeedbackSlotKind::kStoreNamedStrict:
- case FeedbackSlotKind::kStoreOwnNamed: {
- StoreICNexus* nexus = casted_nexus<StoreICNexus>();
- nexus->ConfigurePolymorphic(maps, handlers);
- break;
- }
- case FeedbackSlotKind::kStoreKeyedSloppy:
- case FeedbackSlotKind::kStoreKeyedStrict: {
- KeyedStoreICNexus* nexus = casted_nexus<KeyedStoreICNexus>();
- nexus->ConfigurePolymorphic(name, maps, handlers);
- break;
- }
- case FeedbackSlotKind::kCall:
- case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
- case FeedbackSlotKind::kLoadGlobalInsideTypeof:
- case FeedbackSlotKind::kBinaryOp:
- case FeedbackSlotKind::kCompareOp:
- case FeedbackSlotKind::kToBoolean:
- case FeedbackSlotKind::kCreateClosure:
- case FeedbackSlotKind::kLiteral:
- case FeedbackSlotKind::kGeneral:
- case FeedbackSlotKind::kStoreDataPropertyInLiteral:
- case FeedbackSlotKind::kInvalid:
- case FeedbackSlotKind::kKindsNumber:
- UNREACHABLE();
- break;
- }
-
- vector_set_ = true;
- OnFeedbackChanged(isolate(), GetHostFunction());
-}
-
-void IC::ConfigureVectorState(MapHandleList* maps,
- MapHandleList* transitioned_maps,
- List<Handle<Object>>* handlers) {
- DCHECK(UseVector());
- DCHECK(IsKeyedStoreIC());
- KeyedStoreICNexus* nexus = casted_nexus<KeyedStoreICNexus>();
- nexus->ConfigurePolymorphic(maps, transitioned_maps, handlers);
+ DCHECK(!IsLoadGlobalIC());
+ // Non-keyed ICs don't track the name explicitly.
+ if (!is_keyed()) name = Handle<Name>::null();
+ nexus()->ConfigurePolymorphic(name, maps, handlers);
vector_set_ = true;
OnFeedbackChanged(isolate(), GetHostFunction());
}
-
MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<Name> name) {
// If the object is undefined or null it's illegal to try to get any
// of its properties; throw a TypeError in that case.
@@ -771,11 +680,10 @@ bool IC::UpdatePolymorphicIC(Handle<Name> name, Handle<Object> handler) {
int number_of_valid_maps =
number_of_maps - deprecated_maps - (handler_to_overwrite != -1);
- if (number_of_valid_maps >= 4) return false;
+ if (number_of_valid_maps >= kMaxPolymorphicMapCount) return false;
if (number_of_maps == 0 && state() != MONOMORPHIC && state() != POLYMORPHIC) {
return false;
}
- DCHECK(UseVector());
if (!nexus()->FindHandlers(&handlers, maps.length())) return false;
number_of_valid_maps++;
@@ -834,7 +742,7 @@ bool IC::IsTransitionOfMonomorphicTarget(Map* source_map, Map* target_map) {
void IC::PatchCache(Handle<Name> name, Handle<Object> handler) {
DCHECK(IsHandler(*handler));
// Currently only load and store ICs support non-code handlers.
- DCHECK_IMPLIES(!handler->IsCode(), IsAnyLoad() || IsAnyStore());
+ DCHECK(IsAnyLoad() || IsAnyStore());
switch (state()) {
case UNINITIALIZED:
case PREMONOMORPHIC:
@@ -854,13 +762,11 @@ void IC::PatchCache(Handle<Name> name, Handle<Object> handler) {
// same key.
CopyICToMegamorphicCache(name);
}
- DCHECK(UseVector());
ConfigureVectorState(MEGAMORPHIC, name);
// Fall through.
case MEGAMORPHIC:
UpdateMegamorphicCache(*receiver_map(), *name, *handler);
// Indicate that we've handled this case.
- DCHECK(UseVector());
vector_set_ = true;
break;
case GENERIC:
@@ -869,7 +775,7 @@ void IC::PatchCache(Handle<Name> name, Handle<Object> handler) {
}
}
-Handle<Object> LoadIC::SimpleFieldLoad(Isolate* isolate, FieldIndex index) {
+Handle<Smi> LoadIC::SimpleFieldLoad(Isolate* isolate, FieldIndex index) {
TRACE_HANDLER_STATS(isolate, LoadIC_LoadFieldDH);
return LoadHandler::LoadField(isolate, index);
}
@@ -880,11 +786,7 @@ template <bool fill_array = true>
int InitPrototypeChecks(Isolate* isolate, Handle<Map> receiver_map,
Handle<JSObject> holder, Handle<Name> name,
Handle<FixedArray> array, int first_index) {
- DCHECK(holder.is_null() || holder->HasFastProperties());
-
- // We don't encode the requirement to check access rights because we already
- // passed the access check for current native context and the access
- // can't be revoked.
+ if (!holder.is_null() && holder->map() == *receiver_map) return 0;
HandleScope scope(isolate);
int checks_count = 0;
@@ -904,6 +806,8 @@ int InitPrototypeChecks(Isolate* isolate, Handle<Map> receiver_map,
checks_count++;
} else if (receiver_map->IsJSGlobalObjectMap()) {
+ // If we are creating a handler for [Load/Store]GlobalIC then we need to
+ // check that the property did not appear in the global object.
if (fill_array) {
Handle<JSGlobalObject> global = isolate->global_object();
Handle<PropertyCell> cell = JSGlobalObject::EnsureEmptyPropertyCell(
@@ -964,25 +868,40 @@ int GetPrototypeCheckCount(Isolate* isolate, Handle<Map> receiver_map,
Handle<FixedArray>(), 0);
}
+Handle<WeakCell> HolderCell(Isolate* isolate, Handle<JSObject> holder,
+ Handle<Name> name, Handle<Smi> smi_handler) {
+ if (holder->IsJSGlobalObject() &&
+ *smi_handler != *LoadHandler::LoadInterceptor(isolate)) {
+ Handle<JSGlobalObject> global = Handle<JSGlobalObject>::cast(holder);
+ GlobalDictionary* dict = global->global_dictionary();
+ int number = dict->FindEntry(name);
+ DCHECK_NE(NameDictionary::kNotFound, number);
+ Handle<PropertyCell> cell(PropertyCell::cast(dict->ValueAt(number)),
+ isolate);
+ return isolate->factory()->NewWeakCell(cell);
+ }
+ return Map::GetOrCreatePrototypeWeakCell(holder, isolate);
+}
+
} // namespace
Handle<Object> LoadIC::LoadFromPrototype(Handle<Map> receiver_map,
Handle<JSObject> holder,
Handle<Name> name,
- Handle<Object> smi_handler) {
+ Handle<Smi> smi_handler) {
int checks_count =
GetPrototypeCheckCount(isolate(), receiver_map, holder, name);
DCHECK_LE(0, checks_count);
- if (receiver_map->IsPrimitiveMap() || receiver_map->IsJSGlobalProxyMap()) {
+ if (receiver_map->IsPrimitiveMap() ||
+ receiver_map->is_access_check_needed()) {
DCHECK(!receiver_map->is_dictionary_map());
DCHECK_LE(1, checks_count); // For native context.
smi_handler =
LoadHandler::EnableAccessCheckOnReceiver(isolate(), smi_handler);
} else if (receiver_map->is_dictionary_map() &&
!receiver_map->IsJSGlobalObjectMap()) {
- smi_handler =
- LoadHandler::EnableNegativeLookupOnReceiver(isolate(), smi_handler);
+ smi_handler = LoadHandler::EnableLookupOnReceiver(isolate(), smi_handler);
}
Handle<Cell> validity_cell =
@@ -990,7 +909,7 @@ Handle<Object> LoadIC::LoadFromPrototype(Handle<Map> receiver_map,
DCHECK(!validity_cell.is_null());
Handle<WeakCell> holder_cell =
- Map::GetOrCreatePrototypeWeakCell(holder, isolate());
+ HolderCell(isolate(), holder, name, smi_handler);
if (checks_count == 0) {
return isolate()->factory()->NewTuple3(holder_cell, smi_handler,
@@ -1006,86 +925,49 @@ Handle<Object> LoadIC::LoadFromPrototype(Handle<Map> receiver_map,
return handler_array;
}
-Handle<Object> LoadIC::LoadNonExistent(Handle<Map> receiver_map,
- Handle<Name> name) {
- Handle<JSObject> holder; // null handle
- int checks_count =
- GetPrototypeCheckCount(isolate(), receiver_map, holder, name);
+Handle<Object> LoadIC::LoadFullChain(Handle<Map> receiver_map,
+ Handle<Object> holder, Handle<Name> name,
+ Handle<Smi> smi_handler) {
+ Handle<JSObject> end; // null handle
+ int checks_count = GetPrototypeCheckCount(isolate(), receiver_map, end, name);
DCHECK_LE(0, checks_count);
- bool do_negative_lookup_on_receiver =
- receiver_map->is_dictionary_map() && !receiver_map->IsJSGlobalObjectMap();
- Handle<Object> smi_handler =
- LoadHandler::LoadNonExistent(isolate(), do_negative_lookup_on_receiver);
-
- if (receiver_map->IsPrimitiveMap() || receiver_map->IsJSGlobalProxyMap()) {
+ if (receiver_map->IsPrimitiveMap() ||
+ receiver_map->is_access_check_needed()) {
DCHECK(!receiver_map->is_dictionary_map());
DCHECK_LE(1, checks_count); // For native context.
smi_handler =
LoadHandler::EnableAccessCheckOnReceiver(isolate(), smi_handler);
+ } else if (receiver_map->is_dictionary_map() &&
+ !receiver_map->IsJSGlobalObjectMap()) {
+ smi_handler = LoadHandler::EnableLookupOnReceiver(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::FromInt(0), isolate());
+ // Lookup on receiver isn't supported in case of a simple smi handler.
+ if (!LoadHandler::LookupOnReceiverBits::decode(smi_handler->value())) {
+ return smi_handler;
+ }
+ validity_cell = handle(Smi::kZero, isolate());
}
Factory* factory = isolate()->factory();
if (checks_count == 0) {
- return factory->NewTuple3(factory->null_value(), smi_handler,
- validity_cell);
+ return factory->NewTuple3(holder, smi_handler, validity_cell);
}
Handle<FixedArray> handler_array(factory->NewFixedArray(
LoadHandler::kFirstPrototypeIndex + checks_count, TENURED));
handler_array->set(LoadHandler::kSmiHandlerIndex, *smi_handler);
handler_array->set(LoadHandler::kValidityCellIndex, *validity_cell);
- handler_array->set(LoadHandler::kHolderCellIndex, *factory->null_value());
- InitPrototypeChecks(isolate(), receiver_map, holder, name, handler_array,
+ handler_array->set(LoadHandler::kHolderCellIndex, *holder);
+ InitPrototypeChecks(isolate(), receiver_map, end, name, handler_array,
LoadHandler::kFirstPrototypeIndex);
return handler_array;
}
-bool IsCompatibleReceiver(LookupIterator* lookup, Handle<Map> receiver_map) {
- DCHECK(lookup->state() == LookupIterator::ACCESSOR);
- Isolate* isolate = lookup->isolate();
- Handle<Object> accessors = lookup->GetAccessors();
- if (accessors->IsAccessorInfo()) {
- Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors);
- if (info->getter() != NULL &&
- !AccessorInfo::IsCompatibleReceiverMap(isolate, info, receiver_map)) {
- return false;
- }
- } else if (accessors->IsAccessorPair()) {
- Handle<Object> getter(Handle<AccessorPair>::cast(accessors)->getter(),
- isolate);
- if (!getter->IsJSFunction() && !getter->IsFunctionTemplateInfo()) {
- return false;
- }
- Handle<JSObject> holder = lookup->GetHolder<JSObject>();
- Handle<Object> receiver = lookup->GetReceiver();
- if (holder->HasFastProperties()) {
- if (getter->IsJSFunction()) {
- Handle<JSFunction> function = Handle<JSFunction>::cast(getter);
- if (!receiver->IsJSObject() && function->shared()->IsUserJavaScript() &&
- is_sloppy(function->shared()->language_mode())) {
- // Calling sloppy non-builtins with a value as the receiver
- // requires boxing.
- return false;
- }
- }
- CallOptimization call_optimization(getter);
- if (call_optimization.is_simple_api_call() &&
- !call_optimization.IsCompatibleReceiverMap(receiver_map, holder)) {
- return false;
- }
- }
- }
- return true;
-}
-
-
void LoadIC::UpdateCaches(LookupIterator* lookup) {
if (state() == UNINITIALIZED && !IsLoadGlobalIC()) {
// This is the first time we execute this inline cache. Set the target to
@@ -1102,34 +984,25 @@ void LoadIC::UpdateCaches(LookupIterator* lookup) {
code = slow_stub();
} else if (!lookup->IsFound()) {
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNonexistentDH);
- code = LoadNonExistent(receiver_map(), lookup->name());
+ Handle<Smi> smi_handler = LoadHandler::LoadNonExistent(isolate());
+ code = LoadFullChain(receiver_map(), isolate()->factory()->null_value(),
+ lookup->name(), smi_handler);
} else {
- if (IsLoadGlobalIC() && lookup->state() == LookupIterator::DATA &&
- lookup->GetReceiver().is_identical_to(lookup->GetHolder<Object>())) {
- DCHECK(lookup->GetReceiver()->IsJSGlobalObject());
- // Now update the cell in the feedback vector.
- LoadGlobalICNexus* nexus = casted_nexus<LoadGlobalICNexus>();
- nexus->ConfigurePropertyCellMode(lookup->GetPropertyCell());
- TRACE_IC("LoadGlobalIC", lookup->name());
- return;
- } else if (lookup->state() == LookupIterator::ACCESSOR) {
- if (!IsCompatibleReceiver(lookup, receiver_map())) {
- TRACE_GENERIC_IC("incompatible receiver type");
- code = slow_stub();
+ if (IsLoadGlobalIC()) {
+ if (lookup->TryLookupCachedProperty()) {
+ DCHECK_EQ(LookupIterator::DATA, lookup->state());
}
- } else if (lookup->state() == LookupIterator::INTERCEPTOR) {
- // Perform a lookup behind the interceptor. Copy the LookupIterator
- // since the original iterator will be used to fetch the value.
- LookupIterator it = *lookup;
- it.Next();
- LookupForRead(&it);
- if (it.state() == LookupIterator::ACCESSOR &&
- !IsCompatibleReceiver(&it, receiver_map())) {
- TRACE_GENERIC_IC("incompatible receiver type");
- code = slow_stub();
+ if (lookup->state() == LookupIterator::DATA &&
+ lookup->GetReceiver().is_identical_to(lookup->GetHolder<Object>())) {
+ DCHECK(lookup->GetReceiver()->IsJSGlobalObject());
+ // Now update the cell in the feedback vector.
+ LoadGlobalICNexus* nexus = casted_nexus<LoadGlobalICNexus>();
+ nexus->ConfigurePropertyCellMode(lookup->GetPropertyCell());
+ TRACE_IC("LoadGlobalIC", lookup->name());
+ return;
}
}
- if (code.is_null()) code = ComputeHandler(lookup);
+ code = ComputeHandler(lookup);
}
PatchCache(lookup->name(), code);
@@ -1150,69 +1023,17 @@ void IC::UpdateMegamorphicCache(Map* map, Name* name, Object* handler) {
}
void IC::TraceHandlerCacheHitStats(LookupIterator* lookup) {
- if (!FLAG_runtime_call_stats) return;
-
+ DCHECK_EQ(LookupIterator::ACCESSOR, lookup->state());
+ if (V8_LIKELY(!FLAG_runtime_stats)) return;
if (IsAnyLoad()) {
- switch (lookup->state()) {
- case LookupIterator::ACCESS_CHECK:
- TRACE_HANDLER_STATS(isolate(), LoadIC_HandlerCacheHit_AccessCheck);
- break;
- case LookupIterator::INTEGER_INDEXED_EXOTIC:
- TRACE_HANDLER_STATS(isolate(), LoadIC_HandlerCacheHit_Exotic);
- break;
- case LookupIterator::INTERCEPTOR:
- TRACE_HANDLER_STATS(isolate(), LoadIC_HandlerCacheHit_Interceptor);
- break;
- case LookupIterator::JSPROXY:
- TRACE_HANDLER_STATS(isolate(), LoadIC_HandlerCacheHit_JSProxy);
- break;
- case LookupIterator::NOT_FOUND:
- TRACE_HANDLER_STATS(isolate(), LoadIC_HandlerCacheHit_NonExistent);
- break;
- case LookupIterator::ACCESSOR:
- TRACE_HANDLER_STATS(isolate(), LoadIC_HandlerCacheHit_Accessor);
- break;
- case LookupIterator::DATA:
- TRACE_HANDLER_STATS(isolate(), LoadIC_HandlerCacheHit_Data);
- break;
- case LookupIterator::TRANSITION:
- TRACE_HANDLER_STATS(isolate(), LoadIC_HandlerCacheHit_Transition);
- break;
- }
- } else if (IsAnyStore()) {
- switch (lookup->state()) {
- case LookupIterator::ACCESS_CHECK:
- TRACE_HANDLER_STATS(isolate(), StoreIC_HandlerCacheHit_AccessCheck);
- break;
- case LookupIterator::INTEGER_INDEXED_EXOTIC:
- TRACE_HANDLER_STATS(isolate(), StoreIC_HandlerCacheHit_Exotic);
- break;
- case LookupIterator::INTERCEPTOR:
- TRACE_HANDLER_STATS(isolate(), StoreIC_HandlerCacheHit_Interceptor);
- break;
- case LookupIterator::JSPROXY:
- TRACE_HANDLER_STATS(isolate(), StoreIC_HandlerCacheHit_JSProxy);
- break;
- case LookupIterator::NOT_FOUND:
- TRACE_HANDLER_STATS(isolate(), StoreIC_HandlerCacheHit_NonExistent);
- break;
- case LookupIterator::ACCESSOR:
- TRACE_HANDLER_STATS(isolate(), StoreIC_HandlerCacheHit_Accessor);
- break;
- case LookupIterator::DATA:
- TRACE_HANDLER_STATS(isolate(), StoreIC_HandlerCacheHit_Data);
- break;
- case LookupIterator::TRANSITION:
- TRACE_HANDLER_STATS(isolate(), StoreIC_HandlerCacheHit_Transition);
- break;
- }
+ TRACE_HANDLER_STATS(isolate(), LoadIC_HandlerCacheHit_Accessor);
} else {
- TRACE_HANDLER_STATS(isolate(), IC_HandlerCacheHit);
+ DCHECK(IsAnyStore());
+ TRACE_HANDLER_STATS(isolate(), StoreIC_HandlerCacheHit_Accessor);
}
}
-Handle<Object> IC::ComputeHandler(LookupIterator* lookup,
- Handle<Object> value) {
+Handle<Object> IC::ComputeHandler(LookupIterator* lookup) {
// Try to find a globally shared handler stub.
Handle<Object> shared_handler = GetMapIndependentHandler(lookup);
if (!shared_handler.is_null()) {
@@ -1220,24 +1041,8 @@ Handle<Object> IC::ComputeHandler(LookupIterator* lookup,
return shared_handler;
}
- // Otherwise check the map's handler cache for a map-specific handler, and
- // compile one if the cache comes up empty.
- bool receiver_is_holder =
- lookup->GetReceiver().is_identical_to(lookup->GetHolder<JSObject>());
- CacheHolderFlag flag;
- Handle<Map> stub_holder_map;
- if (IsAnyLoad()) {
- stub_holder_map = IC::GetHandlerCacheHolder(
- receiver_map(), receiver_is_holder, isolate(), &flag);
- } else {
- DCHECK(IsAnyStore());
- // Store handlers cannot be cached on prototypes.
- flag = kCacheOnReceiver;
- stub_holder_map = receiver_map();
- }
-
- Handle<Object> handler = PropertyHandlerCompiler::Find(
- lookup->name(), stub_holder_map, handler_kind(), flag);
+ Handle<Code> handler = PropertyHandlerCompiler::Find(
+ lookup->name(), receiver_map(), handler_kind());
// Use the cached value if it exists, and if it is different from the
// handler that just missed.
if (!handler.is_null()) {
@@ -1266,26 +1071,21 @@ Handle<Object> IC::ComputeHandler(LookupIterator* lookup,
}
}
- handler = CompileHandler(lookup, value, flag);
- DCHECK(IC::IsHandler(*handler));
- if (handler->IsCode()) {
- Handle<Code> code = Handle<Code>::cast(handler);
- DCHECK_EQ(Code::ExtractCacheHolderFromFlags(code->flags()), flag);
- Map::UpdateCodeCache(stub_holder_map, lookup->name(), code);
- }
+ handler = CompileHandler(lookup);
+ Map::UpdateCodeCache(receiver_map(), lookup->name(), handler);
return handler;
}
Handle<Object> LoadIC::GetMapIndependentHandler(LookupIterator* lookup) {
Handle<Object> receiver = lookup->GetReceiver();
if (receiver->IsString() &&
- Name::Equals(isolate()->factory()->length_string(), lookup->name())) {
+ *lookup->name() == isolate()->heap()->length_string()) {
FieldIndex index = FieldIndex::ForInObjectOffset(String::kLengthOffset);
return SimpleFieldLoad(isolate(), index);
}
if (receiver->IsStringWrapper() &&
- Name::Equals(isolate()->factory()->length_string(), lookup->name())) {
+ *lookup->name() == isolate()->heap()->length_string()) {
TRACE_HANDLER_STATS(isolate(), LoadIC_StringLengthStub);
StringLengthStub string_length_stub(isolate());
return string_length_stub.GetCode();
@@ -1293,7 +1093,7 @@ Handle<Object> LoadIC::GetMapIndependentHandler(LookupIterator* lookup) {
// Use specialized code for getting prototype of functions.
if (receiver->IsJSFunction() &&
- Name::Equals(isolate()->factory()->prototype_string(), lookup->name()) &&
+ *lookup->name() == isolate()->heap()->prototype_string() &&
receiver->IsConstructor() &&
!Handle<JSFunction>::cast(receiver)
->map()
@@ -1307,8 +1107,27 @@ Handle<Object> LoadIC::GetMapIndependentHandler(LookupIterator* lookup) {
Handle<JSObject> holder = lookup->GetHolder<JSObject>();
bool receiver_is_holder = receiver.is_identical_to(holder);
switch (lookup->state()) {
- case LookupIterator::INTERCEPTOR:
- break; // Custom-compiled handler.
+ case LookupIterator::INTERCEPTOR: {
+ Handle<Smi> smi_handler = LoadHandler::LoadInterceptor(isolate());
+
+ if (holder->GetNamedInterceptor()->non_masking()) {
+ Handle<Object> holder_ref = isolate()->factory()->null_value();
+ if (!receiver_is_holder || IsLoadGlobalIC()) {
+ holder_ref = Map::GetOrCreatePrototypeWeakCell(holder, isolate());
+ }
+ TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNonMaskingInterceptorDH);
+ return LoadFullChain(map, holder_ref, lookup->name(), smi_handler);
+ }
+
+ if (receiver_is_holder) {
+ DCHECK(map->has_named_interceptor());
+ TRACE_HANDLER_STATS(isolate(), LoadIC_LoadInterceptorDH);
+ return smi_handler;
+ }
+
+ TRACE_HANDLER_STATS(isolate(), LoadIC_LoadInterceptorFromPrototypeDH);
+ return LoadFromPrototype(map, holder, lookup->name(), smi_handler);
+ }
case LookupIterator::ACCESSOR: {
// Use simple field loads for some well-known callback properties.
@@ -1321,98 +1140,132 @@ Handle<Object> LoadIC::GetMapIndependentHandler(LookupIterator* lookup) {
return SimpleFieldLoad(isolate(), index);
}
- if (IsCompatibleReceiver(lookup, map)) {
- Handle<Object> accessors = lookup->GetAccessors();
- if (accessors->IsAccessorPair()) {
- if (!holder->HasFastProperties()) {
- TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
- return slow_stub();
- }
- // When debugging we need to go the slow path to flood the accessor.
- if (GetHostFunction()->shared()->HasDebugInfo()) {
- TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
- return slow_stub();
- }
- break; // Custom-compiled handler.
- } else if (accessors->IsAccessorInfo()) {
- Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors);
- if (v8::ToCData<Address>(info->getter()) == nullptr) {
+ Handle<Object> accessors = lookup->GetAccessors();
+ if (accessors->IsAccessorPair()) {
+ if (lookup->TryLookupCachedProperty()) {
+ DCHECK_EQ(LookupIterator::DATA, lookup->state());
+ return ComputeHandler(lookup);
+ }
+
+ // When debugging we need to go the slow path to flood the accessor.
+ if (GetHostFunction()->shared()->HasDebugInfo()) {
+ TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
+ return slow_stub();
+ }
+
+ Handle<Object> getter(AccessorPair::cast(*accessors)->getter(),
+ isolate());
+ if (!getter->IsJSFunction() && !getter->IsFunctionTemplateInfo()) {
+ TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
+ return slow_stub();
+ }
+
+ CallOptimization call_optimization(getter);
+ if (call_optimization.is_simple_api_call()) {
+ if (!call_optimization.IsCompatibleReceiverMap(map, holder) ||
+ !holder->HasFastProperties()) {
TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
return slow_stub();
}
- // Ruled out by IsCompatibleReceiver() above.
- DCHECK(AccessorInfo::IsCompatibleReceiverMap(isolate(), info, map));
- if (!holder->HasFastProperties() ||
- (info->is_sloppy() && !receiver->IsJSReceiver())) {
- DCHECK(!holder->HasFastProperties() || !receiver_is_holder);
+ break;
+ }
+
+ // FunctionTemplate isn't yet supported as smi-handler.
+ if (getter->IsFunctionTemplateInfo()) {
+ if (!holder->HasFastProperties()) {
TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
return slow_stub();
}
- Handle<Object> smi_handler =
- LoadHandler::LoadApiGetter(isolate(), lookup->GetAccessorIndex());
+ break;
+ }
+
+ Handle<Smi> smi_handler;
+ if (holder->HasFastProperties()) {
+ smi_handler =
+ LoadHandler::LoadAccessor(isolate(), lookup->GetAccessorIndex());
+
if (receiver_is_holder) {
- TRACE_HANDLER_STATS(isolate(), LoadIC_LoadApiGetterDH);
+ TRACE_HANDLER_STATS(isolate(), LoadIC_LoadAccessorDH);
return smi_handler;
}
- if (!IsLoadGlobalIC()) {
- TRACE_HANDLER_STATS(isolate(), LoadIC_LoadApiGetterFromPrototypeDH);
- return LoadFromPrototype(map, holder, lookup->name(), smi_handler);
+ TRACE_HANDLER_STATS(isolate(), LoadIC_LoadAccessorFromPrototypeDH);
+ } else if (holder->IsJSGlobalObject()) {
+ TRACE_HANDLER_STATS(isolate(), LoadIC_LoadGlobalFromPrototypeDH);
+ smi_handler = LoadHandler::LoadGlobal(isolate());
+ } else {
+ smi_handler = LoadHandler::LoadNormal(isolate());
+
+ if (receiver_is_holder) {
+ TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNormalDH);
+ return smi_handler;
}
- break; // Custom-compiled handler.
+ TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNormalFromPrototypeDH);
}
+
+ return LoadFromPrototype(map, holder, lookup->name(), smi_handler);
}
- TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
- return slow_stub();
+
+ Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors);
+
+ if (v8::ToCData<Address>(info->getter()) == nullptr ||
+ !AccessorInfo::IsCompatibleReceiverMap(isolate(), info, map) ||
+ !holder->HasFastProperties() ||
+ (info->is_sloppy() && !receiver->IsJSReceiver())) {
+ TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
+ return slow_stub();
+ }
+
+ Handle<Smi> smi_handler =
+ LoadHandler::LoadApiGetter(isolate(), lookup->GetAccessorIndex());
+ TRACE_HANDLER_STATS(isolate(), LoadIC_LoadApiGetterDH);
+ if (receiver_is_holder) return smi_handler;
+ TRACE_HANDLER_STATS(isolate(), LoadIC_LoadApiGetterFromPrototypeDH);
+ return LoadFromPrototype(map, holder, lookup->name(), smi_handler);
}
case LookupIterator::DATA: {
DCHECK_EQ(kData, lookup->property_details().kind());
+ Handle<Smi> smi_handler;
if (lookup->is_dictionary_holder()) {
- if (!IsLoadIC() && !IsLoadGlobalIC()) { // IsKeyedLoadIC()?
- TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
- return slow_stub();
+ smi_handler = LoadHandler::LoadNormal(isolate());
+ if (receiver_is_holder) {
+ if (holder->IsJSGlobalObject()) {
+ // TODO(verwaest): This is a workaround for code that leaks the
+ // global object.
+ TRACE_HANDLER_STATS(isolate(), LoadIC_LoadGlobalDH);
+ smi_handler = LoadHandler::LoadGlobal(isolate());
+ return LoadFromPrototype(map, holder, lookup->name(), smi_handler);
+ }
+ DCHECK(!holder->IsJSGlobalObject());
+ TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNormalDH);
+ return smi_handler;
}
+
if (holder->IsJSGlobalObject()) {
- break; // Custom-compiled handler.
- }
- // There is only one shared stub for loading normalized
- // properties. It does not traverse the prototype chain, so the
- // property must be found in the object for the stub to be
- // applicable.
- if (!receiver_is_holder) {
- TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
- return slow_stub();
+ TRACE_HANDLER_STATS(isolate(), LoadIC_LoadGlobalFromPrototypeDH);
+ smi_handler = LoadHandler::LoadGlobal(isolate());
+ } else {
+ TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNormalFromPrototypeDH);
}
- TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNormal);
- return isolate()->builtins()->LoadIC_Normal();
- }
- // -------------- Fields --------------
- if (lookup->property_details().location() == kField) {
+ } else if (lookup->property_details().location() == kField) {
FieldIndex field = lookup->GetFieldIndex();
- Handle<Object> smi_handler = SimpleFieldLoad(isolate(), field);
- if (receiver_is_holder) {
- return smi_handler;
- }
+ smi_handler = SimpleFieldLoad(isolate(), field);
+ if (receiver_is_holder) return smi_handler;
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldFromPrototypeDH);
- return LoadFromPrototype(map, holder, lookup->name(), smi_handler);
- }
-
- // -------------- Constant properties --------------
- DCHECK_EQ(kDescriptor, lookup->property_details().location());
- Handle<Object> smi_handler =
- LoadHandler::LoadConstant(isolate(), lookup->GetConstantIndex());
- if (receiver_is_holder) {
+ } else {
+ DCHECK_EQ(kDescriptor, lookup->property_details().location());
+ smi_handler =
+ LoadHandler::LoadConstant(isolate(), lookup->GetConstantIndex());
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantDH);
- return smi_handler;
+ if (receiver_is_holder) return smi_handler;
+ TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantFromPrototypeDH);
}
- TRACE_HANDLER_STATS(isolate(), LoadIC_LoadConstantFromPrototypeDH);
return LoadFromPrototype(map, holder, lookup->name(), smi_handler);
}
-
case LookupIterator::INTEGER_INDEXED_EXOTIC:
- TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
- return slow_stub();
+ TRACE_HANDLER_STATS(isolate(), LoadIC_LoadIntegerIndexedExoticDH);
+ return LoadHandler::LoadNonExistent(isolate());
case LookupIterator::ACCESS_CHECK:
case LookupIterator::JSPROXY:
case LookupIterator::NOT_FOUND:
@@ -1423,114 +1276,25 @@ Handle<Object> LoadIC::GetMapIndependentHandler(LookupIterator* lookup) {
return Handle<Code>::null();
}
-Handle<Object> LoadIC::CompileHandler(LookupIterator* lookup,
- Handle<Object> unused,
- CacheHolderFlag cache_holder) {
+Handle<Code> LoadIC::CompileHandler(LookupIterator* lookup) {
+ DCHECK_EQ(LookupIterator::ACCESSOR, lookup->state());
Handle<JSObject> holder = lookup->GetHolder<JSObject>();
-#ifdef DEBUG
- // Only used by DCHECKs below.
- Handle<Object> receiver = lookup->GetReceiver();
- bool receiver_is_holder = receiver.is_identical_to(holder);
-#endif
- // Non-map-specific handler stubs have already been selected.
- DCHECK(!receiver->IsString() ||
- !Name::Equals(isolate()->factory()->length_string(), lookup->name()));
- DCHECK(!receiver->IsStringWrapper() ||
- !Name::Equals(isolate()->factory()->length_string(), lookup->name()));
-
- DCHECK(!(
- receiver->IsJSFunction() &&
- Name::Equals(isolate()->factory()->prototype_string(), lookup->name()) &&
- receiver->IsConstructor() &&
- !Handle<JSFunction>::cast(receiver)
- ->map()
- ->has_non_instance_prototype()));
-
Handle<Map> map = receiver_map();
- switch (lookup->state()) {
- case LookupIterator::INTERCEPTOR: {
- DCHECK(!holder->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
- TRACE_HANDLER_STATS(isolate(), LoadIC_LoadInterceptor);
- NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
- // Perform a lookup behind the interceptor. Copy the LookupIterator since
- // the original iterator will be used to fetch the value.
- LookupIterator it = *lookup;
- it.Next();
- LookupForRead(&it);
- return compiler.CompileLoadInterceptor(&it);
- }
-
- case LookupIterator::ACCESSOR: {
-#ifdef DEBUG
- int object_offset;
- DCHECK(!Accessors::IsJSObjectFieldAccessor(map, lookup->name(),
- &object_offset));
-#endif
-
- DCHECK(IsCompatibleReceiver(lookup, map));
- Handle<Object> accessors = lookup->GetAccessors();
- if (accessors->IsAccessorPair()) {
- if (lookup->TryLookupCachedProperty()) {
- DCHECK_EQ(LookupIterator::DATA, lookup->state());
- return ComputeHandler(lookup);
- }
- DCHECK(holder->HasFastProperties());
- DCHECK(!GetHostFunction()->shared()->HasDebugInfo());
- Handle<Object> getter(Handle<AccessorPair>::cast(accessors)->getter(),
- isolate());
- CallOptimization call_optimization(getter);
- NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
- if (call_optimization.is_simple_api_call()) {
- TRACE_HANDLER_STATS(isolate(), LoadIC_LoadCallback);
- int index = lookup->GetAccessorIndex();
- Handle<Code> code = compiler.CompileLoadCallback(
- lookup->name(), call_optimization, index, slow_stub());
- return code;
- }
- TRACE_HANDLER_STATS(isolate(), LoadIC_LoadViaGetter);
- int expected_arguments = Handle<JSFunction>::cast(getter)
- ->shared()
- ->internal_formal_parameter_count();
- return compiler.CompileLoadViaGetter(
- lookup->name(), lookup->GetAccessorIndex(), expected_arguments);
- } else {
- DCHECK(accessors->IsAccessorInfo());
- Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors);
- DCHECK(v8::ToCData<Address>(info->getter()) != nullptr);
- DCHECK(AccessorInfo::IsCompatibleReceiverMap(isolate(), info, map));
- DCHECK(holder->HasFastProperties());
- DCHECK(!receiver_is_holder);
- DCHECK(!info->is_sloppy() || receiver->IsJSReceiver());
- TRACE_HANDLER_STATS(isolate(), LoadIC_LoadCallback);
- NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
- Handle<Code> code =
- compiler.CompileLoadCallback(lookup->name(), info, slow_stub());
- return code;
- }
- UNREACHABLE();
- }
- case LookupIterator::DATA: {
- DCHECK(lookup->is_dictionary_holder());
- DCHECK(IsLoadIC() || IsLoadGlobalIC());
- DCHECK(holder->IsJSGlobalObject());
- TRACE_HANDLER_STATS(isolate(), LoadIC_LoadGlobal);
- NamedLoadHandlerCompiler compiler(isolate(), map, holder, cache_holder);
- Handle<PropertyCell> cell = lookup->GetPropertyCell();
- Handle<Code> code = compiler.CompileLoadGlobal(cell, lookup->name(),
- lookup->IsConfigurable());
- return code;
- }
-
- case LookupIterator::INTEGER_INDEXED_EXOTIC:
- case LookupIterator::ACCESS_CHECK:
- case LookupIterator::JSPROXY:
- case LookupIterator::NOT_FOUND:
- case LookupIterator::TRANSITION:
- UNREACHABLE();
- }
- UNREACHABLE();
- return slow_stub();
+ Handle<Object> accessors = lookup->GetAccessors();
+ DCHECK(accessors->IsAccessorPair());
+ DCHECK(holder->HasFastProperties());
+ DCHECK(!GetHostFunction()->shared()->HasDebugInfo());
+ Handle<Object> getter(Handle<AccessorPair>::cast(accessors)->getter(),
+ isolate());
+ CallOptimization call_optimization(getter);
+ NamedLoadHandlerCompiler compiler(isolate(), map, holder);
+ DCHECK(call_optimization.is_simple_api_call());
+ TRACE_HANDLER_STATS(isolate(), LoadIC_LoadCallback);
+ int index = lookup->GetAccessorIndex();
+ Handle<Code> code = compiler.CompileLoadCallback(
+ lookup->name(), call_optimization, index, slow_stub());
+ return code;
}
@@ -1563,8 +1327,7 @@ void KeyedLoadIC::UpdateLoadElement(Handle<HeapObject> receiver) {
TargetMaps(&target_receiver_maps);
if (target_receiver_maps.length() == 0) {
- Handle<Object> handler =
- ElementHandlerCompiler::GetKeyedLoadHandler(receiver_map, isolate());
+ Handle<Object> handler = LoadElementHandler(receiver_map);
return ConfigureVectorState(Handle<Name>(), receiver_map, handler);
}
@@ -1592,8 +1355,7 @@ void KeyedLoadIC::UpdateLoadElement(Handle<HeapObject> receiver) {
IsMoreGeneralElementsKindTransition(
target_receiver_maps.at(0)->elements_kind(),
Handle<JSObject>::cast(receiver)->GetElementsKind())) {
- Handle<Object> handler =
- ElementHandlerCompiler::GetKeyedLoadHandler(receiver_map, isolate());
+ Handle<Object> handler = LoadElementHandler(receiver_map);
return ConfigureVectorState(Handle<Name>(), receiver_map, handler);
}
@@ -1616,11 +1378,67 @@ void KeyedLoadIC::UpdateLoadElement(Handle<HeapObject> receiver) {
}
List<Handle<Object>> handlers(target_receiver_maps.length());
- ElementHandlerCompiler compiler(isolate());
- compiler.CompileElementHandlers(&target_receiver_maps, &handlers);
+ LoadElementPolymorphicHandlers(&target_receiver_maps, &handlers);
ConfigureVectorState(Handle<Name>(), &target_receiver_maps, &handlers);
}
+Handle<Object> KeyedLoadIC::LoadElementHandler(Handle<Map> receiver_map) {
+ if (receiver_map->has_indexed_interceptor() &&
+ !receiver_map->GetIndexedInterceptor()->getter()->IsUndefined(
+ isolate()) &&
+ !receiver_map->GetIndexedInterceptor()->non_masking()) {
+ TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_LoadIndexedInterceptorStub);
+ return LoadIndexedInterceptorStub(isolate()).GetCode();
+ }
+ if (receiver_map->IsStringMap()) {
+ TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_LoadIndexedStringStub);
+ return isolate()->builtins()->KeyedLoadIC_IndexedString();
+ }
+ InstanceType instance_type = receiver_map->instance_type();
+ if (instance_type < FIRST_JS_RECEIVER_TYPE) {
+ TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_SlowStub);
+ return isolate()->builtins()->KeyedLoadIC_Slow();
+ }
+
+ ElementsKind elements_kind = receiver_map->elements_kind();
+ if (IsSloppyArgumentsElementsKind(elements_kind)) {
+ TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_KeyedLoadSloppyArgumentsStub);
+ return KeyedLoadSloppyArgumentsStub(isolate()).GetCode();
+ }
+ bool is_js_array = instance_type == JS_ARRAY_TYPE;
+ if (elements_kind == DICTIONARY_ELEMENTS) {
+ TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_LoadElementDH);
+ return LoadHandler::LoadElement(isolate(), elements_kind, false,
+ is_js_array);
+ }
+ DCHECK(IsFastElementsKind(elements_kind) ||
+ IsFixedTypedArrayElementsKind(elements_kind));
+ // TODO(jkummerow): Use IsHoleyElementsKind(elements_kind).
+ bool convert_hole_to_undefined =
+ is_js_array && elements_kind == FAST_HOLEY_ELEMENTS &&
+ *receiver_map == isolate()->get_initial_js_array_map(elements_kind);
+ TRACE_HANDLER_STATS(isolate(), KeyedLoadIC_LoadElementDH);
+ return LoadHandler::LoadElement(isolate(), elements_kind,
+ convert_hole_to_undefined, is_js_array);
+}
+
+void KeyedLoadIC::LoadElementPolymorphicHandlers(
+ MapHandleList* receiver_maps, List<Handle<Object>>* handlers) {
+ for (int i = 0; i < receiver_maps->length(); ++i) {
+ Handle<Map> receiver_map(receiver_maps->at(i));
+
+ // Mark all stable receiver maps that have elements kind transition map
+ // among receiver_maps as unstable because the optimizing compilers may
+ // generate an elements kind transition for this kind of receivers.
+ if (receiver_map->is_stable()) {
+ Map* tmap = receiver_map->FindElementsKindTransitionedMap(receiver_maps);
+ if (tmap != nullptr) {
+ receiver_map->NotifyLeafMapLayoutChange();
+ }
+ }
+ handlers->Add(LoadElementHandler(receiver_map));
+ }
+}
MaybeHandle<Object> KeyedLoadIC::Load(Handle<Object> object,
Handle<Object> key) {
@@ -1738,46 +1556,51 @@ bool StoreIC::LookupForWrite(LookupIterator* it, Handle<Object> value,
return it->IsCacheableTransition();
}
+MaybeHandle<Object> StoreGlobalIC::Store(Handle<Object> object,
+ Handle<Name> name,
+ Handle<Object> value) {
+ DCHECK(object->IsJSGlobalObject());
+ DCHECK(name->IsString());
-MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name,
- Handle<Object> value,
- JSReceiver::StoreFromKeyed store_mode) {
- if (object->IsJSGlobalObject() && name->IsString()) {
- // Look up in script context table.
- Handle<String> str_name = Handle<String>::cast(name);
- Handle<JSGlobalObject> global = Handle<JSGlobalObject>::cast(object);
- Handle<ScriptContextTable> script_contexts(
- global->native_context()->script_context_table());
-
- ScriptContextTable::LookupResult lookup_result;
- if (ScriptContextTable::Lookup(script_contexts, str_name, &lookup_result)) {
- Handle<Context> script_context = ScriptContextTable::GetContext(
- script_contexts, lookup_result.context_index);
- if (lookup_result.mode == CONST) {
- return TypeError(MessageTemplate::kConstAssign, object, name);
- }
+ // Look up in script context table.
+ Handle<String> str_name = Handle<String>::cast(name);
+ Handle<JSGlobalObject> global = Handle<JSGlobalObject>::cast(object);
+ Handle<ScriptContextTable> script_contexts(
+ global->native_context()->script_context_table());
- Handle<Object> previous_value =
- FixedArray::get(*script_context, lookup_result.slot_index, isolate());
+ ScriptContextTable::LookupResult lookup_result;
+ if (ScriptContextTable::Lookup(script_contexts, str_name, &lookup_result)) {
+ Handle<Context> script_context = ScriptContextTable::GetContext(
+ script_contexts, lookup_result.context_index);
+ if (lookup_result.mode == CONST) {
+ return TypeError(MessageTemplate::kConstAssign, object, name);
+ }
- if (previous_value->IsTheHole(isolate())) {
- // Do not install stubs and stay pre-monomorphic for
- // uninitialized accesses.
- return ReferenceError(name);
- }
+ Handle<Object> previous_value =
+ FixedArray::get(*script_context, lookup_result.slot_index, isolate());
- if (FLAG_use_ic &&
- StoreScriptContextFieldStub::Accepted(&lookup_result)) {
- TRACE_HANDLER_STATS(isolate(), StoreIC_StoreScriptContextFieldStub);
- StoreScriptContextFieldStub stub(isolate(), &lookup_result);
- PatchCache(name, stub.GetCode());
- }
+ if (previous_value->IsTheHole(isolate())) {
+ // Do not install stubs and stay pre-monomorphic for
+ // uninitialized accesses.
+ return ReferenceError(name);
+ }
- script_context->set(lookup_result.slot_index, *value);
- return value;
+ if (FLAG_use_ic && StoreScriptContextFieldStub::Accepted(&lookup_result)) {
+ TRACE_HANDLER_STATS(isolate(), StoreIC_StoreScriptContextFieldStub);
+ StoreScriptContextFieldStub stub(isolate(), &lookup_result);
+ PatchCache(name, stub.GetCode());
}
+
+ script_context->set(lookup_result.slot_index, *value);
+ return value;
}
+ return StoreIC::Store(object, name, value);
+}
+
+MaybeHandle<Object> StoreIC::Store(Handle<Object> object, Handle<Name> name,
+ Handle<Object> value,
+ JSReceiver::StoreFromKeyed store_mode) {
// TODO(verwaest): Let SetProperty do the migration, since storing a property
// might deprecate the current map again, if value does not fit.
if (MigrateDeprecated(object) || object->IsJSProxy()) {
@@ -1825,7 +1648,7 @@ void StoreIC::UpdateCaches(LookupIterator* lookup, Handle<Object> value,
Handle<Object> handler;
if (LookupForWrite(lookup, value, store_mode)) {
- handler = ComputeHandler(lookup, value);
+ handler = ComputeHandler(lookup);
} else {
TRACE_GENERIC_IC("LookupForWrite said 'false'");
handler = slow_stub();
@@ -1839,28 +1662,33 @@ Handle<Object> StoreIC::StoreTransition(Handle<Map> receiver_map,
Handle<JSObject> holder,
Handle<Map> transition,
Handle<Name> name) {
- int descriptor = transition->LastAdded();
- Handle<DescriptorArray> descriptors(transition->instance_descriptors());
- PropertyDetails details = descriptors->GetDetails(descriptor);
- Representation representation = details.representation();
- DCHECK(!representation.IsNone());
+ Handle<Object> smi_handler;
+ if (transition->is_dictionary_map()) {
+ smi_handler = StoreHandler::StoreNormal(isolate());
+ } else {
+ int descriptor = transition->LastAdded();
+ Handle<DescriptorArray> descriptors(transition->instance_descriptors());
+ PropertyDetails details = descriptors->GetDetails(descriptor);
+ Representation representation = details.representation();
+ DCHECK(!representation.IsNone());
- // Declarative handlers don't support access checks.
- DCHECK(!transition->is_access_check_needed());
+ // Declarative handlers don't support access checks.
+ DCHECK(!transition->is_access_check_needed());
- Handle<Object> smi_handler;
- DCHECK_EQ(kData, details.kind());
- if (details.location() == kDescriptor) {
- smi_handler = StoreHandler::TransitionToConstant(isolate(), descriptor);
+ DCHECK_EQ(kData, details.kind());
+ if (details.location() == kDescriptor) {
+ smi_handler = StoreHandler::TransitionToConstant(isolate(), descriptor);
- } else {
- DCHECK_EQ(kField, details.location());
- bool extend_storage =
- Map::cast(transition->GetBackPointer())->unused_property_fields() == 0;
+ } else {
+ DCHECK_EQ(kField, details.location());
+ bool extend_storage =
+ Map::cast(transition->GetBackPointer())->unused_property_fields() ==
+ 0;
- FieldIndex index = FieldIndex::ForDescriptor(*transition, descriptor);
- smi_handler = StoreHandler::TransitionToField(
- isolate(), descriptor, index, representation, extend_storage);
+ FieldIndex index = FieldIndex::ForDescriptor(*transition, descriptor);
+ smi_handler = StoreHandler::TransitionToField(
+ isolate(), descriptor, index, representation, extend_storage);
+ }
}
// |holder| is either a receiver if the property is non-existent or
// one of the prototypes.
@@ -1877,7 +1705,7 @@ Handle<Object> StoreIC::StoreTransition(Handle<Map> receiver_map,
Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate());
if (validity_cell.is_null()) {
DCHECK_EQ(0, checks_count);
- validity_cell = handle(Smi::FromInt(0), isolate());
+ validity_cell = handle(Smi::kZero, isolate());
}
Handle<WeakCell> transition_cell = Map::WeakCellForMap(transition);
@@ -1896,21 +1724,14 @@ Handle<Object> StoreIC::StoreTransition(Handle<Map> receiver_map,
return handler_array;
}
-static Handle<Code> PropertyCellStoreHandler(
- Isolate* isolate, Handle<JSObject> receiver, Handle<JSGlobalObject> holder,
- Handle<Name> name, Handle<PropertyCell> cell, PropertyCellType type) {
- auto constant_type = Nothing<PropertyCellConstantType>();
- if (type == PropertyCellType::kConstantType) {
- constant_type = Just(cell->GetConstantType());
- }
- StoreGlobalStub stub(isolate, type, constant_type,
- receiver->IsJSGlobalProxy());
- auto code = stub.GetCodeCopyFromTemplate(holder, cell);
- // TODO(verwaest): Move caching of these NORMAL stubs outside as well.
- HeapObject::UpdateMapCodeCache(receiver, name, code);
- return code;
+namespace {
+
+Handle<Object> StoreGlobal(Isolate* isolate, Handle<PropertyCell> cell) {
+ return isolate->factory()->NewWeakCell(cell);
}
+} // namespace
+
Handle<Object> StoreIC::GetMapIndependentHandler(LookupIterator* lookup) {
DCHECK_NE(LookupIterator::JSPROXY, lookup->state());
@@ -1923,7 +1744,8 @@ Handle<Object> StoreIC::GetMapIndependentHandler(LookupIterator* lookup) {
case LookupIterator::TRANSITION: {
auto store_target = lookup->GetStoreTarget();
if (store_target->IsJSGlobalObject()) {
- break; // Custom-compiled handler.
+ TRACE_HANDLER_STATS(isolate(), StoreIC_StoreGlobalTransitionDH);
+ return StoreGlobal(isolate(), lookup->transition_cell());
}
// Currently not handled by CompileStoreTransition.
if (!holder->HasFastProperties()) {
@@ -1931,6 +1753,7 @@ Handle<Object> StoreIC::GetMapIndependentHandler(LookupIterator* lookup) {
TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
return slow_stub();
}
+
DCHECK(lookup->IsCacheableTransition());
Handle<Map> transition = lookup->transition_map();
TRACE_HANDLER_STATS(isolate(), StoreIC_StoreTransitionDH);
@@ -1971,10 +1794,6 @@ Handle<Object> StoreIC::GetMapIndependentHandler(LookupIterator* lookup) {
TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
return slow_stub();
}
- if (info->is_sloppy() && !receiver->IsJSReceiver()) {
- TRACE_HANDLER_STATS(isolate(), StoreIC_SlowStub);
- return slow_stub();
- }
break; // Custom-compiled handler.
} else if (accessors->IsAccessorPair()) {
Handle<Object> setter(Handle<AccessorPair>::cast(accessors)->setter(),
@@ -2003,11 +1822,12 @@ Handle<Object> StoreIC::GetMapIndependentHandler(LookupIterator* lookup) {
DCHECK_EQ(kData, lookup->property_details().kind());
if (lookup->is_dictionary_holder()) {
if (holder->IsJSGlobalObject()) {
- break; // Custom-compiled handler.
+ TRACE_HANDLER_STATS(isolate(), StoreIC_StoreGlobalDH);
+ return StoreGlobal(isolate(), lookup->GetPropertyCell());
}
- TRACE_HANDLER_STATS(isolate(), StoreIC_StoreNormal);
+ TRACE_HANDLER_STATS(isolate(), StoreIC_StoreNormalDH);
DCHECK(holder.is_identical_to(receiver));
- return isolate()->builtins()->StoreIC_Normal();
+ return StoreHandler::StoreNormal(isolate());
}
// -------------- Fields --------------
@@ -2015,8 +1835,13 @@ Handle<Object> StoreIC::GetMapIndependentHandler(LookupIterator* lookup) {
TRACE_HANDLER_STATS(isolate(), StoreIC_StoreFieldDH);
int descriptor = lookup->GetFieldDescriptorIndex();
FieldIndex index = lookup->GetFieldIndex();
- return StoreHandler::StoreField(isolate(), descriptor, index,
- lookup->constness(),
+ PropertyConstness constness = lookup->constness();
+ if (constness == kConst && IsStoreOwnICKind(nexus()->kind())) {
+ // StoreOwnICs are used for initializing object literals therefore
+ // we must store the value unconditionally even to kConst fields.
+ constness = kMutable;
+ }
+ return StoreHandler::StoreField(isolate(), descriptor, index, constness,
lookup->representation());
}
@@ -2036,104 +1861,55 @@ Handle<Object> StoreIC::GetMapIndependentHandler(LookupIterator* lookup) {
return Handle<Code>::null();
}
-Handle<Object> StoreIC::CompileHandler(LookupIterator* lookup,
- Handle<Object> value,
- CacheHolderFlag cache_holder) {
- DCHECK_NE(LookupIterator::JSPROXY, lookup->state());
+Handle<Code> StoreIC::CompileHandler(LookupIterator* lookup) {
+ DCHECK_EQ(LookupIterator::ACCESSOR, lookup->state());
// This is currently guaranteed by checks in StoreIC::Store.
Handle<JSObject> receiver = Handle<JSObject>::cast(lookup->GetReceiver());
Handle<JSObject> holder = lookup->GetHolder<JSObject>();
DCHECK(!receiver->IsAccessCheckNeeded() || lookup->name()->IsPrivate());
- switch (lookup->state()) {
- case LookupIterator::TRANSITION: {
- auto store_target = lookup->GetStoreTarget();
- if (store_target->IsJSGlobalObject()) {
- TRACE_HANDLER_STATS(isolate(), StoreIC_StoreGlobalTransition);
- Handle<PropertyCell> cell = lookup->transition_cell();
- cell->set_value(*value);
- Handle<Code> code = PropertyCellStoreHandler(
- isolate(), store_target, Handle<JSGlobalObject>::cast(store_target),
- lookup->name(), cell, PropertyCellType::kConstant);
- cell->set_value(isolate()->heap()->the_hole_value());
- return code;
- }
- UNREACHABLE();
- }
-
- case LookupIterator::INTERCEPTOR:
- UNREACHABLE();
-
- case LookupIterator::ACCESSOR: {
- DCHECK(holder->HasFastProperties());
- Handle<Object> accessors = lookup->GetAccessors();
- if (accessors->IsAccessorInfo()) {
- Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors);
- DCHECK(v8::ToCData<Address>(info->setter()) != 0);
- DCHECK(!AccessorInfo::cast(*accessors)->is_special_data_property() ||
- lookup->HolderIsReceiverOrHiddenPrototype());
- DCHECK(AccessorInfo::IsCompatibleReceiverMap(isolate(), info,
- receiver_map()));
- DCHECK(!info->is_sloppy() || receiver->IsJSReceiver());
- TRACE_HANDLER_STATS(isolate(), StoreIC_StoreCallback);
- NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
- // TODO(ishell): don't hard-code language mode into the handler because
- // this handler can be re-used through megamorphic stub cache for wrong
- // language mode.
- // Better pass vector/slot to Runtime::kStoreCallbackProperty and
- // let it decode the language mode from the IC kind.
- Handle<Code> code = compiler.CompileStoreCallback(
- receiver, lookup->name(), info, language_mode());
- return code;
- } else {
- DCHECK(accessors->IsAccessorPair());
- Handle<Object> setter(Handle<AccessorPair>::cast(accessors)->setter(),
- isolate());
- 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,
- lookup->GetAccessorIndex(), slow_stub());
- return code;
- }
- TRACE_HANDLER_STATS(isolate(), StoreIC_StoreViaSetter);
- int expected_arguments = JSFunction::cast(*setter)
- ->shared()
- ->internal_formal_parameter_count();
- return compiler.CompileStoreViaSetter(receiver, lookup->name(),
- lookup->GetAccessorIndex(),
- expected_arguments);
- }
- }
-
- case LookupIterator::DATA: {
- DCHECK(lookup->is_dictionary_holder());
- DCHECK(holder->IsJSGlobalObject());
- TRACE_HANDLER_STATS(isolate(), StoreIC_StoreGlobal);
- DCHECK(holder.is_identical_to(receiver) ||
- receiver->map()->prototype() == *holder);
- auto cell = lookup->GetPropertyCell();
- auto updated_type =
- PropertyCell::UpdatedType(cell, value, lookup->property_details());
- auto code = PropertyCellStoreHandler(isolate(), receiver,
- Handle<JSGlobalObject>::cast(holder),
- lookup->name(), cell, updated_type);
- return code;
- }
+ DCHECK(holder->HasFastProperties());
+ Handle<Object> accessors = lookup->GetAccessors();
- case LookupIterator::INTEGER_INDEXED_EXOTIC:
- case LookupIterator::ACCESS_CHECK:
- case LookupIterator::JSPROXY:
- case LookupIterator::NOT_FOUND:
- UNREACHABLE();
- }
- UNREACHABLE();
- return slow_stub();
+ if (accessors->IsAccessorInfo()) {
+ Handle<AccessorInfo> info = Handle<AccessorInfo>::cast(accessors);
+ DCHECK(v8::ToCData<Address>(info->setter()) != 0);
+ DCHECK(!AccessorInfo::cast(*accessors)->is_special_data_property() ||
+ lookup->HolderIsReceiverOrHiddenPrototype());
+ DCHECK(
+ AccessorInfo::IsCompatibleReceiverMap(isolate(), info, receiver_map()));
+ TRACE_HANDLER_STATS(isolate(), StoreIC_StoreCallback);
+ NamedStoreHandlerCompiler compiler(isolate(), receiver_map(), holder);
+ // TODO(ishell): don't hard-code language mode into the handler because
+ // this handler can be re-used through megamorphic stub cache for wrong
+ // language mode.
+ // Better pass vector/slot to Runtime::kStoreCallbackProperty and
+ // let it decode the language mode from the IC kind.
+ Handle<Code> code = compiler.CompileStoreCallback(receiver, lookup->name(),
+ info, language_mode());
+ return code;
+ }
+
+ DCHECK(accessors->IsAccessorPair());
+ Handle<Object> setter(Handle<AccessorPair>::cast(accessors)->setter(),
+ isolate());
+ 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, lookup->GetAccessorIndex(),
+ slow_stub());
+ return code;
+ }
+ TRACE_HANDLER_STATS(isolate(), StoreIC_StoreViaSetter);
+ int expected_arguments =
+ JSFunction::cast(*setter)->shared()->internal_formal_parameter_count();
+ return compiler.CompileStoreViaSetter(
+ receiver, lookup->name(), lookup->GetAccessorIndex(), expected_arguments);
}
void KeyedStoreIC::UpdateStoreElement(Handle<Map> receiver_map,
@@ -2246,11 +2022,9 @@ void KeyedStoreIC::UpdateStoreElement(Handle<Map> receiver_map,
}
}
- MapHandleList transitioned_maps(target_receiver_maps.length());
List<Handle<Object>> handlers(target_receiver_maps.length());
- StoreElementPolymorphicHandlers(&target_receiver_maps, &transitioned_maps,
- &handlers, store_mode);
- ConfigureVectorState(&target_receiver_maps, &transitioned_maps, &handlers);
+ StoreElementPolymorphicHandlers(&target_receiver_maps, &handlers, store_mode);
+ ConfigureVectorState(Handle<Name>(), &target_receiver_maps, &handlers);
}
@@ -2289,6 +2063,7 @@ Handle<Object> KeyedStoreIC::StoreElementHandler(
store_mode == STORE_AND_GROW_NO_TRANSITION ||
store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
store_mode == STORE_NO_TRANSITION_HANDLE_COW);
+ DCHECK(!receiver_map->DictionaryElementsInPrototypeChainOnly());
ElementsKind elements_kind = receiver_map->elements_kind();
bool is_jsarray = receiver_map->instance_type() == JS_ARRAY_TYPE;
@@ -2309,15 +2084,13 @@ Handle<Object> KeyedStoreIC::StoreElementHandler(
}
Handle<Object> validity_cell =
Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate());
- if (validity_cell.is_null()) {
- return stub;
- }
+ if (validity_cell.is_null()) return stub;
return isolate()->factory()->NewTuple2(validity_cell, stub);
}
void KeyedStoreIC::StoreElementPolymorphicHandlers(
- MapHandleList* receiver_maps, MapHandleList* transitioned_maps,
- List<Handle<Object>>* handlers, KeyedAccessStoreMode store_mode) {
+ MapHandleList* receiver_maps, List<Handle<Object>>* handlers,
+ KeyedAccessStoreMode store_mode) {
DCHECK(store_mode == STANDARD_STORE ||
store_mode == STORE_AND_GROW_NO_TRANSITION ||
store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS ||
@@ -2327,45 +2100,55 @@ void KeyedStoreIC::StoreElementPolymorphicHandlers(
Handle<Map> receiver_map(receiver_maps->at(i));
Handle<Object> handler;
Handle<Map> transitioned_map;
- {
- Map* tmap = receiver_map->FindElementsKindTransitionedMap(receiver_maps);
- if (tmap != nullptr) transitioned_map = handle(tmap);
- }
-
- // TODO(mvstanton): The code below is doing pessimistic elements
- // transitions. I would like to stop doing that and rely on Allocation Site
- // Tracking to do a better job of ensuring the data types are what they need
- // to be. Not all the elements are in place yet, pessimistic elements
- // transitions are still important for performance.
- if (!transitioned_map.is_null()) {
- bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
- ElementsKind elements_kind = receiver_map->elements_kind();
- TRACE_HANDLER_STATS(isolate(),
- KeyedStoreIC_ElementsTransitionAndStoreStub);
- Handle<Code> stub =
- ElementsTransitionAndStoreStub(isolate(), elements_kind,
- transitioned_map->elements_kind(),
- is_js_array, store_mode)
- .GetCode();
- Handle<Object> validity_cell =
- Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate());
- if (validity_cell.is_null()) {
- handler = stub;
- } else {
- handler = isolate()->factory()->NewTuple2(validity_cell, stub);
- }
- } else if (receiver_map->instance_type() < FIRST_JS_RECEIVER_TYPE) {
+ if (receiver_map->instance_type() < FIRST_JS_RECEIVER_TYPE ||
+ receiver_map->DictionaryElementsInPrototypeChainOnly()) {
// TODO(mvstanton): Consider embedding store_mode in the state of the slow
// keyed store ic for uniformity.
TRACE_HANDLER_STATS(isolate(), KeyedStoreIC_SlowStub);
handler = isolate()->builtins()->KeyedStoreIC_Slow();
+
} else {
- handler = StoreElementHandler(receiver_map, store_mode);
+ {
+ Map* tmap =
+ receiver_map->FindElementsKindTransitionedMap(receiver_maps);
+ if (tmap != nullptr) {
+ if (receiver_map->is_stable()) {
+ receiver_map->NotifyLeafMapLayoutChange();
+ }
+ transitioned_map = handle(tmap);
+ }
+ }
+
+ // TODO(mvstanton): The code below is doing pessimistic elements
+ // transitions. I would like to stop doing that and rely on Allocation
+ // Site Tracking to do a better job of ensuring the data types are what
+ // they need to be. Not all the elements are in place yet, pessimistic
+ // elements transitions are still important for performance.
+ if (!transitioned_map.is_null()) {
+ bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
+ ElementsKind elements_kind = receiver_map->elements_kind();
+ TRACE_HANDLER_STATS(isolate(),
+ KeyedStoreIC_ElementsTransitionAndStoreStub);
+ Handle<Code> stub =
+ ElementsTransitionAndStoreStub(isolate(), elements_kind,
+ transitioned_map->elements_kind(),
+ is_js_array, store_mode)
+ .GetCode();
+ Handle<Object> validity_cell =
+ Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate());
+ if (validity_cell.is_null()) {
+ validity_cell = handle(Smi::kZero, isolate());
+ }
+ Handle<WeakCell> transition = Map::WeakCellForMap(transitioned_map);
+ handler =
+ isolate()->factory()->NewTuple3(transition, stub, validity_cell);
+ } else {
+ handler = StoreElementHandler(receiver_map, store_mode);
+ }
}
DCHECK(!handler.is_null());
handlers->Add(handler);
- transitioned_maps->Add(transitioned_map);
}
}
@@ -2561,7 +2344,8 @@ RUNTIME_FUNCTION(Runtime_LoadIC_Miss) {
RETURN_RESULT_OR_FAILURE(isolate, ic.Load(receiver, key));
} else if (IsLoadGlobalICKind(kind)) {
- DCHECK_EQ(*isolate->global_object(), *receiver);
+ DCHECK_EQ(isolate->native_context()->global_proxy(), *receiver);
+ receiver = isolate->global_object();
LoadGlobalICNexus nexus(vector, vector_slot);
LoadGlobalIC ic(isolate, &nexus);
ic.UpdateState(receiver, key);
@@ -2672,6 +2456,11 @@ RUNTIME_FUNCTION(Runtime_StoreIC_Miss) {
StoreIC ic(isolate, &nexus);
ic.UpdateState(receiver, key);
RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value));
+ } else if (IsStoreGlobalICKind(kind)) {
+ StoreICNexus nexus(vector, vector_slot);
+ StoreGlobalIC ic(isolate, &nexus);
+ ic.UpdateState(receiver, key);
+ RETURN_RESULT_OR_FAILURE(isolate, ic.Store(receiver, key, value));
} else {
DCHECK(IsKeyedStoreICKind(kind));
KeyedStoreICNexus nexus(vector, vector_slot);
@@ -3061,56 +2850,15 @@ RUNTIME_FUNCTION(Runtime_StoreCallbackProperty) {
/**
- * Attempts to load a property with an interceptor (which must be present),
- * but doesn't search the prototype chain.
- *
- * Returns |Heap::no_interceptor_result_sentinel()| if interceptor doesn't
- * provide any value for the given name.
- */
-RUNTIME_FUNCTION(Runtime_LoadPropertyWithInterceptorOnly) {
- DCHECK(args.length() == NamedLoadHandlerCompiler::kInterceptorArgsLength);
- Handle<Name> name =
- args.at<Name>(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex);
- Handle<Object> receiver =
- args.at(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex);
- Handle<JSObject> holder =
- args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex);
- HandleScope scope(isolate);
-
- if (!receiver->IsJSReceiver()) {
- ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
- isolate, receiver, Object::ConvertReceiver(isolate, receiver));
- }
-
- InterceptorInfo* interceptor = holder->GetNamedInterceptor();
- PropertyCallbackArguments arguments(isolate, interceptor->data(), *receiver,
- *holder, Object::DONT_THROW);
-
- v8::GenericNamedPropertyGetterCallback getter =
- v8::ToCData<v8::GenericNamedPropertyGetterCallback>(
- interceptor->getter());
- Handle<Object> result = arguments.Call(getter, name);
-
- RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
-
- if (!result.is_null()) return *result;
- return isolate->heap()->no_interceptor_result_sentinel();
-}
-
-
-/**
* Loads a property with an interceptor performing post interceptor
* lookup if interceptor failed.
*/
RUNTIME_FUNCTION(Runtime_LoadPropertyWithInterceptor) {
HandleScope scope(isolate);
- DCHECK(args.length() == NamedLoadHandlerCompiler::kInterceptorArgsLength + 2);
- Handle<Name> name =
- args.at<Name>(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex);
- Handle<Object> receiver =
- args.at(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex);
- Handle<JSObject> holder =
- args.at<JSObject>(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex);
+ DCHECK_EQ(5, args.length());
+ Handle<Name> name = args.at<Name>(0);
+ Handle<Object> receiver = args.at(1);
+ Handle<JSObject> holder = args.at<JSObject>(2);
if (!receiver->IsJSReceiver()) {
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
diff --git a/deps/v8/src/ic/ic.h b/deps/v8/src/ic/ic.h
index c9818f5a5b..4649bc0b0e 100644
--- a/deps/v8/src/ic/ic.h
+++ b/deps/v8/src/ic/ic.h
@@ -26,6 +26,10 @@ class IC {
// or with a single extra frame for supporting calls.
enum FrameDepth { NO_EXTRA_FRAME = 0, EXTRA_CALL_FRAME = 1 };
+ // A polymorphic IC can handle at most 4 distinct maps before transitioning
+ // to megamorphic state.
+ static constexpr int kMaxPolymorphicMapCount = 4;
+
// Construct the IC structure with the given number of extra
// JavaScript frames on the stack.
IC(FrameDepth depth, Isolate* isolate, FeedbackNexus* nexus = NULL);
@@ -51,26 +55,8 @@ class IC {
return IsLoadIC() || IsLoadGlobalIC() || IsKeyedLoadIC();
}
bool IsAnyStore() const {
- return IsStoreIC() || IsStoreOwnIC() || IsKeyedStoreIC();
- }
-
- static inline Handle<Map> GetHandlerCacheHolder(Handle<Map> receiver_map,
- bool receiver_is_holder,
- Isolate* isolate,
- CacheHolderFlag* flag);
- static inline Handle<Map> GetICCacheHolder(Handle<Map> receiver_map,
- Isolate* isolate,
- CacheHolderFlag* flag);
-
- static bool ICUseVector(Code::Kind kind) {
- return kind == Code::LOAD_IC || kind == Code::LOAD_GLOBAL_IC ||
- kind == Code::KEYED_LOAD_IC || kind == Code::STORE_IC ||
- kind == Code::KEYED_STORE_IC;
- }
- static bool ICUseVector(FeedbackSlotKind kind) {
- return IsLoadICKind(kind) || IsLoadGlobalICKind(kind) ||
- IsKeyedLoadICKind(kind) || IsStoreICKind(kind) ||
- IsStoreOwnICKind(kind) || IsKeyedStoreICKind(kind);
+ return IsStoreIC() || IsStoreOwnIC() || IsStoreGlobalIC() ||
+ IsKeyedStoreIC();
}
// The ICs that don't pass slot and vector through the stack have to
@@ -104,13 +90,6 @@ class IC {
inline void set_target(Code* code);
bool is_vector_set() { return vector_set_; }
- bool UseVector() const {
- bool use = ICUseVector(kind());
- // If we are supposed to use the nexus, verify the nexus is non-null.
- DCHECK(!use || nexus_ != nullptr);
- return use;
- }
-
// Configure for most states.
void ConfigureVectorState(IC::State new_state, Handle<Object> key);
// Configure the vector for MONOMORPHIC.
@@ -119,11 +98,6 @@ class IC {
// Configure the vector for POLYMORPHIC.
void ConfigureVectorState(Handle<Name> name, MapHandleList* maps,
List<Handle<Object>>* handlers);
- // Configure the vector for POLYMORPHIC with transitions (only for element
- // keyed stores).
- void ConfigureVectorState(MapHandleList* maps,
- MapHandleList* transitioned_maps,
- List<Handle<Object>>* handlers);
char TransitionMarkFromState(IC::State state);
void TraceIC(const char* type, Handle<Object> name);
@@ -144,17 +118,14 @@ class IC {
void TraceHandlerCacheHitStats(LookupIterator* lookup);
// Compute the handler either by compiling or by retrieving a cached version.
- Handle<Object> ComputeHandler(LookupIterator* lookup,
- Handle<Object> value = Handle<Code>::null());
+ Handle<Object> ComputeHandler(LookupIterator* lookup);
virtual Handle<Object> GetMapIndependentHandler(LookupIterator* lookup) {
UNREACHABLE();
return Handle<Code>::null();
}
- virtual Handle<Object> CompileHandler(LookupIterator* lookup,
- Handle<Object> value,
- CacheHolderFlag cache_holder) {
+ virtual Handle<Code> CompileHandler(LookupIterator* lookup) {
UNREACHABLE();
- return Handle<Object>::null();
+ return Handle<Code>::null();
}
void UpdateMonomorphicIC(Handle<Object> handler, Handle<Name> name);
@@ -170,6 +141,7 @@ class IC {
bool IsLoadIC() const { return IsLoadICKind(kind_); }
bool IsLoadGlobalIC() const { return IsLoadGlobalICKind(kind_); }
bool IsKeyedLoadIC() const { return IsKeyedLoadICKind(kind_); }
+ bool IsStoreGlobalIC() const { return IsStoreGlobalICKind(kind_); }
bool IsStoreIC() const { return IsStoreICKind(kind_); }
bool IsStoreOwnIC() const { return IsStoreOwnICKind(kind_); }
bool IsKeyedStoreIC() const { return IsKeyedStoreICKind(kind_); }
@@ -225,7 +197,6 @@ class IC {
void FindTargetMaps() {
if (target_maps_set_) return;
target_maps_set_ = true;
- DCHECK(UseVector());
nexus()->ExtractMaps(&target_maps_);
}
@@ -302,22 +273,24 @@ class LoadIC : public IC {
Handle<Object> GetMapIndependentHandler(LookupIterator* lookup) override;
- Handle<Object> CompileHandler(LookupIterator* lookup, Handle<Object> unused,
- CacheHolderFlag cache_holder) override;
+ Handle<Code> CompileHandler(LookupIterator* lookup) override;
private:
// Creates a data handler that represents a load of a field by given index.
- static Handle<Object> SimpleFieldLoad(Isolate* isolate, FieldIndex index);
+ static Handle<Smi> SimpleFieldLoad(Isolate* isolate, FieldIndex index);
// Creates a data handler that represents a prototype chain check followed
// by given Smi-handler that encoded a load from the holder.
// Can be used only if GetPrototypeCheckCount() returns non negative value.
Handle<Object> LoadFromPrototype(Handle<Map> receiver_map,
Handle<JSObject> holder, Handle<Name> name,
- Handle<Object> smi_handler);
+ Handle<Smi> smi_handler);
// Creates a data handler that represents a load of a non-existent property.
- Handle<Object> LoadNonExistent(Handle<Map> receiver_map, Handle<Name> name);
+ // {holder} is the object from which the property is loaded. If no holder is
+ // needed (e.g., for "nonexistent"), null_value() may be passed in.
+ Handle<Object> LoadFullChain(Handle<Map> receiver_map, Handle<Object> holder,
+ Handle<Name> name, Handle<Smi> smi_handler);
friend class IC;
friend class NamedLoadHandlerCompiler;
@@ -352,6 +325,11 @@ class KeyedLoadIC : public LoadIC {
private:
friend class IC;
+
+ Handle<Object> LoadElementHandler(Handle<Map> receiver_map);
+
+ void LoadElementPolymorphicHandlers(MapHandleList* receiver_maps,
+ List<Handle<Object>>* handlers);
};
@@ -377,7 +355,7 @@ class StoreIC : public IC {
protected:
// Stub accessors.
Handle<Code> slow_stub() const {
- // StoreIC and KeyedStoreIC share the same slow stub.
+ // All StoreICs share the same slow stub.
return isolate()->builtins()->KeyedStoreIC_Slow();
}
@@ -386,8 +364,7 @@ class StoreIC : public IC {
void UpdateCaches(LookupIterator* lookup, Handle<Object> value,
JSReceiver::StoreFromKeyed store_mode);
Handle<Object> GetMapIndependentHandler(LookupIterator* lookup) override;
- Handle<Object> CompileHandler(LookupIterator* lookup, Handle<Object> value,
- CacheHolderFlag cache_holder) override;
+ Handle<Code> CompileHandler(LookupIterator* lookup) override;
private:
Handle<Object> StoreTransition(Handle<Map> receiver_map,
@@ -397,6 +374,15 @@ class StoreIC : public IC {
friend class IC;
};
+class StoreGlobalIC : public StoreIC {
+ public:
+ StoreGlobalIC(Isolate* isolate, FeedbackNexus* nexus)
+ : StoreIC(isolate, nexus) {}
+
+ MUST_USE_RESULT MaybeHandle<Object> Store(Handle<Object> object,
+ Handle<Name> name,
+ Handle<Object> value);
+};
enum KeyedStoreCheckMap { kDontCheckMap, kCheckMap };
@@ -429,7 +415,6 @@ class KeyedStoreIC : public StoreIC {
KeyedAccessStoreMode store_mode);
void StoreElementPolymorphicHandlers(MapHandleList* receiver_maps,
- MapHandleList* transitioned_maps,
List<Handle<Object>>* handlers,
KeyedAccessStoreMode store_mode);
diff --git a/deps/v8/src/ic/keyed-store-generic.cc b/deps/v8/src/ic/keyed-store-generic.cc
index 8962386c93..29d666d620 100644
--- a/deps/v8/src/ic/keyed-store-generic.cc
+++ b/deps/v8/src/ic/keyed-store-generic.cc
@@ -24,6 +24,8 @@ class KeyedStoreGenericAssembler : public AccessorAssembler {
void KeyedStoreGeneric(LanguageMode language_mode);
+ void StoreIC_Uninitialized(LanguageMode language_mode);
+
private:
enum UpdateLength {
kDontChangeLength,
@@ -31,13 +33,16 @@ class KeyedStoreGenericAssembler : public AccessorAssembler {
kBumpLengthWithGap
};
+ enum UseStubCache { kUseStubCache, kDontUseStubCache };
+
void EmitGenericElementStore(Node* receiver, Node* receiver_map,
Node* instance_type, Node* intptr_index,
Node* value, Node* context, Label* slow);
void EmitGenericPropertyStore(Node* receiver, Node* receiver_map,
const StoreICParameters* p, Label* slow,
- LanguageMode language_mode);
+ LanguageMode language_mode,
+ UseStubCache use_stub_cache = kUseStubCache);
void BranchIfPrototypesHaveNonFastElements(Node* receiver_map,
Label* non_fast_elements,
@@ -67,7 +72,6 @@ class KeyedStoreGenericAssembler : public AccessorAssembler {
ElementsKind packed_kind,
ElementsKind packed_kind_2, Label* bailout);
- void JumpIfDataProperty(Node* details, Label* writable, Label* readonly);
void LookupPropertyOnPrototypeChain(Node* receiver_map, Node* name,
Label* accessor,
Variable* var_accessor_pair,
@@ -88,14 +92,20 @@ void KeyedStoreGenericGenerator::Generate(compiler::CodeAssemblerState* state,
assembler.KeyedStoreGeneric(language_mode);
}
+void StoreICUninitializedGenerator::Generate(
+ compiler::CodeAssemblerState* state, LanguageMode language_mode) {
+ KeyedStoreGenericAssembler assembler(state);
+ assembler.StoreIC_Uninitialized(language_mode);
+}
+
void KeyedStoreGenericAssembler::BranchIfPrototypesHaveNonFastElements(
Node* receiver_map, Label* non_fast_elements, Label* only_fast_elements) {
- Variable var_map(this, MachineRepresentation::kTagged);
+ VARIABLE(var_map, MachineRepresentation::kTagged);
var_map.Bind(receiver_map);
Label loop_body(this, &var_map);
Goto(&loop_body);
- Bind(&loop_body);
+ BIND(&loop_body);
{
Node* map = var_map.value();
Node* prototype = LoadMapPrototype(map);
@@ -126,7 +136,7 @@ void KeyedStoreGenericAssembler::TryRewriteElements(
TrapAllocationMemento(receiver, bailout);
}
Label perform_transition(this), check_holey_map(this);
- Variable var_target_map(this, MachineRepresentation::kTagged);
+ VARIABLE(var_target_map, MachineRepresentation::kTagged);
// Check if the receiver has the default |from_kind| map.
{
Node* packed_map =
@@ -138,7 +148,7 @@ void KeyedStoreGenericAssembler::TryRewriteElements(
}
// Check if the receiver has the default |holey_from_kind| map.
- Bind(&check_holey_map);
+ BIND(&check_holey_map);
{
Node* holey_map = LoadContextElement(
native_context, Context::ArrayMapIndex(holey_from_kind));
@@ -149,7 +159,7 @@ void KeyedStoreGenericAssembler::TryRewriteElements(
}
// Found a supported transition target map, perform the transition!
- Bind(&perform_transition);
+ BIND(&perform_transition);
{
if (IsFastDoubleElementsKind(from_kind) !=
IsFastDoubleElementsKind(to_kind)) {
@@ -189,7 +199,7 @@ void KeyedStoreGenericAssembler::TryChangeToHoleyMap(
Node* native_context = LoadNativeContext(context);
TryChangeToHoleyMapHelper(receiver, receiver_map, native_context, packed_kind,
holey_kind, &already_holey, bailout, bailout);
- Bind(&already_holey);
+ BIND(&already_holey);
}
void KeyedStoreGenericAssembler::TryChangeToHoleyMapMulti(
@@ -209,11 +219,11 @@ void KeyedStoreGenericAssembler::TryChangeToHoleyMapMulti(
TryChangeToHoleyMapHelper(receiver, receiver_map, native_context, packed_kind,
holey_kind, &already_holey, &check_other_kind,
bailout);
- Bind(&check_other_kind);
+ BIND(&check_other_kind);
TryChangeToHoleyMapHelper(receiver, receiver_map, native_context,
packed_kind_2, holey_kind_2, &already_holey,
bailout, bailout);
- Bind(&already_holey);
+ BIND(&already_holey);
}
void KeyedStoreGenericAssembler::MaybeUpdateLengthAndReturn(
@@ -267,7 +277,7 @@ void KeyedStoreGenericAssembler::StoreElementWithCapacity(
}
BranchIfPrototypesHaveNonFastElements(receiver_map, slow,
&hole_check_passed);
- Bind(&hole_check_passed);
+ BIND(&hole_check_passed);
}
// Check if the value we're storing matches the elements_kind. Smis
@@ -284,7 +294,7 @@ void KeyedStoreGenericAssembler::StoreElementWithCapacity(
value);
MaybeUpdateLengthAndReturn(receiver, intptr_index, value, update_length);
- Bind(&non_smi_value);
+ BIND(&non_smi_value);
}
// Check if we already have object elements; just do the store if so.
@@ -302,7 +312,7 @@ void KeyedStoreGenericAssembler::StoreElementWithCapacity(
Store(elements, offset, value);
MaybeUpdateLengthAndReturn(receiver, intptr_index, value, update_length);
- Bind(&must_transition);
+ BIND(&must_transition);
}
// Transition to the required ElementsKind.
@@ -311,7 +321,7 @@ void KeyedStoreGenericAssembler::StoreElementWithCapacity(
Node* native_context = LoadNativeContext(context);
Branch(WordEqual(LoadMap(value), LoadRoot(Heap::kHeapNumberMapRootIndex)),
&transition_to_double, &transition_to_object);
- Bind(&transition_to_double);
+ BIND(&transition_to_double);
{
// If we're adding holes at the end, always transition to a holey
// elements kind, otherwise try to remain packed.
@@ -332,7 +342,7 @@ void KeyedStoreGenericAssembler::StoreElementWithCapacity(
update_length);
}
- Bind(&transition_to_object);
+ BIND(&transition_to_object);
{
// If we're adding holes at the end, always transition to a holey
// elements kind, otherwise try to remain packed.
@@ -350,7 +360,7 @@ void KeyedStoreGenericAssembler::StoreElementWithCapacity(
}
}
- Bind(&check_double_elements);
+ BIND(&check_double_elements);
Node* fixed_double_array_map = LoadRoot(Heap::kFixedDoubleArrayMapRootIndex);
GotoIf(WordNotEqual(elements_map, fixed_double_array_map),
&check_cow_elements);
@@ -369,11 +379,11 @@ void KeyedStoreGenericAssembler::StoreElementWithCapacity(
LoadDoubleWithHoleCheck(elements, offset, &found_hole,
MachineType::None());
Goto(&hole_check_passed);
- Bind(&found_hole);
+ BIND(&found_hole);
}
BranchIfPrototypesHaveNonFastElements(receiver_map, slow,
&hole_check_passed);
- Bind(&hole_check_passed);
+ BIND(&hole_check_passed);
}
// Try to store the value as a double.
@@ -392,7 +402,7 @@ void KeyedStoreGenericAssembler::StoreElementWithCapacity(
double_value);
MaybeUpdateLengthAndReturn(receiver, intptr_index, value, update_length);
- Bind(&non_number_value);
+ BIND(&non_number_value);
}
// Transition to object elements.
@@ -412,7 +422,7 @@ void KeyedStoreGenericAssembler::StoreElementWithCapacity(
}
}
- Bind(&check_cow_elements);
+ BIND(&check_cow_elements);
{
// TODO(jkummerow): Use GrowElementsCapacity instead of bailing out.
Goto(slow);
@@ -428,7 +438,7 @@ void KeyedStoreGenericAssembler::EmitGenericElementStore(
Node* elements = LoadElements(receiver);
Node* elements_kind = LoadMapElementsKind(receiver_map);
Branch(IsFastElementsKind(elements_kind), &if_fast, &if_nonfast);
- Bind(&if_fast);
+ BIND(&if_fast);
Label if_array(this);
GotoIf(Word32Equal(instance_type, Int32Constant(JS_ARRAY_TYPE)), &if_array);
@@ -436,7 +446,7 @@ void KeyedStoreGenericAssembler::EmitGenericElementStore(
Node* capacity = SmiUntag(LoadFixedArrayBaseLength(elements));
Branch(UintPtrLessThan(intptr_index, capacity), &if_in_bounds, &if_grow);
}
- Bind(&if_array);
+ BIND(&if_array);
{
Node* length = SmiUntag(LoadJSArrayLength(receiver));
GotoIf(UintPtrLessThan(intptr_index, length), &if_in_bounds);
@@ -446,21 +456,21 @@ void KeyedStoreGenericAssembler::EmitGenericElementStore(
&if_bump_length_with_gap);
}
- Bind(&if_in_bounds);
+ BIND(&if_in_bounds);
{
StoreElementWithCapacity(receiver, receiver_map, elements, elements_kind,
intptr_index, value, context, slow,
kDontChangeLength);
}
- Bind(&if_increment_length_by_one);
+ BIND(&if_increment_length_by_one);
{
StoreElementWithCapacity(receiver, receiver_map, elements, elements_kind,
intptr_index, value, context, slow,
kIncrementLengthByOne);
}
- Bind(&if_bump_length_with_gap);
+ BIND(&if_bump_length_with_gap);
{
StoreElementWithCapacity(receiver, receiver_map, elements, elements_kind,
intptr_index, value, context, slow,
@@ -471,7 +481,7 @@ void KeyedStoreGenericAssembler::EmitGenericElementStore(
// an ElementsKind transition might be necessary.
// The index can also be negative at this point! Jump to the runtime in that
// case to convert it to a named property.
- Bind(&if_grow);
+ BIND(&if_grow);
{
Comment("Grow backing store");
// TODO(jkummerow): Support inline backing store growth.
@@ -479,7 +489,7 @@ void KeyedStoreGenericAssembler::EmitGenericElementStore(
}
// Any ElementsKind > LAST_FAST_ELEMENTS_KIND jumps here for further dispatch.
- Bind(&if_nonfast);
+ BIND(&if_nonfast);
{
STATIC_ASSERT(LAST_ELEMENTS_KIND == LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND);
GotoIf(Int32GreaterThanOrEqual(
@@ -491,14 +501,14 @@ void KeyedStoreGenericAssembler::EmitGenericElementStore(
Goto(slow);
}
- Bind(&if_dictionary);
+ BIND(&if_dictionary);
{
Comment("Dictionary");
// TODO(jkummerow): Support storing to dictionary elements.
Goto(slow);
}
- Bind(&if_typed_array);
+ BIND(&if_typed_array);
{
Comment("Typed array");
// TODO(jkummerow): Support typed arrays.
@@ -506,31 +516,20 @@ void KeyedStoreGenericAssembler::EmitGenericElementStore(
}
}
-void KeyedStoreGenericAssembler::JumpIfDataProperty(Node* details,
- Label* writable,
- Label* readonly) {
- // Accessor properties never have the READ_ONLY attribute set.
- GotoIf(IsSetWord32(details, PropertyDetails::kAttributesReadOnlyMask),
- readonly);
- Node* kind = DecodeWord32<PropertyDetails::KindField>(details);
- GotoIf(Word32Equal(kind, Int32Constant(kData)), writable);
- // Fall through if it's an accessor property.
-}
-
void KeyedStoreGenericAssembler::LookupPropertyOnPrototypeChain(
Node* receiver_map, Node* name, Label* accessor,
Variable* var_accessor_pair, Variable* var_accessor_holder, Label* readonly,
Label* bailout) {
Label ok_to_write(this);
- Variable var_holder(this, MachineRepresentation::kTagged);
+ VARIABLE(var_holder, MachineRepresentation::kTagged);
var_holder.Bind(LoadMapPrototype(receiver_map));
- Variable var_holder_map(this, MachineRepresentation::kTagged);
+ VARIABLE(var_holder_map, MachineRepresentation::kTagged);
var_holder_map.Bind(LoadMap(var_holder.value()));
Variable* merged_variables[] = {&var_holder, &var_holder_map};
Label loop(this, arraysize(merged_variables), merged_variables);
Goto(&loop);
- Bind(&loop);
+ BIND(&loop);
{
Node* holder = var_holder.value();
Node* holder_map = var_holder_map.value();
@@ -538,12 +537,12 @@ void KeyedStoreGenericAssembler::LookupPropertyOnPrototypeChain(
Label next_proto(this);
{
Label found(this), found_fast(this), found_dict(this), found_global(this);
- Variable var_meta_storage(this, MachineRepresentation::kTagged);
- Variable var_entry(this, MachineType::PointerRepresentation());
+ VARIABLE(var_meta_storage, MachineRepresentation::kTagged);
+ VARIABLE(var_entry, MachineType::PointerRepresentation());
TryLookupProperty(holder, holder_map, instance_type, name, &found_fast,
&found_dict, &found_global, &var_meta_storage,
&var_entry, &next_proto, bailout);
- Bind(&found_fast);
+ BIND(&found_fast);
{
Node* descriptors = var_meta_storage.value();
Node* name_index = var_entry.value();
@@ -553,14 +552,14 @@ void KeyedStoreGenericAssembler::LookupPropertyOnPrototypeChain(
// Accessor case.
// TODO(jkummerow): Implement a trimmed-down LoadAccessorFromFastObject.
- Variable var_details(this, MachineRepresentation::kWord32);
+ VARIABLE(var_details, MachineRepresentation::kWord32);
LoadPropertyFromFastObject(holder, holder_map, descriptors, name_index,
&var_details, var_accessor_pair);
var_accessor_holder->Bind(holder);
Goto(accessor);
}
- Bind(&found_dict);
+ BIND(&found_dict);
{
Node* dictionary = var_meta_storage.value();
Node* entry = var_entry.value();
@@ -575,7 +574,7 @@ void KeyedStoreGenericAssembler::LookupPropertyOnPrototypeChain(
Goto(accessor);
}
- Bind(&found_global);
+ BIND(&found_global);
{
Node* dictionary = var_meta_storage.value();
Node* entry = var_entry.value();
@@ -595,7 +594,7 @@ void KeyedStoreGenericAssembler::LookupPropertyOnPrototypeChain(
}
}
- Bind(&next_proto);
+ BIND(&next_proto);
// Bailout if it can be an integer indexed exotic case.
GotoIf(Word32Equal(instance_type, Int32Constant(JS_TYPED_ARRAY_TYPE)),
bailout);
@@ -605,7 +604,7 @@ void KeyedStoreGenericAssembler::LookupPropertyOnPrototypeChain(
var_holder_map.Bind(LoadMap(proto));
Goto(&loop);
}
- Bind(&ok_to_write);
+ BIND(&ok_to_write);
}
void KeyedStoreGenericAssembler::CheckFieldType(Node* descriptors,
@@ -629,10 +628,10 @@ void KeyedStoreGenericAssembler::CheckFieldType(Node* descriptors,
Int32Constant(Representation::kTagged)));
Goto(&all_fine);
- Bind(&r_smi);
+ BIND(&r_smi);
{ Branch(TaggedIsSmi(value), &all_fine, bailout); }
- Bind(&r_double);
+ BIND(&r_double);
{
GotoIf(TaggedIsSmi(value), &all_fine);
Node* value_map = LoadMap(value);
@@ -644,7 +643,7 @@ void KeyedStoreGenericAssembler::CheckFieldType(Node* descriptors,
Branch(IsHeapNumberMap(value_map), &all_fine, bailout);
}
- Bind(&r_heapobject);
+ BIND(&r_heapobject);
{
GotoIf(TaggedIsSmi(value), bailout);
Node* field_type =
@@ -663,7 +662,7 @@ void KeyedStoreGenericAssembler::CheckFieldType(Node* descriptors,
Branch(WordEqual(LoadMap(value), field_type), &all_fine, bailout);
}
- Bind(&all_fine);
+ BIND(&all_fine);
}
void KeyedStoreGenericAssembler::OverwriteExistingFastProperty(
@@ -696,7 +695,7 @@ void KeyedStoreGenericAssembler::OverwriteExistingFastProperty(
Branch(UintPtrLessThan(field_index, inobject_properties), &inobject,
&backing_store);
- Bind(&inobject);
+ BIND(&inobject);
{
Node* field_offset =
IntPtrMul(IntPtrSub(LoadMapInstanceSize(object_map),
@@ -705,7 +704,7 @@ void KeyedStoreGenericAssembler::OverwriteExistingFastProperty(
Label tagged_rep(this), double_rep(this);
Branch(Word32Equal(representation, Int32Constant(Representation::kDouble)),
&double_rep, &tagged_rep);
- Bind(&double_rep);
+ BIND(&double_rep);
{
Node* double_value = ChangeNumberToFloat64(value);
if (FLAG_unbox_double_fields) {
@@ -718,20 +717,20 @@ void KeyedStoreGenericAssembler::OverwriteExistingFastProperty(
Goto(&done);
}
- Bind(&tagged_rep);
+ BIND(&tagged_rep);
{
StoreObjectField(object, field_offset, value);
Goto(&done);
}
}
- Bind(&backing_store);
+ BIND(&backing_store);
{
Node* backing_store_index = IntPtrSub(field_index, inobject_properties);
Label tagged_rep(this), double_rep(this);
Branch(Word32Equal(representation, Int32Constant(Representation::kDouble)),
&double_rep, &tagged_rep);
- Bind(&double_rep);
+ BIND(&double_rep);
{
Node* double_value = ChangeNumberToFloat64(value);
Node* mutable_heap_number =
@@ -739,20 +738,20 @@ void KeyedStoreGenericAssembler::OverwriteExistingFastProperty(
StoreHeapNumberValue(mutable_heap_number, double_value);
Goto(&done);
}
- Bind(&tagged_rep);
+ BIND(&tagged_rep);
{
StoreFixedArrayElement(properties, backing_store_index, value);
Goto(&done);
}
}
- Bind(&done);
+ BIND(&done);
}
void KeyedStoreGenericAssembler::EmitGenericPropertyStore(
Node* receiver, Node* receiver_map, const StoreICParameters* p, Label* slow,
- LanguageMode language_mode) {
- Variable var_accessor_pair(this, MachineRepresentation::kTagged);
- Variable var_accessor_holder(this, MachineRepresentation::kTagged);
+ LanguageMode language_mode, UseStubCache use_stub_cache) {
+ VARIABLE(var_accessor_pair, MachineRepresentation::kTagged);
+ VARIABLE(var_accessor_holder, MachineRepresentation::kTagged);
Label stub_cache(this), fast_properties(this), dictionary_properties(this),
accessor(this), readonly(this);
Node* properties = LoadProperties(receiver);
@@ -760,19 +759,19 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore(
Branch(WordEqual(properties_map, LoadRoot(Heap::kHashTableMapRootIndex)),
&dictionary_properties, &fast_properties);
- Bind(&fast_properties);
+ BIND(&fast_properties);
{
Comment("fast property store");
Node* bitfield3 = LoadMapBitField3(receiver_map);
Node* descriptors = LoadMapDescriptors(receiver_map);
Label descriptor_found(this);
- Variable var_name_index(this, MachineType::PointerRepresentation());
+ VARIABLE(var_name_index, MachineType::PointerRepresentation());
// TODO(jkummerow): Maybe look for existing map transitions?
- Label* notfound = &stub_cache;
+ Label* notfound = use_stub_cache == kUseStubCache ? &stub_cache : slow;
DescriptorLookup(p->name, descriptors, bitfield3, &descriptor_found,
&var_name_index, notfound);
- Bind(&descriptor_found);
+ BIND(&descriptor_found);
{
Node* name_index = var_name_index.value();
Node* details =
@@ -782,13 +781,13 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore(
// Accessor case.
// TODO(jkummerow): Implement a trimmed-down LoadAccessorFromFastObject.
- Variable var_details(this, MachineRepresentation::kWord32);
+ VARIABLE(var_details, MachineRepresentation::kWord32);
LoadPropertyFromFastObject(receiver, receiver_map, descriptors,
name_index, &var_details, &var_accessor_pair);
var_accessor_holder.Bind(receiver);
Goto(&accessor);
- Bind(&data_property);
+ BIND(&data_property);
{
OverwriteExistingFastProperty(receiver, receiver_map, properties,
descriptors, name_index, details,
@@ -798,17 +797,17 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore(
}
}
- Bind(&dictionary_properties);
+ BIND(&dictionary_properties);
{
Comment("dictionary property store");
// We checked for LAST_CUSTOM_ELEMENTS_RECEIVER before, which rules out
// seeing global objects here (which would need special handling).
- Variable var_name_index(this, MachineType::PointerRepresentation());
+ VARIABLE(var_name_index, MachineType::PointerRepresentation());
Label dictionary_found(this, &var_name_index), not_found(this);
NameDictionaryLookup<NameDictionary>(properties, p->name, &dictionary_found,
&var_name_index, &not_found);
- Bind(&dictionary_found);
+ BIND(&dictionary_found);
{
Label overwrite(this);
Node* details = LoadDetailsByKeyIndex<NameDictionary>(
@@ -821,7 +820,7 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore(
var_accessor_holder.Bind(receiver);
Goto(&accessor);
- Bind(&overwrite);
+ BIND(&overwrite);
{
StoreValueByKeyIndex<NameDictionary>(properties, var_name_index.value(),
p->value);
@@ -829,8 +828,15 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore(
}
}
- Bind(&not_found);
+ BIND(&not_found);
{
+ Label extensible(this);
+ GotoIf(IsPrivateSymbol(p->name), &extensible);
+ Node* bitfield2 = LoadMapBitField2(receiver_map);
+ Branch(IsSetWord32(bitfield2, 1 << Map::kIsExtensible), &extensible,
+ slow);
+
+ BIND(&extensible);
LookupPropertyOnPrototypeChain(receiver_map, p->name, &accessor,
&var_accessor_pair, &var_accessor_holder,
&readonly, slow);
@@ -839,7 +845,7 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore(
}
}
- Bind(&accessor);
+ BIND(&accessor);
{
Label not_callable(this);
Node* accessor_pair = var_accessor_pair.value();
@@ -855,7 +861,7 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore(
CallJS(callable, p->context, setter, receiver, p->value);
Return(p->value);
- Bind(&not_callable);
+ BIND(&not_callable);
{
if (language_mode == STRICT) {
Node* message =
@@ -869,12 +875,12 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore(
}
}
- Bind(&readonly);
+ BIND(&readonly);
{
if (language_mode == STRICT) {
Node* message =
SmiConstant(Smi::FromInt(MessageTemplate::kStrictReadOnlyProperty));
- Node* type = Typeof(p->receiver, p->context);
+ Node* type = Typeof(p->receiver);
TailCallRuntime(Runtime::kThrowTypeError, p->context, message, p->name,
type, p->receiver);
} else {
@@ -883,19 +889,19 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore(
}
}
- Bind(&stub_cache);
- {
+ if (use_stub_cache == kUseStubCache) {
+ BIND(&stub_cache);
Comment("stub cache probe");
- Variable var_handler(this, MachineRepresentation::kTagged);
+ VARIABLE(var_handler, MachineRepresentation::kTagged);
Label found_handler(this, &var_handler), stub_cache_miss(this);
TryProbeStubCache(isolate()->store_stub_cache(), receiver, p->name,
&found_handler, &var_handler, &stub_cache_miss);
- Bind(&found_handler);
+ BIND(&found_handler);
{
Comment("KeyedStoreGeneric found handler");
HandleStoreICHandlerCase(p, var_handler.value(), &stub_cache_miss);
}
- Bind(&stub_cache_miss);
+ BIND(&stub_cache_miss);
{
Comment("KeyedStoreGeneric_miss");
TailCallRuntime(Runtime::kKeyedStoreIC_Miss, p->context, p->value,
@@ -914,8 +920,8 @@ void KeyedStoreGenericAssembler::KeyedStoreGeneric(LanguageMode language_mode) {
Node* vector = Parameter(Descriptor::kVector);
Node* context = Parameter(Descriptor::kContext);
- Variable var_index(this, MachineType::PointerRepresentation());
- Variable var_unique(this, MachineRepresentation::kTagged);
+ VARIABLE(var_index, MachineType::PointerRepresentation());
+ VARIABLE(var_unique, MachineRepresentation::kTagged);
var_unique.Bind(name); // Dummy initialization.
Label if_index(this), if_unique_name(this), slow(this);
@@ -930,14 +936,14 @@ void KeyedStoreGenericAssembler::KeyedStoreGeneric(LanguageMode language_mode) {
TryToName(name, &if_index, &var_index, &if_unique_name, &var_unique, &slow);
- Bind(&if_index);
+ BIND(&if_index);
{
Comment("integer index");
EmitGenericElementStore(receiver, receiver_map, instance_type,
var_index.value(), value, context, &slow);
}
- Bind(&if_unique_name);
+ BIND(&if_unique_name);
{
Comment("key is unique name");
StoreICParameters p(context, receiver, var_unique.value(), value, slot,
@@ -945,7 +951,7 @@ void KeyedStoreGenericAssembler::KeyedStoreGeneric(LanguageMode language_mode) {
EmitGenericPropertyStore(receiver, receiver_map, &p, &slow, language_mode);
}
- Bind(&slow);
+ BIND(&slow);
{
Comment("KeyedStoreGeneric_slow");
TailCallRuntime(Runtime::kSetProperty, context, receiver, name, value,
@@ -953,5 +959,47 @@ void KeyedStoreGenericAssembler::KeyedStoreGeneric(LanguageMode language_mode) {
}
}
+void KeyedStoreGenericAssembler::StoreIC_Uninitialized(
+ LanguageMode language_mode) {
+ typedef StoreWithVectorDescriptor Descriptor;
+
+ Node* receiver = Parameter(Descriptor::kReceiver);
+ Node* name = Parameter(Descriptor::kName);
+ Node* value = Parameter(Descriptor::kValue);
+ Node* slot = Parameter(Descriptor::kSlot);
+ Node* vector = Parameter(Descriptor::kVector);
+ Node* context = Parameter(Descriptor::kContext);
+
+ Label miss(this);
+
+ GotoIf(TaggedIsSmi(receiver), &miss);
+ Node* receiver_map = LoadMap(receiver);
+ Node* instance_type = LoadMapInstanceType(receiver_map);
+ // Receivers requiring non-standard element accesses (interceptors, access
+ // checks, strings and string wrappers, proxies) are handled in the runtime.
+ GotoIf(Int32LessThanOrEqual(instance_type,
+ Int32Constant(LAST_SPECIAL_RECEIVER_TYPE)),
+ &miss);
+
+ // Optimistically write the state transition to the vector.
+ StoreFixedArrayElement(vector, slot,
+ LoadRoot(Heap::kpremonomorphic_symbolRootIndex),
+ SKIP_WRITE_BARRIER, 0, SMI_PARAMETERS);
+
+ StoreICParameters p(context, receiver, name, value, slot, vector);
+ EmitGenericPropertyStore(receiver, receiver_map, &p, &miss, language_mode,
+ kDontUseStubCache);
+
+ BIND(&miss);
+ {
+ // Undo the optimistic state transition.
+ StoreFixedArrayElement(vector, slot,
+ LoadRoot(Heap::kuninitialized_symbolRootIndex),
+ SKIP_WRITE_BARRIER, 0, SMI_PARAMETERS);
+ TailCallRuntime(Runtime::kStoreIC_Miss, context, value, slot, vector,
+ receiver, name);
+ }
+}
+
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/ic/keyed-store-generic.h b/deps/v8/src/ic/keyed-store-generic.h
index 8028736aa1..70f87f83ad 100644
--- a/deps/v8/src/ic/keyed-store-generic.h
+++ b/deps/v8/src/ic/keyed-store-generic.h
@@ -20,6 +20,12 @@ class KeyedStoreGenericGenerator {
LanguageMode language_mode);
};
+class StoreICUninitializedGenerator {
+ public:
+ static void Generate(compiler::CodeAssemblerState* state,
+ LanguageMode language_mode);
+};
+
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/ic/mips/handler-compiler-mips.cc b/deps/v8/src/ic/mips/handler-compiler-mips.cc
index c14652cf47..6e581a5bf2 100644
--- a/deps/v8/src/ic/mips/handler-compiler-mips.cc
+++ b/deps/v8/src/ic/mips/handler-compiler-mips.cc
@@ -17,43 +17,13 @@ namespace internal {
#define __ ACCESS_MASM(masm)
-
-void NamedLoadHandlerCompiler::GenerateLoadViaGetter(
- MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder,
- int accessor_index, int expected_arguments, Register scratch) {
- // ----------- S t a t e -------------
- // -- a0 : receiver
- // -- a2 : name
- // -- ra : return address
- // -----------------------------------
+void NamedLoadHandlerCompiler::GenerateLoadViaGetterForDeopt(
+ MacroAssembler* masm) {
{
FrameScope scope(masm, StackFrame::INTERNAL);
-
- // Save context register
- __ push(cp);
-
- if (accessor_index >= 0) {
- DCHECK(!holder.is(scratch));
- DCHECK(!receiver.is(scratch));
- // Call the JavaScript getter with the receiver on the stack.
- if (map->IsJSGlobalObjectMap()) {
- // Swap in the global receiver.
- __ lw(scratch,
- FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
- receiver = scratch;
- }
- __ push(receiver);
- __ LoadAccessor(a1, holder, accessor_index, ACCESSOR_GETTER);
- __ li(a0, Operand(0));
- __ Call(masm->isolate()->builtins()->CallFunction(
- ConvertReceiverMode::kNotNullOrUndefined),
- RelocInfo::CODE_TARGET);
- } else {
- // If we generate a global code snippet for deoptimization only, remember
- // the place to continue after deoptimization.
- masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
- }
-
+ // If we generate a global code snippet for deoptimization only, remember
+ // the place to continue after deoptimization.
+ masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
// Restore context register.
__ pop(cp);
}
@@ -190,22 +160,6 @@ void PropertyHandlerCompiler::GenerateCheckPropertyCell(
__ Branch(miss, ne, scratch, Operand(at));
}
-static void CompileCallLoadPropertyWithInterceptor(
- MacroAssembler* masm, Register receiver, Register holder, Register name,
- Handle<JSObject> holder_obj, Runtime::FunctionId id) {
- DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength ==
- Runtime::FunctionForId(id)->nargs);
-
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
- __ Push(name, receiver, holder);
-
- __ CallRuntime(id);
-}
-
-
// Generate call to api function.
void PropertyHandlerCompiler::GenerateApiAccessorCall(
MacroAssembler* masm, const CallOptimization& optimization,
@@ -276,12 +230,6 @@ void PropertyHandlerCompiler::GenerateApiAccessorCall(
__ lw(data, FieldMemOperand(data, CallHandlerInfo::kDataOffset));
}
- if (api_call_info->fast_handler()->IsCode()) {
- // Just tail call into the fast handler if present.
- __ Jump(handle(Code::cast(api_call_info->fast_handler())),
- RelocInfo::CODE_TARGET);
- return;
- }
// Put api_function_address in place.
Address function_address = v8::ToCData<Address>(api_call_info->callback());
ApiFunction fun(function_address);
@@ -330,8 +278,7 @@ void PropertyHandlerCompiler::GenerateAccessCheck(
Register PropertyHandlerCompiler::CheckPrototypes(
Register object_reg, Register holder_reg, Register scratch1,
- Register scratch2, Handle<Name> name, Label* miss,
- ReturnHolder return_what) {
+ Register scratch2, Handle<Name> name, Label* miss) {
Handle<Map> receiver_map = map();
// Make sure there's no overlap between holder and object registers.
@@ -396,15 +343,14 @@ Register PropertyHandlerCompiler::CheckPrototypes(
// Log the check depth.
LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
- bool return_holder = return_what == RETURN_HOLDER;
- if (return_holder && depth != 0) {
+ if (depth != 0) {
Handle<WeakCell> weak_cell =
Map::GetOrCreatePrototypeWeakCell(current, isolate());
__ LoadWeakValue(reg, weak_cell, miss);
}
// Return the register containing the holder.
- return return_holder ? reg : no_reg;
+ return reg;
}
@@ -413,10 +359,8 @@ void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
Label success;
__ Branch(&success);
__ bind(miss);
- if (IC::ICUseVector(kind())) {
- DCHECK(kind() == Code::LOAD_IC);
- PopVectorAndSlot();
- }
+ DCHECK(kind() == Code::LOAD_IC);
+ PopVectorAndSlot();
TailCallBuiltin(masm(), MissBuiltin(kind()));
__ bind(&success);
}
@@ -428,91 +372,12 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
Label success;
__ Branch(&success);
GenerateRestoreName(miss, name);
- if (IC::ICUseVector(kind())) PopVectorAndSlot();
+ PopVectorAndSlot();
TailCallBuiltin(masm(), MissBuiltin(kind()));
__ bind(&success);
}
}
-void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
- LookupIterator* it, Register holder_reg) {
- DCHECK(holder()->HasNamedInterceptor());
- DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
-
- // Compile the interceptor call, followed by inline code to load the
- // property from further up the prototype chain if the call fails.
- // Check that the maps haven't changed.
- DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
-
- // Preserve the receiver register explicitly whenever it is different from the
- // holder and it is needed should the interceptor return without any result.
- // The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD
- // case might cause a miss during the prototype check.
- bool must_perform_prototype_check =
- !holder().is_identical_to(it->GetHolder<JSObject>());
- bool must_preserve_receiver_reg =
- !receiver().is(holder_reg) &&
- (it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check);
-
- // Save necessary data before invoking an interceptor.
- // Requires a frame to make GC aware of pushed pointers.
- {
- FrameScope frame_scope(masm(), StackFrame::INTERNAL);
- if (must_preserve_receiver_reg) {
- __ Push(receiver(), holder_reg, this->name());
- } else {
- __ Push(holder_reg, this->name());
- }
- InterceptorVectorSlotPush(holder_reg);
- // Invoke an interceptor. Note: map checks from receiver to
- // interceptor's holder has been compiled before (see a caller
- // of this method).
- CompileCallLoadPropertyWithInterceptor(
- masm(), receiver(), holder_reg, this->name(), holder(),
- Runtime::kLoadPropertyWithInterceptorOnly);
-
- // Check if interceptor provided a value for property. If it's
- // the case, return immediately.
- Label interceptor_failed;
- __ LoadRoot(scratch1(), Heap::kNoInterceptorResultSentinelRootIndex);
- __ Branch(&interceptor_failed, eq, v0, Operand(scratch1()));
- frame_scope.GenerateLeaveFrame();
- __ Ret();
-
- __ bind(&interceptor_failed);
- InterceptorVectorSlotPop(holder_reg);
- if (must_preserve_receiver_reg) {
- __ Pop(receiver(), holder_reg, this->name());
- } else {
- __ Pop(holder_reg, this->name());
- }
- // Leave the internal frame.
- }
-
- GenerateLoadPostInterceptor(it, holder_reg);
-}
-
-
-void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
- // Call the runtime system to load the interceptor.
- DCHECK(holder()->HasNamedInterceptor());
- DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
-
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
- __ Push(name(), receiver(), holder_reg);
- // See NamedLoadHandlerCompiler::InterceptorVectorSlotPop() for details.
- if (holder_reg.is(receiver())) {
- __ Push(slot(), vector());
- } else {
- __ Push(scratch3(), scratch2()); // slot, vector
- }
-
- __ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor);
-}
-
void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() {
STATIC_ASSERT(!StoreWithVectorDescriptor::kPassLastArgsOnStack);
}
@@ -549,42 +414,6 @@ Register NamedStoreHandlerCompiler::value() {
}
-Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
- Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) {
- Label miss;
- if (IC::ICUseVector(kind())) {
- PushVectorAndSlot();
- }
-
- FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING);
-
- // Get the value from the cell.
- Register result = StoreDescriptor::ValueRegister();
- Handle<WeakCell> weak_cell = factory()->NewWeakCell(cell);
- __ LoadWeakValue(result, weak_cell, &miss);
- __ lw(result, FieldMemOperand(result, PropertyCell::kValueOffset));
-
- // Check for deleted property if property can actually be deleted.
- if (is_configurable) {
- __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
- __ Branch(&miss, eq, result, Operand(at));
- }
-
- Counters* counters = isolate()->counters();
- __ IncrementCounter(counters->ic_named_load_global_stub(), 1, a1, a3);
- if (IC::ICUseVector(kind())) {
- DiscardVectorAndSlot();
- }
- __ Ret(USE_DELAY_SLOT);
- __ Move(v0, result); // Ensure the stub returns correct value.
-
- FrontendFooter(name, &miss);
-
- // Return the generated code.
- return GetCode(kind(), name);
-}
-
-
#undef __
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/ic/mips64/handler-compiler-mips64.cc b/deps/v8/src/ic/mips64/handler-compiler-mips64.cc
index 1a38d329e7..99ca45a136 100644
--- a/deps/v8/src/ic/mips64/handler-compiler-mips64.cc
+++ b/deps/v8/src/ic/mips64/handler-compiler-mips64.cc
@@ -17,43 +17,13 @@ namespace internal {
#define __ ACCESS_MASM(masm)
-
-void NamedLoadHandlerCompiler::GenerateLoadViaGetter(
- MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder,
- int accessor_index, int expected_arguments, Register scratch) {
- // ----------- S t a t e -------------
- // -- a0 : receiver
- // -- a2 : name
- // -- ra : return address
- // -----------------------------------
+void NamedLoadHandlerCompiler::GenerateLoadViaGetterForDeopt(
+ MacroAssembler* masm) {
{
FrameScope scope(masm, StackFrame::INTERNAL);
-
- // Save context register
- __ push(cp);
-
- if (accessor_index >= 0) {
- DCHECK(!holder.is(scratch));
- DCHECK(!receiver.is(scratch));
- // Call the JavaScript getter with the receiver on the stack.
- if (map->IsJSGlobalObjectMap()) {
- // Swap in the global receiver.
- __ ld(scratch,
- FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
- receiver = scratch;
- }
- __ push(receiver);
- __ LoadAccessor(a1, holder, accessor_index, ACCESSOR_GETTER);
- __ li(a0, Operand(V8_INT64_C(0)));
- __ Call(masm->isolate()->builtins()->CallFunction(
- ConvertReceiverMode::kNotNullOrUndefined),
- RelocInfo::CODE_TARGET);
- } else {
- // If we generate a global code snippet for deoptimization only, remember
- // the place to continue after deoptimization.
- masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
- }
-
+ // If we generate a global code snippet for deoptimization only, remember
+ // the place to continue after deoptimization.
+ masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
// Restore context register.
__ pop(cp);
}
@@ -190,22 +160,6 @@ void PropertyHandlerCompiler::GenerateCheckPropertyCell(
__ Branch(miss, ne, scratch, Operand(at));
}
-static void CompileCallLoadPropertyWithInterceptor(
- MacroAssembler* masm, Register receiver, Register holder, Register name,
- Handle<JSObject> holder_obj, Runtime::FunctionId id) {
- DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength ==
- Runtime::FunctionForId(id)->nargs);
-
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
- __ Push(name, receiver, holder);
-
- __ CallRuntime(id);
-}
-
-
// Generate call to api function.
void PropertyHandlerCompiler::GenerateApiAccessorCall(
MacroAssembler* masm, const CallOptimization& optimization,
@@ -276,12 +230,6 @@ void PropertyHandlerCompiler::GenerateApiAccessorCall(
__ ld(data, FieldMemOperand(data, CallHandlerInfo::kDataOffset));
}
- if (api_call_info->fast_handler()->IsCode()) {
- // Just tail call into the fast handler if present.
- __ Jump(handle(Code::cast(api_call_info->fast_handler())),
- RelocInfo::CODE_TARGET);
- return;
- }
// Put api_function_address in place.
Address function_address = v8::ToCData<Address>(api_call_info->callback());
ApiFunction fun(function_address);
@@ -330,8 +278,7 @@ void PropertyHandlerCompiler::GenerateAccessCheck(
Register PropertyHandlerCompiler::CheckPrototypes(
Register object_reg, Register holder_reg, Register scratch1,
- Register scratch2, Handle<Name> name, Label* miss,
- ReturnHolder return_what) {
+ Register scratch2, Handle<Name> name, Label* miss) {
Handle<Map> receiver_map = map();
// Make sure there's no overlap between holder and object registers.
@@ -396,15 +343,14 @@ Register PropertyHandlerCompiler::CheckPrototypes(
// Log the check depth.
LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
- bool return_holder = return_what == RETURN_HOLDER;
- if (return_holder && depth != 0) {
+ if (depth != 0) {
Handle<WeakCell> weak_cell =
Map::GetOrCreatePrototypeWeakCell(current, isolate());
__ LoadWeakValue(reg, weak_cell, miss);
}
// Return the register containing the holder.
- return return_holder ? reg : no_reg;
+ return reg;
}
@@ -413,10 +359,8 @@ void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
Label success;
__ Branch(&success);
__ bind(miss);
- if (IC::ICUseVector(kind())) {
- DCHECK(kind() == Code::LOAD_IC);
- PopVectorAndSlot();
- }
+ DCHECK(kind() == Code::LOAD_IC);
+ PopVectorAndSlot();
TailCallBuiltin(masm(), MissBuiltin(kind()));
__ bind(&success);
}
@@ -428,91 +372,12 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
Label success;
__ Branch(&success);
GenerateRestoreName(miss, name);
- if (IC::ICUseVector(kind())) PopVectorAndSlot();
+ PopVectorAndSlot();
TailCallBuiltin(masm(), MissBuiltin(kind()));
__ bind(&success);
}
}
-void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
- LookupIterator* it, Register holder_reg) {
- DCHECK(holder()->HasNamedInterceptor());
- DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
-
- // Compile the interceptor call, followed by inline code to load the
- // property from further up the prototype chain if the call fails.
- // Check that the maps haven't changed.
- DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
-
- // Preserve the receiver register explicitly whenever it is different from the
- // holder and it is needed should the interceptor return without any result.
- // The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD
- // case might cause a miss during the prototype check.
- bool must_perform_prototype_check =
- !holder().is_identical_to(it->GetHolder<JSObject>());
- bool must_preserve_receiver_reg =
- !receiver().is(holder_reg) &&
- (it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check);
-
- // Save necessary data before invoking an interceptor.
- // Requires a frame to make GC aware of pushed pointers.
- {
- FrameScope frame_scope(masm(), StackFrame::INTERNAL);
- if (must_preserve_receiver_reg) {
- __ Push(receiver(), holder_reg, this->name());
- } else {
- __ Push(holder_reg, this->name());
- }
- InterceptorVectorSlotPush(holder_reg);
- // Invoke an interceptor. Note: map checks from receiver to
- // interceptor's holder has been compiled before (see a caller
- // of this method).
- CompileCallLoadPropertyWithInterceptor(
- masm(), receiver(), holder_reg, this->name(), holder(),
- Runtime::kLoadPropertyWithInterceptorOnly);
-
- // Check if interceptor provided a value for property. If it's
- // the case, return immediately.
- Label interceptor_failed;
- __ LoadRoot(scratch1(), Heap::kNoInterceptorResultSentinelRootIndex);
- __ Branch(&interceptor_failed, eq, v0, Operand(scratch1()));
- frame_scope.GenerateLeaveFrame();
- __ Ret();
-
- __ bind(&interceptor_failed);
- InterceptorVectorSlotPop(holder_reg);
- if (must_preserve_receiver_reg) {
- __ Pop(receiver(), holder_reg, this->name());
- } else {
- __ Pop(holder_reg, this->name());
- }
- // Leave the internal frame.
- }
-
- GenerateLoadPostInterceptor(it, holder_reg);
-}
-
-
-void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
- // Call the runtime system to load the interceptor.
- DCHECK(holder()->HasNamedInterceptor());
- DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
-
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
- __ Push(name(), receiver(), holder_reg);
- // See NamedLoadHandlerCompiler::InterceptorVectorSlotPop() for details.
- if (holder_reg.is(receiver())) {
- __ Push(slot(), vector());
- } else {
- __ Push(scratch3(), scratch2()); // slot, vector
- }
-
- __ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor);
-}
-
void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() {
STATIC_ASSERT(!StoreWithVectorDescriptor::kPassLastArgsOnStack);
}
@@ -549,42 +414,6 @@ Register NamedStoreHandlerCompiler::value() {
}
-Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
- Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) {
- Label miss;
- if (IC::ICUseVector(kind())) {
- PushVectorAndSlot();
- }
-
- FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING);
-
- // Get the value from the cell.
- Register result = StoreDescriptor::ValueRegister();
- Handle<WeakCell> weak_cell = factory()->NewWeakCell(cell);
- __ LoadWeakValue(result, weak_cell, &miss);
- __ ld(result, FieldMemOperand(result, PropertyCell::kValueOffset));
-
- // Check for deleted property if property can actually be deleted.
- if (is_configurable) {
- __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
- __ Branch(&miss, eq, result, Operand(at));
- }
-
- Counters* counters = isolate()->counters();
- __ IncrementCounter(counters->ic_named_load_global_stub(), 1, a1, a3);
- if (IC::ICUseVector(kind())) {
- DiscardVectorAndSlot();
- }
- __ Ret(USE_DELAY_SLOT);
- __ Move(v0, result); // Ensure the stub returns correct value.
-
- FrontendFooter(name, &miss);
-
- // Return the generated code.
- return GetCode(kind(), name);
-}
-
-
#undef __
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/ic/ppc/handler-compiler-ppc.cc b/deps/v8/src/ic/ppc/handler-compiler-ppc.cc
index 3da558d10e..5736c12ffc 100644
--- a/deps/v8/src/ic/ppc/handler-compiler-ppc.cc
+++ b/deps/v8/src/ic/ppc/handler-compiler-ppc.cc
@@ -17,43 +17,13 @@ namespace internal {
#define __ ACCESS_MASM(masm)
-
-void NamedLoadHandlerCompiler::GenerateLoadViaGetter(
- MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder,
- int accessor_index, int expected_arguments, Register scratch) {
- // ----------- S t a t e -------------
- // -- r3 : receiver
- // -- r5 : name
- // -- lr : return address
- // -----------------------------------
+void NamedLoadHandlerCompiler::GenerateLoadViaGetterForDeopt(
+ MacroAssembler* masm) {
{
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
-
- // Save context register
- __ push(cp);
-
- if (accessor_index >= 0) {
- DCHECK(!holder.is(scratch));
- DCHECK(!receiver.is(scratch));
- // Call the JavaScript getter with the receiver on the stack.
- if (map->IsJSGlobalObjectMap()) {
- // Swap in the global receiver.
- __ LoadP(scratch,
- FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
- receiver = scratch;
- }
- __ push(receiver);
- __ LoadAccessor(r4, holder, accessor_index, ACCESSOR_GETTER);
- __ li(r3, Operand::Zero());
- __ Call(masm->isolate()->builtins()->CallFunction(
- ConvertReceiverMode::kNotNullOrUndefined),
- RelocInfo::CODE_TARGET);
- } else {
- // If we generate a global code snippet for deoptimization only, remember
- // the place to continue after deoptimization.
- masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
- }
-
+ // If we generate a global code snippet for deoptimization only, remember
+ // the place to continue after deoptimization.
+ masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
// Restore context register.
__ pop(cp);
}
@@ -195,22 +165,6 @@ void PropertyHandlerCompiler::GenerateCheckPropertyCell(
}
-static void CompileCallLoadPropertyWithInterceptor(
- MacroAssembler* masm, Register receiver, Register holder, Register name,
- Handle<JSObject> holder_obj, Runtime::FunctionId id) {
- DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength ==
- Runtime::FunctionForId(id)->nargs);
-
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
- __ Push(name, receiver, holder);
-
- __ CallRuntime(id);
-}
-
-
// Generate call to api function.
void PropertyHandlerCompiler::GenerateApiAccessorCall(
MacroAssembler* masm, const CallOptimization& optimization,
@@ -282,13 +236,6 @@ void PropertyHandlerCompiler::GenerateApiAccessorCall(
__ LoadP(data, FieldMemOperand(data, CallHandlerInfo::kDataOffset));
}
- if (api_call_info->fast_handler()->IsCode()) {
- // Just tail call into the fast handler if present.
- __ Jump(handle(Code::cast(api_call_info->fast_handler())),
- RelocInfo::CODE_TARGET);
- return;
- }
-
// Put api_function_address in place.
Address function_address = v8::ToCData<Address>(api_call_info->callback());
ApiFunction fun(function_address);
@@ -341,8 +288,7 @@ void PropertyHandlerCompiler::GenerateAccessCheck(
Register PropertyHandlerCompiler::CheckPrototypes(
Register object_reg, Register holder_reg, Register scratch1,
- Register scratch2, Handle<Name> name, Label* miss,
- ReturnHolder return_what) {
+ Register scratch2, Handle<Name> name, Label* miss) {
Handle<Map> receiver_map = map();
// Make sure there's no overlap between holder and object registers.
@@ -412,15 +358,14 @@ Register PropertyHandlerCompiler::CheckPrototypes(
// Log the check depth.
LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
- bool return_holder = return_what == RETURN_HOLDER;
- if (return_holder && depth != 0) {
+ if (depth != 0) {
Handle<WeakCell> weak_cell =
Map::GetOrCreatePrototypeWeakCell(current, isolate());
__ LoadWeakValue(reg, weak_cell, miss);
}
// Return the register containing the holder.
- return return_holder ? reg : no_reg;
+ return reg;
}
@@ -429,10 +374,8 @@ void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
Label success;
__ b(&success);
__ bind(miss);
- if (IC::ICUseVector(kind())) {
- DCHECK(kind() == Code::LOAD_IC);
- PopVectorAndSlot();
- }
+ DCHECK(kind() == Code::LOAD_IC);
+ PopVectorAndSlot();
TailCallBuiltin(masm(), MissBuiltin(kind()));
__ bind(&success);
}
@@ -444,92 +387,12 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
Label success;
__ b(&success);
GenerateRestoreName(miss, name);
- if (IC::ICUseVector(kind())) PopVectorAndSlot();
+ PopVectorAndSlot();
TailCallBuiltin(masm(), MissBuiltin(kind()));
__ bind(&success);
}
}
-void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
- LookupIterator* it, Register holder_reg) {
- DCHECK(holder()->HasNamedInterceptor());
- DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
-
- // Compile the interceptor call, followed by inline code to load the
- // property from further up the prototype chain if the call fails.
- // Check that the maps haven't changed.
- DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
-
- // Preserve the receiver register explicitly whenever it is different from the
- // holder and it is needed should the interceptor return without any result.
- // The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD
- // case might cause a miss during the prototype check.
- bool must_perform_prototype_check =
- !holder().is_identical_to(it->GetHolder<JSObject>());
- bool must_preserve_receiver_reg =
- !receiver().is(holder_reg) &&
- (it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check);
-
- // Save necessary data before invoking an interceptor.
- // Requires a frame to make GC aware of pushed pointers.
- {
- FrameAndConstantPoolScope frame_scope(masm(), StackFrame::INTERNAL);
- if (must_preserve_receiver_reg) {
- __ Push(receiver(), holder_reg, this->name());
- } else {
- __ Push(holder_reg, this->name());
- }
- InterceptorVectorSlotPush(holder_reg);
- // Invoke an interceptor. Note: map checks from receiver to
- // interceptor's holder has been compiled before (see a caller
- // of this method.)
- CompileCallLoadPropertyWithInterceptor(
- masm(), receiver(), holder_reg, this->name(), holder(),
- Runtime::kLoadPropertyWithInterceptorOnly);
-
- // Check if interceptor provided a value for property. If it's
- // the case, return immediately.
- Label interceptor_failed;
- __ LoadRoot(scratch1(), Heap::kNoInterceptorResultSentinelRootIndex);
- __ cmp(r3, scratch1());
- __ beq(&interceptor_failed);
- frame_scope.GenerateLeaveFrame();
- __ Ret();
-
- __ bind(&interceptor_failed);
- InterceptorVectorSlotPop(holder_reg);
- __ pop(this->name());
- __ pop(holder_reg);
- if (must_preserve_receiver_reg) {
- __ pop(receiver());
- }
- // Leave the internal frame.
- }
-
- GenerateLoadPostInterceptor(it, holder_reg);
-}
-
-
-void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
- // Call the runtime system to load the interceptor.
- DCHECK(holder()->HasNamedInterceptor());
- DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
-
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
- __ Push(name(), receiver(), holder_reg);
- // See NamedLoadHandlerCompiler::InterceptorVectorSlotPop() for details.
- if (holder_reg.is(receiver())) {
- __ Push(slot(), vector());
- } else {
- __ Push(scratch3(), scratch2()); // slot, vector
- }
-
- __ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor);
-}
-
void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() {
STATIC_ASSERT(!StoreWithVectorDescriptor::kPassLastArgsOnStack);
}
@@ -567,41 +430,6 @@ Register NamedStoreHandlerCompiler::value() {
}
-Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
- Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) {
- Label miss;
- if (IC::ICUseVector(kind())) {
- PushVectorAndSlot();
- }
- FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING);
-
- // Get the value from the cell.
- Register result = StoreDescriptor::ValueRegister();
- Handle<WeakCell> weak_cell = factory()->NewWeakCell(cell);
- __ LoadWeakValue(result, weak_cell, &miss);
- __ LoadP(result, FieldMemOperand(result, PropertyCell::kValueOffset));
-
- // Check for deleted property if property can actually be deleted.
- if (is_configurable) {
- __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
- __ cmp(result, ip);
- __ beq(&miss);
- }
-
- Counters* counters = isolate()->counters();
- __ IncrementCounter(counters->ic_named_load_global_stub(), 1, r4, r6);
- if (IC::ICUseVector(kind())) {
- DiscardVectorAndSlot();
- }
- __ Ret();
-
- FrontendFooter(name, &miss);
-
- // Return the generated code.
- return GetCode(kind(), name);
-}
-
-
#undef __
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/ic/s390/handler-compiler-s390.cc b/deps/v8/src/ic/s390/handler-compiler-s390.cc
index 9f087977a1..bfca871bab 100644
--- a/deps/v8/src/ic/s390/handler-compiler-s390.cc
+++ b/deps/v8/src/ic/s390/handler-compiler-s390.cc
@@ -17,42 +17,13 @@ namespace internal {
#define __ ACCESS_MASM(masm)
-void NamedLoadHandlerCompiler::GenerateLoadViaGetter(
- MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder,
- int accessor_index, int expected_arguments, Register scratch) {
- // ----------- S t a t e -------------
- // -- r2 : receiver
- // -- r4 : name
- // -- lr : return address
- // -----------------------------------
+void NamedLoadHandlerCompiler::GenerateLoadViaGetterForDeopt(
+ MacroAssembler* masm) {
{
FrameScope scope(masm, StackFrame::INTERNAL);
-
- // Save context register
- __ push(cp);
-
- if (accessor_index >= 0) {
- DCHECK(!holder.is(scratch));
- DCHECK(!receiver.is(scratch));
- // Call the JavaScript getter with the receiver on the stack.
- if (map->IsJSGlobalObjectMap()) {
- // Swap in the global receiver.
- __ LoadP(scratch,
- FieldMemOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
- receiver = scratch;
- }
- __ Push(receiver);
- __ LoadAccessor(r3, holder, accessor_index, ACCESSOR_GETTER);
- __ LoadImmP(r2, Operand::Zero());
- __ Call(masm->isolate()->builtins()->CallFunction(
- ConvertReceiverMode::kNotNullOrUndefined),
- RelocInfo::CODE_TARGET);
- } else {
- // If we generate a global code snippet for deoptimization only, remember
- // the place to continue after deoptimization.
- masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
- }
-
+ // If we generate a global code snippet for deoptimization only, remember
+ // the place to continue after deoptimization.
+ masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
// Restore context register.
__ pop(cp);
}
@@ -186,21 +157,6 @@ void PropertyHandlerCompiler::GenerateCheckPropertyCell(
__ bne(miss);
}
-static void CompileCallLoadPropertyWithInterceptor(
- MacroAssembler* masm, Register receiver, Register holder, Register name,
- Handle<JSObject> holder_obj, Runtime::FunctionId id) {
- DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength ==
- Runtime::FunctionForId(id)->nargs);
-
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
- __ Push(name, receiver, holder);
-
- __ CallRuntime(id);
-}
-
// Generate call to api function.
void PropertyHandlerCompiler::GenerateApiAccessorCall(
MacroAssembler* masm, const CallOptimization& optimization,
@@ -272,13 +228,6 @@ void PropertyHandlerCompiler::GenerateApiAccessorCall(
__ LoadP(data, FieldMemOperand(data, CallHandlerInfo::kDataOffset));
}
- if (api_call_info->fast_handler()->IsCode()) {
- // Just tail call into the fast handler if present.
- __ Jump(handle(Code::cast(api_call_info->fast_handler())),
- RelocInfo::CODE_TARGET);
- return;
- }
-
// Put api_function_address in place.
Address function_address = v8::ToCData<Address>(api_call_info->callback());
ApiFunction fun(function_address);
@@ -330,8 +279,7 @@ void PropertyHandlerCompiler::GenerateAccessCheck(
Register PropertyHandlerCompiler::CheckPrototypes(
Register object_reg, Register holder_reg, Register scratch1,
- Register scratch2, Handle<Name> name, Label* miss,
- ReturnHolder return_what) {
+ Register scratch2, Handle<Name> name, Label* miss) {
Handle<Map> receiver_map = map();
// Make sure there's no overlap between holder and object registers.
@@ -396,15 +344,14 @@ Register PropertyHandlerCompiler::CheckPrototypes(
// Log the check depth.
LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
- bool return_holder = return_what == RETURN_HOLDER;
- if (return_holder && depth != 0) {
+ if (depth != 0) {
Handle<WeakCell> weak_cell =
Map::GetOrCreatePrototypeWeakCell(current, isolate());
__ LoadWeakValue(reg, weak_cell, miss);
}
// Return the register containing the holder.
- return return_holder ? reg : no_reg;
+ return reg;
}
void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
@@ -412,10 +359,8 @@ void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
Label success;
__ b(&success);
__ bind(miss);
- if (IC::ICUseVector(kind())) {
- DCHECK(kind() == Code::LOAD_IC);
- PopVectorAndSlot();
- }
+ DCHECK(kind() == Code::LOAD_IC);
+ PopVectorAndSlot();
TailCallBuiltin(masm(), MissBuiltin(kind()));
__ bind(&success);
}
@@ -426,90 +371,12 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
Label success;
__ b(&success);
GenerateRestoreName(miss, name);
- if (IC::ICUseVector(kind())) PopVectorAndSlot();
+ PopVectorAndSlot();
TailCallBuiltin(masm(), MissBuiltin(kind()));
__ bind(&success);
}
}
-void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
- LookupIterator* it, Register holder_reg) {
- DCHECK(holder()->HasNamedInterceptor());
- DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
-
- // Compile the interceptor call, followed by inline code to load the
- // property from further up the prototype chain if the call fails.
- // Check that the maps haven't changed.
- DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
-
- // Preserve the receiver register explicitly whenever it is different from the
- // holder and it is needed should the interceptor return without any result.
- // The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD
- // case might cause a miss during the prototype check.
- bool must_perform_prototype_check =
- !holder().is_identical_to(it->GetHolder<JSObject>());
- bool must_preserve_receiver_reg =
- !receiver().is(holder_reg) &&
- (it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check);
-
- // Save necessary data before invoking an interceptor.
- // Requires a frame to make GC aware of pushed pointers.
- {
- FrameScope frame_scope(masm(), StackFrame::INTERNAL);
- if (must_preserve_receiver_reg) {
- __ Push(receiver(), holder_reg, this->name());
- } else {
- __ Push(holder_reg, this->name());
- }
- InterceptorVectorSlotPush(holder_reg);
- // Invoke an interceptor. Note: map checks from receiver to
- // interceptor's holder has been compiled before (see a caller
- // of this method.)
- CompileCallLoadPropertyWithInterceptor(
- masm(), receiver(), holder_reg, this->name(), holder(),
- Runtime::kLoadPropertyWithInterceptorOnly);
-
- // Check if interceptor provided a value for property. If it's
- // the case, return immediately.
- Label interceptor_failed;
- __ CompareRoot(r2, Heap::kNoInterceptorResultSentinelRootIndex);
- __ beq(&interceptor_failed, Label::kNear);
- frame_scope.GenerateLeaveFrame();
- __ Ret();
-
- __ bind(&interceptor_failed);
- InterceptorVectorSlotPop(holder_reg);
- __ Pop(this->name());
- __ Pop(holder_reg);
- if (must_preserve_receiver_reg) {
- __ Pop(receiver());
- }
- // Leave the internal frame.
- }
-
- GenerateLoadPostInterceptor(it, holder_reg);
-}
-
-void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
- // Call the runtime system to load the interceptor.
- DCHECK(holder()->HasNamedInterceptor());
- DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
-
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
- __ Push(name(), receiver(), holder_reg);
- // See NamedLoadHandlerCompiler::InterceptorVectorSlotPop() for details.
- if (holder_reg.is(receiver())) {
- __ Push(slot(), vector());
- } else {
- __ Push(scratch3(), scratch2()); // slot, vector
- }
-
- __ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor);
-}
-
void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() {
STATIC_ASSERT(!StoreWithVectorDescriptor::kPassLastArgsOnStack);
}
@@ -545,39 +412,6 @@ Register NamedStoreHandlerCompiler::value() {
return StoreDescriptor::ValueRegister();
}
-Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
- Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) {
- Label miss;
- if (IC::ICUseVector(kind())) {
- PushVectorAndSlot();
- }
- FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING);
-
- // Get the value from the cell.
- Register result = StoreDescriptor::ValueRegister();
- Handle<WeakCell> weak_cell = factory()->NewWeakCell(cell);
- __ LoadWeakValue(result, weak_cell, &miss);
- __ LoadP(result, FieldMemOperand(result, PropertyCell::kValueOffset));
-
- // Check for deleted property if property can actually be deleted.
- if (is_configurable) {
- __ CompareRoot(result, Heap::kTheHoleValueRootIndex);
- __ beq(&miss);
- }
-
- Counters* counters = isolate()->counters();
- __ IncrementCounter(counters->ic_named_load_global_stub(), 1, r3, r5);
- if (IC::ICUseVector(kind())) {
- DiscardVectorAndSlot();
- }
- __ Ret();
-
- FrontendFooter(name, &miss);
-
- // Return the generated code.
- return GetCode(kind(), name);
-}
-
#undef __
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/ic/stub-cache.cc b/deps/v8/src/ic/stub-cache.cc
index 5fc8cc318d..d62aceec96 100644
--- a/deps/v8/src/ic/stub-cache.cc
+++ b/deps/v8/src/ic/stub-cache.cc
@@ -42,9 +42,9 @@ bool CommonStubCacheChecks(StubCache* stub_cache, Name* name, Map* map,
DCHECK(IC::IsHandler(handler));
if (handler->IsCode()) {
Code* code = Code::cast(handler);
- Code::Flags expected_flags = Code::RemoveHolderFromFlags(
- Code::ComputeHandlerFlags(stub_cache->ic_kind()));
- Code::Flags flags = Code::RemoveHolderFromFlags(code->flags());
+ Code::Flags expected_flags =
+ Code::ComputeHandlerFlags(stub_cache->ic_kind());
+ Code::Flags flags = code->flags();
DCHECK_EQ(expected_flags, flags);
DCHECK_EQ(Code::HANDLER, Code::ExtractKindFromFlags(code->flags()));
}
diff --git a/deps/v8/src/ic/x64/handler-compiler-x64.cc b/deps/v8/src/ic/x64/handler-compiler-x64.cc
index 425ed4762e..cd831c8b5f 100644
--- a/deps/v8/src/ic/x64/handler-compiler-x64.cc
+++ b/deps/v8/src/ic/x64/handler-compiler-x64.cc
@@ -83,24 +83,6 @@ void PropertyHandlerCompiler::GenerateDictionaryNegativeLookup(
__ DecrementCounter(counters->negative_lookups_miss(), 1);
}
-static void CompileCallLoadPropertyWithInterceptor(
- MacroAssembler* masm, Register receiver, Register holder, Register name,
- Handle<JSObject> holder_obj, Runtime::FunctionId id) {
- DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength ==
- Runtime::FunctionForId(id)->nargs);
-
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
- __ Push(name);
- __ Push(receiver);
- __ Push(holder);
-
- __ CallRuntime(id);
-}
-
-
// Generate call to api function.
void PropertyHandlerCompiler::GenerateApiAccessorCall(
MacroAssembler* masm, const CallOptimization& optimization,
@@ -176,13 +158,6 @@ void PropertyHandlerCompiler::GenerateApiAccessorCall(
__ movp(data, FieldOperand(data, CallHandlerInfo::kDataOffset));
}
- if (api_call_info->fast_handler()->IsCode()) {
- // Just tail call into the fast handler if present.
- __ Jump(handle(Code::cast(api_call_info->fast_handler())),
- RelocInfo::CODE_TARGET);
- return;
- }
-
// Put api_function_address in place.
Address function_address = v8::ToCData<Address>(api_call_info->callback());
__ Move(api_function_address, function_address,
@@ -257,43 +232,12 @@ void NamedStoreHandlerCompiler::GenerateStoreViaSetter(
__ ret(0);
}
-
-void NamedLoadHandlerCompiler::GenerateLoadViaGetter(
- MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder,
- int accessor_index, int expected_arguments, Register scratch) {
- // ----------- S t a t e -------------
- // -- rax : receiver
- // -- rcx : name
- // -- rsp[0] : return address
- // -----------------------------------
+void NamedLoadHandlerCompiler::GenerateLoadViaGetterForDeopt(
+ MacroAssembler* masm) {
{
FrameScope scope(masm, StackFrame::INTERNAL);
-
- // Save context register
- __ pushq(rsi);
-
- if (accessor_index >= 0) {
- DCHECK(!holder.is(scratch));
- DCHECK(!receiver.is(scratch));
- // Call the JavaScript getter with the receiver on the stack.
- if (map->IsJSGlobalObjectMap()) {
- // Swap in the global receiver.
- __ movp(scratch,
- FieldOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
- receiver = scratch;
- }
- __ Push(receiver);
- __ LoadAccessor(rdi, holder, accessor_index, ACCESSOR_GETTER);
- __ Set(rax, 0);
- __ Call(masm->isolate()->builtins()->CallFunction(
- ConvertReceiverMode::kNotNullOrUndefined),
- RelocInfo::CODE_TARGET);
- } else {
- // If we generate a global code snippet for deoptimization only, remember
- // the place to continue after deoptimization.
- masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
- }
-
+ // Remember the place to continue after deoptimization.
+ masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
// Restore context register.
__ popq(rsi);
}
@@ -337,8 +281,7 @@ void PropertyHandlerCompiler::GenerateAccessCheck(
Register PropertyHandlerCompiler::CheckPrototypes(
Register object_reg, Register holder_reg, Register scratch1,
- Register scratch2, Handle<Name> name, Label* miss,
- ReturnHolder return_what) {
+ Register scratch2, Handle<Name> name, Label* miss) {
Handle<Map> receiver_map = map();
// Make sure there's no overlap between holder and object registers.
@@ -406,15 +349,14 @@ Register PropertyHandlerCompiler::CheckPrototypes(
// Log the check depth.
LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
- bool return_holder = return_what == RETURN_HOLDER;
- if (return_holder && depth != 0) {
+ if (depth != 0) {
Handle<WeakCell> weak_cell =
Map::GetOrCreatePrototypeWeakCell(current, isolate());
__ LoadWeakValue(reg, weak_cell, miss);
}
// Return the register containing the holder.
- return return_holder ? reg : no_reg;
+ return reg;
}
@@ -423,10 +365,8 @@ void NamedLoadHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
Label success;
__ jmp(&success);
__ bind(miss);
- if (IC::ICUseVector(kind())) {
- DCHECK(kind() == Code::LOAD_IC);
- PopVectorAndSlot();
- }
+ DCHECK(kind() == Code::LOAD_IC);
+ PopVectorAndSlot();
TailCallBuiltin(masm(), MissBuiltin(kind()));
__ bind(&success);
}
@@ -438,102 +378,12 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
Label success;
__ jmp(&success);
GenerateRestoreName(miss, name);
- if (IC::ICUseVector(kind())) PopVectorAndSlot();
+ PopVectorAndSlot();
TailCallBuiltin(masm(), MissBuiltin(kind()));
__ bind(&success);
}
}
-void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
- LookupIterator* it, Register holder_reg) {
- DCHECK(holder()->HasNamedInterceptor());
- DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
-
- // Compile the interceptor call, followed by inline code to load the
- // property from further up the prototype chain if the call fails.
- // Check that the maps haven't changed.
- DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
-
- // Preserve the receiver register explicitly whenever it is different from the
- // holder and it is needed should the interceptor return without any result.
- // The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD
- // case might cause a miss during the prototype check.
- bool must_perform_prototype_check =
- !holder().is_identical_to(it->GetHolder<JSObject>());
- bool must_preserve_receiver_reg =
- !receiver().is(holder_reg) &&
- (it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check);
-
- // Save necessary data before invoking an interceptor.
- // Requires a frame to make GC aware of pushed pointers.
- {
- FrameScope frame_scope(masm(), StackFrame::INTERNAL);
-
- if (must_preserve_receiver_reg) {
- __ Push(receiver());
- }
- __ Push(holder_reg);
- __ Push(this->name());
- InterceptorVectorSlotPush(holder_reg);
-
- // Invoke an interceptor. Note: map checks from receiver to
- // interceptor's holder has been compiled before (see a caller
- // of this method.)
- CompileCallLoadPropertyWithInterceptor(
- masm(), receiver(), holder_reg, this->name(), holder(),
- Runtime::kLoadPropertyWithInterceptorOnly);
-
- // Check if interceptor provided a value for property. If it's
- // the case, return immediately.
- Label interceptor_failed;
- __ CompareRoot(rax, Heap::kNoInterceptorResultSentinelRootIndex);
- __ j(equal, &interceptor_failed);
- frame_scope.GenerateLeaveFrame();
- __ ret(0);
-
- __ bind(&interceptor_failed);
- InterceptorVectorSlotPop(holder_reg);
- __ Pop(this->name());
- __ Pop(holder_reg);
- if (must_preserve_receiver_reg) {
- __ Pop(receiver());
- }
-
- // Leave the internal frame.
- }
-
- GenerateLoadPostInterceptor(it, holder_reg);
-}
-
-
-void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
- // Call the runtime system to load the interceptor.
- DCHECK(holder()->HasNamedInterceptor());
- DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
-
- // Stack:
- // return address
-
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
- __ Push(receiver());
- __ Push(holder_reg);
- // See NamedLoadHandlerCompiler::InterceptorVectorSlotPop() for details.
- if (holder_reg.is(receiver())) {
- __ Push(slot());
- __ Push(vector());
- } else {
- __ Push(scratch3()); // slot
- __ Push(scratch2()); // vector
- }
- __ Push(Operand(rsp, 4 * kPointerSize)); // return address
- __ movp(Operand(rsp, 5 * kPointerSize), name());
-
- __ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor);
-}
-
void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() {
STATIC_ASSERT(!StoreWithVectorDescriptor::kPassLastArgsOnStack);
}
@@ -572,43 +422,6 @@ Register NamedStoreHandlerCompiler::value() {
}
-Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
- Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) {
- Label miss;
- if (IC::ICUseVector(kind())) {
- PushVectorAndSlot();
- }
- FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING);
-
- // Get the value from the cell.
- Register result = StoreDescriptor::ValueRegister();
- Handle<WeakCell> weak_cell = factory()->NewWeakCell(cell);
- __ LoadWeakValue(result, weak_cell, &miss);
- __ movp(result, FieldOperand(result, PropertyCell::kValueOffset));
-
- // Check for deleted property if property can actually be deleted.
- if (is_configurable) {
- __ CompareRoot(result, Heap::kTheHoleValueRootIndex);
- __ j(equal, &miss);
- } else if (FLAG_debug_code) {
- __ CompareRoot(result, Heap::kTheHoleValueRootIndex);
- __ Check(not_equal, kDontDeleteCellsCannotContainTheHole);
- }
-
- Counters* counters = isolate()->counters();
- __ IncrementCounter(counters->ic_named_load_global_stub(), 1);
- if (IC::ICUseVector(kind())) {
- DiscardVectorAndSlot();
- }
- __ ret(0);
-
- FrontendFooter(name, &miss);
-
- // Return the generated code.
- return GetCode(kind(), name);
-}
-
-
#undef __
} // namespace internal
} // namespace v8
diff --git a/deps/v8/src/ic/x87/handler-compiler-x87.cc b/deps/v8/src/ic/x87/handler-compiler-x87.cc
index 5a61eee163..dc572a19cc 100644
--- a/deps/v8/src/ic/x87/handler-compiler-x87.cc
+++ b/deps/v8/src/ic/x87/handler-compiler-x87.cc
@@ -17,38 +17,13 @@ namespace internal {
#define __ ACCESS_MASM(masm)
-
-void NamedLoadHandlerCompiler::GenerateLoadViaGetter(
- MacroAssembler* masm, Handle<Map> map, Register receiver, Register holder,
- int accessor_index, int expected_arguments, Register scratch) {
+void NamedLoadHandlerCompiler::GenerateLoadViaGetterForDeopt(
+ MacroAssembler* masm) {
{
FrameScope scope(masm, StackFrame::INTERNAL);
-
- // Save context register
- __ push(esi);
-
- if (accessor_index >= 0) {
- DCHECK(!holder.is(scratch));
- DCHECK(!receiver.is(scratch));
- // Call the JavaScript getter with the receiver on the stack.
- if (map->IsJSGlobalObjectMap()) {
- // Swap in the global receiver.
- __ mov(scratch,
- FieldOperand(receiver, JSGlobalObject::kGlobalProxyOffset));
- receiver = scratch;
- }
- __ push(receiver);
- __ LoadAccessor(edi, holder, accessor_index, ACCESSOR_GETTER);
- __ Set(eax, 0);
- __ Call(masm->isolate()->builtins()->CallFunction(
- ConvertReceiverMode::kNotNullOrUndefined),
- RelocInfo::CODE_TARGET);
- } else {
- // If we generate a global code snippet for deoptimization only, remember
- // the place to continue after deoptimization.
- masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
- }
-
+ // If we generate a global code snippet for deoptimization only, remember
+ // the place to continue after deoptimization.
+ masm->isolate()->heap()->SetGetterStubDeoptPCOffset(masm->pc_offset());
// Restore context register.
__ pop(esi);
}
@@ -201,12 +176,6 @@ void PropertyHandlerCompiler::GenerateApiAccessorCall(
__ mov(data, FieldOperand(data, CallHandlerInfo::kDataOffset));
}
- if (api_call_info->fast_handler()->IsCode()) {
- // Just tail call into the code.
- __ Jump(handle(Code::cast(api_call_info->fast_handler())),
- RelocInfo::CODE_TARGET);
- return;
- }
// Put api_function_address in place.
Address function_address = v8::ToCData<Address>(api_call_info->callback());
__ mov(api_function_address, Immediate(function_address));
@@ -293,23 +262,6 @@ void NamedStoreHandlerCompiler::GenerateStoreViaSetter(
}
}
-static void CompileCallLoadPropertyWithInterceptor(
- MacroAssembler* masm, Register receiver, Register holder, Register name,
- Handle<JSObject> holder_obj, Runtime::FunctionId id) {
- DCHECK(NamedLoadHandlerCompiler::kInterceptorArgsLength ==
- Runtime::FunctionForId(id)->nargs);
-
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
- __ push(name);
- __ push(receiver);
- __ push(holder);
-
- __ CallRuntime(id);
-}
-
#undef __
#define __ ACCESS_MASM(masm())
@@ -347,8 +299,7 @@ void PropertyHandlerCompiler::GenerateAccessCheck(
Register PropertyHandlerCompiler::CheckPrototypes(
Register object_reg, Register holder_reg, Register scratch1,
- Register scratch2, Handle<Name> name, Label* miss,
- ReturnHolder return_what) {
+ Register scratch2, Handle<Name> name, Label* miss) {
Handle<Map> receiver_map = map();
// Make sure there's no overlap between holder and object registers.
@@ -413,15 +364,14 @@ Register PropertyHandlerCompiler::CheckPrototypes(
// Log the check depth.
LOG(isolate(), IntEvent("check-maps-depth", depth + 1));
- bool return_holder = return_what == RETURN_HOLDER;
- if (return_holder && depth != 0) {
+ if (depth != 0) {
Handle<WeakCell> weak_cell =
Map::GetOrCreatePrototypeWeakCell(current, isolate());
__ LoadWeakValue(reg, weak_cell, miss);
}
// Return the register containing the holder.
- return return_holder ? reg : no_reg;
+ return reg;
}
@@ -451,102 +401,6 @@ void NamedStoreHandlerCompiler::FrontendFooter(Handle<Name> name, Label* miss) {
}
}
-void NamedLoadHandlerCompiler::GenerateLoadInterceptorWithFollowup(
- LookupIterator* it, Register holder_reg) {
- DCHECK(holder()->HasNamedInterceptor());
- DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
-
- // Compile the interceptor call, followed by inline code to load the
- // property from further up the prototype chain if the call fails.
- // Check that the maps haven't changed.
- DCHECK(holder_reg.is(receiver()) || holder_reg.is(scratch1()));
-
- // Preserve the receiver register explicitly whenever it is different from the
- // holder and it is needed should the interceptor return without any result.
- // The ACCESSOR case needs the receiver to be passed into C++ code, the FIELD
- // case might cause a miss during the prototype check.
- bool must_perform_prototype_check =
- !holder().is_identical_to(it->GetHolder<JSObject>());
- bool must_preserve_receiver_reg =
- !receiver().is(holder_reg) &&
- (it->state() == LookupIterator::ACCESSOR || must_perform_prototype_check);
-
- // Save necessary data before invoking an interceptor.
- // Requires a frame to make GC aware of pushed pointers.
- {
- FrameScope frame_scope(masm(), StackFrame::INTERNAL);
-
- if (must_preserve_receiver_reg) {
- __ push(receiver());
- }
- __ push(holder_reg);
- __ push(this->name());
- InterceptorVectorSlotPush(holder_reg);
- // Invoke an interceptor. Note: map checks from receiver to
- // interceptor's holder has been compiled before (see a caller
- // of this method.)
- CompileCallLoadPropertyWithInterceptor(
- masm(), receiver(), holder_reg, this->name(), holder(),
- Runtime::kLoadPropertyWithInterceptorOnly);
-
- // Check if interceptor provided a value for property. If it's
- // the case, return immediately.
- Label interceptor_failed;
- __ cmp(eax, factory()->no_interceptor_result_sentinel());
- __ j(equal, &interceptor_failed);
- frame_scope.GenerateLeaveFrame();
- __ ret(0);
-
- // Clobber registers when generating debug-code to provoke errors.
- __ bind(&interceptor_failed);
- if (FLAG_debug_code) {
- __ mov(receiver(), Immediate(bit_cast<int32_t>(kZapValue)));
- __ mov(holder_reg, Immediate(bit_cast<int32_t>(kZapValue)));
- __ mov(this->name(), Immediate(bit_cast<int32_t>(kZapValue)));
- }
-
- InterceptorVectorSlotPop(holder_reg);
- __ pop(this->name());
- __ pop(holder_reg);
- if (must_preserve_receiver_reg) {
- __ pop(receiver());
- }
-
- // Leave the internal frame.
- }
-
- GenerateLoadPostInterceptor(it, holder_reg);
-}
-
-
-void NamedLoadHandlerCompiler::GenerateLoadInterceptor(Register holder_reg) {
- DCHECK(holder()->HasNamedInterceptor());
- DCHECK(!holder()->GetNamedInterceptor()->getter()->IsUndefined(isolate()));
- // Call the runtime system to load the interceptor.
-
- // Stack:
- // return address
-
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsNameIndex == 0);
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsThisIndex == 1);
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsHolderIndex == 2);
- STATIC_ASSERT(NamedLoadHandlerCompiler::kInterceptorArgsLength == 3);
- __ push(receiver());
- __ push(holder_reg);
- // See NamedLoadHandlerCompiler::InterceptorVectorSlotPop() for details.
- if (holder_reg.is(receiver())) {
- __ push(slot());
- __ push(vector());
- } else {
- __ push(scratch3()); // slot
- __ push(scratch2()); // vector
- }
- __ push(Operand(esp, 4 * kPointerSize)); // return address
- __ mov(Operand(esp, 5 * kPointerSize), name());
-
- __ TailCallRuntime(Runtime::kLoadPropertyWithInterceptor);
-}
-
void NamedStoreHandlerCompiler::ZapStackArgumentsRegisterAliases() {
// Zap register aliases of the arguments passed on the stack to ensure they
// are properly loaded by the handler (debug-only).
@@ -595,43 +449,6 @@ Register NamedStoreHandlerCompiler::value() {
}
-Handle<Code> NamedLoadHandlerCompiler::CompileLoadGlobal(
- Handle<PropertyCell> cell, Handle<Name> name, bool is_configurable) {
- Label miss;
- if (IC::ShouldPushPopSlotAndVector(kind())) {
- PushVectorAndSlot();
- }
- FrontendHeader(receiver(), name, &miss, DONT_RETURN_ANYTHING);
- // Get the value from the cell.
- Register result = StoreDescriptor::ValueRegister();
- Handle<WeakCell> weak_cell = factory()->NewWeakCell(cell);
- __ LoadWeakValue(result, weak_cell, &miss);
- __ mov(result, FieldOperand(result, PropertyCell::kValueOffset));
-
- // Check for deleted property if property can actually be deleted.
- if (is_configurable) {
- __ cmp(result, factory()->the_hole_value());
- __ j(equal, &miss);
- } else if (FLAG_debug_code) {
- __ cmp(result, factory()->the_hole_value());
- __ Check(not_equal, kDontDeleteCellsCannotContainTheHole);
- }
-
- Counters* counters = isolate()->counters();
- __ IncrementCounter(counters->ic_named_load_global_stub(), 1);
- // The code above already loads the result into the return register.
- if (IC::ShouldPushPopSlotAndVector(kind())) {
- DiscardVectorAndSlot();
- }
- __ ret(0);
-
- FrontendFooter(name, &miss);
-
- // Return the generated code.
- return GetCode(kind(), name);
-}
-
-
#undef __
} // namespace internal
} // namespace v8