[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: Jakob Kummerow <jkummerow@chromium.org> Reviewed-by: Camillo Bruni <cbruni@chromium.org> Reviewed-by: Tobias Tebbi <tebbi@chromium.org> Cr-Commit-Position: refs/heads/main@{#80748}
This commit is contained in:
parent
51d2256b8a
commit
5480e036d2
@ -1386,6 +1386,16 @@ Local<FunctionTemplate> FunctionTemplate::New(
|
||||
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);
|
||||
return FunctionTemplateNew(
|
||||
i_isolate, callback, data, signature, length, behavior, false,
|
||||
|
@ -1064,6 +1064,11 @@ bool CompilationDependencies::DependOnProtector(const PropertyCellRef& cell) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CompilationDependencies::DependOnMegaDOMProtector() {
|
||||
return DependOnProtector(
|
||||
MakeRef(broker_, broker_->isolate()->factory()->mega_dom_protector()));
|
||||
}
|
||||
|
||||
bool CompilationDependencies::DependOnArrayBufferDetachingProtector() {
|
||||
return DependOnProtector(MakeRef(
|
||||
broker_,
|
||||
|
@ -89,6 +89,7 @@ class V8_EXPORT_PRIVATE CompilationDependencies : public ZoneObject {
|
||||
bool DependOnPromiseHookProtector();
|
||||
bool DependOnPromiseSpeciesProtector();
|
||||
bool DependOnPromiseThenProtector();
|
||||
bool DependOnMegaDOMProtector();
|
||||
|
||||
// Record the assumption that {site}'s {ElementsKind} doesn't change.
|
||||
void DependOnElementsKind(const AllocationSiteRef& site);
|
||||
|
@ -1508,6 +1508,10 @@ bool FunctionTemplateInfoRef::is_signature_undefined() const {
|
||||
}
|
||||
|
||||
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(
|
||||
MapRef receiver_map) {
|
||||
|
@ -745,6 +745,9 @@ class FunctionTemplateInfoRef : public HeapObjectRef {
|
||||
|
||||
bool is_signature_undefined() 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;
|
||||
ZoneVector<Address> c_functions() const;
|
||||
ZoneVector<const CFunctionInfo*> c_signatures() const;
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "src/objects/js-array-inl.h"
|
||||
#include "src/objects/literal-objects-inl.h"
|
||||
#include "src/objects/map-updater.h"
|
||||
#include "src/objects/megadom-handler-inl.h"
|
||||
#include "src/objects/objects-inl.h"
|
||||
#include "src/objects/oddball.h"
|
||||
#include "src/objects/property-cell.h"
|
||||
@ -425,6 +426,12 @@ bool ElementAccessFeedback::HasOnlyStringMaps(JSHeapBroker* broker) const {
|
||||
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,
|
||||
ZoneVector<MapRef> const& maps,
|
||||
FeedbackSlotKind slot_kind)
|
||||
@ -510,6 +517,21 @@ ProcessedFeedback const& JSHeapBroker::ReadFeedbackForPropertyAccess(
|
||||
base::Optional<NameRef> name =
|
||||
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
|
||||
// and we should soft-deopt.
|
||||
if (maps.empty() && nexus.ic_state() != InlineCacheState::MEGAMORPHIC) {
|
||||
@ -936,6 +958,12 @@ NamedAccessFeedback const& ProcessedFeedback::AsNamedAccess() const {
|
||||
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 {
|
||||
CHECK_EQ(kLiteral, kind());
|
||||
return *static_cast<LiteralFeedback const*>(this);
|
||||
|
@ -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(
|
||||
Node* node, Node* value, NamedAccessFeedback const& feedback,
|
||||
AccessMode access_mode, Node* key) {
|
||||
@ -2047,6 +2139,11 @@ Reduction JSNativeContextSpecialization::ReducePropertyAccess(
|
||||
case ProcessedFeedback::kNamedAccess:
|
||||
return ReduceNamedAccess(node, value, feedback.AsNamedAccess(),
|
||||
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:
|
||||
DCHECK_EQ(feedback.AsElementAccess().keyed_mode().access_mode(),
|
||||
access_mode);
|
||||
|
@ -107,6 +107,9 @@ class V8_EXPORT_PRIVATE JSNativeContextSpecialization final
|
||||
Reduction ReduceNamedAccess(Node* node, Node* value,
|
||||
NamedAccessFeedback const& feedback,
|
||||
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,
|
||||
Node* receiver, Node* value, NameRef const& name,
|
||||
AccessMode access_mode, Node* key,
|
||||
|
@ -20,6 +20,7 @@ class ForInFeedback;
|
||||
class GlobalAccessFeedback;
|
||||
class InstanceOfFeedback;
|
||||
class LiteralFeedback;
|
||||
class MegaDOMPropertyAccessFeedback;
|
||||
class NamedAccessFeedback;
|
||||
class RegExpLiteralFeedback;
|
||||
class TemplateObjectFeedback;
|
||||
@ -36,6 +37,7 @@ class ProcessedFeedback : public ZoneObject {
|
||||
kGlobalAccess,
|
||||
kInstanceOf,
|
||||
kLiteral,
|
||||
kMegaDOMPropertyAccess,
|
||||
kNamedAccess,
|
||||
kRegExpLiteral,
|
||||
kTemplateObject,
|
||||
@ -53,6 +55,7 @@ class ProcessedFeedback : public ZoneObject {
|
||||
GlobalAccessFeedback const& AsGlobalAccess() const;
|
||||
InstanceOfFeedback const& AsInstanceOf() const;
|
||||
NamedAccessFeedback const& AsNamedAccess() const;
|
||||
MegaDOMPropertyAccessFeedback const& AsMegaDOMPropertyAccess() const;
|
||||
LiteralFeedback const& AsLiteral() const;
|
||||
RegExpLiteralFeedback const& AsRegExpLiteral() const;
|
||||
TemplateObjectFeedback const& AsTemplateObject() const;
|
||||
@ -169,6 +172,17 @@ class NamedAccessFeedback : public ProcessedFeedback {
|
||||
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 {
|
||||
public:
|
||||
CallFeedback(base::Optional<HeapObjectRef> target, float frequency,
|
||||
|
58
src/d8/d8.cc
58
src/d8/d8.cc
@ -1656,6 +1656,14 @@ void PerIsolateData::SetSnapshotObjectCtor(Local<FunctionTemplate> 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) {
|
||||
data_->realm_count_ = 1;
|
||||
data_->realm_current_ = 0;
|
||||
@ -2992,26 +3000,58 @@ Local<String> Shell::Stringify(Isolate* isolate, Local<Value> value) {
|
||||
|
||||
void Shell::NodeTypeCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
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));
|
||||
}
|
||||
|
||||
Local<FunctionTemplate> Shell::CreateNodeTemplates(Isolate* isolate) {
|
||||
Local<FunctionTemplate> node = FunctionTemplate::New(isolate);
|
||||
Local<FunctionTemplate> NewDOMFunctionTemplate(Isolate* 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<Signature> signature = v8::Signature::New(isolate, node);
|
||||
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);
|
||||
proto_template->SetAccessorProperty(
|
||||
String::NewFromUtf8Literal(isolate, "nodeType"), nodeType);
|
||||
|
||||
Local<FunctionTemplate> element = FunctionTemplate::New(isolate);
|
||||
Local<FunctionTemplate> element =
|
||||
NewDOMFunctionTemplate(isolate, i::Internals::kFirstJSApiObjectType + 3);
|
||||
element->Inherit(node);
|
||||
|
||||
Local<FunctionTemplate> html_element = FunctionTemplate::New(isolate);
|
||||
Local<FunctionTemplate> html_element =
|
||||
NewDOMFunctionTemplate(isolate, i::Internals::kFirstJSApiObjectType + 4);
|
||||
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);
|
||||
|
||||
return div_element;
|
||||
@ -3210,7 +3250,11 @@ Local<ObjectTemplate> Shell::CreateD8Template(Isolate* 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);
|
||||
}
|
||||
{
|
||||
|
@ -324,6 +324,9 @@ class PerIsolateData {
|
||||
Local<FunctionTemplate> GetSnapshotObjectCtor() const;
|
||||
void SetSnapshotObjectCtor(Local<FunctionTemplate> ctor);
|
||||
|
||||
Local<FunctionTemplate> GetDomNodeCtor() const;
|
||||
void SetDomNodeCtor(Local<FunctionTemplate> ctor);
|
||||
|
||||
private:
|
||||
friend class Shell;
|
||||
friend class RealmScope;
|
||||
@ -344,6 +347,7 @@ class PerIsolateData {
|
||||
#endif
|
||||
Global<FunctionTemplate> test_api_object_ctor_;
|
||||
Global<FunctionTemplate> snapshot_object_ctor_;
|
||||
Global<FunctionTemplate> dom_node_ctor_;
|
||||
|
||||
int RealmIndexOrThrow(const v8::FunctionCallbackInfo<v8::Value>& args,
|
||||
int arg_offset);
|
||||
@ -741,7 +745,9 @@ class Shell : public i::AllStatic {
|
||||
|
||||
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> CreateOSTemplate(Isolate* isolate);
|
||||
static Local<FunctionTemplate> CreateWorkerTemplate(Isolate* isolate);
|
||||
|
@ -3527,7 +3527,7 @@ Handle<MegaDomHandler> Factory::NewMegaDomHandler(MaybeObjectHandle accessor,
|
||||
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_accessor(*accessor, kReleaseStore);
|
||||
handler.set_context(*context);
|
||||
return handle(handler, isolate());
|
||||
}
|
||||
|
11
src/ic/ic.cc
11
src/ic/ic.cc
@ -642,9 +642,16 @@ bool IC::UpdateMegaDOMIC(const MaybeObjectHandle& handler, Handle<Name> name) {
|
||||
Handle<Context> accessor_context(call_optimization.GetAccessorContext(*map),
|
||||
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(
|
||||
MaybeObjectHandle::Weak(accessor_obj),
|
||||
MaybeObjectHandle::Weak(accessor_context));
|
||||
MaybeObjectHandle::Weak(fti), MaybeObjectHandle::Weak(accessor_context));
|
||||
nexus()->ConfigureMegaDOM(MaybeObjectHandle(new_handler));
|
||||
return true;
|
||||
}
|
||||
|
@ -1089,6 +1089,20 @@ int FeedbackNexus::ExtractMapsAndFeedback(
|
||||
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(
|
||||
std::vector<MapAndHandler>* maps_and_handlers,
|
||||
TryUpdateHandler map_handler) const {
|
||||
|
@ -818,6 +818,7 @@ class V8_EXPORT_PRIVATE FeedbackNexus final {
|
||||
Handle<Name> name, std::vector<MapAndHandler> const& maps_and_handlers);
|
||||
|
||||
void ConfigureMegaDOM(const MaybeObjectHandle& handler);
|
||||
MaybeObjectHandle ExtractMegaDOMHandler();
|
||||
|
||||
BinaryOperationHint GetBinaryOperationFeedback() const;
|
||||
CompareOperationHint GetCompareOperationFeedback() const;
|
||||
|
@ -18,6 +18,8 @@ namespace internal {
|
||||
|
||||
TQ_OBJECT_CONSTRUCTORS_IMPL(MegaDomHandler)
|
||||
|
||||
RELEASE_ACQUIRE_WEAK_ACCESSORS(MegaDomHandler, accessor, kAccessorOffset)
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
|
@ -21,6 +21,8 @@ class MegaDomHandler
|
||||
void BriefPrintDetails(std::ostream& os);
|
||||
class BodyDescriptor;
|
||||
|
||||
DECL_RELEASE_ACQUIRE_WEAK_ACCESSORS(accessor)
|
||||
|
||||
TQ_OBJECT_CONSTRUCTORS(MegaDomHandler)
|
||||
};
|
||||
|
||||
|
@ -178,6 +178,11 @@ bool ComparisonResultToBool(Operation op, ComparisonResult result) {
|
||||
}
|
||||
|
||||
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) {
|
||||
#define WRITE_TYPE(TYPE) \
|
||||
case TYPE: \
|
||||
@ -2133,7 +2138,7 @@ void Tuple2::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) {
|
||||
|
@ -29366,26 +29366,29 @@ TEST(EmbedderInstanceTypes) {
|
||||
Local<FunctionTemplate> nodeType = v8::FunctionTemplate::New(
|
||||
isolate, NodeTypeCallback, Local<Value>(),
|
||||
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(
|
||||
String::NewFromUtf8Literal(isolate, "nodeType"), nodeType);
|
||||
|
||||
Local<FunctionTemplate> element = FunctionTemplate::New(
|
||||
isolate, nullptr, Local<Value>(), Local<v8::Signature>(), 0,
|
||||
v8::ConstructorBehavior::kAllow, v8::SideEffectType::kHasSideEffect,
|
||||
nullptr, 1);
|
||||
nullptr, i::Internals::kFirstJSApiObjectType + 1);
|
||||
element->Inherit(node);
|
||||
|
||||
Local<FunctionTemplate> html_element = FunctionTemplate::New(
|
||||
isolate, nullptr, Local<Value>(), Local<v8::Signature>(), 0,
|
||||
v8::ConstructorBehavior::kAllow, v8::SideEffectType::kHasSideEffect,
|
||||
nullptr, 2);
|
||||
nullptr, i::Internals::kFirstJSApiObjectType + 2);
|
||||
html_element->Inherit(element);
|
||||
|
||||
Local<FunctionTemplate> div_element = FunctionTemplate::New(
|
||||
isolate, nullptr, Local<Value>(), Local<v8::Signature>(), 0,
|
||||
v8::ConstructorBehavior::kAllow, v8::SideEffectType::kHasSideEffect,
|
||||
nullptr, 3);
|
||||
nullptr, i::Internals::kFirstJSApiObjectType + 3);
|
||||
div_element->Inherit(html_element);
|
||||
|
||||
CHECK(env->Global()
|
||||
|
@ -4,6 +4,9 @@
|
||||
//
|
||||
// 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) {
|
||||
return obj.nodeType;
|
||||
}
|
||||
@ -30,7 +33,6 @@ const objs = [
|
||||
a, b, c, d, e, f
|
||||
];
|
||||
|
||||
|
||||
function test() {
|
||||
let result = 0;
|
||||
for (let i = 0; i < objs.length; i++) {
|
||||
@ -49,4 +51,4 @@ assertEquals(load({ nodeType: 'foo' }), 'foo');
|
||||
result = test();
|
||||
assertEquals(6, result);
|
||||
assertEquals(load({}), undefined)
|
||||
assertEquals(load({nodeType: 'foo'}), 'foo')
|
||||
assertEquals(load({nodeType: 'foo'}), 'foo');
|
||||
|
57
test/mjsunit/ic-megadom-3.js
Normal file
57
test/mjsunit/ic-megadom-3.js
Normal file
@ -0,0 +1,57 @@
|
||||
// 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 @@
|
||||
//
|
||||
// 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) {
|
||||
return obj.nodeType;
|
||||
}
|
||||
@ -29,8 +32,6 @@ const objs = [
|
||||
a, b, c, d, e, f
|
||||
];
|
||||
|
||||
|
||||
|
||||
function test() {
|
||||
let result = 0;
|
||||
for (let i = 0; i < objs.length; i++) {
|
||||
|
@ -345,6 +345,7 @@ header = '''
|
||||
#include "src/objects/data-handler.h"
|
||||
#include "src/objects/js-promise.h"
|
||||
#include "src/objects/js-regexp-string-iterator.h"
|
||||
#include "src/objects/megadom-handler.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
Loading…
Reference in New Issue
Block a user