Commit 5480e036 authored by Maya Lekova's avatar Maya Lekova Committed by V8 LUCI CQ

[megadom] Add TF inlining for Megadom

The generated code checks if the receiver is a JS_API_OBJECT and if the
receiver requires an access check, and if not it lowers the call to an
API call.

We also add compilation dependencies on the protector cell to deopt if
our invariants change. (Note - the actual invalidation of these cells
will be implemented in a follow up CL)

Bug: v8:11321
Change-Id: I15722f1e5fac7176e292da4a35186e4609636aba
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2719563
Commit-Queue: Maya Lekova <mslekova@chromium.org>
Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Reviewed-by: 's avatarCamillo Bruni <cbruni@chromium.org>
Reviewed-by: 's avatarTobias Tebbi <tebbi@chromium.org>
Cr-Commit-Position: refs/heads/main@{#80748}
parent 51d2256b
...@@ -1386,6 +1386,16 @@ Local<FunctionTemplate> FunctionTemplate::New( ...@@ -1386,6 +1386,16 @@ Local<FunctionTemplate> FunctionTemplate::New(
return Local<FunctionTemplate>(); return Local<FunctionTemplate>();
} }
if (instance_type != 0) {
if (!Utils::ApiCheck(
instance_type >= i::Internals::kFirstJSApiObjectType &&
instance_type <= i::Internals::kLastJSApiObjectType,
"FunctionTemplate::New",
"instance_type is outside the range of valid JSApiObject types.")) {
return Local<FunctionTemplate>();
}
}
ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate); ENTER_V8_NO_SCRIPT_NO_EXCEPTION(i_isolate);
return FunctionTemplateNew( return FunctionTemplateNew(
i_isolate, callback, data, signature, length, behavior, false, i_isolate, callback, data, signature, length, behavior, false,
......
...@@ -1064,6 +1064,11 @@ bool CompilationDependencies::DependOnProtector(const PropertyCellRef& cell) { ...@@ -1064,6 +1064,11 @@ bool CompilationDependencies::DependOnProtector(const PropertyCellRef& cell) {
return true; return true;
} }
bool CompilationDependencies::DependOnMegaDOMProtector() {
return DependOnProtector(
MakeRef(broker_, broker_->isolate()->factory()->mega_dom_protector()));
}
bool CompilationDependencies::DependOnArrayBufferDetachingProtector() { bool CompilationDependencies::DependOnArrayBufferDetachingProtector() {
return DependOnProtector(MakeRef( return DependOnProtector(MakeRef(
broker_, broker_,
......
...@@ -89,6 +89,7 @@ class V8_EXPORT_PRIVATE CompilationDependencies : public ZoneObject { ...@@ -89,6 +89,7 @@ class V8_EXPORT_PRIVATE CompilationDependencies : public ZoneObject {
bool DependOnPromiseHookProtector(); bool DependOnPromiseHookProtector();
bool DependOnPromiseSpeciesProtector(); bool DependOnPromiseSpeciesProtector();
bool DependOnPromiseThenProtector(); bool DependOnPromiseThenProtector();
bool DependOnMegaDOMProtector();
// Record the assumption that {site}'s {ElementsKind} doesn't change. // Record the assumption that {site}'s {ElementsKind} doesn't change.
void DependOnElementsKind(const AllocationSiteRef& site); void DependOnElementsKind(const AllocationSiteRef& site);
......
...@@ -1508,6 +1508,10 @@ bool FunctionTemplateInfoRef::is_signature_undefined() const { ...@@ -1508,6 +1508,10 @@ bool FunctionTemplateInfoRef::is_signature_undefined() const {
} }
HEAP_ACCESSOR_C(FunctionTemplateInfo, bool, accept_any_receiver) HEAP_ACCESSOR_C(FunctionTemplateInfo, bool, accept_any_receiver)
HEAP_ACCESSOR_C(FunctionTemplateInfo, int16_t,
allowed_receiver_instance_type_range_start)
HEAP_ACCESSOR_C(FunctionTemplateInfo, int16_t,
allowed_receiver_instance_type_range_end)
HolderLookupResult FunctionTemplateInfoRef::LookupHolderOfExpectedType( HolderLookupResult FunctionTemplateInfoRef::LookupHolderOfExpectedType(
MapRef receiver_map) { MapRef receiver_map) {
......
...@@ -745,6 +745,9 @@ class FunctionTemplateInfoRef : public HeapObjectRef { ...@@ -745,6 +745,9 @@ class FunctionTemplateInfoRef : public HeapObjectRef {
bool is_signature_undefined() const; bool is_signature_undefined() const;
bool accept_any_receiver() const; bool accept_any_receiver() const;
int16_t allowed_receiver_instance_type_range_start() const;
int16_t allowed_receiver_instance_type_range_end() const;
base::Optional<CallHandlerInfoRef> call_code() const; base::Optional<CallHandlerInfoRef> call_code() const;
ZoneVector<Address> c_functions() const; ZoneVector<Address> c_functions() const;
ZoneVector<const CFunctionInfo*> c_signatures() const; ZoneVector<const CFunctionInfo*> c_signatures() const;
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include "src/objects/js-array-inl.h" #include "src/objects/js-array-inl.h"
#include "src/objects/literal-objects-inl.h" #include "src/objects/literal-objects-inl.h"
#include "src/objects/map-updater.h" #include "src/objects/map-updater.h"
#include "src/objects/megadom-handler-inl.h"
#include "src/objects/objects-inl.h" #include "src/objects/objects-inl.h"
#include "src/objects/oddball.h" #include "src/objects/oddball.h"
#include "src/objects/property-cell.h" #include "src/objects/property-cell.h"
...@@ -425,6 +426,12 @@ bool ElementAccessFeedback::HasOnlyStringMaps(JSHeapBroker* broker) const { ...@@ -425,6 +426,12 @@ bool ElementAccessFeedback::HasOnlyStringMaps(JSHeapBroker* broker) const {
return true; return true;
} }
MegaDOMPropertyAccessFeedback::MegaDOMPropertyAccessFeedback(
FunctionTemplateInfoRef info_ref, FeedbackSlotKind slot_kind)
: ProcessedFeedback(kMegaDOMPropertyAccess, slot_kind), info_(info_ref) {
DCHECK(IsLoadICKind(slot_kind));
}
NamedAccessFeedback::NamedAccessFeedback(NameRef const& name, NamedAccessFeedback::NamedAccessFeedback(NameRef const& name,
ZoneVector<MapRef> const& maps, ZoneVector<MapRef> const& maps,
FeedbackSlotKind slot_kind) FeedbackSlotKind slot_kind)
...@@ -510,6 +517,21 @@ ProcessedFeedback const& JSHeapBroker::ReadFeedbackForPropertyAccess( ...@@ -510,6 +517,21 @@ ProcessedFeedback const& JSHeapBroker::ReadFeedbackForPropertyAccess(
base::Optional<NameRef> name = base::Optional<NameRef> name =
static_name.has_value() ? static_name : GetNameFeedback(nexus); static_name.has_value() ? static_name : GetNameFeedback(nexus);
if (nexus.ic_state() == InlineCacheState::MEGADOM) {
DCHECK(maps.empty());
MaybeObjectHandle maybe_handler = nexus.ExtractMegaDOMHandler();
if (!maybe_handler.is_null()) {
Handle<MegaDomHandler> handler =
Handle<MegaDomHandler>::cast(maybe_handler.object());
if (!handler->accessor(kAcquireLoad)->IsCleared()) {
FunctionTemplateInfoRef info = MakeRefAssumeMemoryFence(
this, FunctionTemplateInfo::cast(
handler->accessor(kAcquireLoad).GetHeapObject()));
return *zone()->New<MegaDOMPropertyAccessFeedback>(info, kind);
}
}
}
// If no maps were found for a non-megamorphic access, then our maps died // If no maps were found for a non-megamorphic access, then our maps died
// and we should soft-deopt. // and we should soft-deopt.
if (maps.empty() && nexus.ic_state() != InlineCacheState::MEGAMORPHIC) { if (maps.empty() && nexus.ic_state() != InlineCacheState::MEGAMORPHIC) {
...@@ -936,6 +958,12 @@ NamedAccessFeedback const& ProcessedFeedback::AsNamedAccess() const { ...@@ -936,6 +958,12 @@ NamedAccessFeedback const& ProcessedFeedback::AsNamedAccess() const {
return *static_cast<NamedAccessFeedback const*>(this); return *static_cast<NamedAccessFeedback const*>(this);
} }
MegaDOMPropertyAccessFeedback const&
ProcessedFeedback::AsMegaDOMPropertyAccess() const {
CHECK_EQ(kMegaDOMPropertyAccess, kind());
return *static_cast<MegaDOMPropertyAccessFeedback const*>(this);
}
LiteralFeedback const& ProcessedFeedback::AsLiteral() const { LiteralFeedback const& ProcessedFeedback::AsLiteral() const {
CHECK_EQ(kLiteral, kind()); CHECK_EQ(kLiteral, kind());
return *static_cast<LiteralFeedback const*>(this); return *static_cast<LiteralFeedback const*>(this);
......
...@@ -1037,6 +1037,98 @@ Reduction JSNativeContextSpecialization::ReduceJSStoreGlobal(Node* node) { ...@@ -1037,6 +1037,98 @@ Reduction JSNativeContextSpecialization::ReduceJSStoreGlobal(Node* node) {
} }
} }
Reduction JSNativeContextSpecialization::ReduceMegaDOMPropertyAccess(
Node* node, Node* value, MegaDOMPropertyAccessFeedback const& feedback,
FeedbackSource const& source) {
DCHECK(node->opcode() == IrOpcode::kJSLoadNamed ||
node->opcode() == IrOpcode::kJSLoadProperty);
// TODO(mslekova): Add support and tests for kJSLoadNamedFromSuper.
static_assert(JSLoadNamedNode::ObjectIndex() == 0 &&
JSLoadPropertyNode::ObjectIndex() == 0,
"Assumptions about ObjectIndex have changed, please update "
"this function.");
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
Node* frame_state = NodeProperties::GetFrameStateInput(node);
Node* lookup_start_object = NodeProperties::GetValueInput(node, 0);
if (!dependencies()->DependOnMegaDOMProtector()) {
return NoChange();
}
FunctionTemplateInfoRef function_template_info = feedback.info();
int16_t range_start =
function_template_info.allowed_receiver_instance_type_range_start();
int16_t range_end =
function_template_info.allowed_receiver_instance_type_range_end();
DCHECK_IMPLIES(range_start == 0, range_end == 0);
DCHECK_LE(range_start, range_end);
// TODO(mslekova): This could be a new InstanceTypeCheck operator
// that gets lowered later on (e.g. during generic lowering).
Node* receiver_map = effect =
graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
lookup_start_object, effect, control);
Node* receiver_instance_type = effect = graph()->NewNode(
simplified()->LoadField(AccessBuilder::ForMapInstanceType()),
receiver_map, effect, control);
if (FLAG_embedder_instance_types && range_start != 0) {
// Embedder instance ID is set, doing a simple range check.
Node* diff_to_start =
graph()->NewNode(simplified()->NumberSubtract(), receiver_instance_type,
jsgraph()->Constant(range_start));
Node* range_length = jsgraph()->Constant(range_end - range_start);
// TODO(mslekova): Once we have the InstanceTypeCheck operator, we could
// lower it to Uint32LessThan later on to perform what is done in bounds.h.
Node* check = graph()->NewNode(simplified()->NumberLessThanOrEqual(),
diff_to_start, range_length);
effect = graph()->NewNode(
simplified()->CheckIf(DeoptimizeReason::kWrongInstanceType), check,
effect, control);
} else if (function_template_info.is_signature_undefined()) {
// Signature is undefined, enough to check if the receiver is a JSApiObject.
Node* check =
graph()->NewNode(simplified()->NumberEqual(), receiver_instance_type,
jsgraph()->Constant(JS_API_OBJECT_TYPE));
effect = graph()->NewNode(
simplified()->CheckIf(DeoptimizeReason::kWrongInstanceType), check,
effect, control);
} else {
// Calling out to builtin to do signature check.
Callable callable = Builtins::CallableFor(
isolate(), Builtin::kCallFunctionTemplate_CheckCompatibleReceiver);
int stack_arg_count = callable.descriptor().GetStackParameterCount() +
1 /* implicit receiver */;
CallDescriptor* call_descriptor = Linkage::GetStubCallDescriptor(
graph()->zone(), callable.descriptor(), stack_arg_count,
CallDescriptor::kNeedsFrameState, Operator::kNoProperties);
Node* inputs[8] = {jsgraph()->HeapConstant(callable.code()),
jsgraph()->Constant(function_template_info),
jsgraph()->Constant(stack_arg_count),
lookup_start_object,
jsgraph()->Constant(native_context()),
frame_state,
effect,
control};
value = effect = control =
graph()->NewNode(common()->Call(call_descriptor), 8, inputs);
return Replace(value);
}
value = InlineApiCall(lookup_start_object, lookup_start_object, frame_state,
nullptr /*value*/, &effect, &control,
function_template_info);
ReplaceWithValue(node, value, effect, control);
return Replace(value);
}
Reduction JSNativeContextSpecialization::ReduceNamedAccess( Reduction JSNativeContextSpecialization::ReduceNamedAccess(
Node* node, Node* value, NamedAccessFeedback const& feedback, Node* node, Node* value, NamedAccessFeedback const& feedback,
AccessMode access_mode, Node* key) { AccessMode access_mode, Node* key) {
...@@ -2047,6 +2139,11 @@ Reduction JSNativeContextSpecialization::ReducePropertyAccess( ...@@ -2047,6 +2139,11 @@ Reduction JSNativeContextSpecialization::ReducePropertyAccess(
case ProcessedFeedback::kNamedAccess: case ProcessedFeedback::kNamedAccess:
return ReduceNamedAccess(node, value, feedback.AsNamedAccess(), return ReduceNamedAccess(node, value, feedback.AsNamedAccess(),
access_mode, key); access_mode, key);
case ProcessedFeedback::kMegaDOMPropertyAccess:
DCHECK_EQ(access_mode, AccessMode::kLoad);
DCHECK_NULL(key);
return ReduceMegaDOMPropertyAccess(
node, value, feedback.AsMegaDOMPropertyAccess(), source);
case ProcessedFeedback::kElementAccess: case ProcessedFeedback::kElementAccess:
DCHECK_EQ(feedback.AsElementAccess().keyed_mode().access_mode(), DCHECK_EQ(feedback.AsElementAccess().keyed_mode().access_mode(),
access_mode); access_mode);
......
...@@ -107,6 +107,9 @@ class V8_EXPORT_PRIVATE JSNativeContextSpecialization final ...@@ -107,6 +107,9 @@ class V8_EXPORT_PRIVATE JSNativeContextSpecialization final
Reduction ReduceNamedAccess(Node* node, Node* value, Reduction ReduceNamedAccess(Node* node, Node* value,
NamedAccessFeedback const& feedback, NamedAccessFeedback const& feedback,
AccessMode access_mode, Node* key = nullptr); AccessMode access_mode, Node* key = nullptr);
Reduction ReduceMegaDOMPropertyAccess(
Node* node, Node* value, MegaDOMPropertyAccessFeedback const& feedback,
FeedbackSource const& source);
Reduction ReduceGlobalAccess(Node* node, Node* lookup_start_object, Reduction ReduceGlobalAccess(Node* node, Node* lookup_start_object,
Node* receiver, Node* value, NameRef const& name, Node* receiver, Node* value, NameRef const& name,
AccessMode access_mode, Node* key, AccessMode access_mode, Node* key,
......
...@@ -20,6 +20,7 @@ class ForInFeedback; ...@@ -20,6 +20,7 @@ class ForInFeedback;
class GlobalAccessFeedback; class GlobalAccessFeedback;
class InstanceOfFeedback; class InstanceOfFeedback;
class LiteralFeedback; class LiteralFeedback;
class MegaDOMPropertyAccessFeedback;
class NamedAccessFeedback; class NamedAccessFeedback;
class RegExpLiteralFeedback; class RegExpLiteralFeedback;
class TemplateObjectFeedback; class TemplateObjectFeedback;
...@@ -36,6 +37,7 @@ class ProcessedFeedback : public ZoneObject { ...@@ -36,6 +37,7 @@ class ProcessedFeedback : public ZoneObject {
kGlobalAccess, kGlobalAccess,
kInstanceOf, kInstanceOf,
kLiteral, kLiteral,
kMegaDOMPropertyAccess,
kNamedAccess, kNamedAccess,
kRegExpLiteral, kRegExpLiteral,
kTemplateObject, kTemplateObject,
...@@ -53,6 +55,7 @@ class ProcessedFeedback : public ZoneObject { ...@@ -53,6 +55,7 @@ class ProcessedFeedback : public ZoneObject {
GlobalAccessFeedback const& AsGlobalAccess() const; GlobalAccessFeedback const& AsGlobalAccess() const;
InstanceOfFeedback const& AsInstanceOf() const; InstanceOfFeedback const& AsInstanceOf() const;
NamedAccessFeedback const& AsNamedAccess() const; NamedAccessFeedback const& AsNamedAccess() const;
MegaDOMPropertyAccessFeedback const& AsMegaDOMPropertyAccess() const;
LiteralFeedback const& AsLiteral() const; LiteralFeedback const& AsLiteral() const;
RegExpLiteralFeedback const& AsRegExpLiteral() const; RegExpLiteralFeedback const& AsRegExpLiteral() const;
TemplateObjectFeedback const& AsTemplateObject() const; TemplateObjectFeedback const& AsTemplateObject() const;
...@@ -169,6 +172,17 @@ class NamedAccessFeedback : public ProcessedFeedback { ...@@ -169,6 +172,17 @@ class NamedAccessFeedback : public ProcessedFeedback {
ZoneVector<MapRef> const maps_; ZoneVector<MapRef> const maps_;
}; };
class MegaDOMPropertyAccessFeedback : public ProcessedFeedback {
public:
MegaDOMPropertyAccessFeedback(FunctionTemplateInfoRef info_ref,
FeedbackSlotKind slot_kind);
FunctionTemplateInfoRef const& info() const { return info_; }
private:
FunctionTemplateInfoRef const info_;
};
class CallFeedback : public ProcessedFeedback { class CallFeedback : public ProcessedFeedback {
public: public:
CallFeedback(base::Optional<HeapObjectRef> target, float frequency, CallFeedback(base::Optional<HeapObjectRef> target, float frequency,
......
...@@ -1656,6 +1656,14 @@ void PerIsolateData::SetSnapshotObjectCtor(Local<FunctionTemplate> ctor) { ...@@ -1656,6 +1656,14 @@ void PerIsolateData::SetSnapshotObjectCtor(Local<FunctionTemplate> ctor) {
snapshot_object_ctor_.Reset(isolate_, ctor); snapshot_object_ctor_.Reset(isolate_, ctor);
} }
Local<FunctionTemplate> PerIsolateData::GetDomNodeCtor() const {
return dom_node_ctor_.Get(isolate_);
}
void PerIsolateData::SetDomNodeCtor(Local<FunctionTemplate> ctor) {
dom_node_ctor_.Reset(isolate_, ctor);
}
PerIsolateData::RealmScope::RealmScope(PerIsolateData* data) : data_(data) { PerIsolateData::RealmScope::RealmScope(PerIsolateData* data) : data_(data) {
data_->realm_count_ = 1; data_->realm_count_ = 1;
data_->realm_current_ = 0; data_->realm_current_ = 0;
...@@ -2992,26 +3000,58 @@ Local<String> Shell::Stringify(Isolate* isolate, Local<Value> value) { ...@@ -2992,26 +3000,58 @@ Local<String> Shell::Stringify(Isolate* isolate, Local<Value> value) {
void Shell::NodeTypeCallback(const v8::FunctionCallbackInfo<v8::Value>& args) { void Shell::NodeTypeCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::Isolate* isolate = args.GetIsolate(); v8::Isolate* isolate = args.GetIsolate();
// TODO(mslekova): Enable this once we have signature check in TF.
PerIsolateData* data = PerIsolateData::Get(isolate);
CHECK(data->GetDomNodeCtor()->HasInstance(args.This()));
args.GetReturnValue().Set(v8::Number::New(isolate, 1)); args.GetReturnValue().Set(v8::Number::New(isolate, 1));
} }
Local<FunctionTemplate> Shell::CreateNodeTemplates(Isolate* isolate) { Local<FunctionTemplate> NewDOMFunctionTemplate(Isolate* isolate,
Local<FunctionTemplate> node = FunctionTemplate::New(isolate); uint16_t instance_type) {
return FunctionTemplate::New(
isolate, nullptr, Local<Value>(), Local<Signature>(), 0,
ConstructorBehavior::kAllow, SideEffectType::kHasSideEffect, nullptr,
instance_type);
}
Local<FunctionTemplate> Shell::CreateEventTargetTemplate(Isolate* isolate) {
Local<FunctionTemplate> event_target =
NewDOMFunctionTemplate(isolate, i::Internals::kFirstJSApiObjectType + 1);
return event_target;
}
Local<FunctionTemplate> Shell::CreateNodeTemplates(
Isolate* isolate, Local<FunctionTemplate> event_target) {
Local<FunctionTemplate> node =
NewDOMFunctionTemplate(isolate, i::Internals::kFirstJSApiObjectType + 2);
node->Inherit(event_target);
PerIsolateData* data = PerIsolateData::Get(isolate);
data->SetDomNodeCtor(node);
Local<ObjectTemplate> proto_template = node->PrototypeTemplate(); Local<ObjectTemplate> proto_template = node->PrototypeTemplate();
Local<Signature> signature = v8::Signature::New(isolate, node); Local<Signature> signature = v8::Signature::New(isolate, node);
Local<FunctionTemplate> nodeType = FunctionTemplate::New( Local<FunctionTemplate> nodeType = FunctionTemplate::New(
isolate, NodeTypeCallback, Local<Value>(), signature); isolate, NodeTypeCallback, Local<Value>(), signature, 0,
ConstructorBehavior::kThrow, SideEffectType::kHasSideEffect, nullptr,
i::Internals::kFirstJSApiObjectType,
i::Internals::kFirstJSApiObjectType + 3,
i::Internals::kFirstJSApiObjectType + 5);
nodeType->SetAcceptAnyReceiver(false); nodeType->SetAcceptAnyReceiver(false);
proto_template->SetAccessorProperty( proto_template->SetAccessorProperty(
String::NewFromUtf8Literal(isolate, "nodeType"), nodeType); String::NewFromUtf8Literal(isolate, "nodeType"), nodeType);
Local<FunctionTemplate> element = FunctionTemplate::New(isolate); Local<FunctionTemplate> element =
NewDOMFunctionTemplate(isolate, i::Internals::kFirstJSApiObjectType + 3);
element->Inherit(node); element->Inherit(node);
Local<FunctionTemplate> html_element = FunctionTemplate::New(isolate); Local<FunctionTemplate> html_element =
NewDOMFunctionTemplate(isolate, i::Internals::kFirstJSApiObjectType + 4);
html_element->Inherit(element); html_element->Inherit(element);
Local<FunctionTemplate> div_element = FunctionTemplate::New(isolate); Local<FunctionTemplate> div_element =
NewDOMFunctionTemplate(isolate, i::Internals::kFirstJSApiObjectType + 5);
div_element->Inherit(html_element); div_element->Inherit(html_element);
return div_element; return div_element;
...@@ -3210,7 +3250,11 @@ Local<ObjectTemplate> Shell::CreateD8Template(Isolate* isolate) { ...@@ -3210,7 +3250,11 @@ Local<ObjectTemplate> Shell::CreateD8Template(Isolate* isolate) {
} }
{ {
Local<ObjectTemplate> dom_template = ObjectTemplate::New(isolate); Local<ObjectTemplate> dom_template = ObjectTemplate::New(isolate);
dom_template->Set(isolate, "Div", Shell::CreateNodeTemplates(isolate)); Local<FunctionTemplate> event_target =
Shell::CreateEventTargetTemplate(isolate);
dom_template->Set(isolate, "EventTarget", event_target);
dom_template->Set(isolate, "Div",
Shell::CreateNodeTemplates(isolate, event_target));
d8_template->Set(isolate, "dom", dom_template); d8_template->Set(isolate, "dom", dom_template);
} }
{ {
......
...@@ -324,6 +324,9 @@ class PerIsolateData { ...@@ -324,6 +324,9 @@ class PerIsolateData {
Local<FunctionTemplate> GetSnapshotObjectCtor() const; Local<FunctionTemplate> GetSnapshotObjectCtor() const;
void SetSnapshotObjectCtor(Local<FunctionTemplate> ctor); void SetSnapshotObjectCtor(Local<FunctionTemplate> ctor);
Local<FunctionTemplate> GetDomNodeCtor() const;
void SetDomNodeCtor(Local<FunctionTemplate> ctor);
private: private:
friend class Shell; friend class Shell;
friend class RealmScope; friend class RealmScope;
...@@ -344,6 +347,7 @@ class PerIsolateData { ...@@ -344,6 +347,7 @@ class PerIsolateData {
#endif #endif
Global<FunctionTemplate> test_api_object_ctor_; Global<FunctionTemplate> test_api_object_ctor_;
Global<FunctionTemplate> snapshot_object_ctor_; Global<FunctionTemplate> snapshot_object_ctor_;
Global<FunctionTemplate> dom_node_ctor_;
int RealmIndexOrThrow(const v8::FunctionCallbackInfo<v8::Value>& args, int RealmIndexOrThrow(const v8::FunctionCallbackInfo<v8::Value>& args,
int arg_offset); int arg_offset);
...@@ -741,7 +745,9 @@ class Shell : public i::AllStatic { ...@@ -741,7 +745,9 @@ class Shell : public i::AllStatic {
static void NodeTypeCallback(const v8::FunctionCallbackInfo<v8::Value>& args); static void NodeTypeCallback(const v8::FunctionCallbackInfo<v8::Value>& args);
static Local<FunctionTemplate> CreateNodeTemplates(Isolate* isolate); static Local<FunctionTemplate> CreateEventTargetTemplate(Isolate* isolate);
static Local<FunctionTemplate> CreateNodeTemplates(
Isolate* isolate, Local<FunctionTemplate> event_target);
static Local<ObjectTemplate> CreateGlobalTemplate(Isolate* isolate); static Local<ObjectTemplate> CreateGlobalTemplate(Isolate* isolate);
static Local<ObjectTemplate> CreateOSTemplate(Isolate* isolate); static Local<ObjectTemplate> CreateOSTemplate(Isolate* isolate);
static Local<FunctionTemplate> CreateWorkerTemplate(Isolate* isolate); static Local<FunctionTemplate> CreateWorkerTemplate(Isolate* isolate);
......
...@@ -3527,7 +3527,7 @@ Handle<MegaDomHandler> Factory::NewMegaDomHandler(MaybeObjectHandle accessor, ...@@ -3527,7 +3527,7 @@ Handle<MegaDomHandler> Factory::NewMegaDomHandler(MaybeObjectHandle accessor,
Handle<Map> map = read_only_roots().mega_dom_handler_map_handle(); Handle<Map> map = read_only_roots().mega_dom_handler_map_handle();
MegaDomHandler handler = MegaDomHandler::cast(New(map, AllocationType::kOld)); MegaDomHandler handler = MegaDomHandler::cast(New(map, AllocationType::kOld));
DisallowGarbageCollection no_gc; DisallowGarbageCollection no_gc;
handler.set_accessor(*accessor); handler.set_accessor(*accessor, kReleaseStore);
handler.set_context(*context); handler.set_context(*context);
return handle(handler, isolate()); return handle(handler, isolate());
} }
......
...@@ -642,9 +642,16 @@ bool IC::UpdateMegaDOMIC(const MaybeObjectHandle& handler, Handle<Name> name) { ...@@ -642,9 +642,16 @@ bool IC::UpdateMegaDOMIC(const MaybeObjectHandle& handler, Handle<Name> name) {
Handle<Context> accessor_context(call_optimization.GetAccessorContext(*map), Handle<Context> accessor_context(call_optimization.GetAccessorContext(*map),
isolate()); isolate());
Handle<FunctionTemplateInfo> fti;
if (accessor_obj->IsJSFunction()) {
fti = handle(JSFunction::cast(*accessor_obj).shared().get_api_func_data(),
isolate());
} else {
fti = Handle<FunctionTemplateInfo>::cast(accessor_obj);
}
Handle<MegaDomHandler> new_handler = isolate()->factory()->NewMegaDomHandler( Handle<MegaDomHandler> new_handler = isolate()->factory()->NewMegaDomHandler(
MaybeObjectHandle::Weak(accessor_obj), MaybeObjectHandle::Weak(fti), MaybeObjectHandle::Weak(accessor_context));
MaybeObjectHandle::Weak(accessor_context));
nexus()->ConfigureMegaDOM(MaybeObjectHandle(new_handler)); nexus()->ConfigureMegaDOM(MaybeObjectHandle(new_handler));
return true; return true;
} }
......
...@@ -1089,6 +1089,20 @@ int FeedbackNexus::ExtractMapsAndFeedback( ...@@ -1089,6 +1089,20 @@ int FeedbackNexus::ExtractMapsAndFeedback(
return found; return found;
} }
MaybeObjectHandle FeedbackNexus::ExtractMegaDOMHandler() {
DCHECK(ic_state() == InlineCacheState::MEGADOM);
DisallowGarbageCollection no_gc;
auto pair = GetFeedbackPair();
MaybeObject maybe_handler = pair.second;
if (!maybe_handler->IsCleared()) {
MaybeObjectHandle handler = config()->NewHandle(maybe_handler);
return handler;
}
return MaybeObjectHandle();
}
int FeedbackNexus::ExtractMapsAndHandlers( int FeedbackNexus::ExtractMapsAndHandlers(
std::vector<MapAndHandler>* maps_and_handlers, std::vector<MapAndHandler>* maps_and_handlers,
TryUpdateHandler map_handler) const { TryUpdateHandler map_handler) const {
......
...@@ -818,6 +818,7 @@ class V8_EXPORT_PRIVATE FeedbackNexus final { ...@@ -818,6 +818,7 @@ class V8_EXPORT_PRIVATE FeedbackNexus final {
Handle<Name> name, std::vector<MapAndHandler> const& maps_and_handlers); Handle<Name> name, std::vector<MapAndHandler> const& maps_and_handlers);
void ConfigureMegaDOM(const MaybeObjectHandle& handler); void ConfigureMegaDOM(const MaybeObjectHandle& handler);
MaybeObjectHandle ExtractMegaDOMHandler();
BinaryOperationHint GetBinaryOperationFeedback() const; BinaryOperationHint GetBinaryOperationFeedback() const;
CompareOperationHint GetCompareOperationFeedback() const; CompareOperationHint GetCompareOperationFeedback() const;
......
...@@ -18,6 +18,8 @@ namespace internal { ...@@ -18,6 +18,8 @@ namespace internal {
TQ_OBJECT_CONSTRUCTORS_IMPL(MegaDomHandler) TQ_OBJECT_CONSTRUCTORS_IMPL(MegaDomHandler)
RELEASE_ACQUIRE_WEAK_ACCESSORS(MegaDomHandler, accessor, kAccessorOffset)
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
......
...@@ -21,6 +21,8 @@ class MegaDomHandler ...@@ -21,6 +21,8 @@ class MegaDomHandler
void BriefPrintDetails(std::ostream& os); void BriefPrintDetails(std::ostream& os);
class BodyDescriptor; class BodyDescriptor;
DECL_RELEASE_ACQUIRE_WEAK_ACCESSORS(accessor)
TQ_OBJECT_CONSTRUCTORS(MegaDomHandler) TQ_OBJECT_CONSTRUCTORS(MegaDomHandler)
}; };
......
...@@ -178,6 +178,11 @@ bool ComparisonResultToBool(Operation op, ComparisonResult result) { ...@@ -178,6 +178,11 @@ bool ComparisonResultToBool(Operation op, ComparisonResult result) {
} }
std::ostream& operator<<(std::ostream& os, InstanceType instance_type) { std::ostream& operator<<(std::ostream& os, InstanceType instance_type) {
if (InstanceTypeChecker::IsJSApiObject(instance_type)) {
return os << "[api object] "
<< static_cast<int16_t>(instance_type) -
i::Internals::kFirstJSApiObjectType;
}
switch (instance_type) { switch (instance_type) {
#define WRITE_TYPE(TYPE) \ #define WRITE_TYPE(TYPE) \
case TYPE: \ case TYPE: \
...@@ -2133,7 +2138,7 @@ void Tuple2::BriefPrintDetails(std::ostream& os) { ...@@ -2133,7 +2138,7 @@ void Tuple2::BriefPrintDetails(std::ostream& os) {
} }
void MegaDomHandler::BriefPrintDetails(std::ostream& os) { void MegaDomHandler::BriefPrintDetails(std::ostream& os) {
os << " " << Brief(accessor()) << ", " << Brief(context()); os << " " << Brief(accessor(kAcquireLoad)) << ", " << Brief(context());
} }
void ClassPositions::BriefPrintDetails(std::ostream& os) { void ClassPositions::BriefPrintDetails(std::ostream& os) {
......
...@@ -29366,26 +29366,29 @@ TEST(EmbedderInstanceTypes) { ...@@ -29366,26 +29366,29 @@ TEST(EmbedderInstanceTypes) {
Local<FunctionTemplate> nodeType = v8::FunctionTemplate::New( Local<FunctionTemplate> nodeType = v8::FunctionTemplate::New(
isolate, NodeTypeCallback, Local<Value>(), isolate, NodeTypeCallback, Local<Value>(),
v8::Signature::New(isolate, node), 0, v8::ConstructorBehavior::kThrow, v8::Signature::New(isolate, node), 0, v8::ConstructorBehavior::kThrow,
v8::SideEffectType::kHasSideEffect, nullptr, 0, 1, 3); v8::SideEffectType::kHasSideEffect, nullptr,
i::Internals::kFirstJSApiObjectType,
i::Internals::kFirstJSApiObjectType + 1,
i::Internals::kFirstJSApiObjectType + 3);
proto_template->SetAccessorProperty( proto_template->SetAccessorProperty(
String::NewFromUtf8Literal(isolate, "nodeType"), nodeType); String::NewFromUtf8Literal(isolate, "nodeType"), nodeType);
Local<FunctionTemplate> element = FunctionTemplate::New( Local<FunctionTemplate> element = FunctionTemplate::New(
isolate, nullptr, Local<Value>(), Local<v8::Signature>(), 0, isolate, nullptr, Local<Value>(), Local<v8::Signature>(), 0,
v8::ConstructorBehavior::kAllow, v8::SideEffectType::kHasSideEffect, v8::ConstructorBehavior::kAllow, v8::SideEffectType::kHasSideEffect,
nullptr, 1); nullptr, i::Internals::kFirstJSApiObjectType + 1);
element->Inherit(node); element->Inherit(node);
Local<FunctionTemplate> html_element = FunctionTemplate::New( Local<FunctionTemplate> html_element = FunctionTemplate::New(
isolate, nullptr, Local<Value>(), Local<v8::Signature>(), 0, isolate, nullptr, Local<Value>(), Local<v8::Signature>(), 0,
v8::ConstructorBehavior::kAllow, v8::SideEffectType::kHasSideEffect, v8::ConstructorBehavior::kAllow, v8::SideEffectType::kHasSideEffect,
nullptr, 2); nullptr, i::Internals::kFirstJSApiObjectType + 2);
html_element->Inherit(element); html_element->Inherit(element);
Local<FunctionTemplate> div_element = FunctionTemplate::New( Local<FunctionTemplate> div_element = FunctionTemplate::New(
isolate, nullptr, Local<Value>(), Local<v8::Signature>(), 0, isolate, nullptr, Local<Value>(), Local<v8::Signature>(), 0,
v8::ConstructorBehavior::kAllow, v8::SideEffectType::kHasSideEffect, v8::ConstructorBehavior::kAllow, v8::SideEffectType::kHasSideEffect,
nullptr, 3); nullptr, i::Internals::kFirstJSApiObjectType + 3);
div_element->Inherit(html_element); div_element->Inherit(html_element);
CHECK(env->Global() CHECK(env->Global()
...@@ -4,6 +4,9 @@ ...@@ -4,6 +4,9 @@
// //
// Flags: --enable-mega-dom-ic --allow-natives-syntax // Flags: --enable-mega-dom-ic --allow-natives-syntax
// This tests checks that load property access using megadom IC returns
// correct results both on API objects and plain JS objects.
function load(obj) { function load(obj) {
return obj.nodeType; return obj.nodeType;
} }
...@@ -30,7 +33,6 @@ const objs = [ ...@@ -30,7 +33,6 @@ const objs = [
a, b, c, d, e, f a, b, c, d, e, f
]; ];
function test() { function test() {
let result = 0; let result = 0;
for (let i = 0; i < objs.length; i++) { for (let i = 0; i < objs.length; i++) {
...@@ -49,4 +51,4 @@ assertEquals(load({ nodeType: 'foo' }), 'foo'); ...@@ -49,4 +51,4 @@ assertEquals(load({ nodeType: 'foo' }), 'foo');
result = test(); result = test();
assertEquals(6, result); assertEquals(6, result);
assertEquals(load({}), undefined) assertEquals(load({}), undefined)
assertEquals(load({nodeType: 'foo'}), 'foo') 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
// This tests checks that load property access using megadom IC
// handles correctly the error of signature mismatch.
function load(obj) {
return obj.nodeType;
}
%PrepareFunctionForOptimization(load);
let a = new d8.dom.Div();
let b = new d8.dom.Div();
b.b = 1;
let c = new d8.dom.Div();
c.c = 1;
let d = new d8.dom.Div();
d.d = 1;
let e = new d8.dom.Div();
e.e = 1;
let 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]);
}
try {
load(new d8.dom.EventTarget());
} catch (err) {
assertInstanceof(err, TypeError);
assertEquals("Illegal invocation", err.message, 'Error message');
}
return result;
}
%PrepareFunctionForOptimization(test);
let result = test();
assertEquals(6, result);
%OptimizeFunctionOnNextCall(test);
result = test();
assertEquals(6, result);
...@@ -4,6 +4,9 @@ ...@@ -4,6 +4,9 @@
// //
// Flags: --enable-mega-dom-ic --allow-natives-syntax // Flags: --enable-mega-dom-ic --allow-natives-syntax
// This tests checks that load property access using megadom IC returns
// correct results on API.
function load(obj) { function load(obj) {
return obj.nodeType; return obj.nodeType;
} }
...@@ -29,8 +32,6 @@ const objs = [ ...@@ -29,8 +32,6 @@ const objs = [
a, b, c, d, e, f a, b, c, d, e, f
]; ];
function test() { function test() {
let result = 0; let result = 0;
for (let i = 0; i < objs.length; i++) { for (let i = 0; i < objs.length; i++) {
......
...@@ -345,6 +345,7 @@ header = ''' ...@@ -345,6 +345,7 @@ header = '''
#include "src/objects/data-handler.h" #include "src/objects/data-handler.h"
#include "src/objects/js-promise.h" #include "src/objects/js-promise.h"
#include "src/objects/js-regexp-string-iterator.h" #include "src/objects/js-regexp-string-iterator.h"
#include "src/objects/megadom-handler.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
......
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