Commit 248a3e25 authored by jkummerow's avatar jkummerow Committed by Commit bot

[refactoring] Pull AccessorAssembler out of CodeStubAssembler

The new AccessorAssembler encapsulates all the functionality that's
specific to building LoadIC/StoreIC stubs.
There are two header files (accessor-assembler.h and
accessor-assembler-impl.h) so that clients of the assembler can include
the one, and subclassing assemblers can include the other.

Review-Url: https://codereview.chromium.org/2507733002
Cr-Commit-Position: refs/heads/master@{#41037}
parent f21a6b25
......@@ -1414,6 +1414,9 @@ v8_source_set("v8_base") {
"src/ic/access-compiler-data.h",
"src/ic/access-compiler.cc",
"src/ic/access-compiler.h",
"src/ic/accessor-assembler-impl.h",
"src/ic/accessor-assembler.cc",
"src/ic/accessor-assembler.h",
"src/ic/call-optimization.cc",
"src/ic/call-optimization.h",
"src/ic/handler-compiler.cc",
......
......@@ -4,6 +4,7 @@
#include "src/builtins/builtins-utils.h"
#include "src/builtins/builtins.h"
#include "src/ic/accessor-assembler.h"
#include "src/ic/handler-compiler.h"
#include "src/ic/ic.h"
#include "src/ic/keyed-store-generic.h"
......@@ -13,18 +14,7 @@ namespace internal {
void Builtins::Generate_KeyedLoadIC_Megamorphic_TF(
compiler::CodeAssemblerState* state) {
typedef compiler::Node Node;
typedef LoadWithVectorDescriptor Descriptor;
CodeStubAssembler assembler(state);
Node* receiver = assembler.Parameter(Descriptor::kReceiver);
Node* name = assembler.Parameter(Descriptor::kName);
Node* slot = assembler.Parameter(Descriptor::kSlot);
Node* vector = assembler.Parameter(Descriptor::kVector);
Node* context = assembler.Parameter(Descriptor::kContext);
CodeStubAssembler::LoadICParameters p(context, receiver, name, slot, vector);
assembler.KeyedLoadICGeneric(&p);
AccessorAssembler::GenerateKeyedLoadICMegamorphic(state);
}
void Builtins::Generate_KeyedLoadIC_Miss(MacroAssembler* masm) {
......
This diff is collapsed.
......@@ -861,33 +861,6 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
compiler::Node* callable,
compiler::Node* object);
// Load/StoreIC helpers.
struct LoadICParameters {
LoadICParameters(compiler::Node* context, compiler::Node* receiver,
compiler::Node* name, compiler::Node* slot,
compiler::Node* vector)
: context(context),
receiver(receiver),
name(name),
slot(slot),
vector(vector) {}
compiler::Node* context;
compiler::Node* receiver;
compiler::Node* name;
compiler::Node* slot;
compiler::Node* vector;
};
struct StoreICParameters : public LoadICParameters {
StoreICParameters(compiler::Node* context, compiler::Node* receiver,
compiler::Node* name, compiler::Node* value,
compiler::Node* slot, compiler::Node* vector)
: LoadICParameters(context, receiver, name, slot, vector),
value(value) {}
compiler::Node* value;
};
// Load type feedback vector from the stub caller's frame.
compiler::Node* LoadTypeFeedbackVectorForStub();
......@@ -898,43 +871,6 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
compiler::Node* LoadReceiverMap(compiler::Node* receiver);
// Checks monomorphic case. Returns {feedback} entry of the vector.
compiler::Node* TryMonomorphicCase(compiler::Node* slot,
compiler::Node* vector,
compiler::Node* receiver_map,
Label* if_handler, Variable* var_handler,
Label* if_miss);
void HandlePolymorphicCase(compiler::Node* receiver_map,
compiler::Node* feedback, Label* if_handler,
Variable* var_handler, Label* if_miss,
int unroll_count);
void HandleKeyedStorePolymorphicCase(compiler::Node* receiver_map,
compiler::Node* feedback,
Label* if_handler, Variable* var_handler,
Label* if_transition_handler,
Variable* var_transition_map_cell,
Label* if_miss);
compiler::Node* StubCachePrimaryOffset(compiler::Node* name,
compiler::Node* map);
compiler::Node* StubCacheSecondaryOffset(compiler::Node* name,
compiler::Node* seed);
// This enum is used here as a replacement for StubCache::Table to avoid
// including stub cache header.
enum StubCacheTable : int;
void TryProbeStubCacheTable(StubCache* stub_cache, StubCacheTable table_id,
compiler::Node* entry_offset,
compiler::Node* name, compiler::Node* map,
Label* if_handler, Variable* var_handler,
Label* if_miss);
void TryProbeStubCache(StubCache* stub_cache, compiler::Node* receiver,
compiler::Node* name, Label* if_handler,
Variable* var_handler, Label* if_miss);
// Extends properties backing store by JSObject::kFieldsAdded elements.
void ExtendPropertiesBackingStore(compiler::Node* object);
......@@ -991,14 +927,6 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
ElementsKind kind, compiler::Node* length,
ParameterMode mode, Label* bailout);
void LoadIC(const LoadICParameters* p);
void LoadICProtoArray(const LoadICParameters* p, compiler::Node* handler);
void LoadGlobalIC(const LoadICParameters* p);
void KeyedLoadIC(const LoadICParameters* p);
void KeyedLoadICGeneric(const LoadICParameters* p);
void StoreIC(const StoreICParameters* p);
void KeyedStoreIC(const StoreICParameters* p, LanguageMode language_mode);
void TransitionElementsKind(compiler::Node* object, compiler::Node* map,
ElementsKind from_kind, ElementsKind to_kind,
bool is_jsarray, Label* bailout);
......@@ -1124,84 +1052,26 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
int base_size = 0);
protected:
void HandleStoreICHandlerCase(const StoreICParameters* p,
compiler::Node* handler, Label* miss);
private:
friend class CodeStubArguments;
enum ElementSupport { kOnlyProperties, kSupportElements };
void DescriptorLookupLinear(compiler::Node* unique_name,
compiler::Node* descriptors, compiler::Node* nof,
Label* if_found, Variable* var_name_index,
Label* if_not_found);
compiler::Node* CallGetterIfAccessor(compiler::Node* value,
compiler::Node* details,
compiler::Node* context,
compiler::Node* receiver,
Label* if_bailout);
void HandleLoadICHandlerCase(
const LoadICParameters* p, compiler::Node* handler, Label* miss,
ElementSupport support_elements = kOnlyProperties);
void HandleLoadICSmiHandlerCase(const LoadICParameters* p,
compiler::Node* holder,
compiler::Node* smi_handler, Label* miss,
ElementSupport support_elements);
void HandleLoadICProtoHandler(const LoadICParameters* p,
compiler::Node* handler, Variable* var_holder,
Variable* var_smi_handler,
Label* if_smi_handler, Label* miss);
compiler::Node* EmitLoadICProtoArrayCheck(const LoadICParameters* p,
compiler::Node* handler,
compiler::Node* handler_length,
compiler::Node* handler_flags,
Label* miss);
void CheckPrototype(compiler::Node* prototype_cell, compiler::Node* name,
Label* miss);
void NameDictionaryNegativeLookup(compiler::Node* object,
compiler::Node* name, Label* miss);
// If |transition| is nullptr then the normal field store is generated or
// transitioning store otherwise.
void HandleStoreFieldAndReturn(compiler::Node* handler_word,
compiler::Node* holder,
Representation representation,
compiler::Node* value,
compiler::Node* transition, Label* miss);
// If |transition| is nullptr then the normal field store is generated or
// transitioning store otherwise.
void HandleStoreICSmiHandlerCase(compiler::Node* handler_word,
compiler::Node* holder,
compiler::Node* value,
compiler::Node* transition, Label* miss);
void HandleStoreICProtoHandler(const StoreICParameters* p,
compiler::Node* handler, Label* miss);
compiler::Node* TryToIntptr(compiler::Node* key, Label* miss);
void EmitFastElementsBoundsCheck(compiler::Node* object,
compiler::Node* elements,
compiler::Node* intptr_index,
compiler::Node* is_jsarray_condition,
Label* miss);
void EmitElementLoad(compiler::Node* object, compiler::Node* elements,
compiler::Node* elements_kind, compiler::Node* key,
compiler::Node* is_jsarray_condition, Label* if_hole,
Label* rebox_double, Variable* var_double_value,
Label* unimplemented_elements_kind, Label* out_of_bounds,
Label* miss);
void BranchIfPrototypesHaveNoElements(compiler::Node* receiver_map,
Label* definitely_no_elements,
Label* possibly_elements);
private:
friend class CodeStubArguments;
compiler::Node* AllocateRawAligned(compiler::Node* size_in_bytes,
AllocationFlags flags,
compiler::Node* top_address,
......
......@@ -12,6 +12,7 @@
#include "src/code-stub-assembler.h"
#include "src/factory.h"
#include "src/gdb-jit.h"
#include "src/ic/accessor-assembler.h"
#include "src/ic/handler-compiler.h"
#include "src/ic/ic.h"
#include "src/macro-assembler.h"
......@@ -19,6 +20,7 @@
namespace v8 {
namespace internal {
using compiler::CodeAssemblerState;
RUNTIME_FUNCTION(UnexpectedStubMiss) {
FATAL("Unexpected deopt of a stub");
......@@ -430,174 +432,33 @@ Handle<Code> TurboFanCodeStub::GenerateCode() {
return compiler::CodeAssembler::GenerateCode(&state);
}
void LoadICTrampolineStub::GenerateAssembly(
compiler::CodeAssemblerState* state) const {
typedef compiler::Node Node;
CodeStubAssembler assembler(state);
Node* receiver = assembler.Parameter(Descriptor::kReceiver);
Node* name = assembler.Parameter(Descriptor::kName);
Node* slot = assembler.Parameter(Descriptor::kSlot);
Node* context = assembler.Parameter(Descriptor::kContext);
Node* vector = assembler.LoadTypeFeedbackVectorForStub();
CodeStubAssembler::LoadICParameters p(context, receiver, name, slot, vector);
assembler.LoadIC(&p);
}
void LoadICStub::GenerateAssembly(compiler::CodeAssemblerState* state) const {
typedef compiler::Node Node;
CodeStubAssembler assembler(state);
Node* receiver = assembler.Parameter(Descriptor::kReceiver);
Node* name = assembler.Parameter(Descriptor::kName);
Node* slot = assembler.Parameter(Descriptor::kSlot);
Node* vector = assembler.Parameter(Descriptor::kVector);
Node* context = assembler.Parameter(Descriptor::kContext);
CodeStubAssembler::LoadICParameters p(context, receiver, name, slot, vector);
assembler.LoadIC(&p);
}
void LoadICProtoArrayStub::GenerateAssembly(
compiler::CodeAssemblerState* state) const {
typedef compiler::Node Node;
CodeStubAssembler assembler(state);
Node* receiver = assembler.Parameter(Descriptor::kReceiver);
Node* name = assembler.Parameter(Descriptor::kName);
Node* slot = assembler.Parameter(Descriptor::kSlot);
Node* vector = assembler.Parameter(Descriptor::kVector);
Node* handler = assembler.Parameter(Descriptor::kHandler);
Node* context = assembler.Parameter(Descriptor::kContext);
CodeStubAssembler::LoadICParameters p(context, receiver, name, slot, vector);
assembler.LoadICProtoArray(&p, handler);
}
void LoadGlobalICTrampolineStub::GenerateAssembly(
compiler::CodeAssemblerState* state) const {
typedef compiler::Node Node;
CodeStubAssembler assembler(state);
Node* slot = assembler.Parameter(Descriptor::kSlot);
Node* context = assembler.Parameter(Descriptor::kContext);
Node* vector = assembler.LoadTypeFeedbackVectorForStub();
CodeStubAssembler::LoadICParameters p(context, nullptr, nullptr, slot,
vector);
assembler.LoadGlobalIC(&p);
}
void LoadGlobalICStub::GenerateAssembly(
compiler::CodeAssemblerState* state) const {
typedef compiler::Node Node;
CodeStubAssembler assembler(state);
Node* slot = assembler.Parameter(Descriptor::kSlot);
Node* vector = assembler.Parameter(Descriptor::kVector);
Node* context = assembler.Parameter(Descriptor::kContext);
CodeStubAssembler::LoadICParameters p(context, nullptr, nullptr, slot,
vector);
assembler.LoadGlobalIC(&p);
}
void KeyedLoadICTrampolineTFStub::GenerateAssembly(
compiler::CodeAssemblerState* state) const {
typedef compiler::Node Node;
CodeStubAssembler assembler(state);
Node* receiver = assembler.Parameter(Descriptor::kReceiver);
Node* name = assembler.Parameter(Descriptor::kName);
Node* slot = assembler.Parameter(Descriptor::kSlot);
Node* context = assembler.Parameter(Descriptor::kContext);
Node* vector = assembler.LoadTypeFeedbackVectorForStub();
CodeStubAssembler::LoadICParameters p(context, receiver, name, slot, vector);
assembler.KeyedLoadIC(&p);
}
void KeyedLoadICTFStub::GenerateAssembly(
compiler::CodeAssemblerState* state) const {
typedef compiler::Node Node;
CodeStubAssembler assembler(state);
Node* receiver = assembler.Parameter(Descriptor::kReceiver);
Node* name = assembler.Parameter(Descriptor::kName);
Node* slot = assembler.Parameter(Descriptor::kSlot);
Node* vector = assembler.Parameter(Descriptor::kVector);
Node* context = assembler.Parameter(Descriptor::kContext);
CodeStubAssembler::LoadICParameters p(context, receiver, name, slot, vector);
assembler.KeyedLoadIC(&p);
}
void StoreICTrampolineStub::GenerateAssembly(
compiler::CodeAssemblerState* state) const {
typedef compiler::Node Node;
CodeStubAssembler assembler(state);
Node* receiver = assembler.Parameter(Descriptor::kReceiver);
Node* name = assembler.Parameter(Descriptor::kName);
Node* value = assembler.Parameter(Descriptor::kValue);
Node* slot = assembler.Parameter(Descriptor::kSlot);
Node* context = assembler.Parameter(Descriptor::kContext);
Node* vector = assembler.LoadTypeFeedbackVectorForStub();
CodeStubAssembler::StoreICParameters p(context, receiver, name, value, slot,
vector);
assembler.StoreIC(&p);
}
void StoreICStub::GenerateAssembly(compiler::CodeAssemblerState* state) const {
typedef compiler::Node Node;
CodeStubAssembler assembler(state);
#define ACCESSOR_ASSEMBLER(Name) \
void Name##Stub::GenerateAssembly(CodeAssemblerState* state) const { \
AccessorAssembler::Generate##Name(state); \
}
Node* receiver = assembler.Parameter(Descriptor::kReceiver);
Node* name = assembler.Parameter(Descriptor::kName);
Node* value = assembler.Parameter(Descriptor::kValue);
Node* slot = assembler.Parameter(Descriptor::kSlot);
Node* vector = assembler.Parameter(Descriptor::kVector);
Node* context = assembler.Parameter(Descriptor::kContext);
ACCESSOR_ASSEMBLER(LoadIC)
ACCESSOR_ASSEMBLER(LoadICTrampoline)
ACCESSOR_ASSEMBLER(LoadICProtoArray)
ACCESSOR_ASSEMBLER(LoadGlobalIC)
ACCESSOR_ASSEMBLER(LoadGlobalICTrampoline)
ACCESSOR_ASSEMBLER(KeyedLoadICTF)
ACCESSOR_ASSEMBLER(KeyedLoadICTrampolineTF)
ACCESSOR_ASSEMBLER(StoreIC)
ACCESSOR_ASSEMBLER(StoreICTrampoline)
CodeStubAssembler::StoreICParameters p(context, receiver, name, value, slot,
vector);
assembler.StoreIC(&p);
}
#undef ACCESSOR_ASSEMBLER
void KeyedStoreICTrampolineTFStub::GenerateAssembly(
compiler::CodeAssemblerState* state) const {
typedef compiler::Node Node;
CodeStubAssembler assembler(state);
Node* receiver = assembler.Parameter(Descriptor::kReceiver);
Node* name = assembler.Parameter(Descriptor::kName);
Node* value = assembler.Parameter(Descriptor::kValue);
Node* slot = assembler.Parameter(Descriptor::kSlot);
Node* context = assembler.Parameter(Descriptor::kContext);
Node* vector = assembler.LoadTypeFeedbackVectorForStub();
CodeStubAssembler::StoreICParameters p(context, receiver, name, value, slot,
vector);
assembler.KeyedStoreIC(&p, StoreICState::GetLanguageMode(GetExtraICState()));
CodeAssemblerState* state) const {
LanguageMode language_mode = StoreICState::GetLanguageMode(GetExtraICState());
AccessorAssembler::GenerateKeyedStoreICTrampolineTF(state, language_mode);
}
void KeyedStoreICTFStub::GenerateAssembly(
compiler::CodeAssemblerState* state) const {
typedef compiler::Node Node;
CodeStubAssembler assembler(state);
Node* receiver = assembler.Parameter(Descriptor::kReceiver);
Node* name = assembler.Parameter(Descriptor::kName);
Node* value = assembler.Parameter(Descriptor::kValue);
Node* slot = assembler.Parameter(Descriptor::kSlot);
Node* vector = assembler.Parameter(Descriptor::kVector);
Node* context = assembler.Parameter(Descriptor::kContext);
CodeStubAssembler::StoreICParameters p(context, receiver, name, value, slot,
vector);
assembler.KeyedStoreIC(&p, StoreICState::GetLanguageMode(GetExtraICState()));
LanguageMode language_mode = StoreICState::GetLanguageMode(GetExtraICState());
AccessorAssembler::GenerateKeyedStoreICTF(state, language_mode);
}
void StoreMapStub::GenerateAssembly(compiler::CodeAssemblerState* state) const {
......
// 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.
#ifndef V8_SRC_IC_ACCESSOR_ASSEMBLER_IMPL_H_
#define V8_SRC_IC_ACCESSOR_ASSEMBLER_IMPL_H_
#include "src/code-stub-assembler.h"
namespace v8 {
namespace internal {
namespace compiler {
class CodeAssemblerState;
}
using compiler::Node;
#define ACCESSOR_ASSEMBLER_PUBLIC_INTERFACE(V) \
V(LoadIC) \
V(LoadICTrampoline) \
V(LoadICProtoArray) \
V(LoadGlobalIC) \
V(LoadGlobalICTrampoline) \
V(KeyedLoadICTF) \
V(KeyedLoadICTrampolineTF) \
V(KeyedLoadICMegamorphic) \
V(StoreIC) \
V(StoreICTrampoline)
// KeyedStoreIC and KeyedStoreICTrampoline need custom handling because of
// their "language_mode" parameter.
class AccessorAssemblerImpl : public CodeStubAssembler {
public:
explicit AccessorAssemblerImpl(compiler::CodeAssemblerState* state)
: CodeStubAssembler(state) {}
#define DECLARE_PUBLIC_METHOD(Name) void Generate##Name();
ACCESSOR_ASSEMBLER_PUBLIC_INTERFACE(DECLARE_PUBLIC_METHOD)
#undef DECLARE_PUBLIC_METHOD
void GenerateKeyedStoreICTF(LanguageMode language_mode);
void GenerateKeyedStoreICTrampolineTF(LanguageMode language_mode);
void TryProbeStubCache(StubCache* stub_cache, Node* receiver, Node* name,
Label* if_handler, Variable* var_handler,
Label* if_miss);
Node* StubCachePrimaryOffsetForTesting(Node* name, Node* map) {
return StubCachePrimaryOffset(name, map);
}
Node* StubCacheSecondaryOffsetForTesting(Node* name, Node* map) {
return StubCacheSecondaryOffset(name, map);
}
protected:
struct LoadICParameters {
LoadICParameters(Node* context, Node* receiver, Node* name, Node* slot,
Node* vector)
: context(context),
receiver(receiver),
name(name),
slot(slot),
vector(vector) {}
Node* context;
Node* receiver;
Node* name;
Node* slot;
Node* vector;
};
struct StoreICParameters : public LoadICParameters {
StoreICParameters(Node* context, Node* receiver, Node* name, Node* value,
Node* slot, Node* vector)
: LoadICParameters(context, receiver, name, slot, vector),
value(value) {}
Node* value;
};
void HandleStoreICHandlerCase(const StoreICParameters* p, Node* handler,
Label* miss);
private:
enum ElementSupport { kOnlyProperties, kSupportElements };
// Stub generation entry points.
void LoadIC(const LoadICParameters* p);
void LoadICProtoArray(const LoadICParameters* p, Node* handler);
void LoadGlobalIC(const LoadICParameters* p);
void KeyedLoadIC(const LoadICParameters* p);
void KeyedLoadICGeneric(const LoadICParameters* p);
void StoreIC(const StoreICParameters* p);
void KeyedStoreIC(const StoreICParameters* p, LanguageMode language_mode);
// IC dispatcher behavior.
// Checks monomorphic case. Returns {feedback} entry of the vector.
Node* TryMonomorphicCase(Node* slot, Node* vector, Node* receiver_map,
Label* if_handler, Variable* var_handler,
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);
// LoadIC implementation.
void HandleLoadICHandlerCase(
const LoadICParameters* p, Node* handler, Label* miss,
ElementSupport support_elements = kOnlyProperties);
void HandleLoadICSmiHandlerCase(const LoadICParameters* p, Node* holder,
Node* smi_handler, Label* miss,
ElementSupport support_elements);
void HandleLoadICProtoHandler(const LoadICParameters* p, Node* handler,
Variable* var_holder, Variable* var_smi_handler,
Label* if_smi_handler, Label* miss);
Node* EmitLoadICProtoArrayCheck(const LoadICParameters* p, Node* handler,
Node* handler_length, Node* handler_flags,
Label* miss);
// StoreIC implementation.
void HandleStoreICProtoHandler(const StoreICParameters* p, Node* handler,
Label* miss);
// If |transition| is nullptr then the normal field store is generated or
// transitioning store otherwise.
void HandleStoreICSmiHandlerCase(Node* handler_word, Node* holder,
Node* value, Node* transition, Label* miss);
// If |transition| is nullptr then the normal field store is generated or
// transitioning store otherwise.
void HandleStoreFieldAndReturn(Node* handler_word, Node* holder,
Representation representation, Node* value,
Node* transition, Label* miss);
// Low-level helpers.
void EmitFastElementsBoundsCheck(Node* object, Node* elements,
Node* intptr_index,
Node* is_jsarray_condition, Label* miss);
void EmitElementLoad(Node* object, Node* elements, Node* elements_kind,
Node* key, Node* is_jsarray_condition, Label* if_hole,
Label* rebox_double, Variable* var_double_value,
Label* unimplemented_elements_kind, Label* out_of_bounds,
Label* miss);
void CheckPrototype(Node* prototype_cell, Node* name, Label* miss);
void NameDictionaryNegativeLookup(Node* object, Node* name, Label* miss);
// Stub cache access helpers.
// This enum is used here as a replacement for StubCache::Table to avoid
// including stub cache header.
enum StubCacheTable : int;
Node* StubCachePrimaryOffset(Node* name, Node* map);
Node* StubCacheSecondaryOffset(Node* name, Node* seed);
void TryProbeStubCacheTable(StubCache* stub_cache, StubCacheTable table_id,
Node* entry_offset, Node* name, Node* map,
Label* if_handler, Variable* var_handler,
Label* if_miss);
};
} // namespace internal
} // namespace v8
#endif // V8_SRC_IC_ACCESSOR_ASSEMBLER_IMPL_H_
This diff is collapsed.
// 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.
#ifndef V8_SRC_IC_ACCESSOR_ASSEMBLER_H_
#define V8_SRC_IC_ACCESSOR_ASSEMBLER_H_
#include "src/globals.h"
namespace v8 {
namespace internal {
namespace compiler {
class CodeAssemblerState;
}
class AccessorAssembler {
public:
static void GenerateLoadIC(compiler::CodeAssemblerState* state);
static void GenerateLoadICTrampoline(compiler::CodeAssemblerState* state);
static void GenerateLoadICProtoArray(compiler::CodeAssemblerState* state);
static void GenerateLoadGlobalIC(compiler::CodeAssemblerState* state);
static void GenerateLoadGlobalICTrampoline(
compiler::CodeAssemblerState* state);
static void GenerateKeyedLoadICTF(compiler::CodeAssemblerState* state);
static void GenerateKeyedLoadICTrampolineTF(
compiler::CodeAssemblerState* state);
static void GenerateKeyedLoadICMegamorphic(
compiler::CodeAssemblerState* state);
static void GenerateStoreIC(compiler::CodeAssemblerState* state);
static void GenerateStoreICTrampoline(compiler::CodeAssemblerState* state);
static void GenerateKeyedStoreICTF(compiler::CodeAssemblerState* state,
LanguageMode language_mode);
static void GenerateKeyedStoreICTrampolineTF(
compiler::CodeAssemblerState* state, LanguageMode language_mode);
};
} // namespace internal
} // namespace v8
#endif // V8_SRC_IC_ACCESSOR_ASSEMBLER_H_
......@@ -6,6 +6,7 @@
#include "src/code-stub-assembler.h"
#include "src/contexts.h"
#include "src/ic/accessor-assembler-impl.h"
#include "src/interface-descriptors.h"
#include "src/isolate.h"
......@@ -14,13 +15,12 @@ namespace internal {
using compiler::Node;
class KeyedStoreGenericAssembler : public CodeStubAssembler {
class KeyedStoreGenericAssembler : public AccessorAssemblerImpl {
public:
explicit KeyedStoreGenericAssembler(compiler::CodeAssemblerState* state)
: CodeStubAssembler(state) {}
: AccessorAssemblerImpl(state) {}
void KeyedStoreGeneric(const StoreICParameters* p,
LanguageMode language_mode);
void KeyedStoreGeneric(LanguageMode language_mode);
private:
enum UpdateLength {
......@@ -67,19 +67,8 @@ class KeyedStoreGenericAssembler : public CodeStubAssembler {
void KeyedStoreGenericGenerator::Generate(compiler::CodeAssemblerState* state,
LanguageMode language_mode) {
typedef StoreWithVectorDescriptor Descriptor;
KeyedStoreGenericAssembler assembler(state);
Node* receiver = assembler.Parameter(Descriptor::kReceiver);
Node* name = assembler.Parameter(Descriptor::kName);
Node* value = assembler.Parameter(Descriptor::kValue);
Node* slot = assembler.Parameter(Descriptor::kSlot);
Node* vector = assembler.Parameter(Descriptor::kVector);
Node* context = assembler.Parameter(Descriptor::kContext);
CodeStubAssembler::StoreICParameters p(context, receiver, name, value, slot,
vector);
assembler.KeyedStoreGeneric(&p, language_mode);
assembler.KeyedStoreGeneric(language_mode);
}
void KeyedStoreGenericAssembler::BranchIfPrototypesHaveNonFastElements(
......@@ -104,9 +93,7 @@ void KeyedStoreGenericAssembler::BranchIfPrototypesHaveNonFastElements(
non_fast_elements);
Node* elements_kind = LoadMapElementsKind(prototype_map);
STATIC_ASSERT(FIRST_ELEMENTS_KIND == FIRST_FAST_ELEMENTS_KIND);
GotoIf(Int32LessThanOrEqual(elements_kind,
Int32Constant(LAST_FAST_ELEMENTS_KIND)),
&loop_body);
GotoIf(IsFastElementsKind(elements_kind), &loop_body);
GotoIf(Word32Equal(elements_kind, Int32Constant(NO_ELEMENTS)), &loop_body);
Goto(non_fast_elements);
}
......@@ -409,14 +396,13 @@ void KeyedStoreGenericAssembler::StoreElementWithCapacity(
void KeyedStoreGenericAssembler::EmitGenericElementStore(
Node* receiver, Node* receiver_map, Node* instance_type, Node* intptr_index,
Node* value, Node* context, Label* slow) {
Label if_in_bounds(this), if_increment_length_by_one(this),
Label if_fast(this), if_in_bounds(this), if_increment_length_by_one(this),
if_bump_length_with_gap(this), if_grow(this), if_nonfast(this),
if_typed_array(this), if_dictionary(this);
Node* elements = LoadElements(receiver);
Node* elements_kind = LoadMapElementsKind(receiver_map);
GotoIf(
Int32GreaterThan(elements_kind, Int32Constant(LAST_FAST_ELEMENTS_KIND)),
&if_nonfast);
Branch(IsFastElementsKind(elements_kind), &if_fast, &if_nonfast);
Bind(&if_fast);
Label if_array(this);
GotoIf(Word32Equal(instance_type, Int32Constant(JS_ARRAY_TYPE)), &if_array);
......@@ -517,12 +503,19 @@ void KeyedStoreGenericAssembler::EmitGenericPropertyStore(
}
}
void KeyedStoreGenericAssembler::KeyedStoreGeneric(const StoreICParameters* p,
LanguageMode language_mode) {
void KeyedStoreGenericAssembler::KeyedStoreGeneric(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);
Variable var_index(this, MachineType::PointerRepresentation());
Label if_index(this), if_unique_name(this), slow(this);
Node* receiver = p->receiver;
GotoIf(TaggedIsSmi(receiver), &slow);
Node* receiver_map = LoadMap(receiver);
Node* instance_type = LoadMapInstanceType(receiver_map);
......@@ -532,26 +525,28 @@ void KeyedStoreGenericAssembler::KeyedStoreGeneric(const StoreICParameters* p,
Int32Constant(LAST_CUSTOM_ELEMENTS_RECEIVER)),
&slow);
TryToName(p->name, &if_index, &var_index, &if_unique_name, &slow);
TryToName(name, &if_index, &var_index, &if_unique_name, &slow);
Bind(&if_index);
{
Comment("integer index");
EmitGenericElementStore(receiver, receiver_map, instance_type,
var_index.value(), p->value, p->context, &slow);
var_index.value(), value, context, &slow);
}
Bind(&if_unique_name);
{
Comment("key is unique name");
EmitGenericPropertyStore(receiver, receiver_map, p, &slow);
KeyedStoreGenericAssembler::StoreICParameters p(context, receiver, name,
value, slot, vector);
EmitGenericPropertyStore(receiver, receiver_map, &p, &slow);
}
Bind(&slow);
{
Comment("KeyedStoreGeneric_slow");
TailCallRuntime(Runtime::kSetProperty, p->context, p->receiver, p->name,
p->value, SmiConstant(language_mode));
TailCallRuntime(Runtime::kSetProperty, context, receiver, name, value,
SmiConstant(language_mode));
}
}
......
......@@ -952,6 +952,9 @@
'ic/access-compiler-data.h',
'ic/access-compiler.cc',
'ic/access-compiler.h',
'ic/accessor-assembler.cc',
'ic/accessor-assembler-impl.h',
'ic/accessor-assembler.h',
'ic/call-optimization.cc',
'ic/call-optimization.h',
'ic/handler-compiler.cc',
......
......@@ -98,6 +98,7 @@ v8_executable("cctest") {
"profiler-extension.cc",
"profiler-extension.h",
"test-access-checks.cc",
"test-accessor-assembler.cc",
"test-accessors.cc",
"test-api-accessors.cc",
"test-api-fast-accessor-builder.cc",
......
......@@ -119,6 +119,7 @@
'profiler-extension.cc',
'profiler-extension.h',
'test-access-checks.cc',
'test-accessor-assembler.cc',
'test-accessors.cc',
'test-api.cc',
'test-api.h',
......
// 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 "test/cctest/cctest.h"
#include "src/base/utils/random-number-generator.h"
#include "src/ic/accessor-assembler-impl.h"
#include "src/ic/stub-cache.h"
#include "test/cctest/compiler/code-assembler-tester.h"
#include "test/cctest/compiler/function-tester.h"
namespace v8 {
namespace internal {
using compiler::CodeAssemblerTester;
using compiler::FunctionTester;
using compiler::Node;
namespace {
void TestStubCacheOffsetCalculation(StubCache::Table table) {
Isolate* isolate(CcTest::InitIsolateOnce());
const int kNumParams = 2;
CodeAssemblerTester data(isolate, kNumParams);
AccessorAssemblerImpl m(data.state());
{
Node* name = m.Parameter(0);
Node* map = m.Parameter(1);
Node* primary_offset = m.StubCachePrimaryOffsetForTesting(name, map);
Node* result;
if (table == StubCache::kPrimary) {
result = primary_offset;
} else {
CHECK_EQ(StubCache::kSecondary, table);
result = m.StubCacheSecondaryOffsetForTesting(name, primary_offset);
}
m.Return(m.SmiFromWord32(result));
}
Handle<Code> code = data.GenerateCode();
FunctionTester ft(code, kNumParams);
Factory* factory = isolate->factory();
Handle<Name> names[] = {
factory->NewSymbol(),
factory->InternalizeUtf8String("a"),
factory->InternalizeUtf8String("bb"),
factory->InternalizeUtf8String("ccc"),
factory->NewPrivateSymbol(),
factory->InternalizeUtf8String("dddd"),
factory->InternalizeUtf8String("eeeee"),
factory->InternalizeUtf8String("name"),
factory->NewSymbol(),
factory->NewPrivateSymbol(),
};
Handle<Map> maps[] = {
Handle<Map>(nullptr, isolate),
factory->cell_map(),
Map::Create(isolate, 0),
factory->meta_map(),
factory->code_map(),
Map::Create(isolate, 0),
factory->hash_table_map(),
factory->symbol_map(),
factory->string_map(),
Map::Create(isolate, 0),
factory->sloppy_arguments_elements_map(),
};
for (size_t name_index = 0; name_index < arraysize(names); name_index++) {
Handle<Name> name = names[name_index];
for (size_t map_index = 0; map_index < arraysize(maps); map_index++) {
Handle<Map> map = maps[map_index];
int expected_result;
{
int primary_offset = StubCache::PrimaryOffsetForTesting(*name, *map);
if (table == StubCache::kPrimary) {
expected_result = primary_offset;
} else {
expected_result =
StubCache::SecondaryOffsetForTesting(*name, primary_offset);
}
}
Handle<Object> result = ft.Call(name, map).ToHandleChecked();
Smi* expected = Smi::FromInt(expected_result & Smi::kMaxValue);
CHECK_EQ(expected, Smi::cast(*result));
}
}
}
} // namespace
TEST(StubCachePrimaryOffset) {
TestStubCacheOffsetCalculation(StubCache::kPrimary);
}
TEST(StubCacheSecondaryOffset) {
TestStubCacheOffsetCalculation(StubCache::kSecondary);
}
namespace {
Handle<Code> CreateCodeWithFlags(Code::Flags flags) {
Isolate* isolate(CcTest::InitIsolateOnce());
CodeAssemblerTester data(isolate, flags);
CodeStubAssembler m(data.state());
m.Return(m.UndefinedConstant());
return data.GenerateCodeCloseAndEscape();
}
} // namespace
TEST(TryProbeStubCache) {
typedef CodeStubAssembler::Label Label;
typedef CodeStubAssembler::Variable Variable;
Isolate* isolate(CcTest::InitIsolateOnce());
const int kNumParams = 3;
CodeAssemblerTester data(isolate, kNumParams);
AccessorAssemblerImpl m(data.state());
Code::Kind ic_kind = Code::LOAD_IC;
StubCache stub_cache(isolate, ic_kind);
stub_cache.Clear();
{
Node* receiver = m.Parameter(0);
Node* name = m.Parameter(1);
Node* expected_handler = m.Parameter(2);
Label passed(&m), failed(&m);
Variable var_handler(&m, MachineRepresentation::kTagged);
Label if_handler(&m), if_miss(&m);
m.TryProbeStubCache(&stub_cache, receiver, name, &if_handler, &var_handler,
&if_miss);
m.Bind(&if_handler);
m.Branch(m.WordEqual(expected_handler, var_handler.value()), &passed,
&failed);
m.Bind(&if_miss);
m.Branch(m.WordEqual(expected_handler, m.IntPtrConstant(0)), &passed,
&failed);
m.Bind(&passed);
m.Return(m.BooleanConstant(true));
m.Bind(&failed);
m.Return(m.BooleanConstant(false));
}
Handle<Code> code = data.GenerateCode();
FunctionTester ft(code, kNumParams);
std::vector<Handle<Name>> names;
std::vector<Handle<JSObject>> receivers;
std::vector<Handle<Code>> handlers;
base::RandomNumberGenerator rand_gen(FLAG_random_seed);
Factory* factory = isolate->factory();
// Generate some number of names.
for (int i = 0; i < StubCache::kPrimaryTableSize / 7; i++) {
Handle<Name> name;
switch (rand_gen.NextInt(3)) {
case 0: {
// Generate string.
std::stringstream ss;
ss << "s" << std::hex
<< (rand_gen.NextInt(Smi::kMaxValue) % StubCache::kPrimaryTableSize);
name = factory->InternalizeUtf8String(ss.str().c_str());
break;
}
case 1: {
// Generate number string.
std::stringstream ss;
ss << (rand_gen.NextInt(Smi::kMaxValue) % StubCache::kPrimaryTableSize);
name = factory->InternalizeUtf8String(ss.str().c_str());
break;
}
case 2: {
// Generate symbol.
name = factory->NewSymbol();
break;
}
default:
UNREACHABLE();
}
names.push_back(name);
}
// Generate some number of receiver maps and receivers.
for (int i = 0; i < StubCache::kSecondaryTableSize / 2; i++) {
Handle<Map> map = Map::Create(isolate, 0);
receivers.push_back(factory->NewJSObjectFromMap(map));
}
// Generate some number of handlers.
for (int i = 0; i < 30; i++) {
Code::Flags flags =
Code::RemoveHolderFromFlags(Code::ComputeHandlerFlags(ic_kind));
handlers.push_back(CreateCodeWithFlags(flags));
}
// Ensure that GC does happen because from now on we are going to fill our
// own stub cache instance with raw values.
DisallowHeapAllocation no_gc;
// Populate {stub_cache}.
const int N = StubCache::kPrimaryTableSize + StubCache::kSecondaryTableSize;
for (int i = 0; i < N; i++) {
int index = rand_gen.NextInt();
Handle<Name> name = names[index % names.size()];
Handle<JSObject> receiver = receivers[index % receivers.size()];
Handle<Code> handler = handlers[index % handlers.size()];
stub_cache.Set(*name, receiver->map(), *handler);
}
// Perform some queries.
bool queried_existing = false;
bool queried_non_existing = false;
for (int i = 0; i < N; i++) {
int index = rand_gen.NextInt();
Handle<Name> name = names[index % names.size()];
Handle<JSObject> receiver = receivers[index % receivers.size()];
Object* handler = stub_cache.Get(*name, receiver->map());
if (handler == nullptr) {
queried_non_existing = true;
} else {
queried_existing = true;
}
Handle<Object> expected_handler(handler, isolate);
ft.CheckTrue(receiver, name, expected_handler);
}
for (int i = 0; i < N; i++) {
int index1 = rand_gen.NextInt();
int index2 = rand_gen.NextInt();
Handle<Name> name = names[index1 % names.size()];
Handle<JSObject> receiver = receivers[index2 % receivers.size()];
Object* handler = stub_cache.Get(*name, receiver->map());
if (handler == nullptr) {
queried_non_existing = true;
} else {
queried_existing = true;
}
Handle<Object> expected_handler(handler, isolate);
ft.CheckTrue(receiver, name, expected_handler);
}
// Ensure we performed both kind of queries.
CHECK(queried_existing && queried_non_existing);
}
} // namespace internal
} // namespace v8
......@@ -6,7 +6,6 @@
#include "src/code-factory.h"
#include "src/code-stub-assembler.h"
#include "src/compiler/node.h"
#include "src/ic/stub-cache.h"
#include "src/isolate.h"
#include "test/cctest/compiler/code-assembler-tester.h"
#include "test/cctest/compiler/function-tester.h"
......@@ -1274,248 +1273,6 @@ TEST(TestOutOfScopeVariable) {
CHECK(!data.GenerateCode().is_null());
}
namespace {
void TestStubCacheOffsetCalculation(StubCache::Table table) {
Isolate* isolate(CcTest::InitIsolateOnce());
const int kNumParams = 2;
CodeAssemblerTester data(isolate, kNumParams);
CodeStubAssembler m(data.state());
{
Node* name = m.Parameter(0);
Node* map = m.Parameter(1);
Node* primary_offset = m.StubCachePrimaryOffset(name, map);
Node* result;
if (table == StubCache::kPrimary) {
result = primary_offset;
} else {
CHECK_EQ(StubCache::kSecondary, table);
result = m.StubCacheSecondaryOffset(name, primary_offset);
}
m.Return(m.SmiFromWord32(result));
}
Handle<Code> code = data.GenerateCode();
FunctionTester ft(code, kNumParams);
Factory* factory = isolate->factory();
Handle<Name> names[] = {
factory->NewSymbol(),
factory->InternalizeUtf8String("a"),
factory->InternalizeUtf8String("bb"),
factory->InternalizeUtf8String("ccc"),
factory->NewPrivateSymbol(),
factory->InternalizeUtf8String("dddd"),
factory->InternalizeUtf8String("eeeee"),
factory->InternalizeUtf8String("name"),
factory->NewSymbol(),
factory->NewPrivateSymbol(),
};
Handle<Map> maps[] = {
Handle<Map>(nullptr, isolate),
factory->cell_map(),
Map::Create(isolate, 0),
factory->meta_map(),
factory->code_map(),
Map::Create(isolate, 0),
factory->hash_table_map(),
factory->symbol_map(),
factory->string_map(),
Map::Create(isolate, 0),
factory->sloppy_arguments_elements_map(),
};
for (size_t name_index = 0; name_index < arraysize(names); name_index++) {
Handle<Name> name = names[name_index];
for (size_t map_index = 0; map_index < arraysize(maps); map_index++) {
Handle<Map> map = maps[map_index];
int expected_result;
{
int primary_offset = StubCache::PrimaryOffsetForTesting(*name, *map);
if (table == StubCache::kPrimary) {
expected_result = primary_offset;
} else {
expected_result =
StubCache::SecondaryOffsetForTesting(*name, primary_offset);
}
}
Handle<Object> result = ft.Call(name, map).ToHandleChecked();
Smi* expected = Smi::FromInt(expected_result & Smi::kMaxValue);
CHECK_EQ(expected, Smi::cast(*result));
}
}
}
} // namespace
TEST(StubCachePrimaryOffset) {
TestStubCacheOffsetCalculation(StubCache::kPrimary);
}
TEST(StubCacheSecondaryOffset) {
TestStubCacheOffsetCalculation(StubCache::kSecondary);
}
namespace {
Handle<Code> CreateCodeWithFlags(Code::Flags flags) {
Isolate* isolate(CcTest::InitIsolateOnce());
CodeAssemblerTester data(isolate, flags);
CodeStubAssembler m(data.state());
m.Return(m.UndefinedConstant());
return data.GenerateCodeCloseAndEscape();
}
} // namespace
TEST(TryProbeStubCache) {
typedef CodeStubAssembler::Label Label;
typedef CodeStubAssembler::Variable Variable;
Isolate* isolate(CcTest::InitIsolateOnce());
const int kNumParams = 3;
CodeAssemblerTester data(isolate, kNumParams);
CodeStubAssembler m(data.state());
Code::Kind ic_kind = Code::LOAD_IC;
StubCache stub_cache(isolate, ic_kind);
stub_cache.Clear();
{
Node* receiver = m.Parameter(0);
Node* name = m.Parameter(1);
Node* expected_handler = m.Parameter(2);
Label passed(&m), failed(&m);
Variable var_handler(&m, MachineRepresentation::kTagged);
Label if_handler(&m), if_miss(&m);
m.TryProbeStubCache(&stub_cache, receiver, name, &if_handler, &var_handler,
&if_miss);
m.Bind(&if_handler);
m.Branch(m.WordEqual(expected_handler, var_handler.value()), &passed,
&failed);
m.Bind(&if_miss);
m.Branch(m.WordEqual(expected_handler, m.IntPtrConstant(0)), &passed,
&failed);
m.Bind(&passed);
m.Return(m.BooleanConstant(true));
m.Bind(&failed);
m.Return(m.BooleanConstant(false));
}
Handle<Code> code = data.GenerateCode();
FunctionTester ft(code, kNumParams);
std::vector<Handle<Name>> names;
std::vector<Handle<JSObject>> receivers;
std::vector<Handle<Code>> handlers;
base::RandomNumberGenerator rand_gen(FLAG_random_seed);
Factory* factory = isolate->factory();
// Generate some number of names.
for (int i = 0; i < StubCache::kPrimaryTableSize / 7; i++) {
Handle<Name> name;
switch (rand_gen.NextInt(3)) {
case 0: {
// Generate string.
std::stringstream ss;
ss << "s" << std::hex
<< (rand_gen.NextInt(Smi::kMaxValue) % StubCache::kPrimaryTableSize);
name = factory->InternalizeUtf8String(ss.str().c_str());
break;
}
case 1: {
// Generate number string.
std::stringstream ss;
ss << (rand_gen.NextInt(Smi::kMaxValue) % StubCache::kPrimaryTableSize);
name = factory->InternalizeUtf8String(ss.str().c_str());
break;
}
case 2: {
// Generate symbol.
name = factory->NewSymbol();
break;
}
default:
UNREACHABLE();
}
names.push_back(name);
}
// Generate some number of receiver maps and receivers.
for (int i = 0; i < StubCache::kSecondaryTableSize / 2; i++) {
Handle<Map> map = Map::Create(isolate, 0);
receivers.push_back(factory->NewJSObjectFromMap(map));
}
// Generate some number of handlers.
for (int i = 0; i < 30; i++) {
Code::Flags flags =
Code::RemoveHolderFromFlags(Code::ComputeHandlerFlags(ic_kind));
handlers.push_back(CreateCodeWithFlags(flags));
}
// Ensure that GC does happen because from now on we are going to fill our
// own stub cache instance with raw values.
DisallowHeapAllocation no_gc;
// Populate {stub_cache}.
const int N = StubCache::kPrimaryTableSize + StubCache::kSecondaryTableSize;
for (int i = 0; i < N; i++) {
int index = rand_gen.NextInt();
Handle<Name> name = names[index % names.size()];
Handle<JSObject> receiver = receivers[index % receivers.size()];
Handle<Code> handler = handlers[index % handlers.size()];
stub_cache.Set(*name, receiver->map(), *handler);
}
// Perform some queries.
bool queried_existing = false;
bool queried_non_existing = false;
for (int i = 0; i < N; i++) {
int index = rand_gen.NextInt();
Handle<Name> name = names[index % names.size()];
Handle<JSObject> receiver = receivers[index % receivers.size()];
Object* handler = stub_cache.Get(*name, receiver->map());
if (handler == nullptr) {
queried_non_existing = true;
} else {
queried_existing = true;
}
Handle<Object> expected_handler(handler, isolate);
ft.CheckTrue(receiver, name, expected_handler);
}
for (int i = 0; i < N; i++) {
int index1 = rand_gen.NextInt();
int index2 = rand_gen.NextInt();
Handle<Name> name = names[index1 % names.size()];
Handle<JSObject> receiver = receivers[index2 % receivers.size()];
Object* handler = stub_cache.Get(*name, receiver->map());
if (handler == nullptr) {
queried_non_existing = true;
} else {
queried_existing = true;
}
Handle<Object> expected_handler(handler, isolate);
ft.CheckTrue(receiver, name, expected_handler);
}
// Ensure we performed both kind of queries.
CHECK(queried_existing && queried_non_existing);
}
TEST(GotoIfException) {
typedef CodeStubAssembler::Label Label;
typedef CodeStubAssembler::Variable Variable;
......
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