Commit ca10d2ba authored by Maya Lekova's avatar Maya Lekova Committed by Commit Bot

[turbofan] Brokerize reduction of API calls

JSCallReducer::ReduceCallApiFunction is now heap access free.

Bug: v8:7790
Change-Id: I5718d73589d0bed14149ef0bc084b8a6ab1b9b5b
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1624792
Commit-Queue: Maya Lekova <mslekova@chromium.org>
Reviewed-by: 's avatarGeorg Neis <neis@chromium.org>
Reviewed-by: 's avatarMichael Stanton <mvstanton@chromium.org>
Cr-Commit-Position: refs/heads/master@{#62014}
parent 65a25fed
This diff is collapsed.
......@@ -121,6 +121,10 @@ class PropertyCellData : public HeapObjectData {
ObjectData* value_ = nullptr;
};
// TODO(mslekova): Once we have real-world usage data, we might want to
// reimplement this as sorted vector instead, to reduce the memory overhead.
typedef ZoneMap<MapData*, HolderLookupResult> KnownReceiversMap;
class FunctionTemplateInfoData : public HeapObjectData {
public:
FunctionTemplateInfoData(JSHeapBroker* broker, ObjectData** storage,
......@@ -128,10 +132,19 @@ class FunctionTemplateInfoData : public HeapObjectData {
void Serialize(JSHeapBroker* broker);
ObjectData* call_code() const { return call_code_; }
bool is_signature_undefined() const { return is_signature_undefined_; }
bool accept_any_receiver() const { return accept_any_receiver_; }
bool has_call_code() const { return has_call_code_; }
KnownReceiversMap& known_receivers() { return known_receivers_; }
private:
bool serialized_ = false;
ObjectData* call_code_ = nullptr;
bool is_signature_undefined_ = false;
bool accept_any_receiver_ = false;
bool has_call_code_ = false;
KnownReceiversMap known_receivers_;
};
class CallHandlerInfoData : public HeapObjectData {
......@@ -154,7 +167,16 @@ class CallHandlerInfoData : public HeapObjectData {
FunctionTemplateInfoData::FunctionTemplateInfoData(
JSHeapBroker* broker, ObjectData** storage,
Handle<FunctionTemplateInfo> object)
: HeapObjectData(broker, storage, object) {}
: HeapObjectData(broker, storage, object),
known_receivers_(broker->zone()) {
auto function_template_info = Handle<FunctionTemplateInfo>::cast(object);
is_signature_undefined_ =
function_template_info->signature().IsUndefined(broker->isolate());
accept_any_receiver_ = function_template_info->accept_any_receiver();
CallOptimization call_optimization(broker->isolate(), object);
has_call_code_ = call_optimization.is_simple_api_call();
}
CallHandlerInfoData::CallHandlerInfoData(JSHeapBroker* broker,
ObjectData** storage,
......@@ -1377,6 +1399,10 @@ class SharedFunctionInfoData : public HeapObjectData {
void SetSerializedForCompilation(JSHeapBroker* broker,
FeedbackVectorRef feedback);
bool IsSerializedForCompilation(FeedbackVectorRef feedback) const;
void SerializeFunctionTemplateInfo(JSHeapBroker* broker);
FunctionTemplateInfoData* function_template_info() const {
return function_template_info_;
}
#define DECL_ACCESSOR(type, name) \
type name() const { return name##_; }
BROKER_SFI_FIELDS(DECL_ACCESSOR)
......@@ -1391,6 +1417,7 @@ class SharedFunctionInfoData : public HeapObjectData {
#define DECL_MEMBER(type, name) type const name##_;
BROKER_SFI_FIELDS(DECL_MEMBER)
#undef DECL_MEMBER
FunctionTemplateInfoData* function_template_info_;
};
SharedFunctionInfoData::SharedFunctionInfoData(
......@@ -1408,7 +1435,8 @@ SharedFunctionInfoData::SharedFunctionInfoData(
#define INIT_MEMBER(type, name) , name##_(object->name())
BROKER_SFI_FIELDS(INIT_MEMBER)
#undef INIT_MEMBER
{
,
function_template_info_(nullptr) {
DCHECK_EQ(HasBuiltinId_, builtin_id_ != Builtins::kNoBuiltinId);
DCHECK_EQ(HasBytecodeArray_, GetBytecodeArray_ != nullptr);
}
......@@ -1420,6 +1448,18 @@ void SharedFunctionInfoData::SetSerializedForCompilation(
<< " as serialized for compilation");
}
void SharedFunctionInfoData::SerializeFunctionTemplateInfo(
JSHeapBroker* broker) {
if (function_template_info_) return;
function_template_info_ =
broker
->GetOrCreateData(handle(
Handle<SharedFunctionInfo>::cast(object())->function_data(),
broker->isolate()))
->AsFunctionTemplateInfo();
}
bool SharedFunctionInfoData::IsSerializedForCompilation(
FeedbackVectorRef feedback) const {
return serialized_for_compilation_.find(feedback.object()) !=
......@@ -2663,6 +2703,100 @@ BIMODAL_ACCESSOR_C(PropertyCell, PropertyDetails, property_details)
BIMODAL_ACCESSOR(FunctionTemplateInfo, Object, call_code)
bool FunctionTemplateInfoRef::is_signature_undefined() const {
if (broker()->mode() == JSHeapBroker::kDisabled) {
AllowHandleDereference allow_handle_dereference;
AllowHandleAllocation allow_handle_allocation;
return object()->signature().IsUndefined(broker()->isolate());
}
return data()->AsFunctionTemplateInfo()->is_signature_undefined();
}
bool FunctionTemplateInfoRef::has_call_code() const {
if (broker()->mode() == JSHeapBroker::kDisabled) {
AllowHandleDereference allow_handle_dereference;
AllowHandleAllocation allow_handle_allocation;
CallOptimization call_optimization(broker()->isolate(), object());
return call_optimization.is_simple_api_call();
}
return data()->AsFunctionTemplateInfo()->has_call_code();
}
BIMODAL_ACCESSOR_C(FunctionTemplateInfo, bool, accept_any_receiver)
HolderLookupResult FunctionTemplateInfoRef::LookupHolderOfExpectedType(
MapRef receiver_map, bool serialize) {
const HolderLookupResult not_found;
if (broker()->mode() == JSHeapBroker::kDisabled) {
AllowHandleDereference allow_handle_dereference;
AllowHandleAllocation allow_handle_allocation;
CallOptimization call_optimization(broker()->isolate(), object());
Handle<Map> receiver_map_ref(receiver_map.object());
if (!receiver_map_ref->IsJSReceiverMap() ||
(receiver_map_ref->is_access_check_needed() &&
!object()->accept_any_receiver())) {
return not_found;
}
HolderLookupResult result;
Handle<JSObject> holder = call_optimization.LookupHolderOfExpectedType(
receiver_map_ref, &result.lookup);
switch (result.lookup) {
case CallOptimization::kHolderFound: {
result.holder = JSObjectRef(broker(), holder);
break;
}
default: {
DCHECK_EQ(result.holder, base::nullopt);
}
}
return result;
}
FunctionTemplateInfoData* fti_data = data()->AsFunctionTemplateInfo();
KnownReceiversMap::iterator lookup_it =
fti_data->known_receivers().find(receiver_map.data()->AsMap());
if (lookup_it != fti_data->known_receivers().cend()) {
return lookup_it->second;
}
if (!serialize) {
TRACE_BROKER_MISSING(broker(),
"holder for receiver with map " << receiver_map);
return not_found;
}
if (!receiver_map.IsJSReceiverMap() ||
(receiver_map.is_access_check_needed() && !accept_any_receiver())) {
fti_data->known_receivers().insert(
{receiver_map.data()->AsMap(), not_found});
return not_found;
}
HolderLookupResult result;
CallOptimization call_optimization(broker()->isolate(), object());
Handle<JSObject> holder = call_optimization.LookupHolderOfExpectedType(
receiver_map.object(), &result.lookup);
switch (result.lookup) {
case CallOptimization::kHolderFound: {
result.holder = JSObjectRef(broker(), holder);
fti_data->known_receivers().insert(
{receiver_map.data()->AsMap(), result});
break;
}
default: {
DCHECK_EQ(result.holder, base::nullopt);
fti_data->known_receivers().insert(
{receiver_map.data()->AsMap(), result});
}
}
return result;
}
BIMODAL_ACCESSOR(CallHandlerInfo, Object, data)
BIMODAL_ACCESSOR_C(SharedFunctionInfo, int, builtin_id)
......@@ -3138,6 +3272,24 @@ void SharedFunctionInfoRef::SetSerializedForCompilation(
feedback);
}
void SharedFunctionInfoRef::SerializeFunctionTemplateInfo() {
CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
data()->AsSharedFunctionInfo()->SerializeFunctionTemplateInfo(broker());
}
base::Optional<FunctionTemplateInfoRef>
SharedFunctionInfoRef::function_template_info() const {
if (broker()->mode() == JSHeapBroker::kDisabled) {
return FunctionTemplateInfoRef(
broker(), handle(object()->function_data(), broker()->isolate()));
}
FunctionTemplateInfoData* function_template_info =
data()->AsSharedFunctionInfo()->function_template_info();
if (!function_template_info) return base::nullopt;
return FunctionTemplateInfoRef(broker(), function_template_info);
}
bool SharedFunctionInfoRef::IsSerializedForCompilation(
FeedbackVectorRef feedback) const {
CHECK_NE(broker()->mode(), JSHeapBroker::kDisabled);
......
......@@ -10,6 +10,7 @@
#include "src/common/globals.h"
#include "src/compiler/refs-map.h"
#include "src/handles/handles.h"
#include "src/ic/call-optimization.h"
#include "src/objects/feedback-vector.h"
#include "src/objects/function-kind.h"
#include "src/objects/instance-type.h"
......@@ -147,6 +148,7 @@ class V8_EXPORT_PRIVATE ObjectRef {
ObjectData* data_; // Should be used only by object() getters.
private:
friend class FunctionTemplateInfoRef;
friend class JSArrayData;
friend class JSGlobalProxyRef;
friend class JSGlobalProxyData;
......@@ -430,15 +432,6 @@ class FeedbackVectorRef : public HeapObjectRef {
void SerializeSlots();
};
class FunctionTemplateInfoRef : public HeapObjectRef {
public:
using HeapObjectRef::HeapObjectRef;
Handle<FunctionTemplateInfo> object() const;
void Serialize();
ObjectRef call_code() const;
};
class CallHandlerInfoRef : public HeapObjectRef {
public:
using HeapObjectRef::HeapObjectRef;
......@@ -542,6 +535,30 @@ class V8_EXPORT_PRIVATE MapRef : public HeapObjectRef {
base::Optional<MapRef> AsElementsKind(ElementsKind kind) const;
};
struct HolderLookupResult {
HolderLookupResult(CallOptimization::HolderLookup lookup_ =
CallOptimization::kHolderNotFound,
base::Optional<JSObjectRef> holder_ = base::nullopt)
: lookup(lookup_), holder(holder_) {}
CallOptimization::HolderLookup lookup;
base::Optional<JSObjectRef> holder;
};
class FunctionTemplateInfoRef : public HeapObjectRef {
public:
using HeapObjectRef::HeapObjectRef;
Handle<FunctionTemplateInfo> object() const;
void Serialize();
ObjectRef call_code() const;
bool is_signature_undefined() const;
bool accept_any_receiver() const;
bool has_call_code() const;
HolderLookupResult LookupHolderOfExpectedType(MapRef receiver_map,
bool serialize);
};
class FixedArrayBaseRef : public HeapObjectRef {
public:
using HeapObjectRef::HeapObjectRef;
......@@ -627,6 +644,9 @@ class V8_EXPORT_PRIVATE SharedFunctionInfoRef : public HeapObjectRef {
bool IsSerializedForCompilation(FeedbackVectorRef feedback) const;
void SetSerializedForCompilation(FeedbackVectorRef feedback);
void SerializeFunctionTemplateInfo();
base::Optional<FunctionTemplateInfoRef> function_template_info() const;
};
class StringRef : public NameRef {
......
......@@ -2025,7 +2025,9 @@ Node* JSNativeContextSpecialization::InlinePropertyGetterCall(
ConvertReceiverMode::kNotNullOrUndefined),
target, receiver, context, frame_state, *effect, *control);
} else {
auto function_template_info = constant.AsFunctionTemplateInfo();
// TODO(mslekova): Move this to the serialization of property loads.
FunctionTemplateInfoRef function_template_info =
constant.AsFunctionTemplateInfo();
function_template_info.Serialize();
Node* holder =
access_info.holder().is_null()
......@@ -2033,6 +2035,7 @@ Node* JSNativeContextSpecialization::InlinePropertyGetterCall(
: jsgraph()->Constant(access_info.holder().ToHandleChecked());
SharedFunctionInfoRef shared_info(
broker(), frame_info.shared_info().ToHandleChecked());
value = InlineApiCall(receiver, holder, frame_state, nullptr, effect,
control, shared_info, function_template_info);
}
......@@ -2062,6 +2065,7 @@ void JSNativeContextSpecialization::InlinePropertySetterCall(
ConvertReceiverMode::kNotNullOrUndefined),
target, receiver, value, context, frame_state, *effect, *control);
} else {
// TODO(mslekova): Move this to the serialization of property stores.
auto function_template_info = constant.AsFunctionTemplateInfo();
function_template_info.Serialize();
Node* holder =
......
......@@ -122,7 +122,10 @@ bool MapInference::RelyOnMapsHelper(CompilationDependencies* dependencies,
const VectorSlotPair& feedback) {
if (Safe()) return true;
auto is_stable = [](Handle<Map> map) { return map->is_stable(); };
auto is_stable = [this](Handle<Map> map) {
MapRef map_ref(broker_, map);
return map_ref.is_stable();
};
if (dependencies != nullptr &&
std::all_of(maps_.cbegin(), maps_.cend(), is_stable)) {
for (Handle<Map> map : maps_) {
......
......@@ -9,6 +9,7 @@
#include "src/compiler/js-heap-broker.h"
#include "src/compiler/vector-slot-pair.h"
#include "src/handles/handles-inl.h"
#include "src/ic/call-optimization.h"
#include "src/interpreter/bytecode-array-iterator.h"
#include "src/objects/code.h"
#include "src/objects/shared-function-info-inl.h"
......@@ -740,15 +741,28 @@ void SerializerForBackgroundCompilation::ProcessCallOrConstruct(
if (!hint->IsJSFunction()) continue;
Handle<JSFunction> function = Handle<JSFunction>::cast(hint);
if (!function->shared().IsInlineable() || !function->has_feedback_vector())
continue;
Handle<SharedFunctionInfo> shared(function->shared(), broker()->isolate());
if (shared->IsApiFunction()) {
ProcessApiCall(shared, arguments);
DCHECK(!shared->IsInlineable());
}
if (!shared->IsInlineable() || !function->has_feedback_vector()) continue;
environment()->accumulator_hints().Add(RunChildSerializer(
{function, broker()->isolate()}, new_target, arguments, with_spread));
}
for (auto hint : callee.function_blueprints()) {
if (!hint.shared->IsInlineable()) continue;
Handle<SharedFunctionInfo> shared = hint.shared;
if (shared->IsApiFunction()) {
ProcessApiCall(shared, arguments);
DCHECK(!shared->IsInlineable());
}
if (!shared->IsInlineable()) continue;
environment()->accumulator_hints().Add(RunChildSerializer(
CompilationSubject(hint), new_target, arguments, with_spread));
}
......@@ -776,6 +790,58 @@ void SerializerForBackgroundCompilation::ProcessCallVarArgs(
ProcessCallOrConstruct(callee, base::nullopt, arguments, slot);
}
void SerializerForBackgroundCompilation::ProcessApiCall(
Handle<SharedFunctionInfo> target, const HintsVector& arguments) {
FunctionTemplateInfoRef target_template_info(
broker(), handle(target->function_data(), broker()->isolate()));
target_template_info.Serialize();
if (!target_template_info.has_call_code()) return;
SharedFunctionInfoRef target_ref(broker(), target);
target_ref.SerializeFunctionTemplateInfo();
if (target_template_info.accept_any_receiver() &&
target_template_info.is_signature_undefined())
return;
CHECK_GE(arguments.size(), 1);
Hints const& receiver_hints = arguments[0];
for (auto hint : receiver_hints.constants()) {
if (hint->IsUndefined()) {
// The receiver is the global proxy.
Handle<JSGlobalProxy> global_proxy =
broker()->native_context().global_proxy_object().object();
ProcessReceiverMapForApiCall(
target_template_info,
handle(global_proxy->map(), broker()->isolate()));
continue;
}
if (!hint->IsJSReceiver()) continue;
Handle<JSReceiver> receiver(Handle<JSReceiver>::cast(hint));
ProcessReceiverMapForApiCall(target_template_info,
handle(receiver->map(), broker()->isolate()));
}
for (auto receiver_map : receiver_hints.maps()) {
ProcessReceiverMapForApiCall(target_template_info, receiver_map);
}
}
void SerializerForBackgroundCompilation::ProcessReceiverMapForApiCall(
FunctionTemplateInfoRef& target, Handle<Map> receiver) {
if (receiver->is_access_check_needed()) {
return;
}
MapRef receiver_map(broker(), receiver);
TRACE_BROKER(broker(), "Serializing holder for target:" << target);
target.LookupHolderOfExpectedType(receiver_map, true);
}
void SerializerForBackgroundCompilation::ContributeToJumpTargetEnvironment(
int target_offset) {
auto it = jump_target_environments_.find(target_offset);
......
......@@ -315,6 +315,10 @@ class SerializerForBackgroundCompilation {
void ProcessCallVarArgs(interpreter::BytecodeArrayIterator* iterator,
ConvertReceiverMode receiver_mode,
bool with_spread = false);
void ProcessApiCall(Handle<SharedFunctionInfo> target,
const HintsVector& arguments);
void ProcessReceiverMapForApiCall(FunctionTemplateInfoRef& target,
Handle<Map> receiver);
void ProcessJump(interpreter::BytecodeArrayIterator* iterator);
......
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