Commit 88366741 authored by epertoso's avatar epertoso Committed by Commit bot

[turbofan] Handle inlining of API getters/setters.

Similar to what crankshaft does, we introduce a mapcheck if necessary and a call to the CallApiCallbackStub.

BUG=

Review-Url: https://codereview.chromium.org/2458643002
Cr-Commit-Position: refs/heads/master@{#40664}
parent b4b436de
......@@ -10,6 +10,7 @@
#include "src/compiler/type-cache.h"
#include "src/field-index-inl.h"
#include "src/field-type.h"
#include "src/ic/call-optimization.h"
#include "src/objects-inl.h"
namespace v8 {
......@@ -343,8 +344,13 @@ bool AccessInfoFactory::ComputePropertyAccessInfo(
: Handle<AccessorPair>::cast(accessors)->setter(),
isolate());
if (!accessor->IsJSFunction()) {
// TODO(turbofan): Add support for API accessors.
return false;
CallOptimization optimization(accessor);
if (!optimization.is_simple_api_call()) {
return false;
}
if (optimization.api_call_info()->fast_handler()->IsCode()) {
return false;
}
}
*access_info = PropertyAccessInfo::AccessorConstant(
MapList{receiver_map}, accessor, holder);
......
......@@ -869,12 +869,26 @@ JSNativeContextSpecialization::BuildPropertyAccess(
context, target, frame_state);
// Introduce the call to the getter function.
value = effect = graph()->NewNode(
javascript()->CallFunction(
2, 0.0f, VectorSlotPair(),
ConvertReceiverMode::kNotNullOrUndefined),
target, receiver, context, frame_state0, effect, control);
control = graph()->NewNode(common()->IfSuccess(), value);
if (access_info.constant()->IsJSFunction()) {
value = effect = graph()->NewNode(
javascript()->CallFunction(
2, 0.0f, VectorSlotPair(),
ConvertReceiverMode::kNotNullOrUndefined),
target, receiver, context, frame_state0, effect, control);
control = graph()->NewNode(common()->IfSuccess(), value);
} else {
DCHECK(access_info.constant()->IsFunctionTemplateInfo());
Handle<FunctionTemplateInfo> function_template_info(
Handle<FunctionTemplateInfo>::cast(access_info.constant()));
DCHECK(!function_template_info->call_code()->IsUndefined(isolate()));
ZoneVector<Node*> stack_parameters(graph()->zone());
ValueEffectControl value_effect_control = InlineApiCall(
receiver, context, target, frame_state0, &stack_parameters,
effect, control, shared_info, function_template_info);
value = value_effect_control.value();
effect = value_effect_control.effect();
control = value_effect_control.control();
}
break;
}
case AccessMode::kStore: {
......@@ -892,12 +906,27 @@ JSNativeContextSpecialization::BuildPropertyAccess(
context, target, frame_state);
// Introduce the call to the setter function.
effect = graph()->NewNode(javascript()->CallFunction(
3, 0.0f, VectorSlotPair(),
ConvertReceiverMode::kNotNullOrUndefined),
target, receiver, value, context,
frame_state0, effect, control);
control = graph()->NewNode(common()->IfSuccess(), effect);
if (access_info.constant()->IsJSFunction()) {
effect = graph()->NewNode(
javascript()->CallFunction(
3, 0.0f, VectorSlotPair(),
ConvertReceiverMode::kNotNullOrUndefined),
target, receiver, value, context, frame_state0, effect, control);
control = graph()->NewNode(common()->IfSuccess(), effect);
} else {
DCHECK(access_info.constant()->IsFunctionTemplateInfo());
Handle<FunctionTemplateInfo> function_template_info(
Handle<FunctionTemplateInfo>::cast(access_info.constant()));
DCHECK(!function_template_info->call_code()->IsUndefined(isolate()));
ZoneVector<Node*> stack_parameters(graph()->zone());
stack_parameters.push_back(value);
ValueEffectControl value_effect_control = InlineApiCall(
receiver, context, target, frame_state0, &stack_parameters,
effect, control, shared_info, function_template_info);
value = value_effect_control.value();
effect = value_effect_control.effect();
control = value_effect_control.control();
}
break;
}
}
......@@ -1323,6 +1352,65 @@ JSNativeContextSpecialization::BuildElementAccess(
return ValueEffectControl(value, effect, control);
}
JSNativeContextSpecialization::ValueEffectControl
JSNativeContextSpecialization::InlineApiCall(
Node* receiver, Node* context, Node* target, Node* frame_state,
ZoneVector<Node*>* stack_parameters, Node* effect, Node* control,
Handle<SharedFunctionInfo> shared_info,
Handle<FunctionTemplateInfo> function_template_info) {
Handle<CallHandlerInfo> call_handler_info = handle(
CallHandlerInfo::cast(function_template_info->call_code()), isolate());
Handle<Object> call_data_object(call_handler_info->data(), isolate());
// The stub always expects the receiver as the first param on the stack.
CallApiCallbackStub stub(
isolate(), static_cast<int>(stack_parameters->size()),
call_data_object->IsUndefined(isolate()),
true /* TODO(epertoso): similar to CallOptimization */);
CallInterfaceDescriptor call_interface_descriptor =
stub.GetCallInterfaceDescriptor();
CallDescriptor* call_descriptor = Linkage::GetStubCallDescriptor(
isolate(), graph()->zone(), call_interface_descriptor,
call_interface_descriptor.GetStackParameterCount() +
static_cast<int>(stack_parameters->size()) + 1,
CallDescriptor::kNeedsFrameState, Operator::kNoProperties,
MachineType::AnyTagged(), 1);
Node* data = jsgraph()->Constant(call_data_object);
ApiFunction function(v8::ToCData<Address>(call_handler_info->callback()));
Node* function_reference =
graph()->NewNode(common()->ExternalConstant(ExternalReference(
&function, ExternalReference::DIRECT_API_CALL, isolate())));
Node* code = jsgraph()->HeapConstant(stub.GetCode());
ZoneVector<Node*> inputs(zone());
inputs.push_back(code);
// CallApiCallbackStub's register arguments.
inputs.push_back(target);
inputs.push_back(data);
inputs.push_back(receiver);
inputs.push_back(function_reference);
// Stack parameters: CallApiCallbackStub expects the first one to be the
// receiver.
inputs.push_back(receiver);
for (Node* node : *stack_parameters) {
inputs.push_back(node);
}
inputs.push_back(context);
inputs.push_back(frame_state);
inputs.push_back(effect);
inputs.push_back(control);
Node* effect0;
Node* value0 = effect0 =
graph()->NewNode(common()->Call(call_descriptor),
static_cast<int>(inputs.size()), inputs.data());
Node* control0 = graph()->NewNode(common()->IfSuccess(), value0);
return ValueEffectControl(value0, effect0, control0);
}
Node* JSNativeContextSpecialization::BuildCheckMaps(
Node* receiver, Node* effect, Node* control,
std::vector<Handle<Map>> const& maps) {
......
......@@ -145,6 +145,12 @@ class JSNativeContextSpecialization final : public AdvancedReducer {
// program location.
MaybeHandle<Map> InferReceiverRootMap(Node* receiver);
ValueEffectControl InlineApiCall(
Node* receiver, Node* context, Node* target, Node* frame_state,
ZoneVector<Node*>* stack_parameters, Node* effect, Node* control,
Handle<SharedFunctionInfo> shared_info,
Handle<FunctionTemplateInfo> function_template_info);
Graph* graph() const;
JSGraph* jsgraph() const { return jsgraph_; }
Isolate* isolate() const;
......
......@@ -268,6 +268,7 @@ Type::bitset BitsetType::Lub(i::Map* map) {
case ALLOCATION_SITE_TYPE:
case ACCESSOR_INFO_TYPE:
case SHARED_FUNCTION_INFO_TYPE:
case FUNCTION_TEMPLATE_INFO_TYPE:
case ACCESSOR_PAIR_TYPE:
case FIXED_ARRAY_TYPE:
case FIXED_DOUBLE_ARRAY_TYPE:
......@@ -294,7 +295,6 @@ Type::bitset BitsetType::Lub(i::Map* map) {
case ACCESS_CHECK_INFO_TYPE:
case INTERCEPTOR_INFO_TYPE:
case CALL_HANDLER_INFO_TYPE:
case FUNCTION_TEMPLATE_INFO_TYPE:
case OBJECT_TEMPLATE_INFO_TYPE:
case SIGNATURE_INFO_TYPE:
case TYPE_SWITCH_INFO_TYPE:
......
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