Commit c97535f5 authored by ishell's avatar ishell Committed by Commit bot

[ic] Support non-code handlers in megamorphic stub cache.

BUG=

Review-Url: https://codereview.chromium.org/2412043003
Cr-Commit-Position: refs/heads/master@{#40255}
parent 77bda187
...@@ -85,29 +85,6 @@ inline int FieldIndex::GetLoadByFieldIndex() const { ...@@ -85,29 +85,6 @@ inline int FieldIndex::GetLoadByFieldIndex() const {
return is_double() ? (result | 1) : result; return is_double() ? (result | 1) : result;
} }
// Takes an offset as computed by GetLoadByFieldOffset and reconstructs a
// FieldIndex object from it.
// static
inline FieldIndex FieldIndex::ForLoadByFieldOffset(Map* map, int offset) {
DCHECK(LoadHandlerTypeBit::decode(offset) == kLoadICHandlerForProperties);
bool is_inobject = FieldOffsetIsInobject::decode(offset);
bool is_double = FieldOffsetIsDouble::decode(offset);
int field_index = FieldOffsetOffset::decode(offset) >> kPointerSizeLog2;
int first_inobject_offset = 0;
if (is_inobject) {
first_inobject_offset =
map->IsJSObjectMap() ? map->GetInObjectPropertyOffset(0) : 0;
} else {
first_inobject_offset = FixedArray::kHeaderSize;
}
int inobject_properties =
map->IsJSObjectMap() ? map->GetInObjectProperties() : 0;
FieldIndex result(is_inobject, field_index, is_double, inobject_properties,
first_inobject_offset);
DCHECK(result.GetLoadByFieldOffset() == offset);
return result;
}
// Returns the offset format consumed by TurboFan stubs: // Returns the offset format consumed by TurboFan stubs:
// (offset << 3) | (is_double << 2) | (is_inobject << 1) | is_property // (offset << 3) | (is_double << 2) | (is_inobject << 1) | is_property
// Where |offset| is relative to object start or FixedArray start, respectively. // Where |offset| is relative to object start or FixedArray start, respectively.
......
...@@ -27,7 +27,6 @@ class FieldIndex final { ...@@ -27,7 +27,6 @@ class FieldIndex final {
static FieldIndex ForInObjectOffset(int offset, Map* map = NULL); static FieldIndex ForInObjectOffset(int offset, Map* map = NULL);
static FieldIndex ForDescriptor(Map* map, int descriptor_index); static FieldIndex ForDescriptor(Map* map, int descriptor_index);
static FieldIndex ForLoadByFieldIndex(Map* map, int index); static FieldIndex ForLoadByFieldIndex(Map* map, int index);
static FieldIndex ForLoadByFieldOffset(Map* map, int index);
static FieldIndex ForKeyedLookupCacheIndex(Map* map, int index); static FieldIndex ForKeyedLookupCacheIndex(Map* map, int index);
static FieldIndex FromFieldAccessStubKey(int key); static FieldIndex FromFieldAccessStubKey(int key);
......
...@@ -92,6 +92,11 @@ Code* IC::target() const { ...@@ -92,6 +92,11 @@ Code* IC::target() const {
return GetTargetAtAddress(address(), constant_pool()); return GetTargetAtAddress(address(), constant_pool());
} }
bool IC::IsHandler(Object* object) {
return (object->IsSmi() && (object != nullptr)) ||
(object->IsCode() && Code::cast(object)->is_handler());
}
Handle<Map> IC::GetHandlerCacheHolder(Handle<Map> receiver_map, Handle<Map> IC::GetHandlerCacheHolder(Handle<Map> receiver_map,
bool receiver_is_holder, Isolate* isolate, bool receiver_is_holder, Isolate* isolate,
CacheHolderFlag* flag) { CacheHolderFlag* flag) {
......
...@@ -691,11 +691,8 @@ static bool AddOneReceiverMapIfMissing(MapHandleList* receiver_maps, ...@@ -691,11 +691,8 @@ static bool AddOneReceiverMapIfMissing(MapHandleList* receiver_maps,
return true; return true;
} }
bool IC::UpdatePolymorphicIC(Handle<Name> name, Handle<Object> code) { bool IC::UpdatePolymorphicIC(Handle<Name> name, Handle<Object> handler) {
DCHECK(code->IsSmi() || code->IsCode()); DCHECK(IsHandler(*handler));
if (!code->IsSmi() && !Code::cast(*code)->is_handler()) {
return false;
}
if (is_keyed() && state() != RECOMPUTE_HANDLER) return false; if (is_keyed() && state() != RECOMPUTE_HANDLER) return false;
Handle<Map> map = receiver_map(); Handle<Map> map = receiver_map();
MapHandleList maps; MapHandleList maps;
...@@ -735,16 +732,16 @@ bool IC::UpdatePolymorphicIC(Handle<Name> name, Handle<Object> code) { ...@@ -735,16 +732,16 @@ bool IC::UpdatePolymorphicIC(Handle<Name> name, Handle<Object> code) {
number_of_valid_maps++; number_of_valid_maps++;
if (number_of_valid_maps > 1 && is_keyed()) return false; if (number_of_valid_maps > 1 && is_keyed()) return false;
if (number_of_valid_maps == 1) { if (number_of_valid_maps == 1) {
ConfigureVectorState(name, receiver_map(), code); ConfigureVectorState(name, receiver_map(), handler);
} else { } else {
if (handler_to_overwrite >= 0) { if (handler_to_overwrite >= 0) {
handlers.Set(handler_to_overwrite, code); handlers.Set(handler_to_overwrite, handler);
if (!map.is_identical_to(maps.at(handler_to_overwrite))) { if (!map.is_identical_to(maps.at(handler_to_overwrite))) {
maps.Set(handler_to_overwrite, map); maps.Set(handler_to_overwrite, map);
} }
} else { } else {
maps.Add(map); maps.Add(map);
handlers.Add(code); handlers.Add(handler);
} }
ConfigureVectorState(name, &maps, &handlers); ConfigureVectorState(name, &maps, &handlers);
...@@ -754,8 +751,7 @@ bool IC::UpdatePolymorphicIC(Handle<Name> name, Handle<Object> code) { ...@@ -754,8 +751,7 @@ bool IC::UpdatePolymorphicIC(Handle<Name> name, Handle<Object> code) {
} }
void IC::UpdateMonomorphicIC(Handle<Object> handler, Handle<Name> name) { void IC::UpdateMonomorphicIC(Handle<Object> handler, Handle<Name> name) {
DCHECK(handler->IsSmi() || DCHECK(IsHandler(*handler));
(handler->IsCode() && Handle<Code>::cast(handler)->is_handler()));
ConfigureVectorState(name, receiver_map(), handler); ConfigureVectorState(name, receiver_map(), handler);
} }
...@@ -786,24 +782,26 @@ bool IC::IsTransitionOfMonomorphicTarget(Map* source_map, Map* target_map) { ...@@ -786,24 +782,26 @@ bool IC::IsTransitionOfMonomorphicTarget(Map* source_map, Map* target_map) {
return transitioned_map == target_map; return transitioned_map == target_map;
} }
void IC::PatchCache(Handle<Name> name, Handle<Object> code) { void IC::PatchCache(Handle<Name> name, Handle<Object> handler) {
DCHECK(code->IsCode() || (code->IsSmi() && (kind() == Code::LOAD_IC || DCHECK(IsHandler(*handler));
kind() == Code::KEYED_LOAD_IC))); // Currently only LoadIC and KeyedLoadIC support non-code handlers.
DCHECK_IMPLIES(!handler->IsCode(),
kind() == Code::LOAD_IC || kind() == Code::KEYED_LOAD_IC);
switch (state()) { switch (state()) {
case UNINITIALIZED: case UNINITIALIZED:
case PREMONOMORPHIC: case PREMONOMORPHIC:
UpdateMonomorphicIC(code, name); UpdateMonomorphicIC(handler, name);
break; break;
case RECOMPUTE_HANDLER: case RECOMPUTE_HANDLER:
case MONOMORPHIC: case MONOMORPHIC:
if (kind() == Code::LOAD_GLOBAL_IC) { if (kind() == Code::LOAD_GLOBAL_IC) {
UpdateMonomorphicIC(code, name); UpdateMonomorphicIC(handler, name);
break; break;
} }
// Fall through. // Fall through.
case POLYMORPHIC: case POLYMORPHIC:
if (!is_keyed() || state() == RECOMPUTE_HANDLER) { if (!is_keyed() || state() == RECOMPUTE_HANDLER) {
if (UpdatePolymorphicIC(name, code)) break; if (UpdatePolymorphicIC(name, handler)) break;
// For keyed stubs, we can't know whether old handlers were for the // For keyed stubs, we can't know whether old handlers were for the
// same key. // same key.
CopyICToMegamorphicCache(name); CopyICToMegamorphicCache(name);
...@@ -812,7 +810,7 @@ void IC::PatchCache(Handle<Name> name, Handle<Object> code) { ...@@ -812,7 +810,7 @@ void IC::PatchCache(Handle<Name> name, Handle<Object> code) {
ConfigureVectorState(MEGAMORPHIC, name); ConfigureVectorState(MEGAMORPHIC, name);
// Fall through. // Fall through.
case MEGAMORPHIC: case MEGAMORPHIC:
UpdateMegamorphicCache(*receiver_map(), *name, *code); UpdateMegamorphicCache(*receiver_map(), *name, *handler);
// Indicate that we've handled this case. // Indicate that we've handled this case.
DCHECK(UseVector()); DCHECK(UseVector());
vector_set_ = true; vector_set_ = true;
...@@ -964,30 +962,17 @@ StubCache* IC::stub_cache() { ...@@ -964,30 +962,17 @@ StubCache* IC::stub_cache() {
return nullptr; return nullptr;
} }
void IC::UpdateMegamorphicCache(Map* map, Name* name, Object* code) { void IC::UpdateMegamorphicCache(Map* map, Name* name, Object* handler) {
if (code->IsSmi()) { stub_cache()->Set(name, map, handler);
// TODO(jkummerow): Support Smis in the code cache.
Handle<Map> map_handle(map, isolate());
Handle<Name> name_handle(name, isolate());
FieldIndex index =
FieldIndex::ForLoadByFieldOffset(map, Smi::cast(code)->value());
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadFieldStub);
LoadFieldStub stub(isolate(), index);
Code* handler = *stub.GetCode();
stub_cache()->Set(*name_handle, *map_handle, handler);
return;
}
DCHECK(code->IsCode());
stub_cache()->Set(name, map, Code::cast(code));
} }
Handle<Object> IC::ComputeHandler(LookupIterator* lookup, Handle<Object> IC::ComputeHandler(LookupIterator* lookup,
Handle<Object> value) { Handle<Object> value) {
// Try to find a globally shared handler stub. // Try to find a globally shared handler stub.
Handle<Object> handler_or_index = GetMapIndependentHandler(lookup); Handle<Object> handler = GetMapIndependentHandler(lookup);
if (!handler_or_index.is_null()) { if (!handler.is_null()) {
DCHECK(handler_or_index->IsCode() || handler_or_index->IsSmi()); DCHECK(IC::IsHandler(*handler));
return handler_or_index; return handler;
} }
// Otherwise check the map's handler cache for a map-specific handler, and // Otherwise check the map's handler cache for a map-specific handler, and
...@@ -1024,8 +1009,9 @@ Handle<Object> IC::ComputeHandler(LookupIterator* lookup, ...@@ -1024,8 +1009,9 @@ Handle<Object> IC::ComputeHandler(LookupIterator* lookup,
// cache (which just missed) is different from the cached handler. // cache (which just missed) is different from the cached handler.
if (state() == MEGAMORPHIC && lookup->GetReceiver()->IsHeapObject()) { if (state() == MEGAMORPHIC && lookup->GetReceiver()->IsHeapObject()) {
Map* map = Handle<HeapObject>::cast(lookup->GetReceiver())->map(); Map* map = Handle<HeapObject>::cast(lookup->GetReceiver())->map();
Code* megamorphic_cached_code = stub_cache()->Get(*lookup->name(), map); Object* megamorphic_cached_handler =
if (megamorphic_cached_code != *code) { stub_cache()->Get(*lookup->name(), map);
if (megamorphic_cached_handler != *code) {
TRACE_HANDLER_STATS(isolate(), IC_HandlerCacheHit); TRACE_HANDLER_STATS(isolate(), IC_HandlerCacheHit);
return code; return code;
} }
......
...@@ -81,6 +81,8 @@ class IC { ...@@ -81,6 +81,8 @@ class IC {
static InlineCacheState StateFromCode(Code* code); static InlineCacheState StateFromCode(Code* code);
static inline bool IsHandler(Object* object);
protected: protected:
Address fp() const { return fp_; } Address fp() const { return fp_; }
Address pc() const { return *pc_address_; } Address pc() const { return *pc_address_; }
......
...@@ -6,13 +6,18 @@ ...@@ -6,13 +6,18 @@
#include "src/ast/ast.h" #include "src/ast/ast.h"
#include "src/base/bits.h" #include "src/base/bits.h"
#include "src/ic/ic-inl.h"
#include "src/type-info.h" #include "src/type-info.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
StubCache::StubCache(Isolate* isolate, Code::Kind ic_kind) StubCache::StubCache(Isolate* isolate, Code::Kind ic_kind)
: isolate_(isolate), ic_kind_(ic_kind) {} : isolate_(isolate), ic_kind_(ic_kind) {
// Ensure the nullptr (aka Smi::kZero) which StubCache::Get() returns
// when the entry is not found is not considered as a handler.
DCHECK(!IC::IsHandler(nullptr));
}
void StubCache::Initialize() { void StubCache::Initialize() {
DCHECK(base::bits::IsPowerOfTwo32(kPrimaryTableSize)); DCHECK(base::bits::IsPowerOfTwo32(kPrimaryTableSize));
...@@ -24,18 +29,22 @@ void StubCache::Initialize() { ...@@ -24,18 +29,22 @@ void StubCache::Initialize() {
namespace { namespace {
bool CommonStubCacheChecks(StubCache* stub_cache, Name* name, Map* map, bool CommonStubCacheChecks(StubCache* stub_cache, Name* name, Map* map,
Code* code) { Object* handler) {
// Validate that the name does not move on scavenge, and that we // Validate that the name does not move on scavenge, and that we
// can use identity checks instead of structural equality checks. // can use identity checks instead of structural equality checks.
DCHECK(!name->GetHeap()->InNewSpace(name)); DCHECK(!name->GetHeap()->InNewSpace(name));
DCHECK(name->IsUniqueName()); DCHECK(name->IsUniqueName());
DCHECK(name->HasHashCode()); DCHECK(name->HasHashCode());
if (code) { if (handler) {
Code::Flags expected_flags = Code::RemoveHolderFromFlags( DCHECK(IC::IsHandler(handler));
Code::ComputeHandlerFlags(stub_cache->ic_kind())); if (handler->IsCode()) {
Code::Flags flags = Code::RemoveHolderFromFlags(code->flags()); Code* code = Code::cast(handler);
DCHECK_EQ(expected_flags, flags); Code::Flags expected_flags = Code::RemoveHolderFromFlags(
DCHECK_EQ(Code::HANDLER, Code::ExtractKindFromFlags(code->flags())); Code::ComputeHandlerFlags(stub_cache->ic_kind()));
Code::Flags flags = Code::RemoveHolderFromFlags(code->flags());
DCHECK_EQ(expected_flags, flags);
DCHECK_EQ(Code::HANDLER, Code::ExtractKindFromFlags(code->flags()));
}
} }
return true; return true;
} }
...@@ -43,17 +52,17 @@ bool CommonStubCacheChecks(StubCache* stub_cache, Name* name, Map* map, ...@@ -43,17 +52,17 @@ bool CommonStubCacheChecks(StubCache* stub_cache, Name* name, Map* map,
} // namespace } // namespace
#endif #endif
Code* StubCache::Set(Name* name, Map* map, Code* code) { Object* StubCache::Set(Name* name, Map* map, Object* handler) {
DCHECK(CommonStubCacheChecks(this, name, map, code)); DCHECK(CommonStubCacheChecks(this, name, map, handler));
// Compute the primary entry. // Compute the primary entry.
int primary_offset = PrimaryOffset(name, map); int primary_offset = PrimaryOffset(name, map);
Entry* primary = entry(primary_, primary_offset); Entry* primary = entry(primary_, primary_offset);
Code* old_code = primary->value; Object* old_handler = primary->value;
// If the primary entry has useful data in it, we retire it to the // If the primary entry has useful data in it, we retire it to the
// secondary cache before overwriting it. // secondary cache before overwriting it.
if (old_code != isolate_->builtins()->builtin(Builtins::kIllegal)) { if (old_handler != isolate_->builtins()->builtin(Builtins::kIllegal)) {
Map* old_map = primary->map; Map* old_map = primary->map;
int seed = PrimaryOffset(primary->key, old_map); int seed = PrimaryOffset(primary->key, old_map);
int secondary_offset = SecondaryOffset(primary->key, seed); int secondary_offset = SecondaryOffset(primary->key, seed);
...@@ -63,13 +72,13 @@ Code* StubCache::Set(Name* name, Map* map, Code* code) { ...@@ -63,13 +72,13 @@ Code* StubCache::Set(Name* name, Map* map, Code* code) {
// Update primary cache. // Update primary cache.
primary->key = name; primary->key = name;
primary->value = code; primary->value = handler;
primary->map = map; primary->map = map;
isolate()->counters()->megamorphic_stub_cache_updates()->Increment(); isolate()->counters()->megamorphic_stub_cache_updates()->Increment();
return code; return handler;
} }
Code* StubCache::Get(Name* name, Map* map) { Object* StubCache::Get(Name* name, Map* map) {
DCHECK(CommonStubCacheChecks(this, name, map, nullptr)); DCHECK(CommonStubCacheChecks(this, name, map, nullptr));
int primary_offset = PrimaryOffset(name, map); int primary_offset = PrimaryOffset(name, map);
Entry* primary = entry(primary_, primary_offset); Entry* primary = entry(primary_, primary_offset);
...@@ -81,7 +90,7 @@ Code* StubCache::Get(Name* name, Map* map) { ...@@ -81,7 +90,7 @@ Code* StubCache::Get(Name* name, Map* map) {
if (secondary->key == name && secondary->map == map) { if (secondary->key == name && secondary->map == map) {
return secondary->value; return secondary->value;
} }
return NULL; return nullptr;
} }
......
...@@ -35,14 +35,14 @@ class StubCache { ...@@ -35,14 +35,14 @@ class StubCache {
public: public:
struct Entry { struct Entry {
Name* key; Name* key;
Code* value; Object* value;
Map* map; Map* map;
}; };
void Initialize(); void Initialize();
// Access cache for entry hash(name, map). // Access cache for entry hash(name, map).
Code* Set(Name* name, Map* map, Code* code); Object* Set(Name* name, Map* map, Object* handler);
Code* Get(Name* name, Map* map); Object* Get(Name* name, Map* map);
// Clear the lookup table (@ mark compact collection). // Clear the lookup table (@ mark compact collection).
void Clear(); void Clear();
// Collect all maps that match the name. // Collect all maps that match the name.
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
#include "src/type-feedback-vector.h" #include "src/type-feedback-vector.h"
#include "src/code-stubs.h" #include "src/code-stubs.h"
#include "src/ic/ic.h" #include "src/ic/ic-inl.h"
#include "src/ic/ic-state.h" #include "src/ic/ic-state.h"
#include "src/objects.h" #include "src/objects.h"
#include "src/type-feedback-vector-inl.h" #include "src/type-feedback-vector-inl.h"
...@@ -851,17 +851,10 @@ int GetStepSize(FixedArray* array, Isolate* isolate) { ...@@ -851,17 +851,10 @@ int GetStepSize(FixedArray* array, Isolate* isolate) {
DCHECK(array->length() >= 2); DCHECK(array->length() >= 2);
Object* second = array->get(1); Object* second = array->get(1);
if (second->IsWeakCell() || second->IsUndefined(isolate)) return 3; if (second->IsWeakCell() || second->IsUndefined(isolate)) return 3;
DCHECK(second->IsCode() || second->IsSmi()); DCHECK(IC::IsHandler(second));
return 2; return 2;
} }
#ifdef DEBUG // Only used by DCHECKs below.
bool IsHandler(Object* object) {
return object->IsSmi() ||
(object->IsCode() && Code::cast(object)->is_handler());
}
#endif
} // namespace } // namespace
int FeedbackNexus::ExtractMaps(MapHandleList* maps) const { int FeedbackNexus::ExtractMaps(MapHandleList* maps) const {
...@@ -914,7 +907,7 @@ MaybeHandle<Object> FeedbackNexus::FindHandlerForMap(Handle<Map> map) const { ...@@ -914,7 +907,7 @@ MaybeHandle<Object> FeedbackNexus::FindHandlerForMap(Handle<Map> map) const {
Map* array_map = Map::cast(cell->value()); Map* array_map = Map::cast(cell->value());
if (array_map == *map) { if (array_map == *map) {
Object* code = array->get(i + increment - 1); Object* code = array->get(i + increment - 1);
DCHECK(IsHandler(code)); DCHECK(IC::IsHandler(code));
return handle(code, isolate); return handle(code, isolate);
} }
} }
...@@ -925,7 +918,7 @@ MaybeHandle<Object> FeedbackNexus::FindHandlerForMap(Handle<Map> map) const { ...@@ -925,7 +918,7 @@ MaybeHandle<Object> FeedbackNexus::FindHandlerForMap(Handle<Map> map) const {
Map* cell_map = Map::cast(cell->value()); Map* cell_map = Map::cast(cell->value());
if (cell_map == *map) { if (cell_map == *map) {
Object* code = GetFeedbackExtra(); Object* code = GetFeedbackExtra();
DCHECK(IsHandler(code)); DCHECK(IC::IsHandler(code));
return handle(code, isolate); return handle(code, isolate);
} }
} }
...@@ -952,7 +945,7 @@ bool FeedbackNexus::FindHandlers(List<Handle<Object>>* code_list, ...@@ -952,7 +945,7 @@ bool FeedbackNexus::FindHandlers(List<Handle<Object>>* code_list,
// Be sure to skip handlers whose maps have been cleared. // Be sure to skip handlers whose maps have been cleared.
if (!cell->cleared()) { if (!cell->cleared()) {
Object* code = array->get(i + increment - 1); Object* code = array->get(i + increment - 1);
DCHECK(IsHandler(code)); DCHECK(IC::IsHandler(code));
code_list->Add(handle(code, isolate)); code_list->Add(handle(code, isolate));
count++; count++;
} }
...@@ -961,7 +954,7 @@ bool FeedbackNexus::FindHandlers(List<Handle<Object>>* code_list, ...@@ -961,7 +954,7 @@ bool FeedbackNexus::FindHandlers(List<Handle<Object>>* code_list,
WeakCell* cell = WeakCell::cast(feedback); WeakCell* cell = WeakCell::cast(feedback);
if (!cell->cleared()) { if (!cell->cleared()) {
Object* code = GetFeedbackExtra(); Object* code = GetFeedbackExtra();
DCHECK(IsHandler(code)); DCHECK(IC::IsHandler(code));
code_list->Add(handle(code, isolate)); code_list->Add(handle(code, isolate));
count++; count++;
} }
......
...@@ -1346,14 +1346,14 @@ TEST(TryProbeStubCache) { ...@@ -1346,14 +1346,14 @@ TEST(TryProbeStubCache) {
int index = rand_gen.NextInt(); int index = rand_gen.NextInt();
Handle<Name> name = names[index % names.size()]; Handle<Name> name = names[index % names.size()];
Handle<JSObject> receiver = receivers[index % receivers.size()]; Handle<JSObject> receiver = receivers[index % receivers.size()];
Code* handler = stub_cache.Get(*name, receiver->map()); Object* handler = stub_cache.Get(*name, receiver->map());
if (handler == nullptr) { if (handler == nullptr) {
queried_non_existing = true; queried_non_existing = true;
} else { } else {
queried_existing = true; queried_existing = true;
} }
Handle<Code> expected_handler(handler, isolate); Handle<Object> expected_handler(handler, isolate);
ft.CheckTrue(receiver, name, expected_handler); ft.CheckTrue(receiver, name, expected_handler);
} }
...@@ -1362,14 +1362,14 @@ TEST(TryProbeStubCache) { ...@@ -1362,14 +1362,14 @@ TEST(TryProbeStubCache) {
int index2 = rand_gen.NextInt(); int index2 = rand_gen.NextInt();
Handle<Name> name = names[index1 % names.size()]; Handle<Name> name = names[index1 % names.size()];
Handle<JSObject> receiver = receivers[index2 % receivers.size()]; Handle<JSObject> receiver = receivers[index2 % receivers.size()];
Code* handler = stub_cache.Get(*name, receiver->map()); Object* handler = stub_cache.Get(*name, receiver->map());
if (handler == nullptr) { if (handler == nullptr) {
queried_non_existing = true; queried_non_existing = true;
} else { } else {
queried_existing = true; queried_existing = true;
} }
Handle<Code> expected_handler(handler, isolate); Handle<Object> expected_handler(handler, isolate);
ft.CheckTrue(receiver, name, expected_handler); ft.CheckTrue(receiver, name, expected_handler);
} }
// Ensure we performed both kind of queries. // Ensure we performed both kind of queries.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment