Commit fbd114bd authored by Sathya Gunasekaran's avatar Sathya Gunasekaran Committed by Commit Bot

Reland "[ic] Add a new MegaDOM IC"

This is a reland of c83c9590

Changes since revert: nothing, issue was crbug.com/v8/11666

Original change's description:
> [ic] Add a new MegaDOM IC
>
> This patch implements the MegaDOM IC setup and access. A new MegaDOM
> IC state indicates that we've seen only DOM accessors at this access
> site.
>
> This CL only adds support for DOM getters in LoadIC, other kinds of
> access will be added in follow on CLs.
>
> Still remaining TODO before shipping:
> 1. Have a mechanism to invalidate the protector
> 2. Have a mechanism to find the accessors that aren't overloaded
> 3. Use a new builtin to miss to runtime on access check failure
>
> Change-Id: Ie12efe5e9fa284f023043b996d61e7d74e710ee2
> Bug: v8:11321
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2618239
> Reviewed-by: Omer Katz <omerkatz@chromium.org>
> Reviewed-by: Camillo Bruni <cbruni@chromium.org>
> Reviewed-by: Dan Elphick <delphick@chromium.org>
> Reviewed-by: Mythri Alle <mythria@chromium.org>
> Commit-Queue: Sathya Gunasekaran  <gsathya@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#73733}

