Commit 689980f7 authored by ishell's avatar ishell Committed by Commit bot

[crankshaft] Fixing ES6 tail call elimination.

In case when F inlined normal call to G which tail calls H we should not write translation for G for the tail call site.
Otherwise we will see G in a stack trace inside H.

This CL also enables all existing tests related to ES6 tail call elimination.

TBR=bmeurer@chromium.org
BUG=v8:4698
LOG=N

Review URL: https://codereview.chromium.org/1780043004

Cr-Commit-Position: refs/heads/master@{#34830}
parent b64bcb41
......@@ -546,12 +546,7 @@ LInstruction* LChunkBuilder::DefineFixedDouble(
LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) {
HEnvironment* hydrogen_env = current_block_->last_environment();
int argument_index_accumulator = 0;
ZoneList<HValue*> objects_to_materialize(0, zone());
instr->set_environment(CreateEnvironment(hydrogen_env,
&argument_index_accumulator,
&objects_to_materialize));
return instr;
return LChunkBuilderBase::AssignEnvironment(instr, hydrogen_env);
}
......@@ -877,15 +872,28 @@ void LChunkBuilder::AddInstruction(LInstruction* instr,
chunk_->AddInstruction(instr, current_block_);
if (instr->IsCall()) {
HEnvironment* hydrogen_env = current_block_->last_environment();
HValue* hydrogen_value_for_lazy_bailout = hydrogen_val;
if (hydrogen_val->HasObservableSideEffects()) {
HSimulate* sim = HSimulate::cast(hydrogen_val->next());
sim->ReplayEnvironment(current_block_->last_environment());
hydrogen_value_for_lazy_bailout = sim;
DCHECK_NOT_NULL(hydrogen_env);
if (instr->IsTailCall()) {
hydrogen_env = hydrogen_env->outer();
if (hydrogen_env != nullptr &&
hydrogen_env->frame_type() == ARGUMENTS_ADAPTOR) {
hydrogen_env = hydrogen_env->outer();
}
} else {
if (hydrogen_val->HasObservableSideEffects()) {
HSimulate* sim = HSimulate::cast(hydrogen_val->next());
sim->ReplayEnvironment(hydrogen_env);
hydrogen_value_for_lazy_bailout = sim;
}
}
if (hydrogen_env != nullptr) {
LInstruction* bailout = LChunkBuilderBase::AssignEnvironment(
new (zone()) LLazyBailout(), hydrogen_env);
bailout->set_hydrogen_value(hydrogen_value_for_lazy_bailout);
chunk_->AddInstruction(bailout, current_block_);
}
LInstruction* bailout = AssignEnvironment(new(zone()) LLazyBailout());
bailout->set_hydrogen_value(hydrogen_value_for_lazy_bailout);
chunk_->AddInstruction(bailout, current_block_);
}
}
......@@ -1065,6 +1073,9 @@ LInstruction* LChunkBuilder::DoCallWithDescriptor(
LCallWithDescriptor* result = new(zone()) LCallWithDescriptor(
descriptor, ops, zone());
if (instr->syntactic_tail_call_mode() == TailCallMode::kAllow) {
result->MarkAsTailCall();
}
return MarkAsCall(DefineFixed(result, r0), instr);
}
......@@ -1073,6 +1084,9 @@ LInstruction* LChunkBuilder::DoInvokeFunction(HInvokeFunction* instr) {
LOperand* context = UseFixed(instr->context(), cp);
LOperand* function = UseFixed(instr->function(), r1);
LInvokeFunction* result = new(zone()) LInvokeFunction(context, function);
if (instr->syntactic_tail_call_mode() == TailCallMode::kAllow) {
result->MarkAsTailCall();
}
return MarkAsCall(DefineFixed(result, r0), instr, CANNOT_DEOPTIMIZE_EAGERLY);
}
......
......@@ -224,6 +224,11 @@ class LInstruction : public ZoneObject {
void MarkAsCall() { bit_field_ = IsCallBits::update(bit_field_, true); }
bool IsCall() const { return IsCallBits::decode(bit_field_); }
void MarkAsTailCall() {
bit_field_ = IsTailCallBits::update(bit_field_, true);
}
bool IsTailCall() const { return IsTailCallBits::decode(bit_field_); }
// Interface to the register allocator and iterators.
bool ClobbersTemps() const { return IsCall(); }
bool ClobbersRegisters() const { return IsCall(); }
......@@ -258,6 +263,7 @@ class LInstruction : public ZoneObject {
virtual LOperand* TempAt(int i) = 0;
class IsCallBits: public BitField<bool, 0, 1> {};
class IsTailCallBits : public BitField<bool, IsCallBits::kNext, 1> {};
LEnvironment* environment_;
SetOncePointer<LPointerMap> pointer_map_;
......
......@@ -715,27 +715,35 @@ void LChunkBuilder::AddInstruction(LInstruction* instr,
chunk_->AddInstruction(instr, current_block_);
if (instr->IsCall()) {
HEnvironment* hydrogen_env = current_block_->last_environment();
HValue* hydrogen_value_for_lazy_bailout = hydrogen_val;
if (hydrogen_val->HasObservableSideEffects()) {
HSimulate* sim = HSimulate::cast(hydrogen_val->next());
sim->ReplayEnvironment(current_block_->last_environment());
hydrogen_value_for_lazy_bailout = sim;
DCHECK_NOT_NULL(hydrogen_env);
if (instr->IsTailCall()) {
hydrogen_env = hydrogen_env->outer();
if (hydrogen_env != nullptr &&
hydrogen_env->frame_type() == ARGUMENTS_ADAPTOR) {
hydrogen_env = hydrogen_env->outer();
}
} else {
if (hydrogen_val->HasObservableSideEffects()) {
HSimulate* sim = HSimulate::cast(hydrogen_val->next());
sim->ReplayEnvironment(hydrogen_env);
hydrogen_value_for_lazy_bailout = sim;
}
}
if (hydrogen_env != nullptr) {
LInstruction* bailout = LChunkBuilderBase::AssignEnvironment(
new (zone()) LLazyBailout(), hydrogen_env);
bailout->set_hydrogen_value(hydrogen_value_for_lazy_bailout);
chunk_->AddInstruction(bailout, current_block_);
}
LInstruction* bailout = AssignEnvironment(new(zone()) LLazyBailout());
bailout->set_hydrogen_value(hydrogen_value_for_lazy_bailout);
chunk_->AddInstruction(bailout, current_block_);
}
}
LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) {
HEnvironment* hydrogen_env = current_block_->last_environment();
int argument_index_accumulator = 0;
ZoneList<HValue*> objects_to_materialize(0, zone());
instr->set_environment(CreateEnvironment(hydrogen_env,
&argument_index_accumulator,
&objects_to_materialize));
return instr;
return LChunkBuilderBase::AssignEnvironment(instr, hydrogen_env);
}
......@@ -1018,6 +1026,9 @@ LInstruction* LChunkBuilder::DoCallWithDescriptor(
LCallWithDescriptor* result = new(zone()) LCallWithDescriptor(descriptor,
ops,
zone());
if (instr->syntactic_tail_call_mode() == TailCallMode::kAllow) {
result->MarkAsTailCall();
}
return MarkAsCall(DefineFixed(result, x0), instr);
}
......@@ -1510,6 +1521,9 @@ LInstruction* LChunkBuilder::DoInvokeFunction(HInvokeFunction* instr) {
// The function is required (by MacroAssembler::InvokeFunction) to be in x1.
LOperand* function = UseFixed(instr->function(), x1);
LInvokeFunction* result = new(zone()) LInvokeFunction(context, function);
if (instr->syntactic_tail_call_mode() == TailCallMode::kAllow) {
result->MarkAsTailCall();
}
return MarkAsCall(DefineFixed(result, x0), instr, CANNOT_DEOPTIMIZE_EAGERLY);
}
......
......@@ -235,6 +235,11 @@ class LInstruction : public ZoneObject {
void MarkAsCall() { bit_field_ = IsCallBits::update(bit_field_, true); }
bool IsCall() const { return IsCallBits::decode(bit_field_); }
void MarkAsTailCall() {
bit_field_ = IsTailCallBits::update(bit_field_, true);
}
bool IsTailCall() const { return IsTailCallBits::decode(bit_field_); }
// Interface to the register allocator and iterators.
bool ClobbersTemps() const { return IsCall(); }
bool ClobbersRegisters() const { return IsCall(); }
......@@ -262,6 +267,7 @@ class LInstruction : public ZoneObject {
private:
class IsCallBits: public BitField<bool, 0, 1> {};
class IsTailCallBits : public BitField<bool, IsCallBits::kNext, 1> {};
LEnvironment* environment_;
SetOncePointer<LPointerMap> pointer_map_;
......
......@@ -911,6 +911,18 @@ std::ostream& HBinaryCall::PrintDataTo(std::ostream& os) const { // NOLINT
<< argument_count();
}
std::ostream& HInvokeFunction::PrintTo(std::ostream& os) const { // NOLINT
if (tail_call_mode() == TailCallMode::kAllow) os << "Tail";
return HBinaryCall::PrintTo(os);
}
std::ostream& HInvokeFunction::PrintDataTo(std::ostream& os) const { // NOLINT
HBinaryCall::PrintDataTo(os);
if (syntactic_tail_call_mode() == TailCallMode::kAllow) {
os << ", JSTailCall";
}
return os;
}
void HBoundsCheck::ApplyIndexChange() {
if (skip_check()) return;
......@@ -1033,7 +1045,11 @@ std::ostream& HCallWithDescriptor::PrintDataTo(
for (int i = 0; i < OperandCount(); i++) {
os << NameOf(OperandAt(i)) << " ";
}
return os << "#" << argument_count();
os << "#" << argument_count();
if (syntactic_tail_call_mode() == TailCallMode::kAllow) {
os << ", JSTailCall";
}
return os;
}
......
......@@ -2214,19 +2214,17 @@ class HBinaryCall : public HCall<2> {
};
enum CallMode { NORMAL_CALL, TAIL_CALL };
class HCallWithDescriptor final : public HInstruction {
public:
static HCallWithDescriptor* New(Isolate* isolate, Zone* zone, HValue* context,
HValue* target, int argument_count,
CallInterfaceDescriptor descriptor,
const Vector<HValue*>& operands,
CallMode call_mode = NORMAL_CALL) {
HCallWithDescriptor* res = new (zone) HCallWithDescriptor(
target, argument_count, descriptor, operands, call_mode, zone);
DCHECK_EQ(operands.length(), res->GetParameterCount());
static HCallWithDescriptor* New(
Isolate* isolate, Zone* zone, HValue* context, HValue* target,
int argument_count, CallInterfaceDescriptor descriptor,
const Vector<HValue*>& operands,
TailCallMode syntactic_tail_call_mode = TailCallMode::kDisallow,
TailCallMode tail_call_mode = TailCallMode::kDisallow) {
HCallWithDescriptor* res = new (zone)
HCallWithDescriptor(target, argument_count, descriptor, operands,
syntactic_tail_call_mode, tail_call_mode, zone);
return res;
}
......@@ -2248,7 +2246,16 @@ class HCallWithDescriptor final : public HInstruction {
HType CalculateInferredType() final { return HType::Tagged(); }
bool IsTailCall() const { return call_mode_ == TAIL_CALL; }
// Defines whether this instruction corresponds to a JS call at tail position.
TailCallMode syntactic_tail_call_mode() const {
return SyntacticTailCallModeField::decode(bit_field_);
}
// Defines whether this call should be generated as a tail call.
TailCallMode tail_call_mode() const {
return TailCallModeField::decode(bit_field_);
}
bool IsTailCall() const { return tail_call_mode() == TailCallMode::kAllow; }
virtual int argument_count() const {
return argument_count_;
......@@ -2268,14 +2275,18 @@ class HCallWithDescriptor final : public HInstruction {
// The argument count includes the receiver.
HCallWithDescriptor(HValue* target, int argument_count,
CallInterfaceDescriptor descriptor,
const Vector<HValue*>& operands, CallMode call_mode,
Zone* zone)
const Vector<HValue*>& operands,
TailCallMode syntactic_tail_call_mode,
TailCallMode tail_call_mode, Zone* zone)
: descriptor_(descriptor),
values_(GetParameterCount() + 1, zone),
argument_count_(argument_count),
call_mode_(call_mode) {
bit_field_(
TailCallModeField::encode(tail_call_mode) |
SyntacticTailCallModeField::encode(syntactic_tail_call_mode)) {
DCHECK_EQ(operands.length(), GetParameterCount());
// We can only tail call without any stack arguments.
DCHECK(call_mode != TAIL_CALL || argument_count == 0);
DCHECK(tail_call_mode != TailCallMode::kAllow || argument_count == 0);
AddOperand(target, zone);
for (int i = 0; i < operands.length(); i++) {
AddOperand(operands[i], zone);
......@@ -2300,15 +2311,18 @@ class HCallWithDescriptor final : public HInstruction {
CallInterfaceDescriptor descriptor_;
ZoneList<HValue*> values_;
int argument_count_;
CallMode call_mode_;
class TailCallModeField : public BitField<TailCallMode, 0, 1> {};
class SyntacticTailCallModeField
: public BitField<TailCallMode, TailCallModeField::kNext, 1> {};
uint32_t bit_field_;
};
class HInvokeFunction final : public HBinaryCall {
public:
DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P4(HInvokeFunction, HValue*,
DECLARE_INSTRUCTION_WITH_CONTEXT_FACTORY_P5(HInvokeFunction, HValue*,
Handle<JSFunction>, int,
TailCallMode);
TailCallMode, TailCallMode);
HValue* context() { return first(); }
HValue* function() { return second(); }
......@@ -2316,12 +2330,22 @@ class HInvokeFunction final : public HBinaryCall {
int formal_parameter_count() const { return formal_parameter_count_; }
bool HasStackCheck() final { return HasStackCheckField::decode(bit_field_); }
// Defines whether this instruction corresponds to a JS call at tail position.
TailCallMode syntactic_tail_call_mode() const {
return SyntacticTailCallModeField::decode(bit_field_);
}
// Defines whether this call should be generated as a tail call.
TailCallMode tail_call_mode() const {
return TailCallModeField::decode(bit_field_);
}
DECLARE_CONCRETE_INSTRUCTION(InvokeFunction)
std::ostream& PrintTo(std::ostream& os) const override; // NOLINT
std::ostream& PrintDataTo(std::ostream& os) const override; // NOLINT
private:
void set_has_stack_check(bool has_stack_check) {
bit_field_ = HasStackCheckField::update(bit_field_, has_stack_check);
......@@ -2329,10 +2353,15 @@ class HInvokeFunction final : public HBinaryCall {
HInvokeFunction(HValue* context, HValue* function,
Handle<JSFunction> known_function, int argument_count,
TailCallMode syntactic_tail_call_mode,
TailCallMode tail_call_mode)
: HBinaryCall(context, function, argument_count),
known_function_(known_function),
bit_field_(TailCallModeField::encode(tail_call_mode)) {
bit_field_(
TailCallModeField::encode(tail_call_mode) |
SyntacticTailCallModeField::encode(syntactic_tail_call_mode)) {
DCHECK(tail_call_mode != TailCallMode::kAllow ||
syntactic_tail_call_mode == TailCallMode::kAllow);
formal_parameter_count_ =
known_function.is_null()
? 0
......@@ -2349,6 +2378,8 @@ class HInvokeFunction final : public HBinaryCall {
class HasStackCheckField : public BitField<bool, 0, 1> {};
class TailCallModeField
: public BitField<TailCallMode, HasStackCheckField::kNext, 1> {};
class SyntacticTailCallModeField
: public BitField<TailCallMode, TailCallModeField::kNext, 1> {};
uint32_t bit_field_;
};
......
This diff is collapsed.
......@@ -2837,16 +2837,19 @@ class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
Handle<Map> receiver_map);
HInstruction* NewCallFunction(HValue* function, int argument_count,
TailCallMode syntactic_tail_call_mode,
ConvertReceiverMode convert_mode,
TailCallMode tail_call_mode);
HInstruction* NewCallFunctionViaIC(HValue* function, int argument_count,
TailCallMode syntactic_tail_call_mode,
ConvertReceiverMode convert_mode,
TailCallMode tail_call_mode,
FeedbackVectorSlot slot);
HInstruction* NewCallConstantFunction(Handle<JSFunction> target,
int argument_count,
TailCallMode syntactic_tail_call_mode,
TailCallMode tail_call_mode);
bool CanBeFunctionApplyArguments(Call* expr);
......
......@@ -590,11 +590,7 @@ LInstruction* LChunkBuilder::DefineFixedDouble(
LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) {
HEnvironment* hydrogen_env = current_block_->last_environment();
int argument_index_accumulator = 0;
ZoneList<HValue*> objects_to_materialize(0, zone());
instr->set_environment(CreateEnvironment(
hydrogen_env, &argument_index_accumulator, &objects_to_materialize));
return instr;
return LChunkBuilderBase::AssignEnvironment(instr, hydrogen_env);
}
......@@ -909,15 +905,28 @@ void LChunkBuilder::AddInstruction(LInstruction* instr,
chunk_->AddInstruction(instr, current_block_);
if (instr->IsCall()) {
HEnvironment* hydrogen_env = current_block_->last_environment();
HValue* hydrogen_value_for_lazy_bailout = hydrogen_val;
if (hydrogen_val->HasObservableSideEffects()) {
HSimulate* sim = HSimulate::cast(hydrogen_val->next());
sim->ReplayEnvironment(current_block_->last_environment());
hydrogen_value_for_lazy_bailout = sim;
DCHECK_NOT_NULL(hydrogen_env);
if (instr->IsTailCall()) {
hydrogen_env = hydrogen_env->outer();
if (hydrogen_env != nullptr &&
hydrogen_env->frame_type() == ARGUMENTS_ADAPTOR) {
hydrogen_env = hydrogen_env->outer();
}
} else {
if (hydrogen_val->HasObservableSideEffects()) {
HSimulate* sim = HSimulate::cast(hydrogen_val->next());
sim->ReplayEnvironment(hydrogen_env);
hydrogen_value_for_lazy_bailout = sim;
}
}
if (hydrogen_env != nullptr) {
LInstruction* bailout = LChunkBuilderBase::AssignEnvironment(
new (zone()) LLazyBailout(), hydrogen_env);
bailout->set_hydrogen_value(hydrogen_value_for_lazy_bailout);
chunk_->AddInstruction(bailout, current_block_);
}
LInstruction* bailout = AssignEnvironment(new(zone()) LLazyBailout());
bailout->set_hydrogen_value(hydrogen_value_for_lazy_bailout);
chunk_->AddInstruction(bailout, current_block_);
}
}
......@@ -1098,6 +1107,9 @@ LInstruction* LChunkBuilder::DoCallWithDescriptor(
LCallWithDescriptor* result = new(zone()) LCallWithDescriptor(
descriptor, ops, zone());
if (instr->syntactic_tail_call_mode() == TailCallMode::kAllow) {
result->MarkAsTailCall();
}
return MarkAsCall(DefineFixed(result, eax), instr, CANNOT_DEOPTIMIZE_EAGERLY);
}
......@@ -1106,6 +1118,9 @@ LInstruction* LChunkBuilder::DoInvokeFunction(HInvokeFunction* instr) {
LOperand* context = UseFixed(instr->context(), esi);
LOperand* function = UseFixed(instr->function(), edi);
LInvokeFunction* result = new(zone()) LInvokeFunction(context, function);
if (instr->syntactic_tail_call_mode() == TailCallMode::kAllow) {
result->MarkAsTailCall();
}
return MarkAsCall(DefineFixed(result, eax), instr, CANNOT_DEOPTIMIZE_EAGERLY);
}
......
......@@ -225,6 +225,11 @@ class LInstruction : public ZoneObject {
void MarkAsCall() { bit_field_ = IsCallBits::update(bit_field_, true); }
bool IsCall() const { return IsCallBits::decode(bit_field_); }
void MarkAsTailCall() {
bit_field_ = IsTailCallBits::update(bit_field_, true);
}
bool IsTailCall() const { return IsTailCallBits::decode(bit_field_); }
// Interface to the register allocator and iterators.
bool ClobbersTemps() const { return IsCall(); }
bool ClobbersRegisters() const { return IsCall(); }
......@@ -259,6 +264,7 @@ class LInstruction : public ZoneObject {
virtual LOperand* TempAt(int i) = 0;
class IsCallBits: public BitField<bool, 0, 1> {};
class IsTailCallBits : public BitField<bool, IsCallBits::kNext, 1> {};
LEnvironment* environment_;
SetOncePointer<LPointerMap> pointer_map_;
......
......@@ -508,6 +508,14 @@ void LChunkBuilderBase::Retry(BailoutReason reason) {
status_ = ABORTED;
}
LInstruction* LChunkBuilderBase::AssignEnvironment(LInstruction* instr,
HEnvironment* hydrogen_env) {
int argument_index_accumulator = 0;
ZoneList<HValue*> objects_to_materialize(0, zone());
instr->set_environment(CreateEnvironment(
hydrogen_env, &argument_index_accumulator, &objects_to_materialize));
return instr;
}
LEnvironment* LChunkBuilderBase::CreateEnvironment(
HEnvironment* hydrogen_env, int* argument_index_accumulator,
......
......@@ -745,6 +745,11 @@ class LChunkBuilderBase BASE_EMBEDDED {
// Will not be moved to a register even if one is freely available.
virtual MUST_USE_RESULT LOperand* UseAny(HValue* value) = 0;
// Assigns given environment to an instruction. An instruction which can
// deoptimize must have an environment.
LInstruction* AssignEnvironment(LInstruction* instr,
HEnvironment* hydrogen_env);
LEnvironment* CreateEnvironment(HEnvironment* hydrogen_env,
int* argument_index_accumulator,
ZoneList<HValue*>* objects_to_materialize);
......
......@@ -553,12 +553,7 @@ LInstruction* LChunkBuilder::DefineFixedDouble(
LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) {
HEnvironment* hydrogen_env = current_block_->last_environment();
int argument_index_accumulator = 0;
ZoneList<HValue*> objects_to_materialize(0, zone());
instr->set_environment(CreateEnvironment(hydrogen_env,
&argument_index_accumulator,
&objects_to_materialize));
return instr;
return LChunkBuilderBase::AssignEnvironment(instr, hydrogen_env);
}
......@@ -887,15 +882,28 @@ void LChunkBuilder::AddInstruction(LInstruction* instr,
chunk_->AddInstruction(instr, current_block_);
if (instr->IsCall()) {
HEnvironment* hydrogen_env = current_block_->last_environment();
HValue* hydrogen_value_for_lazy_bailout = hydrogen_val;
if (hydrogen_val->HasObservableSideEffects()) {
HSimulate* sim = HSimulate::cast(hydrogen_val->next());
sim->ReplayEnvironment(current_block_->last_environment());
hydrogen_value_for_lazy_bailout = sim;
DCHECK_NOT_NULL(hydrogen_env);
if (instr->IsTailCall()) {
hydrogen_env = hydrogen_env->outer();
if (hydrogen_env != nullptr &&
hydrogen_env->frame_type() == ARGUMENTS_ADAPTOR) {
hydrogen_env = hydrogen_env->outer();
}
} else {
if (hydrogen_val->HasObservableSideEffects()) {
HSimulate* sim = HSimulate::cast(hydrogen_val->next());
sim->ReplayEnvironment(hydrogen_env);
hydrogen_value_for_lazy_bailout = sim;
}
}
if (hydrogen_env != nullptr) {
LInstruction* bailout = LChunkBuilderBase::AssignEnvironment(
new (zone()) LLazyBailout(), hydrogen_env);
bailout->set_hydrogen_value(hydrogen_value_for_lazy_bailout);
chunk_->AddInstruction(bailout, current_block_);
}
LInstruction* bailout = AssignEnvironment(new(zone()) LLazyBailout());
bailout->set_hydrogen_value(hydrogen_value_for_lazy_bailout);
chunk_->AddInstruction(bailout, current_block_);
}
}
......@@ -1070,6 +1078,9 @@ LInstruction* LChunkBuilder::DoCallWithDescriptor(
LCallWithDescriptor* result = new(zone()) LCallWithDescriptor(
descriptor, ops, zone());
if (instr->syntactic_tail_call_mode() == TailCallMode::kAllow) {
result->MarkAsTailCall();
}
return MarkAsCall(DefineFixed(result, v0), instr);
}
......@@ -1078,6 +1089,9 @@ LInstruction* LChunkBuilder::DoInvokeFunction(HInvokeFunction* instr) {
LOperand* context = UseFixed(instr->context(), cp);
LOperand* function = UseFixed(instr->function(), a1);
LInvokeFunction* result = new(zone()) LInvokeFunction(context, function);
if (instr->syntactic_tail_call_mode() == TailCallMode::kAllow) {
result->MarkAsTailCall();
}
return MarkAsCall(DefineFixed(result, v0), instr, CANNOT_DEOPTIMIZE_EAGERLY);
}
......
......@@ -221,6 +221,11 @@ class LInstruction : public ZoneObject {
void MarkAsCall() { bit_field_ = IsCallBits::update(bit_field_, true); }
bool IsCall() const { return IsCallBits::decode(bit_field_); }
void MarkAsTailCall() {
bit_field_ = IsTailCallBits::update(bit_field_, true);
}
bool IsTailCall() const { return IsTailCallBits::decode(bit_field_); }
// Interface to the register allocator and iterators.
bool ClobbersTemps() const { return IsCall(); }
bool ClobbersRegisters() const { return IsCall(); }
......@@ -255,6 +260,7 @@ class LInstruction : public ZoneObject {
virtual LOperand* TempAt(int i) = 0;
class IsCallBits: public BitField<bool, 0, 1> {};
class IsTailCallBits : public BitField<bool, IsCallBits::kNext, 1> {};
LEnvironment* environment_;
SetOncePointer<LPointerMap> pointer_map_;
......
......@@ -553,12 +553,7 @@ LInstruction* LChunkBuilder::DefineFixedDouble(
LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) {
HEnvironment* hydrogen_env = current_block_->last_environment();
int argument_index_accumulator = 0;
ZoneList<HValue*> objects_to_materialize(0, zone());
instr->set_environment(CreateEnvironment(hydrogen_env,
&argument_index_accumulator,
&objects_to_materialize));
return instr;
return LChunkBuilderBase::AssignEnvironment(instr, hydrogen_env);
}
......@@ -887,15 +882,28 @@ void LChunkBuilder::AddInstruction(LInstruction* instr,
chunk_->AddInstruction(instr, current_block_);
if (instr->IsCall()) {
HEnvironment* hydrogen_env = current_block_->last_environment();
HValue* hydrogen_value_for_lazy_bailout = hydrogen_val;
if (hydrogen_val->HasObservableSideEffects()) {
HSimulate* sim = HSimulate::cast(hydrogen_val->next());
sim->ReplayEnvironment(current_block_->last_environment());
hydrogen_value_for_lazy_bailout = sim;
DCHECK_NOT_NULL(hydrogen_env);
if (instr->IsTailCall()) {
hydrogen_env = hydrogen_env->outer();
if (hydrogen_env != nullptr &&
hydrogen_env->frame_type() == ARGUMENTS_ADAPTOR) {
hydrogen_env = hydrogen_env->outer();
}
} else {
if (hydrogen_val->HasObservableSideEffects()) {
HSimulate* sim = HSimulate::cast(hydrogen_val->next());
sim->ReplayEnvironment(hydrogen_env);
hydrogen_value_for_lazy_bailout = sim;
}
}
if (hydrogen_env != nullptr) {
LInstruction* bailout = LChunkBuilderBase::AssignEnvironment(
new (zone()) LLazyBailout(), hydrogen_env);
bailout->set_hydrogen_value(hydrogen_value_for_lazy_bailout);
chunk_->AddInstruction(bailout, current_block_);
}
LInstruction* bailout = AssignEnvironment(new(zone()) LLazyBailout());
bailout->set_hydrogen_value(hydrogen_value_for_lazy_bailout);
chunk_->AddInstruction(bailout, current_block_);
}
}
......@@ -1070,6 +1078,9 @@ LInstruction* LChunkBuilder::DoCallWithDescriptor(
LCallWithDescriptor* result = new(zone()) LCallWithDescriptor(
descriptor, ops, zone());
if (instr->syntactic_tail_call_mode() == TailCallMode::kAllow) {
result->MarkAsTailCall();
}
return MarkAsCall(DefineFixed(result, v0), instr);
}
......@@ -1078,6 +1089,9 @@ LInstruction* LChunkBuilder::DoInvokeFunction(HInvokeFunction* instr) {
LOperand* context = UseFixed(instr->context(), cp);
LOperand* function = UseFixed(instr->function(), a1);
LInvokeFunction* result = new(zone()) LInvokeFunction(context, function);
if (instr->syntactic_tail_call_mode() == TailCallMode::kAllow) {
result->MarkAsTailCall();
}
return MarkAsCall(DefineFixed(result, v0), instr, CANNOT_DEOPTIMIZE_EAGERLY);
}
......
......@@ -224,6 +224,11 @@ class LInstruction : public ZoneObject {
void MarkAsCall() { bit_field_ = IsCallBits::update(bit_field_, true); }
bool IsCall() const { return IsCallBits::decode(bit_field_); }
void MarkAsTailCall() {
bit_field_ = IsTailCallBits::update(bit_field_, true);
}
bool IsTailCall() const { return IsTailCallBits::decode(bit_field_); }
// Interface to the register allocator and iterators.
bool ClobbersTemps() const { return IsCall(); }
bool ClobbersRegisters() const { return IsCall(); }
......@@ -258,6 +263,7 @@ class LInstruction : public ZoneObject {
virtual LOperand* TempAt(int i) = 0;
class IsCallBits: public BitField<bool, 0, 1> {};
class IsTailCallBits : public BitField<bool, IsCallBits::kNext, 1> {};
LEnvironment* environment_;
SetOncePointer<LPointerMap> pointer_map_;
......
......@@ -581,11 +581,7 @@ LInstruction* LChunkBuilder::DefineFixedDouble(
LInstruction* LChunkBuilder::AssignEnvironment(LInstruction* instr) {
HEnvironment* hydrogen_env = current_block_->last_environment();
int argument_index_accumulator = 0;
ZoneList<HValue*> objects_to_materialize(0, zone());
instr->set_environment(CreateEnvironment(
hydrogen_env, &argument_index_accumulator, &objects_to_materialize));
return instr;
return LChunkBuilderBase::AssignEnvironment(instr, hydrogen_env);
}
......@@ -901,15 +897,28 @@ void LChunkBuilder::AddInstruction(LInstruction* instr,
chunk_->AddInstruction(instr, current_block_);
if (instr->IsCall()) {
HEnvironment* hydrogen_env = current_block_->last_environment();
HValue* hydrogen_value_for_lazy_bailout = hydrogen_val;
if (hydrogen_val->HasObservableSideEffects()) {
HSimulate* sim = HSimulate::cast(hydrogen_val->next());
sim->ReplayEnvironment(current_block_->last_environment());
hydrogen_value_for_lazy_bailout = sim;
DCHECK_NOT_NULL(hydrogen_env);
if (instr->IsTailCall()) {
hydrogen_env = hydrogen_env->outer();
if (hydrogen_env != nullptr &&
hydrogen_env->frame_type() == ARGUMENTS_ADAPTOR) {
hydrogen_env = hydrogen_env->outer();
}
} else {
if (hydrogen_val->HasObservableSideEffects()) {
HSimulate* sim = HSimulate::cast(hydrogen_val->next());
sim->ReplayEnvironment(hydrogen_env);
hydrogen_value_for_lazy_bailout = sim;
}
}
if (hydrogen_env != nullptr) {
LInstruction* bailout = LChunkBuilderBase::AssignEnvironment(
new (zone()) LLazyBailout(), hydrogen_env);
bailout->set_hydrogen_value(hydrogen_value_for_lazy_bailout);
chunk_->AddInstruction(bailout, current_block_);
}
LInstruction* bailout = AssignEnvironment(new(zone()) LLazyBailout());
bailout->set_hydrogen_value(hydrogen_value_for_lazy_bailout);
chunk_->AddInstruction(bailout, current_block_);
}
}
......@@ -1087,6 +1096,9 @@ LInstruction* LChunkBuilder::DoCallWithDescriptor(
LCallWithDescriptor* result = new(zone()) LCallWithDescriptor(
descriptor, ops, zone());
if (instr->syntactic_tail_call_mode() == TailCallMode::kAllow) {
result->MarkAsTailCall();
}
return MarkAsCall(DefineFixed(result, rax), instr);
}
......@@ -1095,6 +1107,9 @@ LInstruction* LChunkBuilder::DoInvokeFunction(HInvokeFunction* instr) {
LOperand* context = UseFixed(instr->context(), rsi);
LOperand* function = UseFixed(instr->function(), rdi);
LInvokeFunction* result = new(zone()) LInvokeFunction(context, function);
if (instr->syntactic_tail_call_mode() == TailCallMode::kAllow) {
result->MarkAsTailCall();
}
return MarkAsCall(DefineFixed(result, rax), instr, CANNOT_DEOPTIMIZE_EAGERLY);
}
......
......@@ -221,6 +221,11 @@ class LInstruction : public ZoneObject {
void MarkAsCall() { bit_field_ = IsCallBits::update(bit_field_, true); }
bool IsCall() const { return IsCallBits::decode(bit_field_); }
void MarkAsTailCall() {
bit_field_ = IsTailCallBits::update(bit_field_, true);
}
bool IsTailCall() const { return IsTailCallBits::decode(bit_field_); }
// Interface to the register allocator and iterators.
bool ClobbersTemps() const { return IsCall(); }
bool ClobbersRegisters() const { return IsCall(); }
......@@ -259,6 +264,7 @@ class LInstruction : public ZoneObject {
virtual LOperand* TempAt(int i) = 0;
class IsCallBits: public BitField<bool, 0, 1> {};
class IsTailCallBits : public BitField<bool, IsCallBits::kNext, 1> {};
LEnvironment* environment_;
SetOncePointer<LPointerMap> pointer_map_;
......
......@@ -3,8 +3,6 @@
// found in the LICENSE file.
// Flags: --allow-natives-syntax --harmony-tailcalls
// TODO(v8:4698), TODO(ishell): support these cases.
// Flags: --turbo --nostress-opt
try {
load("mjsunit/es6/tail-call-megatest.js");
......
......@@ -3,8 +3,6 @@
// found in the LICENSE file.
// Flags: --allow-natives-syntax --harmony-tailcalls
// TODO(v8:4698), TODO(ishell): support these cases.
// Flags: --turbo --nostress-opt
try {
load("mjsunit/es6/tail-call-megatest.js");
......
......@@ -3,8 +3,6 @@
// found in the LICENSE file.
// Flags: --allow-natives-syntax --harmony-tailcalls
// TODO(v8:4698), TODO(ishell): support these cases.
// Flags: --turbo --nostress-opt
try {
load("mjsunit/es6/tail-call-megatest.js");
......
......@@ -3,8 +3,6 @@
// found in the LICENSE file.
// Flags: --allow-natives-syntax --harmony-tailcalls
// TODO(v8:4698), TODO(ishell): support these cases.
// Flags: --turbo --nostress-opt
try {
load("mjsunit/es6/tail-call-megatest.js");
......
......@@ -3,8 +3,6 @@
// found in the LICENSE file.
// Flags: --allow-natives-syntax --harmony-tailcalls
// TODO(v8:4698), TODO(ishell): support these cases.
// Flags: --turbo --nostress-opt
try {
load("mjsunit/es6/tail-call-megatest.js");
......
......@@ -3,8 +3,6 @@
// found in the LICENSE file.
// Flags: --allow-natives-syntax --harmony-tailcalls
// TODO(v8:4698), TODO(ishell): support these cases.
// Flags: --turbo --nostress-opt
try {
load("mjsunit/es6/tail-call-megatest.js");
......
......@@ -3,8 +3,6 @@
// found in the LICENSE file.
// Flags: --allow-natives-syntax --harmony-tailcalls
// TODO(v8:4698), TODO(ishell): support these cases.
// Flags: --turbo --nostress-opt
try {
load("mjsunit/es6/tail-call-megatest.js");
......
......@@ -3,8 +3,6 @@
// found in the LICENSE file.
// Flags: --allow-natives-syntax --harmony-tailcalls
// TODO(v8:4698), TODO(ishell): support these cases.
// Flags: --turbo --nostress-opt
try {
load("mjsunit/es6/tail-call-megatest.js");
......
......@@ -3,8 +3,6 @@
// found in the LICENSE file.
// Flags: --allow-natives-syntax --harmony-tailcalls
// TODO(v8:4698), TODO(ishell): support these cases.
// Flags: --turbo --nostress-opt
try {
load("mjsunit/es6/tail-call-megatest.js");
......
......@@ -3,8 +3,6 @@
// found in the LICENSE file.
// Flags: --allow-natives-syntax --harmony-tailcalls
// TODO(v8:4698), TODO(ishell): support these cases.
// Flags: --turbo --nostress-opt
try {
load("mjsunit/es6/tail-call-megatest.js");
......
......@@ -3,8 +3,6 @@
// found in the LICENSE file.
// Flags: --allow-natives-syntax --harmony-tailcalls
// TODO(v8:4698), TODO(ishell): support these cases.
// Flags: --turbo --nostress-opt
Error.prepareStackTrace = (error,stack) => {
......
......@@ -3,8 +3,6 @@
// found in the LICENSE file.
// Flags: --allow-natives-syntax --harmony-tailcalls --stack-size=100
// TODO(v8:4698), TODO(ishell): support these cases.
// Flags: --nostress-opt
//
// Tail calls work only in strict mode.
......
......@@ -3,8 +3,6 @@
// found in the LICENSE file.
// Flags: --allow-natives-syntax --harmony-tailcalls
// TODO(v8:4698), TODO(ishell): support these cases.
// Flags: --max-inlined-source-size=0
"use strict";
Error.prepareStackTrace = (error,stack) => {
......
......@@ -43,9 +43,6 @@
# This test non-deterministically runs out of memory on Windows ia32.
'regress/regress-crbug-160010': [SKIP],
# Issue 4698: not fully supported by Turbofan yet
'es6/tail-call': [PASS, NO_VARIANTS],
# Issue 3389: deopt_every_n_garbage_collections is unsafe
'regress/regress-2653': [SKIP],
......
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