Commit fa063904 authored by Suraj Sharma's avatar Suraj Sharma Committed by Commit Bot

[ic] Migrate slow_stub() for LoadICs to use regular data-driven handler.

Bug: v8:9779
Change-Id: Id0d7a214766f91ed8e65f3e24c08e987ba27aff8
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1838923Reviewed-by: 's avatarToon Verwaest <verwaest@chromium.org>
Commit-Queue: Suraj Sharma <surshar@microsoft.com>
Cr-Commit-Position: refs/heads/master@{#64205}
parent fe7b8b80
...@@ -218,9 +218,7 @@ namespace internal { ...@@ -218,9 +218,7 @@ namespace internal {
TFH(KeyedLoadIC_Slow, LoadWithVector) \ TFH(KeyedLoadIC_Slow, LoadWithVector) \
TFH(KeyedStoreIC_Megamorphic, Store) \ TFH(KeyedStoreIC_Megamorphic, Store) \
TFH(KeyedStoreIC_Slow, StoreWithVector) \ TFH(KeyedStoreIC_Slow, StoreWithVector) \
TFH(LoadGlobalIC_Slow, LoadWithVector) \
TFH(LoadIC_FunctionPrototype, LoadWithVector) \ TFH(LoadIC_FunctionPrototype, LoadWithVector) \
TFH(LoadIC_Slow, LoadWithVector) \
TFH(LoadIC_StringLength, LoadWithVector) \ TFH(LoadIC_StringLength, LoadWithVector) \
TFH(LoadIC_StringWrapperLength, LoadWithVector) \ TFH(LoadIC_StringWrapperLength, LoadWithVector) \
TFH(LoadIC_NoFeedback, Load) \ TFH(LoadIC_NoFeedback, Load) \
......
...@@ -388,15 +388,6 @@ TF_BUILTIN(StoreFastElementIC_NoTransitionHandleCOW, HandlerBuiltinsAssembler) { ...@@ -388,15 +388,6 @@ TF_BUILTIN(StoreFastElementIC_NoTransitionHandleCOW, HandlerBuiltinsAssembler) {
Generate_StoreFastElementIC(STORE_HANDLE_COW); Generate_StoreFastElementIC(STORE_HANDLE_COW);
} }
TF_BUILTIN(LoadGlobalIC_Slow, CodeStubAssembler) {
Node* name = Parameter(Descriptor::kName);
Node* slot = Parameter(Descriptor::kSlot);
Node* vector = Parameter(Descriptor::kVector);
Node* context = Parameter(Descriptor::kContext);
TailCallRuntime(Runtime::kLoadGlobalIC_Slow, context, name, slot, vector);
}
TF_BUILTIN(LoadIC_FunctionPrototype, CodeStubAssembler) { TF_BUILTIN(LoadIC_FunctionPrototype, CodeStubAssembler) {
Node* receiver = Parameter(Descriptor::kReceiver); Node* receiver = Parameter(Descriptor::kReceiver);
Node* name = Parameter(Descriptor::kName); Node* name = Parameter(Descriptor::kName);
...@@ -411,14 +402,6 @@ TF_BUILTIN(LoadIC_FunctionPrototype, CodeStubAssembler) { ...@@ -411,14 +402,6 @@ TF_BUILTIN(LoadIC_FunctionPrototype, CodeStubAssembler) {
TailCallRuntime(Runtime::kLoadIC_Miss, context, receiver, name, slot, vector); TailCallRuntime(Runtime::kLoadIC_Miss, context, receiver, name, slot, vector);
} }
TF_BUILTIN(LoadIC_Slow, CodeStubAssembler) {
Node* receiver = Parameter(Descriptor::kReceiver);
Node* name = Parameter(Descriptor::kName);
Node* context = Parameter(Descriptor::kContext);
TailCallRuntime(Runtime::kGetProperty, context, receiver, name);
}
TF_BUILTIN(StoreGlobalIC_Slow, CodeStubAssembler) { TF_BUILTIN(StoreGlobalIC_Slow, CodeStubAssembler) {
Node* receiver = Parameter(Descriptor::kReceiver); Node* receiver = Parameter(Descriptor::kReceiver);
Node* name = Parameter(Descriptor::kName); Node* name = Parameter(Descriptor::kName);
......
...@@ -162,8 +162,8 @@ void AccessorAssembler::HandleLoadICHandlerCase( ...@@ -162,8 +162,8 @@ void AccessorAssembler::HandleLoadICHandlerCase(
BIND(&if_smi_handler); BIND(&if_smi_handler);
{ {
HandleLoadICSmiHandlerCase(p, var_holder.value(), var_smi_handler.value(), HandleLoadICSmiHandlerCase(p, var_holder.value(), var_smi_handler.value(),
handler, miss, exit_point, on_nonexistent, handler, miss, exit_point, ic_mode,
support_elements, access_mode); on_nonexistent, support_elements, access_mode);
} }
BIND(&call_handler); BIND(&call_handler);
...@@ -303,7 +303,7 @@ TNode<MaybeObject> AccessorAssembler::LoadDescriptorValueOrFieldType( ...@@ -303,7 +303,7 @@ TNode<MaybeObject> AccessorAssembler::LoadDescriptorValueOrFieldType(
void AccessorAssembler::HandleLoadICSmiHandlerCase( void AccessorAssembler::HandleLoadICSmiHandlerCase(
const LazyLoadICParameters* p, SloppyTNode<HeapObject> holder, const LazyLoadICParameters* p, SloppyTNode<HeapObject> holder,
SloppyTNode<Smi> smi_handler, SloppyTNode<Object> handler, Label* miss, SloppyTNode<Smi> smi_handler, SloppyTNode<Object> handler, Label* miss,
ExitPoint* exit_point, OnNonExistent on_nonexistent, ExitPoint* exit_point, ICMode ic_mode, OnNonExistent on_nonexistent,
ElementSupport support_elements, LoadAccessMode access_mode) { ElementSupport support_elements, LoadAccessMode access_mode) {
VARIABLE(var_double_value, MachineRepresentation::kFloat64); VARIABLE(var_double_value, MachineRepresentation::kFloat64);
Label rebox_double(this, &var_double_value); Label rebox_double(this, &var_double_value);
...@@ -419,11 +419,11 @@ void AccessorAssembler::HandleLoadICSmiHandlerCase( ...@@ -419,11 +419,11 @@ void AccessorAssembler::HandleLoadICSmiHandlerCase(
if (access_mode == LoadAccessMode::kHas) { if (access_mode == LoadAccessMode::kHas) {
HandleLoadICSmiHandlerHasNamedCase(p, holder, handler_kind, miss, HandleLoadICSmiHandlerHasNamedCase(p, holder, handler_kind, miss,
exit_point); exit_point, ic_mode);
} else { } else {
HandleLoadICSmiHandlerLoadNamedCase( HandleLoadICSmiHandlerLoadNamedCase(
p, holder, handler_kind, handler_word, &rebox_double, &var_double_value, p, holder, handler_kind, handler_word, &rebox_double, &var_double_value,
handler, miss, exit_point, on_nonexistent, support_elements); handler, miss, exit_point, ic_mode, on_nonexistent, support_elements);
} }
} }
...@@ -431,12 +431,13 @@ void AccessorAssembler::HandleLoadICSmiHandlerLoadNamedCase( ...@@ -431,12 +431,13 @@ void AccessorAssembler::HandleLoadICSmiHandlerLoadNamedCase(
const LazyLoadICParameters* p, TNode<HeapObject> holder, const LazyLoadICParameters* p, TNode<HeapObject> holder,
TNode<IntPtrT> handler_kind, TNode<WordT> handler_word, Label* rebox_double, TNode<IntPtrT> handler_kind, TNode<WordT> handler_word, Label* rebox_double,
Variable* var_double_value, SloppyTNode<Object> handler, Label* miss, Variable* var_double_value, SloppyTNode<Object> handler, Label* miss,
ExitPoint* exit_point, OnNonExistent on_nonexistent, ExitPoint* exit_point, ICMode ic_mode, OnNonExistent on_nonexistent,
ElementSupport support_elements) { ElementSupport support_elements) {
Label constant(this), field(this), normal(this, Label::kDeferred), Label constant(this), field(this), normal(this, Label::kDeferred),
interceptor(this, Label::kDeferred), nonexistent(this), slow(this, Label::kDeferred), interceptor(this, Label::kDeferred),
accessor(this, Label::kDeferred), global(this, Label::kDeferred), nonexistent(this), accessor(this, Label::kDeferred),
module_export(this, Label::kDeferred), proxy(this, Label::kDeferred), global(this, Label::kDeferred), module_export(this, Label::kDeferred),
proxy(this, Label::kDeferred),
native_data_property(this, Label::kDeferred), native_data_property(this, Label::kDeferred),
api_getter(this, Label::kDeferred); api_getter(this, Label::kDeferred);
...@@ -469,6 +470,8 @@ void AccessorAssembler::HandleLoadICSmiHandlerLoadNamedCase( ...@@ -469,6 +470,8 @@ void AccessorAssembler::HandleLoadICSmiHandlerLoadNamedCase(
GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kGlobal)), GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kGlobal)),
&global); &global);
GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kSlow)), &slow);
GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kProxy)), &proxy); GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kProxy)), &proxy);
Branch(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kModuleExport)), Branch(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kModuleExport)),
...@@ -596,6 +599,18 @@ void AccessorAssembler::HandleLoadICSmiHandlerLoadNamedCase( ...@@ -596,6 +599,18 @@ void AccessorAssembler::HandleLoadICSmiHandlerLoadNamedCase(
p->context(), p->name(), p->receiver(), p->context(), p->name(), p->receiver(),
holder, p->slot(), p->vector()); holder, p->slot(), p->vector());
} }
BIND(&slow);
{
Comment("load_slow");
if (ic_mode == ICMode::kGlobalIC) {
exit_point->ReturnCallRuntime(Runtime::kLoadGlobalIC_Slow, p->context(),
p->name(), p->slot(), p->vector());
} else {
exit_point->ReturnCallRuntime(Runtime::kGetProperty, p->context(),
p->receiver(), p->name());
}
}
BIND(&module_export); BIND(&module_export);
{ {
...@@ -627,9 +642,10 @@ void AccessorAssembler::HandleLoadICSmiHandlerLoadNamedCase( ...@@ -627,9 +642,10 @@ void AccessorAssembler::HandleLoadICSmiHandlerLoadNamedCase(
void AccessorAssembler::HandleLoadICSmiHandlerHasNamedCase( void AccessorAssembler::HandleLoadICSmiHandlerHasNamedCase(
const LazyLoadICParameters* p, TNode<HeapObject> holder, const LazyLoadICParameters* p, TNode<HeapObject> holder,
TNode<IntPtrT> handler_kind, Label* miss, ExitPoint* exit_point) { TNode<IntPtrT> handler_kind, Label* miss, ExitPoint* exit_point,
ICMode ic_mode) {
Label return_true(this), return_false(this), return_lookup(this), Label return_true(this), return_false(this), return_lookup(this),
normal(this), global(this); normal(this), global(this), slow(this);
GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kField)), GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kField)),
&return_true); &return_true);
...@@ -658,6 +674,8 @@ void AccessorAssembler::HandleLoadICSmiHandlerHasNamedCase( ...@@ -658,6 +674,8 @@ void AccessorAssembler::HandleLoadICSmiHandlerHasNamedCase(
IntPtrConstant(LoadHandler::kApiGetterHolderIsPrototype)), IntPtrConstant(LoadHandler::kApiGetterHolderIsPrototype)),
&return_true); &return_true);
GotoIf(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kSlow)), &slow);
Branch(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kGlobal)), &global, Branch(WordEqual(handler_kind, IntPtrConstant(LoadHandler::kGlobal)), &global,
&return_lookup); &return_lookup);
...@@ -704,6 +722,18 @@ void AccessorAssembler::HandleLoadICSmiHandlerHasNamedCase( ...@@ -704,6 +722,18 @@ void AccessorAssembler::HandleLoadICSmiHandlerHasNamedCase(
exit_point->Return(TrueConstant()); exit_point->Return(TrueConstant());
} }
BIND(&slow);
{
Comment("load_slow");
if (ic_mode == ICMode::kGlobalIC) {
exit_point->ReturnCallRuntime(Runtime::kLoadGlobalIC_Slow, p->context(),
p->name(), p->slot(), p->vector());
} else {
exit_point->ReturnCallRuntime(Runtime::kHasProperty, p->context(),
p->receiver(), p->name());
}
}
} }
// Performs actions common to both load and store handlers: // Performs actions common to both load and store handlers:
......
...@@ -249,7 +249,7 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler { ...@@ -249,7 +249,7 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler {
void HandleLoadICSmiHandlerCase( void HandleLoadICSmiHandlerCase(
const LazyLoadICParameters* p, SloppyTNode<HeapObject> holder, const LazyLoadICParameters* p, SloppyTNode<HeapObject> holder,
SloppyTNode<Smi> smi_handler, SloppyTNode<Object> handler, Label* miss, SloppyTNode<Smi> smi_handler, SloppyTNode<Object> handler, Label* miss,
ExitPoint* exit_point, OnNonExistent on_nonexistent, ExitPoint* exit_point, ICMode ic_mode, OnNonExistent on_nonexistent,
ElementSupport support_elements, LoadAccessMode access_mode); ElementSupport support_elements, LoadAccessMode access_mode);
void HandleLoadICProtoHandler(const LazyLoadICParameters* p, void HandleLoadICProtoHandler(const LazyLoadICParameters* p,
...@@ -282,12 +282,14 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler { ...@@ -282,12 +282,14 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler {
TNode<IntPtrT> handler_kind, TNode<WordT> handler_word, TNode<IntPtrT> handler_kind, TNode<WordT> handler_word,
Label* rebox_double, Variable* var_double_value, Label* rebox_double, Variable* var_double_value,
SloppyTNode<Object> handler, Label* miss, ExitPoint* exit_point, SloppyTNode<Object> handler, Label* miss, ExitPoint* exit_point,
OnNonExistent on_nonexistent, ElementSupport support_elements); ICMode ic_mode, OnNonExistent on_nonexistent,
ElementSupport support_elements);
void HandleLoadICSmiHandlerHasNamedCase(const LazyLoadICParameters* p, void HandleLoadICSmiHandlerHasNamedCase(const LazyLoadICParameters* p,
TNode<HeapObject> holder, TNode<HeapObject> holder,
TNode<IntPtrT> handler_kind, TNode<IntPtrT> handler_kind,
Label* miss, ExitPoint* exit_point); Label* miss, ExitPoint* exit_point,
ICMode ic_mode);
// LoadGlobalIC implementation. // LoadGlobalIC implementation.
......
...@@ -43,6 +43,11 @@ Handle<Smi> LoadHandler::LoadInterceptor(Isolate* isolate) { ...@@ -43,6 +43,11 @@ Handle<Smi> LoadHandler::LoadInterceptor(Isolate* isolate) {
return handle(Smi::FromInt(config), isolate); return handle(Smi::FromInt(config), isolate);
} }
Handle<Smi> LoadHandler::LoadSlow(Isolate* isolate) {
int config = KindBits::encode(kSlow);
return handle(Smi::FromInt(config), isolate);
}
Handle<Smi> LoadHandler::LoadField(Isolate* isolate, FieldIndex field_index) { Handle<Smi> LoadHandler::LoadField(Isolate* isolate, FieldIndex field_index) {
int config = KindBits::encode(kField) | int config = KindBits::encode(kField) |
IsInobjectBits::encode(field_index.is_inobject()) | IsInobjectBits::encode(field_index.is_inobject()) |
......
...@@ -43,6 +43,7 @@ class LoadHandler final : public DataHandler { ...@@ -43,6 +43,7 @@ class LoadHandler final : public DataHandler {
kApiGetter, kApiGetter,
kApiGetterHolderIsPrototype, kApiGetterHolderIsPrototype,
kInterceptor, kInterceptor,
kSlow,
kProxy, kProxy,
kNonExistent, kNonExistent,
kModuleExport kModuleExport
...@@ -113,6 +114,9 @@ class LoadHandler final : public DataHandler { ...@@ -113,6 +114,9 @@ class LoadHandler final : public DataHandler {
// interceptor. // interceptor.
static inline Handle<Smi> LoadInterceptor(Isolate* isolate); static inline Handle<Smi> LoadInterceptor(Isolate* isolate);
// Creates a Smi-handler for loading a property from a object.
static inline Handle<Smi> LoadSlow(Isolate* isolate);
// Creates a Smi-handler for loading a field from fast object. // Creates a Smi-handler for loading a field from fast object.
static inline Handle<Smi> LoadField(Isolate* isolate, FieldIndex field_index); static inline Handle<Smi> LoadField(Isolate* isolate, FieldIndex field_index);
......
...@@ -381,7 +381,7 @@ MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<Name> name) { ...@@ -381,7 +381,7 @@ MaybeHandle<Object> LoadIC::Load(Handle<Object> object, Handle<Name> name) {
// Ensure the IC state progresses. // Ensure the IC state progresses.
TRACE_HANDLER_STATS(isolate(), LoadIC_NonReceiver); TRACE_HANDLER_STATS(isolate(), LoadIC_NonReceiver);
update_receiver_map(object); update_receiver_map(object);
PatchCache(name, slow_stub()); PatchCache(name, LoadHandler::LoadSlow(isolate()));
TraceIC("LoadIC", name); TraceIC("LoadIC", name);
} }
...@@ -484,7 +484,7 @@ MaybeHandle<Object> LoadGlobalIC::Load(Handle<Name> name) { ...@@ -484,7 +484,7 @@ MaybeHandle<Object> LoadGlobalIC::Load(Handle<Name> name) {
} else { } else {
// Given combination of indices can't be encoded, so use slow stub. // Given combination of indices can't be encoded, so use slow stub.
TRACE_HANDLER_STATS(isolate(), LoadGlobalIC_SlowStub); TRACE_HANDLER_STATS(isolate(), LoadGlobalIC_SlowStub);
PatchCache(name, slow_stub()); PatchCache(name, LoadHandler::LoadSlow(isolate()));
} }
TraceIC("LoadGlobalIC", name); TraceIC("LoadGlobalIC", name);
} }
...@@ -652,7 +652,7 @@ __attribute__((__aligned__(32))) ...@@ -652,7 +652,7 @@ __attribute__((__aligned__(32)))
void LoadIC::UpdateCaches(LookupIterator* lookup) { void LoadIC::UpdateCaches(LookupIterator* lookup) {
Handle<Object> code; Handle<Object> code;
if (lookup->state() == LookupIterator::ACCESS_CHECK) { if (lookup->state() == LookupIterator::ACCESS_CHECK) {
code = slow_stub(); code = LoadHandler::LoadSlow(isolate());
} else if (!lookup->IsFound()) { } else if (!lookup->IsFound()) {
TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNonexistentDH); TRACE_HANDLER_STATS(isolate(), LoadIC_LoadNonexistentDH);
Handle<Smi> smi_handler = LoadHandler::LoadNonExistent(isolate()); Handle<Smi> smi_handler = LoadHandler::LoadNonExistent(isolate());
...@@ -791,7 +791,7 @@ Handle<Object> LoadIC::ComputeHandler(LookupIterator* lookup) { ...@@ -791,7 +791,7 @@ Handle<Object> LoadIC::ComputeHandler(LookupIterator* lookup) {
isolate()); isolate());
if (!getter->IsJSFunction() && !getter->IsFunctionTemplateInfo()) { if (!getter->IsJSFunction() && !getter->IsFunctionTemplateInfo()) {
TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub); TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
return slow_stub(); return LoadHandler::LoadSlow(isolate());
} }
if ((getter->IsFunctionTemplateInfo() && if ((getter->IsFunctionTemplateInfo() &&
...@@ -800,7 +800,7 @@ Handle<Object> LoadIC::ComputeHandler(LookupIterator* lookup) { ...@@ -800,7 +800,7 @@ Handle<Object> LoadIC::ComputeHandler(LookupIterator* lookup) {
JSFunction::cast(*getter).shared().BreakAtEntry())) { JSFunction::cast(*getter).shared().BreakAtEntry())) {
// Do not install an IC if the api function has a breakpoint. // Do not install an IC if the api function has a breakpoint.
TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub); TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
return slow_stub(); return LoadHandler::LoadSlow(isolate());
} }
Handle<Smi> smi_handler; Handle<Smi> smi_handler;
...@@ -810,7 +810,7 @@ Handle<Object> LoadIC::ComputeHandler(LookupIterator* lookup) { ...@@ -810,7 +810,7 @@ Handle<Object> LoadIC::ComputeHandler(LookupIterator* lookup) {
if (!call_optimization.IsCompatibleReceiverMap(map, holder) || if (!call_optimization.IsCompatibleReceiverMap(map, holder) ||
!holder->HasFastProperties()) { !holder->HasFastProperties()) {
TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub); TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
return slow_stub(); return LoadHandler::LoadSlow(isolate());
} }
CallOptimization::HolderLookup holder_lookup; CallOptimization::HolderLookup holder_lookup;
...@@ -861,7 +861,7 @@ Handle<Object> LoadIC::ComputeHandler(LookupIterator* lookup) { ...@@ -861,7 +861,7 @@ Handle<Object> LoadIC::ComputeHandler(LookupIterator* lookup) {
!holder->HasFastProperties() || !holder->HasFastProperties() ||
(info->is_sloppy() && !receiver->IsJSReceiver())) { (info->is_sloppy() && !receiver->IsJSReceiver())) {
TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub); TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
return slow_stub(); return LoadHandler::LoadSlow(isolate());
} }
Handle<Smi> smi_handler = LoadHandler::LoadNativeDataProperty( Handle<Smi> smi_handler = LoadHandler::LoadNativeDataProperty(
......
...@@ -186,11 +186,6 @@ class LoadIC : public IC { ...@@ -186,11 +186,6 @@ class LoadIC : public IC {
Handle<Name> name); Handle<Name> name);
protected: protected:
virtual Handle<Code> slow_stub() const {
return IsAnyHas() ? BUILTIN_CODE(isolate(), HasIC_Slow)
: BUILTIN_CODE(isolate(), LoadIC_Slow);
}
// Update the inline cache and the global stub cache based on the // Update the inline cache and the global stub cache based on the
// lookup result. // lookup result.
void UpdateCaches(LookupIterator* lookup); void UpdateCaches(LookupIterator* lookup);
...@@ -209,11 +204,6 @@ class LoadGlobalIC : public LoadIC { ...@@ -209,11 +204,6 @@ class LoadGlobalIC : public LoadIC {
: LoadIC(isolate, vector, slot, kind) {} : LoadIC(isolate, vector, slot, kind) {}
V8_WARN_UNUSED_RESULT MaybeHandle<Object> Load(Handle<Name> name); V8_WARN_UNUSED_RESULT MaybeHandle<Object> Load(Handle<Name> name);
protected:
Handle<Code> slow_stub() const override {
return BUILTIN_CODE(isolate(), LoadGlobalIC_Slow);
}
}; };
class KeyedLoadIC : public LoadIC { class KeyedLoadIC : public LoadIC {
......
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