Bug: v8:11321
Change-Id: I2bec54465542b5b40c42adb6eb12b6ce72cce5bd
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2794439Reviewed-by: 's avatarDan Elphick <delphick@chromium.org>
Reviewed-by: 's avatarMythri Alle <mythria@chromium.org>
Reviewed-by: 's avatarCamillo Bruni <cbruni@chromium.org>
Reviewed-by: 's avatarOmer Katz <omerkatz@chromium.org>
Reviewed-by: 's avatarUlan Degenbaev <ulan@chromium.org>
Commit-Queue: Sathya Gunasekaran  <gsathya@chromium.org>
Cr-Commit-Position: refs/heads/master@{#74056}
parent b477f366
......@@ -1284,6 +1284,8 @@ action("postmortem-metadata") {
"src/objects/map.cc",
"src/objects/map.h",
"src/objects/map-inl.h",
"src/objects/megadom-handler.h",
"src/objects/megadom-handler-inl.h",
"src/objects/name.h",
"src/objects/name-inl.h",
"src/objects/objects.h",
......@@ -1472,6 +1474,7 @@ torque_files = [
"src/objects/js-weak-refs.tq",
"src/objects/literal-objects.tq",
"src/objects/map.tq",
"src/objects/megadom-handler.tq",
"src/objects/microtask.tq",
"src/objects/module.tq",
"src/objects/name.tq",
......@@ -2835,6 +2838,8 @@ v8_header_set("v8_internal_headers") {
"src/objects/map.h",
"src/objects/maybe-object-inl.h",
"src/objects/maybe-object.h",
"src/objects/megadom-handler-inl.h",
"src/objects/megadom-handler.h",
"src/objects/microtask-inl.h",
"src/objects/microtask.h",
"src/objects/module-inl.h",
......
......@@ -8534,6 +8534,7 @@ class V8_EXPORT Isolate {
kWasmBulkMemory = 109, // Unused.
kWasmMultiValue = 110,
kWasmExceptionHandling = 111,
kInvalidatedMegaDOMProtector = 112,
// If you add new values here, you'll also need to update Chromium's:
// web_feature.mojom, use_counter_callback.cc, and enums.xml. V8 changes to
......
......@@ -6064,6 +6064,13 @@ TNode<BoolT> CodeStubAssembler::IsNoElementsProtectorCellInvalid() {
return TaggedEqual(cell_value, invalid);
}
TNode<BoolT> CodeStubAssembler::IsMegaDOMProtectorCellInvalid() {
TNode<Smi> invalid = SmiConstant(Protectors::kProtectorInvalid);
TNode<PropertyCell> cell = MegaDOMProtectorConstant();
TNode<Object> cell_value = LoadObjectField(cell, PropertyCell::kValueOffset);
return TaggedEqual(cell_value, invalid);
}
TNode<BoolT> CodeStubAssembler::IsArrayIteratorProtectorCellInvalid() {
TNode<Smi> invalid = SmiConstant(Protectors::kProtectorInvalid);
TNode<PropertyCell> cell = ArrayIteratorProtectorConstant();
......@@ -6313,14 +6320,27 @@ TNode<BoolT> CodeStubAssembler::IsJSObjectInstanceType(
Int32Constant(FIRST_JS_OBJECT_TYPE));
}
TNode<BoolT> CodeStubAssembler::IsJSApiObjectInstanceType(
TNode<Int32T> instance_type) {
return InstanceTypeEqual(instance_type, JS_API_OBJECT_TYPE);
}
TNode<BoolT> CodeStubAssembler::IsJSObjectMap(TNode<Map> map) {
return IsJSObjectInstanceType(LoadMapInstanceType(map));
}
TNode<BoolT> CodeStubAssembler::IsJSApiObjectMap(TNode<Map> map) {
return IsJSApiObjectInstanceType(LoadMapInstanceType(map));
}
TNode<BoolT> CodeStubAssembler::IsJSObject(TNode<HeapObject> object) {
return IsJSObjectMap(LoadMap(object));
}
TNode<BoolT> CodeStubAssembler::IsJSApiObject(TNode<HeapObject> object) {
return IsJSApiObjectMap(LoadMap(object));
}
TNode<BoolT> CodeStubAssembler::IsJSFinalizationRegistryMap(TNode<Map> map) {
return InstanceTypeEqual(LoadMapInstanceType(map),
JS_FINALIZATION_REGISTRY_TYPE);
......
......@@ -67,6 +67,7 @@ enum class PrimitiveType { kBoolean, kNumber, kString, kSymbol };
AsyncIteratorValueUnwrapSharedFun) \
V(MapIteratorProtector, map_iterator_protector, MapIteratorProtector) \
V(NoElementsProtector, no_elements_protector, NoElementsProtector) \
V(MegaDOMProtector, mega_dom_protector, MegaDOMProtector) \
V(NumberStringCache, number_string_cache, NumberStringCache) \
V(PromiseAllResolveElementSharedFun, promise_all_resolve_element_shared_fun, \
PromiseAllResolveElementSharedFun) \
......@@ -157,6 +158,7 @@ enum class PrimitiveType { kBoolean, kNumber, kString, kSymbol };
V(ManyClosuresCellMap, many_closures_cell_map, ManyClosuresCellMap) \
V(match_symbol, match_symbol, MatchSymbol) \
V(megamorphic_symbol, megamorphic_symbol, MegamorphicSymbol) \
V(mega_dom_symbol, mega_dom_symbol, MegaDOMSymbol) \
V(message_string, message_string, MessageString) \
V(minus_Infinity_string, minus_Infinity_string, MinusInfinityString) \
V(MinusZeroValue, minus_zero_value, MinusZero) \
......@@ -2370,6 +2372,7 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
// JSProxy or an object with interceptors.
TNode<BoolT> InstanceTypeEqual(TNode<Int32T> instance_type, int type);
TNode<BoolT> IsNoElementsProtectorCellInvalid();
TNode<BoolT> IsMegaDOMProtectorCellInvalid();
TNode<BoolT> IsArrayIteratorProtectorCellInvalid();
TNode<BoolT> IsBigIntInstanceType(TNode<Int32T> instance_type);
TNode<BoolT> IsBigInt(TNode<HeapObject> object);
......@@ -2419,6 +2422,9 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
TNode<BoolT> IsJSObjectInstanceType(TNode<Int32T> instance_type);
TNode<BoolT> IsJSObjectMap(TNode<Map> map);
TNode<BoolT> IsJSObject(TNode<HeapObject> object);
TNode<BoolT> IsJSApiObjectInstanceType(TNode<Int32T> instance_type);
TNode<BoolT> IsJSApiObjectMap(TNode<Map> map);
TNode<BoolT> IsJSApiObject(TNode<HeapObject> object);
TNode<BoolT> IsJSFinalizationRegistryMap(TNode<Map> map);
TNode<BoolT> IsJSFinalizationRegistry(TNode<HeapObject> object);
TNode<BoolT> IsJSPromiseMap(TNode<Map> map);
......
......@@ -881,6 +881,8 @@ enum InlineCacheState {
RECOMPUTE_HANDLER,
// Multiple receiver types have been seen.
POLYMORPHIC,
// Many DOM receiver types have been seen for the same accessor.
MEGADOM,
// Many receiver types have been seen.
MEGAMORPHIC,
// A generic handler is installed and no extra typefeedback is recorded.
......@@ -902,6 +904,8 @@ inline const char* InlineCacheState2String(InlineCacheState state) {
return "POLYMORPHIC";
case MEGAMORPHIC:
return "MEGAMORPHIC";
case MEGADOM:
return "MEGADOM";
case GENERIC:
return "GENERIC";
}
......
......@@ -2563,6 +2563,33 @@ Local<String> Shell::Stringify(Isolate* isolate, Local<Value> value) {
return result.ToLocalChecked().As<String>();
}
void Shell::NodeTypeCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::Isolate* isolate = args.GetIsolate();
args.GetReturnValue().Set(v8::Number::New(isolate, 1));
}
Local<FunctionTemplate> Shell::CreateNodeTemplates(Isolate* isolate) {
Local<FunctionTemplate> node = FunctionTemplate::New(isolate);
Local<ObjectTemplate> proto_template = node->PrototypeTemplate();
Local<Signature> signature = v8::Signature::New(isolate, node);
Local<FunctionTemplate> nodeType = FunctionTemplate::New(
isolate, NodeTypeCallback, Local<Value>(), signature);
nodeType->SetAcceptAnyReceiver(false);
proto_template->SetAccessorProperty(
String::NewFromUtf8Literal(isolate, "nodeType"), nodeType);
Local<FunctionTemplate> element = FunctionTemplate::New(isolate);
element->Inherit(node);
Local<FunctionTemplate> html_element = FunctionTemplate::New(isolate);
html_element->Inherit(element);
Local<FunctionTemplate> div_element = FunctionTemplate::New(isolate);
div_element->Inherit(html_element);
return div_element;
}
Local<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) {
Local<ObjectTemplate> global_template = ObjectTemplate::New(isolate);
global_template->Set(Symbol::GetToStringTag(isolate),
......@@ -2594,6 +2621,7 @@ Local<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) {
global_template->Set(isolate, "performance",
Shell::CreatePerformanceTemplate(isolate));
global_template->Set(isolate, "Worker", Shell::CreateWorkerTemplate(isolate));
// Prevent fuzzers from creating side effects.
if (!i::FLAG_fuzzing) {
global_template->Set(isolate, "os", Shell::CreateOSTemplate(isolate));
......@@ -2722,6 +2750,10 @@ Local<ObjectTemplate> Shell::CreateD8Template(Isolate* isolate) {
FunctionTemplate::New(isolate, LogGetAndStop));
d8_template->Set(isolate, "log", log_template);
Local<ObjectTemplate> dom_template = ObjectTemplate::New(isolate);
dom_template->Set(isolate, "Div", Shell::CreateNodeTemplates(isolate));
d8_template->Set(isolate, "dom", dom_template);
}
{
Local<ObjectTemplate> test_template = ObjectTemplate::New(isolate);
......
......@@ -626,6 +626,9 @@ class Shell : public i::AllStatic {
static void RunShell(Isolate* isolate);
static bool SetOptions(int argc, char* argv[]);
static void NodeTypeCallback(const v8::FunctionCallbackInfo<v8::Value>& args);
static Local<FunctionTemplate> CreateNodeTemplates(Isolate* isolate);
static Local<ObjectTemplate> CreateGlobalTemplate(Isolate* isolate);
static Local<ObjectTemplate> CreateOSTemplate(Isolate* isolate);
static Local<FunctionTemplate> CreateWorkerTemplate(Isolate* isolate);
......
......@@ -61,6 +61,7 @@
#include "src/objects/js-weak-refs-inl.h"
#include "src/objects/literal-objects-inl.h"
#include "src/objects/maybe-object.h"
#include "src/objects/megadom-handler-inl.h"
#include "src/objects/microtask-inl.h"
#include "src/objects/module-inl.h"
#include "src/objects/oddball-inl.h"
......
......@@ -26,6 +26,8 @@ class Protectors : public AllStatic {
is_concat_spreadable_protector) \
V(NoElements, NoElementsProtector, no_elements_protector) \
\
V(MegaDOM, MegaDOMProtector, mega_dom_protector) \
\
/* The MapIterator protector protects the original iteration behaviors */ \
/* of Map.prototype.keys(), Map.prototype.values(), and */ \
/* Set.prototype.entries(). It does not protect the original iteration */ \
......
......@@ -1468,6 +1468,8 @@ DEFINE_BOOL(native_code_counters, DEBUG_BOOL,
DEFINE_BOOL(super_ic, true, "use an IC for super property loads")
DEFINE_BOOL(enable_mega_dom_ic, false, "use MegaDOM IC state for API objects")
// objects.cc
DEFINE_BOOL(thin_strings, true, "Enable ThinString support")
DEFINE_BOOL(trace_prototype_users, false,
......
......@@ -53,6 +53,7 @@
#include "src/objects/js-regexp-inl.h"
#include "src/objects/js-weak-refs-inl.h"
#include "src/objects/literal-objects-inl.h"
#include "src/objects/megadom-handler-inl.h"
#include "src/objects/microtask-inl.h"
#include "src/objects/module-inl.h"
#include "src/objects/promise-inl.h"
......@@ -3137,6 +3138,16 @@ Handle<Map> Factory::ObjectLiteralMapFromCache(Handle<NativeContext> context,
return map;
}
Handle<MegaDomHandler> Factory::NewMegaDomHandler(MaybeObjectHandle accessor,
MaybeObjectHandle context) {
Handle<Map> map = read_only_roots().mega_dom_handler_map_handle();
MegaDomHandler handler = MegaDomHandler::cast(New(map, AllocationType::kOld));
DisallowGarbageCollection no_gc;
handler.set_accessor(*accessor);
handler.set_context(*context);
return handle(handler, isolate());
}
Handle<LoadHandler> Factory::NewLoadHandler(int data_count,
AllocationType allocation) {
Handle<Map> map;
......
......@@ -732,7 +732,8 @@ class V8_EXPORT_PRIVATE Factory : public FactoryBase<Factory> {
Handle<LoadHandler> NewLoadHandler(
int data_count, AllocationType allocation = AllocationType::kOld);
Handle<StoreHandler> NewStoreHandler(int data_count);
Handle<MegaDomHandler> NewMegaDomHandler(MaybeObjectHandle accessor,
MaybeObjectHandle context);
Handle<RegExpMatchInfo> NewRegExpMatchInfo();
// Creates a new FixedArray that holds the data associated with the
......
......@@ -381,6 +381,7 @@ bool Heap::CreateInitialMaps() {
ALLOCATE_PRIMITIVE_MAP(SYMBOL_TYPE, Symbol::kSize, symbol,
Context::SYMBOL_FUNCTION_INDEX)
ALLOCATE_MAP(FOREIGN_TYPE, Foreign::kSize, foreign)
ALLOCATE_MAP(MEGA_DOM_HANDLER_TYPE, MegaDomHandler::kSize, mega_dom_handler)
ALLOCATE_PRIMITIVE_MAP(ODDBALL_TYPE, Oddball::kSize, boolean,
Context::BOOLEAN_FUNCTION_INDEX);
......@@ -864,6 +865,7 @@ void Heap::CreateInitialObjects() {
set_is_concat_spreadable_protector(*factory->NewProtector());
set_map_iterator_protector(*factory->NewProtector());
set_no_elements_protector(*factory->NewProtector());
set_mega_dom_protector(*factory->NewProtector());
set_promise_hook_protector(*factory->NewProtector());
set_promise_resolve_protector(*factory->NewProtector());
set_promise_species_protector(*factory->NewProtector());
......
......@@ -17,6 +17,7 @@
#include "src/objects/cell.h"
#include "src/objects/foreign.h"
#include "src/objects/heap-number.h"
#include "src/objects/megadom-handler.h"
#include "src/objects/module.h"
#include "src/objects/objects-inl.h"
#include "src/objects/property-details.h"
......@@ -135,6 +136,55 @@ void AccessorAssembler::HandlePolymorphicCase(
}
}
void AccessorAssembler::TryMegaDOMCase(TNode<Object> lookup_start_object,
TNode<Map> lookup_start_object_map,
TVariable<MaybeObject>* var_handler,
TNode<Object> vector,
TNode<TaggedIndex> slot, Label* miss,
ExitPoint* exit_point) {
// Check if the receiver is a JS_API_OBJECT
GotoIfNot(IsJSApiObjectMap(lookup_start_object_map), miss);
// Check if receiver requires access check
GotoIf(IsSetWord32<Map::Bits1::IsAccessCheckNeededBit>(
LoadMapBitField(lookup_start_object_map)),
miss);
CSA_ASSERT(this, TaggedEqual(LoadFeedbackVectorSlot(CAST(vector), slot),
MegaDOMSymbolConstant()));
// In some cases, we load the
TNode<MegaDomHandler> handler;
if (var_handler->IsBound()) {
handler = CAST(var_handler->value());
} else {
TNode<MaybeObject> maybe_handler =
LoadFeedbackVectorSlot(CAST(vector), slot, kTaggedSize);
CSA_ASSERT(this, IsStrong(maybe_handler));
handler = CAST(maybe_handler);
}
// Check if dom protector cell is still valid
GotoIf(IsMegaDOMProtectorCellInvalid(), miss);
// Load the getter
TNode<MaybeObject> maybe_getter = LoadMegaDomHandlerAccessor(handler);
CSA_ASSERT(this, IsWeakOrCleared(maybe_getter));
TNode<FunctionTemplateInfo> getter =
CAST(GetHeapObjectAssumeWeak(maybe_getter, miss));
// Load the accessor context
TNode<MaybeObject> maybe_context = LoadMegaDomHandlerContext(handler);
CSA_ASSERT(this, IsWeakOrCleared(maybe_context));
TNode<Context> context = CAST(GetHeapObjectAssumeWeak(maybe_context, miss));
// TODO(gsathya): This builtin throws an exception on interface check fail but
// we should miss to the runtime.
exit_point->Return(
CallBuiltin(Builtins::kCallFunctionTemplate_CheckCompatibleReceiver,
context, getter, IntPtrConstant(0), lookup_start_object));
}
void AccessorAssembler::HandleLoadICHandlerCase(
const LazyLoadICParameters* p, TNode<Object> handler, Label* miss,
ExitPoint* exit_point, ICMode ic_mode, OnNonExistent on_nonexistent,
......@@ -2864,11 +2914,23 @@ void AccessorAssembler::LoadIC_Noninlined(const LoadICParameters* p,
DCHECK_EQ(MachineRepresentation::kTagged, var_handler->rep());
{
// Check megamorphic case.
GotoIfNot(TaggedEqual(feedback, MegamorphicSymbolConstant()), miss);
Label try_megamorphic(this), try_megadom(this);
GotoIf(TaggedEqual(feedback, MegamorphicSymbolConstant()),
&try_megamorphic);
GotoIf(TaggedEqual(feedback, MegaDOMSymbolConstant()), &try_megadom);
Goto(miss);
BIND(&try_megamorphic);
{
TryProbeStubCache(isolate()->load_stub_cache(), p->lookup_start_object(),
CAST(p->name()), if_handler, var_handler, miss);
}
TryProbeStubCache(isolate()->load_stub_cache(), p->lookup_start_object(),
CAST(p->name()), if_handler, var_handler, miss);
BIND(&try_megadom);
{
TryMegaDOMCase(p->lookup_start_object(), lookup_start_object_map,
var_handler, p->vector(), p->slot(), miss, exit_point);
}
}
}
......
......@@ -311,6 +311,12 @@ class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler {
TVariable<MaybeObject>* var_handler,
Label* if_miss);
void TryMegaDOMCase(TNode<Object> lookup_start_object,
TNode<Map> lookup_start_object_map,
TVariable<MaybeObject>* var_handler, TNode<Object> vector,
TNode<TaggedIndex> slot, Label* miss,
ExitPoint* exit_point);
// LoadIC implementation.
void HandleLoadICHandlerCase(
const LazyLoadICParameters* p, TNode<Object> handler, Label* miss,
......
......@@ -11,6 +11,7 @@ namespace internal {
CallOptimization::CallOptimization(Isolate* isolate, Handle<Object> function) {
constant_function_ = Handle<JSFunction>::null();
is_simple_api_call_ = false;
accept_any_receiver_ = false;
expected_receiver_type_ = Handle<FunctionTemplateInfo>::null();
api_call_info_ = Handle<CallHandlerInfo>::null();
if (function->IsJSFunction()) {
......@@ -98,6 +99,7 @@ void CallOptimization::Initialize(
handle(FunctionTemplateInfo::cast(signature), isolate);
}
is_simple_api_call_ = true;
accept_any_receiver_ = function_template_info->accept_any_receiver();
}
void CallOptimization::Initialize(Isolate* isolate,
......@@ -125,6 +127,7 @@ void CallOptimization::AnalyzePossibleApiFunction(Isolate* isolate,
}
is_simple_api_call_ = true;
accept_any_receiver_ = info->accept_any_receiver();
}
} // namespace internal
} // namespace v8
......@@ -20,6 +20,10 @@ class CallOptimization {
Map holder_map) const;
bool is_constant_call() const { return !constant_function_.is_null(); }
bool accept_any_receiver() const { return accept_any_receiver_; }
bool requires_signature_check() const {
return !expected_receiver_type_.is_null();
}
Handle<JSFunction> constant_function() const {
DCHECK(is_constant_call());
......@@ -56,9 +60,13 @@ class CallOptimization {
Handle<JSFunction> function);
Handle<JSFunction> constant_function_;
bool is_simple_api_call_;
Handle<FunctionTemplateInfo> expected_receiver_type_;
Handle<CallHandlerInfo> api_call_info_;
// TODO(gsathya): Change these to be a bitfield and do a single fast check
// rather than two checks.
bool is_simple_api_call_;
bool accept_any_receiver_;
};
} // namespace internal
} // namespace v8
......
......@@ -33,6 +33,7 @@
#include "src/objects/heap-number-inl.h"
#include "src/objects/js-array-buffer-inl.h"
#include "src/objects/js-array-inl.h"
#include "src/objects/megadom-handler.h"
#include "src/objects/module-inl.h"
#include "src/objects/prototype.h"
#include "src/objects/struct-inl.h"
......@@ -59,6 +60,8 @@ char IC::TransitionMarkFromState(IC::State state) {
return 'P';
case MEGAMORPHIC:
return 'N';
case MEGADOM:
return 'D';
case GENERIC:
return 'G';
}
......@@ -566,6 +569,55 @@ static bool AddOneReceiverMapIfMissing(
return true;
}
bool IC::UpdateMegaDOMIC(const MaybeObjectHandle& handler, Handle<Name> name) {
if (!FLAG_enable_mega_dom_ic) return false;
// TODO(gsathya): Enable fuzzing once this feature is more stable.
if (FLAG_fuzzing) return false;
// TODO(gsathya): Support KeyedLoadIC, StoreIC and KeyedStoreIC.
if (!IsLoadIC()) return false;
// Check if DOM protector cell is valid.
if (!Protectors::IsMegaDOMIntact(isolate())) return false;
// Check if current lookup object is an API object
Handle<Map> map = lookup_start_object_map();
if (!InstanceTypeChecker::IsJSApiObject(map->instance_type())) return false;
Handle<Object> accessor_obj;
// TODO(gsathya): Check if there are overloads possible for this accessor and
// transition only if it isn't possible.
if (!accessor().ToHandle(&accessor_obj)) return false;
// TODO(gsathya): This is also created in IC::ComputeHandler, find a way to
// reuse it here.
CallOptimization call_optimization(isolate(), accessor_obj);
// Check if accessor is an API function
if (!call_optimization.is_simple_api_call()) return false;
// Check if accessor requires access checks
if (call_optimization.accept_any_receiver()) return false;
// Check if accessor requires signature checks
if (!call_optimization.requires_signature_check()) return false;
// Check if the receiver is the holder
CallOptimization::HolderLookup holder_lookup;
call_optimization.LookupHolderOfExpectedType(map, &holder_lookup);
if (holder_lookup != CallOptimization::kHolderIsReceiver) return false;
Handle<Context> accessor_context(call_optimization.GetAccessorContext(*map),
isolate());
Handle<MegaDomHandler> new_handler = isolate()->factory()->NewMegaDomHandler(
MaybeObjectHandle::Weak(accessor_obj),
MaybeObjectHandle::Weak(accessor_context));
nexus()->ConfigureMegaDOM(MaybeObjectHandle(new_handler));
return true;
}
bool IC::UpdatePolymorphicIC(Handle<Name> name,
const MaybeObjectHandle& handler) {
DCHECK(IsHandler(*handler));
......@@ -703,9 +755,12 @@ void IC::SetCache(Handle<Name> name, const MaybeObjectHandle& handler) {
V8_FALLTHROUGH;
case POLYMORPHIC:
if (UpdatePolymorphicIC(name, handler)) break;
if (UpdateMegaDOMIC(handler, name)) break;
if (!is_keyed() || state() == RECOMPUTE_HANDLER) {
CopyICToMegamorphicCache(name);
}
V8_FALLTHROUGH;
case MEGADOM:
ConfigureVectorState(MEGAMORPHIC, name);
V8_FALLTHROUGH;
case MEGAMORPHIC:
......@@ -875,6 +930,7 @@ Handle<Object> LoadIC::ComputeHandler(LookupIterator* lookup) {
TRACE_HANDLER_STATS(isolate(), LoadIC_SlowStub);
return LoadHandler::LoadSlow(isolate());
}
set_accessor(getter);
if ((getter->IsFunctionTemplateInfo() &&
FunctionTemplateInfo::cast(*getter).BreakAtEntry()) ||
......
......@@ -67,6 +67,8 @@ class IC {
protected:
void set_slow_stub_reason(const char* reason) { slow_stub_reason_ = reason; }
void set_accessor(Handle<Object> accessor) { accessor_ = accessor; }
MaybeHandle<Object> accessor() const { return accessor_; }
Isolate* isolate() const { return isolate_; }
......@@ -96,6 +98,7 @@ class IC {
MaybeHandle<Object> ReferenceError(Handle<Name> name);
void UpdateMonomorphicIC(const MaybeObjectHandle& handler, Handle<Name> name);
bool UpdateMegaDOMIC(const MaybeObjectHandle& handler, Handle<Name> name);
bool UpdatePolymorphicIC(Handle<Name> name, const MaybeObjectHandle& handler);
void UpdateMegamorphicCache(Handle<Map> map, Handle<Name> name,
const MaybeObjectHandle& handler);
......@@ -154,7 +157,7 @@ class IC {
State state_;
FeedbackSlotKind kind_;
Handle<Map> lookup_start_object_map_;
MaybeHandle<Object> accessor_;
MapHandles target_maps_;
bool target_maps_set_;
......
......@@ -350,6 +350,7 @@
V(_, error_start_pos_symbol) \
V(_, frozen_symbol) \
V(_, interpreter_trampoline_symbol) \
V(_, mega_dom_symbol) \
V(_, megamorphic_symbol) \
V(_, native_context_index_symbol) \
V(_, nonextensible_symbol) \
......
......@@ -52,6 +52,7 @@
#include "src/objects/lookup-inl.h"
#include "src/objects/map-inl.h"
#include "src/objects/maybe-object-inl.h"
#include "src/objects/megadom-handler-inl.h"
#include "src/objects/microtask-inl.h"
#include "src/objects/module-inl.h"
#include "src/objects/name-inl.h"
......
......@@ -335,6 +335,10 @@ Handle<Symbol> FeedbackVector::MegamorphicSentinel(Isolate* isolate) {
return isolate->factory()->megamorphic_symbol();
}
Handle<Symbol> FeedbackVector::MegaDOMSentinel(Isolate* isolate) {
return isolate->factory()->mega_dom_symbol();
}
Symbol FeedbackVector::RawUninitializedSentinel(Isolate* isolate) {
return ReadOnlyRoots(isolate).uninitialized_symbol();
}
......@@ -377,6 +381,11 @@ MaybeObject FeedbackNexus::MegamorphicSentinel() const {
*FeedbackVector::MegamorphicSentinel(GetIsolate()));
}
MaybeObject FeedbackNexus::MegaDOMSentinel() const {
return MaybeObject::FromObject(
*FeedbackVector::MegaDOMSentinel(GetIsolate()));
}
MaybeObject FeedbackNexus::FromHandle(MaybeObjectHandle slot) const {
return slot.is_null() ? HeapObjectReference::ClearedValue(config()->isolate())
: *slot;
......
......@@ -54,6 +54,7 @@ static bool IsPropertyNameFeedback(MaybeObject feedback) {
Symbol symbol = Symbol::cast(heap_object);
ReadOnlyRoots roots = symbol.GetReadOnlyRoots();
return symbol != roots.uninitialized_symbol() &&
symbol != roots.mega_dom_symbol() &&
symbol != roots.megamorphic_symbol();
}
......@@ -674,6 +675,13 @@ bool FeedbackNexus::ConfigureMegamorphic() {
return false;
}
void FeedbackNexus::ConfigureMegaDOM(const MaybeObjectHandle& handler) {
DisallowGarbageCollection no_gc;
MaybeObject sentinel = MegaDOMSentinel();
SetFeedback(sentinel, SKIP_WRITE_BARRIER, *handler, UPDATE_WRITE_BARRIER);
}
bool FeedbackNexus::ConfigureMegamorphic(IcCheckType property_type) {
DisallowGarbageCollection no_gc;
MaybeObject sentinel = MegamorphicSentinel();
......@@ -735,6 +743,10 @@ InlineCacheState FeedbackNexus::ic_state() const {
if (feedback == MegamorphicSentinel()) {
return MEGAMORPHIC;
}
if (feedback == MegaDOMSentinel()) {
DCHECK(IsLoadICKind(kind()));
return MEGADOM;
}
if (feedback->IsWeakOrCleared()) {
// Don't check if the map is cleared.
return MONOMORPHIC;
......
......@@ -322,6 +322,9 @@ class FeedbackVector
// The object that indicates a megamorphic state.
static inline Handle<Symbol> MegamorphicSentinel(Isolate* isolate);
// The object that indicates a MegaDOM state.
static inline Handle<Symbol> MegaDOMSentinel(Isolate* isolate);
// A raw version of the uninitialized sentinel that's safe to read during
// garbage collection (e.g., for patching the cache).
static inline Symbol RawUninitializedSentinel(Isolate* isolate);
......@@ -773,6 +776,8 @@ class V8_EXPORT_PRIVATE FeedbackNexus final {
void ConfigurePolymorphic(
Handle<Name> name, std::vector<MapAndHandler> const& maps_and_handlers);
void ConfigureMegaDOM(const MaybeObjectHandle& handler);
BinaryOperationHint GetBinaryOperationFeedback() const;
CompareOperationHint GetCompareOperationFeedback() const;
ForInHint GetForInFeedback() const;
......@@ -847,6 +852,7 @@ class V8_EXPORT_PRIVATE FeedbackNexus final {
inline MaybeObject UninitializedSentinel() const;
inline MaybeObject MegamorphicSentinel() const;
inline MaybeObject MegaDOMSentinel() const;
// Create an array. The caller must install it in a feedback vector slot.
Handle<WeakFixedArray> CreateArrayOfSize(int length);
......
......@@ -258,6 +258,7 @@ TYPED_ARRAYS(TYPED_ARRAY_IS_TYPE_FUNCTION_DECL)
V(_, FunctionTemplateInfoMap, function_template_info_map, \
FunctionTemplateInfo) \
V(_, HeapNumberMap, heap_number_map, HeapNumber) \
V(_, MegaDomHandlerMap, mega_dom_handler_map, MegaDomHandler) \
V(_, MetaMap, meta_map, Map) \
V(_, PreparseDataMap, preparse_data_map, PreparseData) \
V(_, PrototypeInfoMap, prototype_info_map, PrototypeInfo) \
......
// Copyright 2021 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_OBJECTS_MEGADOM_HANDLER_INL_H_
#define V8_OBJECTS_MEGADOM_HANDLER_INL_H_
#include "src/objects/megadom-handler.h"
#include "src/objects/objects-inl.h" // Needed for write barriers
// Has to be the last include (doesn't have include guards):
#include "src/objects/object-macros.h"
namespace v8 {
namespace internal {
#include "torque-generated/src/objects/megadom-handler-tq-inl.inc"
TQ_OBJECT_CONSTRUCTORS_IMPL(MegaDomHandler)
} // namespace internal
} // namespace v8
#include "src/objects/object-macros-undef.h"
#endif // V8_OBJECTS_MEGADOM_HANDLER_INL_H_
// Copyright 2021 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_OBJECTS_MEGADOM_HANDLER_H_
#define V8_OBJECTS_MEGADOM_HANDLER_H_
#include "src/objects/heap-object.h"
// Has to be the last include (doesn't have include guards):
#include "src/objects/object-macros.h"
namespace v8 {
namespace internal {
#include "torque-generated/src/objects/megadom-handler-tq.inc"
class MegaDomHandler
: public TorqueGeneratedMegaDomHandler<MegaDomHandler, HeapObject> {
public:
void BriefPrintDetails(std::ostream& os);
class BodyDescriptor;
TQ_OBJECT_CONSTRUCTORS(MegaDomHandler)
};
} // namespace internal
} // namespace v8
#include "src/objects/object-macros-undef.h"
#endif // V8_OBJECTS_MEGADOM_HANDLER_H_
// Copyright 2021 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.
@generateCppClass
@generatePrint
@generateBodyDescriptor
extern class MegaDomHandler extends HeapObject {
accessor: MaybeObject;
context: MaybeObject;
}
......@@ -166,6 +166,7 @@ class ZoneForwardList;
V(LoadHandler) \
V(Map) \
V(MapCache) \
V(MegaDomHandler) \
V(Module) \
V(Microtask) \
V(Name) \
......
......@@ -15,6 +15,7 @@
#include "src/objects/hash-table.h"
#include "src/objects/js-collection.h"
#include "src/objects/js-weak-refs.h"
#include "src/objects/megadom-handler-inl.h"
#include "src/objects/objects-body-descriptors.h"
#include "src/objects/oddball.h"
#include "src/objects/ordered-hash-table-inl.h"
......
......@@ -101,6 +101,7 @@
#include "src/objects/literal-objects-inl.h"
#include "src/objects/map-inl.h"
#include "src/objects/map.h"
#include "src/objects/megadom-handler-inl.h"
#include "src/objects/microtask-inl.h"
#include "src/objects/module-inl.h"
#include "src/objects/promise-inl.h"
......@@ -2199,6 +2200,10 @@ void Tuple2::BriefPrintDetails(std::ostream& os) {
os << " " << Brief(value1()) << ", " << Brief(value2());
}
void MegaDomHandler::BriefPrintDetails(std::ostream& os) {
os << " " << Brief(accessor()) << ", " << Brief(context());
}
void ClassPositions::BriefPrintDetails(std::ostream& os) {
os << " " << start() << ", " << end();
}
......
......@@ -7,6 +7,7 @@
#include "src/objects/descriptor-array.h"
#include "src/objects/fixed-array.h"
#include "src/objects/heap-object.h"
#include "src/objects/megadom-handler.h"
#include "src/objects/objects.h"
// Has to be the last include (doesn't have include guards):
......
......@@ -88,6 +88,7 @@ class Symbol;
V(Map, fixed_double_array_map, FixedDoubleArrayMap) \
V(Map, global_dictionary_map, GlobalDictionaryMap) \
V(Map, many_closures_cell_map, ManyClosuresCellMap) \
V(Map, mega_dom_handler_map, MegaDomHandlerMap) \
V(Map, module_info_map, ModuleInfoMap) \
V(Map, name_dictionary_map, NameDictionaryMap) \
V(Map, no_closures_cell_map, NoClosuresCellMap) \
......@@ -210,6 +211,7 @@ class Symbol;
/* Protectors */ \
V(PropertyCell, array_constructor_protector, ArrayConstructorProtector) \
V(PropertyCell, no_elements_protector, NoElementsProtector) \
V(PropertyCell, mega_dom_protector, MegaDOMProtector) \
V(PropertyCell, is_concat_spreadable_protector, IsConcatSpreadableProtector) \
V(PropertyCell, array_species_protector, ArraySpeciesProtector) \
V(PropertyCell, typed_array_species_protector, TypedArraySpeciesProtector) \
......
// Copyright 2021 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.
//
// Flags: --enable-mega-dom-ic --allow-natives-syntax
function load(obj) {
return obj.nodeType;
}
%PrepareFunctionForOptimization(load);
var a = new d8.dom.Div();
var b = new d8.dom.Div();
b.b = 1;
var c = new d8.dom.Div();
c.c = 1;
var d = new d8.dom.Div();
d.d = 1;
var e = new d8.dom.Div();
e.e = 1;
var f = new d8.dom.Div();
f.f = 1;
const objs = [
a, b, c, d, e, f
];
function test() {
let result = 0;
for (let i = 0; i < objs.length; i++) {
result += load(objs[i]);
}
return result;
}
%PrepareFunctionForOptimization(test);
let result = test();
assertEquals(6, result);
assertEquals(load({}), undefined);
assertEquals(load({ nodeType: 'foo' }), 'foo');
%OptimizeFunctionOnNextCall(test);
result = test();
assertEquals(6, result);
assertEquals(load({}), undefined)
assertEquals(load({nodeType: 'foo'}), 'foo')
// Copyright 2021 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.
//
// Flags: --enable-mega-dom-ic --allow-natives-syntax
function load(obj) {
return obj.nodeType;
}
%PrepareFunctionForOptimization(load);
var a = new d8.dom.Div();
var b = new d8.dom.Div();
b.b = 1;
var c = new d8.dom.Div();
c.c = 1;
var d = new d8.dom.Div();
d.d = 1;
var e = new d8.dom.Div();
e.e = 1;
var f = new d8.dom.Div();
f.f = 1;
const objs = [
a, b, c, d, e, f
];
function test() {
let result = 0;
for (let i = 0; i < objs.length; i++) {
result += load(objs[i]);
}
return result;
}
%PrepareFunctionForOptimization(test);
let result = test();
assertEquals(6, result);
%OptimizeFunctionOnNextCall(test);
result = test();
assertEquals(6, result);
This diff is collapsed.
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