| Index: src/compiler/js-native-context-specialization.cc
|
| diff --git a/src/compiler/js-native-context-specialization.cc b/src/compiler/js-native-context-specialization.cc
|
| index bbb9531495039648c43b008d3f13d72f6f31fb2b..728e8a33e8276519d37fe7806eb933b1173d0b32 100644
|
| --- a/src/compiler/js-native-context-specialization.cc
|
| +++ b/src/compiler/js-native-context-specialization.cc
|
| @@ -110,6 +110,9 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
|
| node->opcode() == IrOpcode::kJSLoadProperty ||
|
| node->opcode() == IrOpcode::kJSStoreProperty);
|
| Node* receiver = NodeProperties::GetValueInput(node, 0);
|
| + Node* context = NodeProperties::GetContextInput(node);
|
| + Node* frame_state_eager = NodeProperties::FindFrameStateBefore(node);
|
| + Node* frame_state_lazy = NodeProperties::GetFrameStateInput(node, 0);
|
| Node* effect = NodeProperties::GetEffectInput(node);
|
| Node* control = NodeProperties::GetControlInput(node);
|
|
|
| @@ -129,6 +132,14 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
|
| return NoChange();
|
| }
|
|
|
| + // TODO(turbofan): Add support for inlining into try blocks.
|
| + if (NodeProperties::IsExceptionalCall(node) ||
|
| + !(flags() & kAccessorInliningEnabled)) {
|
| + for (auto access_info : access_infos) {
|
| + if (access_info.IsAccessorConstant()) return NoChange();
|
| + }
|
| + }
|
| +
|
| // Nothing to do if we have no non-deprecated maps.
|
| if (access_infos.empty()) {
|
| return ReduceSoftDeoptimize(
|
| @@ -162,9 +173,9 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
|
| }
|
|
|
| // Generate the actual property access.
|
| - ValueEffectControl continuation =
|
| - BuildPropertyAccess(receiver, value, effect, control, name,
|
| - native_context, access_info, access_mode);
|
| + ValueEffectControl continuation = BuildPropertyAccess(
|
| + receiver, value, context, frame_state_lazy, effect, control, name,
|
| + native_context, access_info, access_mode);
|
| value = continuation.value();
|
| effect = continuation.effect();
|
| control = continuation.control();
|
| @@ -250,26 +261,32 @@ Reduction JSNativeContextSpecialization::ReduceNamedAccess(
|
| receiverissmi_effect = receiverissmi_control = nullptr;
|
| }
|
|
|
| - // Create dominating Merge+EffectPhi for this {receiver} type.
|
| + // Create single chokepoint for the control.
|
| int const this_control_count = static_cast<int>(this_controls.size());
|
| - this_control =
|
| - (this_control_count == 1)
|
| - ? this_controls.front()
|
| - : graph()->NewNode(common()->Merge(this_control_count),
|
| - this_control_count, &this_controls.front());
|
| - this_effects.push_back(this_control);
|
| - int const this_effect_count = static_cast<int>(this_effects.size());
|
| - this_effect =
|
| - (this_control_count == 1)
|
| - ? this_effects.front()
|
| - : graph()->NewNode(common()->EffectPhi(this_control_count),
|
| - this_effect_count, &this_effects.front());
|
| + if (this_control_count == 1) {
|
| + this_control = this_controls.front();
|
| + this_effect = this_effects.front();
|
| + } else {
|
| + this_control =
|
| + graph()->NewNode(common()->Merge(this_control_count),
|
| + this_control_count, &this_controls.front());
|
| + this_effects.push_back(this_control);
|
| + this_effect =
|
| + graph()->NewNode(common()->EffectPhi(this_control_count),
|
| + this_control_count + 1, &this_effects.front());
|
| +
|
| + // TODO(turbofan): The effect/control linearization will not find a
|
| + // FrameState after the EffectPhi that is generated above.
|
| + this_effect =
|
| + graph()->NewNode(common()->Checkpoint(), frame_state_eager,
|
| + this_effect, this_control);
|
| + }
|
| }
|
|
|
| // Generate the actual property access.
|
| ValueEffectControl continuation = BuildPropertyAccess(
|
| - this_receiver, this_value, this_effect, this_control, name,
|
| - native_context, access_info, access_mode);
|
| + this_receiver, this_value, context, frame_state_lazy, this_effect,
|
| + this_control, name, native_context, access_info, access_mode);
|
| values.push_back(continuation.value());
|
| effects.push_back(continuation.effect());
|
| controls.push_back(continuation.control());
|
| @@ -555,10 +572,7 @@ Reduction JSNativeContextSpecialization::ReduceElementAccess(
|
| this_control_count + 1, &this_effects.front());
|
|
|
| // TODO(turbofan): The effect/control linearization will not find a
|
| - // FrameState after the StoreField or Call that is generated for the
|
| - // elements kind transition above. This is because those operators
|
| - // don't have the kNoWrite flag on it, even though they are not
|
| - // observable by JavaScript.
|
| + // FrameState after the EffectPhi that is generated above.
|
| this_effect = graph()->NewNode(common()->Checkpoint(), frame_state,
|
| this_effect, this_control);
|
| }
|
| @@ -734,9 +748,9 @@ Reduction JSNativeContextSpecialization::ReduceJSStoreProperty(Node* node) {
|
|
|
| JSNativeContextSpecialization::ValueEffectControl
|
| JSNativeContextSpecialization::BuildPropertyAccess(
|
| - Node* receiver, Node* value, Node* effect, Node* control, Handle<Name> name,
|
| - Handle<Context> native_context, PropertyAccessInfo const& access_info,
|
| - AccessMode access_mode) {
|
| + Node* receiver, Node* value, Node* context, Node* frame_state, Node* effect,
|
| + Node* control, Handle<Name> name, Handle<Context> native_context,
|
| + PropertyAccessInfo const& access_info, AccessMode access_mode) {
|
| // Determine actual holder and perform prototype chain checks.
|
| Handle<JSObject> holder;
|
| if (access_info.holder().ToHandle(&holder)) {
|
| @@ -755,6 +769,58 @@ JSNativeContextSpecialization::BuildPropertyAccess(
|
| effect =
|
| graph()->NewNode(simplified()->CheckIf(), check, effect, control);
|
| }
|
| + } else if (access_info.IsAccessorConstant()) {
|
| + // TODO(bmeurer): Properly rewire the IfException edge here if there's any.
|
| + Node* target = jsgraph()->Constant(access_info.constant());
|
| + FrameStateInfo const& frame_info = OpParameter<FrameStateInfo>(frame_state);
|
| + Handle<SharedFunctionInfo> shared_info =
|
| + frame_info.shared_info().ToHandleChecked();
|
| + switch (access_mode) {
|
| + case AccessMode::kLoad: {
|
| + // We need a FrameState for the getter stub to restore the correct
|
| + // context before returning to fullcodegen.
|
| + FrameStateFunctionInfo const* frame_info0 =
|
| + common()->CreateFrameStateFunctionInfo(FrameStateType::kGetterStub,
|
| + 1, 0, shared_info);
|
| + Node* frame_state0 = graph()->NewNode(
|
| + common()->FrameState(BailoutId::None(),
|
| + OutputFrameStateCombine::Ignore(),
|
| + frame_info0),
|
| + graph()->NewNode(common()->StateValues(1), receiver),
|
| + jsgraph()->EmptyStateValues(), jsgraph()->EmptyStateValues(),
|
| + context, target, frame_state);
|
| +
|
| + // Introduce the call to the getter function.
|
| + value = effect = graph()->NewNode(
|
| + javascript()->CallFunction(
|
| + 2, VectorSlotPair(), ConvertReceiverMode::kNotNullOrUndefined),
|
| + target, receiver, context, frame_state0, effect, control);
|
| + control = graph()->NewNode(common()->IfSuccess(), value);
|
| + break;
|
| + }
|
| + case AccessMode::kStore: {
|
| + // We need a FrameState for the setter stub to restore the correct
|
| + // context and return the appropriate value to fullcodegen.
|
| + FrameStateFunctionInfo const* frame_info0 =
|
| + common()->CreateFrameStateFunctionInfo(FrameStateType::kSetterStub,
|
| + 2, 0, shared_info);
|
| + Node* frame_state0 = graph()->NewNode(
|
| + common()->FrameState(BailoutId::None(),
|
| + OutputFrameStateCombine::Ignore(),
|
| + frame_info0),
|
| + graph()->NewNode(common()->StateValues(2), receiver, value),
|
| + jsgraph()->EmptyStateValues(), jsgraph()->EmptyStateValues(),
|
| + context, target, frame_state);
|
| +
|
| + // Introduce the call to the setter function.
|
| + effect = graph()->NewNode(
|
| + javascript()->CallFunction(
|
| + 3, VectorSlotPair(), ConvertReceiverMode::kNotNullOrUndefined),
|
| + target, receiver, value, context, frame_state0, effect, control);
|
| + control = graph()->NewNode(common()->IfSuccess(), effect);
|
| + break;
|
| + }
|
| + }
|
| } else {
|
| DCHECK(access_info.IsDataField());
|
| FieldIndex const field_index = access_info.field_index();
|
|
|