Commit c820b89b authored by Ross McIlroy's avatar Ross McIlroy Committed by Commit Bot

[Interpreter] Remove new.target from fixed frame slot.

Removes the new.target slot from the interpreter's fixed frame. Instead
adds a field to BytecodeArray to get the bytecode's incoming
new.target or generator object register. The InterpreterEntryTrampoline
then sets this register with the incoming new.target (or generator object)
when the function is called. This register can be directly the new.target
or generator object variable if they are LOCAL location, otherwise it is a
temporary register which is then moved to the variable's location during the
function prologue.

This fixes a hack in the deoptimizer where we would set the new.target fixed
slot to undefined in order to avoid extending it's lifetime through the
optimized code - now it's just a standard register and can be optimized away
as normal.

Bug=v8:6644

Change-Id: Ieb8cc34cccefd9fb6634a90cbc77c6002a54f2ae
Reviewed-on: https://chromium-review.googlesource.com/608966
Commit-Queue: Ross McIlroy <rmcilroy@chromium.org>
Reviewed-by: 's avatarMichael Starzinger <mstarzinger@chromium.org>
Cr-Commit-Position: refs/heads/master@{#47320}
parent a241576f
......@@ -2,9 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/arm64/assembler-arm64.h"
#include "src/arm64/constants-arm64.h"
#ifndef V8_ARM64_FRAMES_ARM64_H_
#define V8_ARM64_FRAMES_ARM64_H_
......
......@@ -1100,7 +1100,7 @@ static void MaybeTailCallOptimizedCodeSlot(MacroAssembler* masm,
//
// The live registers are:
// o r1: the JS function object being called.
// o r3: the new target
// o r3: the incoming new target or generator object
// o cp: our context
// o fp: the caller's frame pointer
// o sp: stack pointer
......@@ -1172,9 +1172,9 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
__ mov(kInterpreterBytecodeOffsetRegister,
Operand(BytecodeArray::kHeaderSize - kHeapObjectTag));
// Push new.target, bytecode array and Smi tagged bytecode array offset.
// Push bytecode array and Smi tagged bytecode array offset.
__ SmiTag(r0, kInterpreterBytecodeOffsetRegister);
__ Push(r3, kInterpreterBytecodeArrayRegister, r0);
__ Push(kInterpreterBytecodeArrayRegister, r0);
// Allocate the local and temporary register file on the stack.
{
......@@ -1205,6 +1205,17 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
__ b(&loop_header, ge);
}
// If the bytecode array has a valid incoming new target or generator object
// register, initialize it with incoming value which was passed in r3.
Label no_incoming_new_target_or_generator_register;
__ ldr(r9, FieldMemOperand(
kInterpreterBytecodeArrayRegister,
BytecodeArray::kIncomingNewTargetOrGeneratorRegisterOffset));
__ tst(r9, r9);
__ b(eq, &no_incoming_new_target_or_generator_register);
__ str(r3, MemOperand(fp, r9, LSL, kPointerSizeLog2));
__ bind(&no_incoming_new_target_or_generator_register);
// Load accumulator and dispatch table into registers.
__ LoadRoot(kInterpreterAccumulatorRegister, Heap::kUndefinedValueRootIndex);
__ mov(kInterpreterDispatchTableRegister,
......
......@@ -1117,7 +1117,7 @@ static void MaybeTailCallOptimizedCodeSlot(MacroAssembler* masm,
//
// The live registers are:
// - x1: the JS function object being called.
// - x3: the new target
// - x3: the incoming new target or generator object
// - cp: our context.
// - fp: our caller's frame pointer.
// - jssp: stack pointer.
......@@ -1189,9 +1189,9 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
__ Mov(kInterpreterBytecodeOffsetRegister,
Operand(BytecodeArray::kHeaderSize - kHeapObjectTag));
// Push new.target, bytecode array and Smi tagged bytecode array offset.
// Push bytecode array and Smi tagged bytecode array offset.
__ SmiTag(x0, kInterpreterBytecodeOffsetRegister);
__ Push(x3, kInterpreterBytecodeArrayRegister, x0);
__ Push(kInterpreterBytecodeArrayRegister, x0);
// Allocate the local and temporary register file on the stack.
{
......@@ -1220,6 +1220,18 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
__ Bind(&loop_header);
}
// If the bytecode array has a valid incoming new target or generator object
// register, initialize it with incoming value which was passed in x3.
Label no_incoming_new_target_or_generator_register;
__ Ldrsw(x10,
FieldMemOperand(
kInterpreterBytecodeArrayRegister,
BytecodeArray::kIncomingNewTargetOrGeneratorRegisterOffset));
__ Tst(x10, x10);
__ B(eq, &no_incoming_new_target_or_generator_register);
__ Str(x3, MemOperand(fp, x10, LSL, kPointerSizeLog2));
__ Bind(&no_incoming_new_target_or_generator_register);
// Load accumulator and dispatch table into registers.
__ LoadRoot(kInterpreterAccumulatorRegister, Heap::kUndefinedValueRootIndex);
__ Mov(kInterpreterDispatchTableRegister,
......
......@@ -754,7 +754,7 @@ static void MaybeTailCallOptimizedCodeSlot(MacroAssembler* masm,
//
// The live registers are:
// o edi: the JS function object being called
// o edx: the new target
// o edx: the incoming new target or generator object
// o esi: our context
// o ebp: the caller's frame pointer
// o esp: stack pointer (pointing to return address)
......@@ -783,7 +783,6 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
__ mov(ebp, esp);
__ push(esi); // Callee's context.
__ push(edi); // Callee's JS function.
__ push(edx); // Callee's new target.
// Get the bytecode array from the function object (or from the DebugInfo if
// it is present) and load it into kInterpreterBytecodeArrayRegister.
......@@ -855,6 +854,17 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
__ j(greater_equal, &loop_header);
}
// If the bytecode array has a valid incoming new target or generator object
// register, initialize it with incoming value which was passed in edx.
Label no_incoming_new_target_or_generator_register;
__ mov(eax, FieldOperand(
kInterpreterBytecodeArrayRegister,
BytecodeArray::kIncomingNewTargetOrGeneratorRegisterOffset));
__ test(eax, eax);
__ j(zero, &no_incoming_new_target_or_generator_register);
__ mov(Operand(ebp, eax, times_pointer_size, 0), edx);
__ bind(&no_incoming_new_target_or_generator_register);
// Load accumulator, bytecode offset and dispatch table into registers.
__ LoadRoot(kInterpreterAccumulatorRegister, Heap::kUndefinedValueRootIndex);
__ mov(kInterpreterBytecodeOffsetRegister,
......@@ -894,7 +904,6 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
// function has been switched to a different kind of code and we heal the
// closure by switching the code entry field over to the new code as well.
__ bind(&switch_to_different_code_kind);
__ pop(edx); // Callee's new target.
__ pop(edi); // Callee's JS function.
__ pop(esi); // Callee's context.
__ leave(); // Leave the frame so we can tail call.
......
......@@ -1081,7 +1081,7 @@ static void MaybeTailCallOptimizedCodeSlot(MacroAssembler* masm,
//
// The live registers are:
// o a1: the JS function object being called.
// o a3: the new target
// o a3: the incoming new target or generator object
// o cp: our context
// o fp: the caller's frame pointer
// o sp: stack pointer
......@@ -1153,9 +1153,9 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
__ li(kInterpreterBytecodeOffsetRegister,
Operand(BytecodeArray::kHeaderSize - kHeapObjectTag));
// Push new.target, bytecode array and Smi tagged bytecode array offset.
// Push bytecode array and Smi tagged bytecode array offset.
__ SmiTag(t0, kInterpreterBytecodeOffsetRegister);
__ Push(a3, kInterpreterBytecodeArrayRegister, t0);
__ Push(kInterpreterBytecodeArrayRegister, t0);
// Allocate the local and temporary register file on the stack.
{
......@@ -1185,6 +1185,18 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
__ Branch(&loop_header, ge, t0, Operand(zero_reg));
}
// If the bytecode array has a valid incoming new target or generator object
// register, initialize it with incoming value which was passed in r3.
Label no_incoming_new_target_or_generator_register;
__ lw(t1, FieldMemOperand(
kInterpreterBytecodeArrayRegister,
BytecodeArray::kIncomingNewTargetOrGeneratorRegisterOffset));
__ Branch(&no_incoming_new_target_or_generator_register, eq, t1,
Operand(zero_reg));
__ Lsa(t1, fp, t1, kPointerSizeLog2);
__ sw(a3, MemOperand(t1));
__ bind(&no_incoming_new_target_or_generator_register);
// Load accumulator and dispatch table into registers.
__ LoadRoot(kInterpreterAccumulatorRegister, Heap::kUndefinedValueRootIndex);
__ li(kInterpreterDispatchTableRegister,
......
......@@ -1085,7 +1085,7 @@ static void MaybeTailCallOptimizedCodeSlot(MacroAssembler* masm,
//
// The live registers are:
// o a1: the JS function object being called.
// o a3: the new target
// o a3: the incoming new target or generator object
// o cp: our context
// o fp: the caller's frame pointer
// o sp: stack pointer
......@@ -1157,9 +1157,9 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
__ li(kInterpreterBytecodeOffsetRegister,
Operand(BytecodeArray::kHeaderSize - kHeapObjectTag));
// Push new.target, bytecode array and Smi tagged bytecode array offset.
// Push bytecode array and Smi tagged bytecode array offset.
__ SmiTag(a4, kInterpreterBytecodeOffsetRegister);
__ Push(a3, kInterpreterBytecodeArrayRegister, a4);
__ Push(kInterpreterBytecodeArrayRegister, a4);
// Allocate the local and temporary register file on the stack.
{
......@@ -1189,6 +1189,18 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
__ Branch(&loop_header, ge, a4, Operand(zero_reg));
}
// If the bytecode array has a valid incoming new target or generator object
// register, initialize it with incoming value which was passed in r3.
Label no_incoming_new_target_or_generator_register;
__ Lw(a5, FieldMemOperand(
kInterpreterBytecodeArrayRegister,
BytecodeArray::kIncomingNewTargetOrGeneratorRegisterOffset));
__ Branch(&no_incoming_new_target_or_generator_register, eq, a5,
Operand(zero_reg));
__ Dlsa(a5, fp, a5, kPointerSizeLog2);
__ Sd(a3, MemOperand(a5));
__ bind(&no_incoming_new_target_or_generator_register);
// Load accumulator and dispatch table into registers.
__ LoadRoot(kInterpreterAccumulatorRegister, Heap::kUndefinedValueRootIndex);
__ li(kInterpreterDispatchTableRegister,
......
......@@ -832,7 +832,7 @@ static void MaybeTailCallOptimizedCodeSlot(MacroAssembler* masm,
//
// The live registers are:
// o rdi: the JS function object being called
// o rdx: the new target
// o rdx: the incoming new target or generator object
// o rsi: our context
// o rbp: the caller's frame pointer
// o rsp: stack pointer (pointing to return address)
......@@ -861,7 +861,6 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
__ movp(rbp, rsp);
__ Push(rsi); // Callee's context.
__ Push(rdi); // Callee's JS function.
__ Push(rdx); // Callee's new target.
// Get the bytecode array from the function object (or from the DebugInfo if
// it is present) and load it into kInterpreterBytecodeArrayRegister.
......@@ -915,9 +914,9 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
// Do a stack check to ensure we don't go over the limit.
Label ok;
__ movp(rdx, rsp);
__ subp(rdx, rcx);
__ CompareRoot(rdx, Heap::kRealStackLimitRootIndex);
__ movp(rax, rsp);
__ subp(rax, rcx);
__ CompareRoot(rax, Heap::kRealStackLimitRootIndex);
__ j(above_equal, &ok, Label::kNear);
__ CallRuntime(Runtime::kThrowStackOverflow);
__ bind(&ok);
......@@ -925,17 +924,29 @@ void Builtins::Generate_InterpreterEntryTrampoline(MacroAssembler* masm) {
// If ok, push undefined as the initial value for all register file entries.
Label loop_header;
Label loop_check;
__ LoadRoot(rdx, Heap::kUndefinedValueRootIndex);
__ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
__ j(always, &loop_check);
__ bind(&loop_header);
// TODO(rmcilroy): Consider doing more than one push per loop iteration.
__ Push(rdx);
__ Push(rax);
// Continue loop if not done.
__ bind(&loop_check);
__ subp(rcx, Immediate(kPointerSize));
__ j(greater_equal, &loop_header, Label::kNear);
}
// If the bytecode array has a valid incoming new target or generator object
// register, initialize it with incoming value which was passed in rdx.
Label no_incoming_new_target_or_generator_register;
__ movsxlq(
rax,
FieldOperand(kInterpreterBytecodeArrayRegister,
BytecodeArray::kIncomingNewTargetOrGeneratorRegisterOffset));
__ testl(rax, rax);
__ j(zero, &no_incoming_new_target_or_generator_register, Label::kNear);
__ movp(Operand(rbp, rax, times_pointer_size, 0), rdx);
__ bind(&no_incoming_new_target_or_generator_register);
// Load accumulator and dispatch table into registers.
__ LoadRoot(kInterpreterAccumulatorRegister, Heap::kUndefinedValueRootIndex);
__ Move(
......
......@@ -25,7 +25,9 @@ namespace compiler {
class BytecodeGraphBuilder::Environment : public ZoneObject {
public:
Environment(BytecodeGraphBuilder* builder, int register_count,
int parameter_count, Node* control_dependency, Node* context);
int parameter_count,
interpreter::Register incoming_new_target_or_generator,
Node* control_dependency);
// Specifies whether environment binding methods should attach frame state
// inputs to nodes representing the value being bound. This is done because
......@@ -123,15 +125,13 @@ struct BytecodeGraphBuilder::SubEnvironment final {
// Issues:
// - Scopes - intimately tied to AST. Need to eval what is needed.
// - Need to resolve closure parameter treatment.
BytecodeGraphBuilder::Environment::Environment(BytecodeGraphBuilder* builder,
int register_count,
int parameter_count,
Node* control_dependency,
Node* context)
BytecodeGraphBuilder::Environment::Environment(
BytecodeGraphBuilder* builder, int register_count, int parameter_count,
interpreter::Register incoming_new_target_or_generator,
Node* control_dependency)
: builder_(builder),
register_count_(register_count),
parameter_count_(parameter_count),
context_(context),
control_dependency_(control_dependency),
effect_dependency_(control_dependency),
values_(builder->local_zone()),
......@@ -160,6 +160,22 @@ BytecodeGraphBuilder::Environment::Environment(BytecodeGraphBuilder* builder,
// Accumulator
accumulator_base_ = static_cast<int>(values()->size());
values()->push_back(undefined_constant);
// Context
int context_index = Linkage::GetJSCallContextParamIndex(parameter_count);
const Operator* op = common()->Parameter(context_index, "%context");
context_ = builder->graph()->NewNode(op, graph()->start());
// Incoming new.target or generator register
if (incoming_new_target_or_generator.is_valid()) {
int new_target_index =
Linkage::GetJSCallNewTargetParamIndex(parameter_count);
const Operator* op = common()->Parameter(new_target_index, "%new.target");
Node* new_target_node = builder->graph()->NewNode(op, graph()->start());
int values_index = RegisterToValuesIndex(incoming_new_target_or_generator);
values()->at(values_index) = new_target_node;
}
}
BytecodeGraphBuilder::Environment::Environment(
......@@ -198,8 +214,6 @@ Node* BytecodeGraphBuilder::Environment::LookupRegister(
return Context();
} else if (the_register.is_function_closure()) {
return builder()->GetFunctionClosure();
} else if (the_register.is_new_target()) {
return builder()->GetNewTarget();
} else {
int values_index = RegisterToValuesIndex(the_register);
return values()->at(values_index);
......@@ -461,30 +475,6 @@ BytecodeGraphBuilder::BytecodeGraphBuilder(
source_positions_(source_positions),
start_position_(shared_info->start_position(), inlining_id) {}
Node* BytecodeGraphBuilder::GetNewTarget() {
if (!new_target_.is_set()) {
int params = bytecode_array()->parameter_count();
int index = Linkage::GetJSCallNewTargetParamIndex(params);
const Operator* op = common()->Parameter(index, "%new.target");
Node* node = NewNode(op, graph()->start());
new_target_.set(node);
}
return new_target_.get();
}
Node* BytecodeGraphBuilder::GetFunctionContext() {
if (!function_context_.is_set()) {
int params = bytecode_array()->parameter_count();
int index = Linkage::GetJSCallContextParamIndex(params);
const Operator* op = common()->Parameter(index, "%context");
Node* node = NewNode(op, graph()->start());
function_context_.set(node);
}
return function_context_.get();
}
Node* BytecodeGraphBuilder::GetFunctionClosure() {
if (!function_closure_.is_set()) {
int index = Linkage::kJSCallClosureParamIndex;
......@@ -495,7 +485,6 @@ Node* BytecodeGraphBuilder::GetFunctionClosure() {
return function_closure_.get();
}
Node* BytecodeGraphBuilder::BuildLoadNativeContextField(int index) {
const Operator* op =
javascript()->LoadContext(0, Context::NATIVE_CONTEXT_INDEX, true);
......@@ -505,7 +494,6 @@ Node* BytecodeGraphBuilder::BuildLoadNativeContextField(int index) {
return result;
}
VectorSlotPair BytecodeGraphBuilder::CreateVectorSlotPair(int slot_id) {
return VectorSlotPair(feedback_vector(), feedback_vector()->ToSlot(slot_id));
}
......@@ -520,8 +508,9 @@ void BytecodeGraphBuilder::CreateGraph() {
graph()->SetStart(graph()->NewNode(common()->Start(actual_parameter_count)));
Environment env(this, bytecode_array()->register_count(),
bytecode_array()->parameter_count(), graph()->start(),
GetFunctionContext());
bytecode_array()->parameter_count(),
bytecode_array()->incoming_new_target_or_generator_register(),
graph()->start());
set_environment(&env);
VisitBytecodes();
......
......@@ -54,12 +54,6 @@ class BytecodeGraphBuilder {
// Get or create the node that represents the outer function closure.
Node* GetFunctionClosure();
// Get or create the node that represents the outer function context.
Node* GetFunctionContext();
// Get or create the node that represents the incoming new target value.
Node* GetNewTarget();
// Builder for loading the a native context field.
Node* BuildLoadNativeContextField(int index);
......@@ -377,9 +371,7 @@ class BytecodeGraphBuilder {
bool needs_eager_checkpoint_;
// Nodes representing values in the activation record.
SetOncePointer<Node> function_context_;
SetOncePointer<Node> function_closure_;
SetOncePointer<Node> new_target_;
// Control nodes that exit the function body.
ZoneVector<Node*> exit_controls_;
......
......@@ -853,7 +853,7 @@ void Deoptimizer::DoComputeInterpretedFrame(TranslatedFrame* translated_frame,
}
// There are no translation commands for the caller's pc and fp, the
// context, the function, new.target and the bytecode offset. Synthesize
// context, the function and the bytecode offset. Synthesize
// their values and set them up
// explicitly.
//
......@@ -942,13 +942,6 @@ void Deoptimizer::DoComputeInterpretedFrame(TranslatedFrame* translated_frame,
value = reinterpret_cast<intptr_t>(function);
WriteValueToOutput(function, 0, frame_index, output_offset, "function ");
// The new.target slot is only used during function activiation which is
// before the first deopt point, so should never be needed. Just set it to
// undefined.
output_offset -= kPointerSize;
Object* new_target = isolate_->heap()->undefined_value();
WriteValueToOutput(new_target, 0, frame_index, output_offset, "new_target ");
// Set the bytecode array pointer.
output_offset -= kPointerSize;
Object* bytecode_array = shared->HasBreakInfo()
......@@ -1961,8 +1954,7 @@ unsigned Deoptimizer::ComputeJavascriptFixedSize(SharedFunctionInfo* shared) {
// static
unsigned Deoptimizer::ComputeInterpretedFixedSize(SharedFunctionInfo* shared) {
// The fixed part of the frame consists of the return address, frame
// pointer, function, context, new.target, bytecode offset and all the
// incoming arguments.
// pointer, function, context, bytecode offset and all the incoming arguments.
return ComputeIncomingArgumentSize(shared) +
InterpreterFrameConstants::kFixedFrameSize;
}
......
......@@ -272,24 +272,22 @@ class BuiltinExitFrameConstants : public CommonFrameConstants {
class InterpreterFrameConstants : public AllStatic {
public:
// Fixed frame includes new.target, bytecode array, and bytecode offset.
// Fixed frame includes bytecode array and bytecode offset.
static const int kFixedFrameSize =
StandardFrameConstants::kFixedFrameSize + 3 * kPointerSize;
StandardFrameConstants::kFixedFrameSize + 2 * kPointerSize;
static const int kFixedFrameSizeFromFp =
StandardFrameConstants::kFixedFrameSizeFromFp + 3 * kPointerSize;
StandardFrameConstants::kFixedFrameSizeFromFp + 2 * kPointerSize;
// FP-relative.
static const int kLastParamFromFp = StandardFrameConstants::kCallerSPOffset;
static const int kCallerPCOffsetFromFp =
StandardFrameConstants::kCallerPCOffset;
static const int kNewTargetFromFp =
-StandardFrameConstants::kFixedFrameSizeFromFp - 1 * kPointerSize;
static const int kBytecodeArrayFromFp =
-StandardFrameConstants::kFixedFrameSizeFromFp - 2 * kPointerSize;
-StandardFrameConstants::kFixedFrameSizeFromFp - 1 * kPointerSize;
static const int kBytecodeOffsetFromFp =
-StandardFrameConstants::kFixedFrameSizeFromFp - 3 * kPointerSize;
-StandardFrameConstants::kFixedFrameSizeFromFp - 2 * kPointerSize;
static const int kRegisterFileFromFp =
-StandardFrameConstants::kFixedFrameSizeFromFp - 4 * kPointerSize;
-StandardFrameConstants::kFixedFrameSizeFromFp - 3 * kPointerSize;
static const int kExpressionsOffset = kRegisterFileFromFp;
......
......@@ -3288,6 +3288,8 @@ AllocationResult Heap::AllocateBytecodeArray(int length,
instance->set_length(length);
instance->set_frame_size(frame_size);
instance->set_parameter_count(parameter_count);
instance->set_incoming_new_target_or_generator_register(
interpreter::Register::invalid_value());
instance->set_interrupt_budget(interpreter::Interpreter::InterruptBudget());
instance->set_osr_loop_nesting_level(0);
instance->set_bytecode_age(BytecodeArray::kNoAgeBytecodeAge);
......@@ -3653,6 +3655,8 @@ AllocationResult Heap::CopyBytecodeArray(BytecodeArray* bytecode_array) {
copy->set_length(bytecode_array->length());
copy->set_frame_size(bytecode_array->frame_size());
copy->set_parameter_count(bytecode_array->parameter_count());
copy->set_incoming_new_target_or_generator_register(
bytecode_array->incoming_new_target_or_generator_register());
copy->set_constant_pool(bytecode_array->constant_pool());
copy->set_handler_table(bytecode_array->handler_table());
copy->set_source_position_table(bytecode_array->source_position_table());
......
......@@ -1455,8 +1455,7 @@ bool BytecodeArrayBuilder::RegisterIsValid(Register reg) const {
return false;
}
if (reg.is_current_context() || reg.is_function_closure() ||
reg.is_new_target()) {
if (reg.is_current_context() || reg.is_function_closure()) {
return true;
} else if (reg.is_parameter()) {
int parameter_index = reg.ToParameterIndex(parameter_count());
......
This diff is collapsed.
......@@ -147,6 +147,7 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
FeedbackSlot async_load_slot,
FeedbackSlot async_call_slot);
void AllocateTopLevelRegisters();
void VisitArgumentsObject(Variable* variable);
void VisitRestArgumentsArray(Variable* rest);
void VisitCallSuper(Call* call);
......@@ -154,8 +155,8 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
Register prototype);
void BuildClassLiteralNameProperty(ClassLiteral* expr, Register constructor);
void BuildClassLiteral(ClassLiteral* expr);
void VisitThisFunctionVariable(Variable* variable);
void VisitNewTargetVariable(Variable* variable);
void VisitThisFunctionVariable(Variable* variable);
void BuildGeneratorObjectVariableInitialization();
void VisitBlockDeclarationsAndStatements(Block* stmt);
void VisitFunctionClosureForContext();
......@@ -208,6 +209,8 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
void VisitInSameTestExecutionScope(Expression* expr);
Register GetRegisterForLocalVariable(Variable* variable);
// Returns the runtime function id for a store to super for the function's
// language mode.
inline Runtime::FunctionId StoreToSuperRuntimeId();
......@@ -218,6 +221,8 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
: ToBooleanMode::kConvertToBoolean;
}
inline Register generator_object() const;
inline BytecodeArrayBuilder* builder() const { return builder_; }
inline Zone* zone() const { return zone_; }
inline DeclarationScope* closure_scope() const { return closure_scope_; }
......@@ -280,8 +285,9 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
ContextScope* execution_context_;
ExpressionResultScope* execution_result_;
Register incoming_new_target_or_generator_;
BytecodeJumpTable* generator_jump_table_;
Register generator_object_;
Register generator_state_;
int loop_depth_;
......
......@@ -20,10 +20,6 @@ static const int kCurrentContextRegisterIndex =
(InterpreterFrameConstants::kRegisterFileFromFp -
StandardFrameConstants::kContextOffset) /
kPointerSize;
static const int kNewTargetRegisterIndex =
(InterpreterFrameConstants::kRegisterFileFromFp -
InterpreterFrameConstants::kNewTargetFromFp) /
kPointerSize;
static const int kBytecodeArrayRegisterIndex =
(InterpreterFrameConstants::kRegisterFileFromFp -
InterpreterFrameConstants::kBytecodeArrayFromFp) /
......@@ -66,12 +62,6 @@ bool Register::is_current_context() const {
return index() == kCurrentContextRegisterIndex;
}
Register Register::new_target() { return Register(kNewTargetRegisterIndex); }
bool Register::is_new_target() const {
return index() == kNewTargetRegisterIndex;
}
Register Register::bytecode_array() {
return Register(kBytecodeArrayRegisterIndex);
}
......@@ -126,8 +116,6 @@ std::string Register::ToString(int parameter_count) const {
return std::string("<context>");
} else if (is_function_closure()) {
return std::string("<closure>");
} else if (is_new_target()) {
return std::string("<new.target>");
} else if (is_parameter()) {
int parameter_index = ToParameterIndex(parameter_count);
if (parameter_index == 0) {
......
......@@ -40,10 +40,6 @@ class V8_EXPORT_PRIVATE Register final {
static Register current_context();
bool is_current_context() const;
// Returns the register for the incoming new target value.
static Register new_target();
bool is_new_target() const;
// Returns the register for the bytecode array.
static Register bytecode_array();
bool is_bytecode_array() const;
......
......@@ -2795,41 +2795,34 @@ int ByteArray::DataSize() const { return RoundUp(length(), kPointerSize); }
int ByteArray::ByteArraySize() { return SizeFor(this->length()); }
Address ByteArray::GetDataStartAddress() {
return reinterpret_cast<Address>(this) - kHeapObjectTag + kHeaderSize;
}
byte BytecodeArray::get(int index) {
DCHECK(index >= 0 && index < this->length());
return READ_BYTE_FIELD(this, kHeaderSize + index * kCharSize);
}
void BytecodeArray::set(int index, byte value) {
DCHECK(index >= 0 && index < this->length());
WRITE_BYTE_FIELD(this, kHeaderSize + index * kCharSize, value);
}
void BytecodeArray::set_frame_size(int frame_size) {
DCHECK_GE(frame_size, 0);
DCHECK(IsAligned(frame_size, static_cast<unsigned>(kPointerSize)));
WRITE_INT_FIELD(this, kFrameSizeOffset, frame_size);
}
int BytecodeArray::frame_size() const {
return READ_INT_FIELD(this, kFrameSizeOffset);
}
int BytecodeArray::register_count() const {
return frame_size() / kPointerSize;
}
void BytecodeArray::set_parameter_count(int number_of_parameters) {
DCHECK_GE(number_of_parameters, 0);
// Parameter count is stored as the size on stack of the parameters to allow
......@@ -2838,6 +2831,30 @@ void BytecodeArray::set_parameter_count(int number_of_parameters) {
(number_of_parameters << kPointerSizeLog2));
}
interpreter::Register BytecodeArray::incoming_new_target_or_generator_register()
const {
int register_operand =
READ_INT_FIELD(this, kIncomingNewTargetOrGeneratorRegisterOffset);
if (register_operand == 0) {
return interpreter::Register::invalid_value();
} else {
return interpreter::Register::FromOperand(register_operand);
}
}
void BytecodeArray::set_incoming_new_target_or_generator_register(
interpreter::Register incoming_new_target_or_generator_register) {
if (!incoming_new_target_or_generator_register.is_valid()) {
WRITE_INT_FIELD(this, kIncomingNewTargetOrGeneratorRegisterOffset, 0);
} else {
DCHECK(incoming_new_target_or_generator_register.index() <
register_count());
DCHECK_NE(0, incoming_new_target_or_generator_register.ToOperand());
WRITE_INT_FIELD(this, kIncomingNewTargetOrGeneratorRegisterOffset,
incoming_new_target_or_generator_register.ToOperand());
}
}
int BytecodeArray::interrupt_budget() const {
return READ_INT_FIELD(this, kInterruptBudgetOffset);
}
......
......@@ -17,6 +17,7 @@
#include "src/elements-kind.h"
#include "src/field-index.h"
#include "src/flags.h"
#include "src/interpreter/bytecode-register.h"
#include "src/list.h"
#include "src/messages.h"
#include "src/property-details.h"
......@@ -3310,6 +3311,13 @@ class BytecodeArray : public FixedArrayBase {
inline int parameter_count() const;
inline void set_parameter_count(int number_of_parameters);
// Register used to pass the incoming new.target or generator object from the
// fucntion call.
inline interpreter::Register incoming_new_target_or_generator_register()
const;
inline void set_incoming_new_target_or_generator_register(
interpreter::Register incoming_new_target_or_generator_register);
// Accessors for profiling count.
inline int interrupt_budget() const;
inline void set_interrupt_budget(int interrupt_budget);
......@@ -3370,7 +3378,10 @@ class BytecodeArray : public FixedArrayBase {
kHandlerTableOffset + kPointerSize;
static const int kFrameSizeOffset = kSourcePositionTableOffset + kPointerSize;
static const int kParameterSizeOffset = kFrameSizeOffset + kIntSize;
static const int kInterruptBudgetOffset = kParameterSizeOffset + kIntSize;
static const int kIncomingNewTargetOrGeneratorRegisterOffset =
kParameterSizeOffset + kIntSize;
static const int kInterruptBudgetOffset =
kIncomingNewTargetOrGeneratorRegisterOffset + kIntSize;
static const int kOSRNestingLevelOffset = kInterruptBudgetOffset + kIntSize;
static const int kBytecodeAgeOffset = kOSRNestingLevelOffset + kCharSize;
static const int kHeaderSize = kBytecodeAgeOffset + kCharSize;
......
......@@ -159,9 +159,7 @@ void BytecodeExpectationsPrinter::PrintBytecodeOperand(
Register register_value = bytecode_iterator.GetRegisterOperand(op_index);
stream << 'R';
if (op_size != OperandSize::kByte) stream << size_tag;
if (register_value.is_new_target()) {
stream << "(new_target)";
} else if (register_value.is_current_context()) {
if (register_value.is_current_context()) {
stream << "(context)";
} else if (register_value.is_function_closure()) {
stream << "(closure)";
......
......@@ -9,40 +9,40 @@ wrap: yes
snippet: "
g = function(){}; eval(''); return g();
"
frame size: 9
frame size: 10
parameter count: 1
bytecode array length: 74
bytecodes: [
B(CreateFunctionContext), U8(3),
B(PushContext), R(0),
B(PushContext), R(1),
B(Ldar), R(this),
B(StaCurrentContextSlot), U8(4),
B(CreateMappedArguments),
B(StaCurrentContextSlot), U8(6),
B(Ldar), R(new_target),
B(Ldar), R(0),
B(StaCurrentContextSlot), U8(5),
/* 30 E> */ B(StackCheck),
/* 34 S> */ B(CreateClosure), U8(0), U8(0), U8(2),
/* 36 E> */ B(StaLookupSlot), U8(1), U8(0),
/* 52 S> */ B(LdaLookupGlobalSlot), U8(2), U8(3), U8(1),
B(Star), R(1),
B(LdaConstant), U8(3),
B(Star), R(2),
B(LdaConstant), U8(3),
B(Star), R(3),
B(LdaZero),
B(Star), R(6),
B(LdaSmi), I8(30),
B(Star), R(7),
B(LdaSmi), I8(52),
B(LdaSmi), I8(30),
B(Star), R(8),
B(Mov), R(1), R(3),
B(LdaSmi), I8(52),
B(Star), R(9),
B(Mov), R(2), R(4),
B(Mov), R(closure), R(5),
B(CallRuntime), U16(Runtime::kResolvePossiblyDirectEval), R(3), U8(6),
B(Star), R(1),
/* 52 E> */ B(CallUndefinedReceiver1), R(1), R(2), U8(1),
B(Mov), R(3), R(5),
B(Mov), R(closure), R(6),
B(CallRuntime), U16(Runtime::kResolvePossiblyDirectEval), R(4), U8(6),
B(Star), R(2),
/* 52 E> */ B(CallUndefinedReceiver1), R(2), R(3), U8(1),
/* 62 S> */ B(LdaLookupGlobalSlot), U8(1), U8(7), U8(1),
B(Star), R(1),
/* 69 E> */ B(CallUndefinedReceiver0), R(1), U8(5),
B(Star), R(2),
/* 69 E> */ B(CallUndefinedReceiver0), R(2), U8(5),
/* 73 S> */ B(Return),
]
constant pool: [
......
......@@ -106,11 +106,9 @@ snippet: "
"
frame size: 4
parameter count: 1
bytecode array length: 45
bytecode array length: 40
bytecodes: [
B(Mov), R(closure), R(1),
B(Mov), R(new_target), R(0),
B(Ldar), R(0),
/* 113 E> */ B(StackCheck),
/* 118 S> */ B(Ldar), R(1),
B(GetSuperConstructor), R(2),
......@@ -151,11 +149,9 @@ snippet: "
"
frame size: 3
parameter count: 1
bytecode array length: 41
bytecode array length: 36
bytecodes: [
B(Mov), R(closure), R(1),
B(Mov), R(new_target), R(0),
B(Ldar), R(0),
/* 112 E> */ B(StackCheck),
/* 117 S> */ B(Ldar), R(1),
B(GetSuperConstructor), R(2),
......
......@@ -385,17 +385,17 @@ snippet: "
var b = 100;
return b
"
frame size: 2
frame size: 3
parameter count: 1
bytecode array length: 787
bytecodes: [
B(CreateFunctionContext), U8(254),
B(PushContext), R(0),
B(PushContext), R(1),
B(Ldar), R(this),
B(StaCurrentContextSlot), U8(4),
B(CreateUnmappedArguments),
B(Wide), B(StaCurrentContextSlot), U16(257),
B(Ldar), R(new_target),
B(Ldar), R(0),
B(StaCurrentContextSlot), U8(5),
/* 30 E> */ B(StackCheck),
/* 57 S> */ B(LdaZero),
......@@ -899,8 +899,8 @@ bytecodes: [
/* 3435 S> */ B(LdaZero),
/* 3435 E> */ B(StaCurrentContextSlot), U8(255),
/* 3438 S> */ B(LdaGlobal), U8(0), U8(2),
B(Star), R(1),
/* 3438 E> */ B(CallUndefinedReceiver0), R(1), U8(0),
B(Star), R(2),
/* 3438 E> */ B(CallUndefinedReceiver0), R(2), U8(0),
/* 3454 S> */ B(LdaSmi), I8(100),
/* 3454 E> */ B(Wide), B(StaCurrentContextSlot), U16(256),
/* 3459 S> */ B(Wide), B(LdaCurrentContextSlot), U16(256),
......
......@@ -9,35 +9,35 @@ wrap: yes
snippet: "
return eval('1;');
"
frame size: 9
frame size: 10
parameter count: 1
bytecode array length: 58
bytecodes: [
B(CreateFunctionContext), U8(3),
B(PushContext), R(0),
B(PushContext), R(1),
B(Ldar), R(this),
B(StaCurrentContextSlot), U8(4),
B(CreateMappedArguments),
B(StaCurrentContextSlot), U8(6),
B(Ldar), R(new_target),
B(Ldar), R(0),
B(StaCurrentContextSlot), U8(5),
/* 30 E> */ B(StackCheck),
/* 34 S> */ B(LdaLookupGlobalSlot), U8(0), U8(2), U8(1),
B(Star), R(1),
B(LdaConstant), U8(1),
B(Star), R(2),
B(LdaConstant), U8(1),
B(Star), R(3),
B(LdaZero),
B(Star), R(6),
B(LdaSmi), I8(30),
B(Star), R(7),
B(LdaSmi), I8(41),
B(LdaSmi), I8(30),
B(Star), R(8),
B(Mov), R(1), R(3),
B(LdaSmi), I8(41),
B(Star), R(9),
B(Mov), R(2), R(4),
B(Mov), R(closure), R(5),
B(CallRuntime), U16(Runtime::kResolvePossiblyDirectEval), R(3), U8(6),
B(Star), R(1),
/* 41 E> */ B(CallUndefinedReceiver1), R(1), R(2), U8(0),
B(Mov), R(3), R(5),
B(Mov), R(closure), R(6),
B(CallRuntime), U16(Runtime::kResolvePossiblyDirectEval), R(4), U8(6),
B(Star), R(2),
/* 41 E> */ B(CallUndefinedReceiver1), R(2), R(3), U8(0),
/* 52 S> */ B(Return),
]
constant pool: [
......
......@@ -11,10 +11,8 @@ snippet: "
"
frame size: 1
parameter count: 1
bytecode array length: 9
bytecode array length: 4
bytecodes: [
B(Mov), R(new_target), R(0),
B(Ldar), R(0),
/* 30 E> */ B(StackCheck),
/* 34 S> */ B(Ldar), R(0),
/* 52 S> */ B(Return),
......@@ -30,10 +28,8 @@ snippet: "
"
frame size: 1
parameter count: 1
bytecode array length: 8
bytecode array length: 3
bytecodes: [
B(Mov), R(new_target), R(0),
B(Ldar), R(0),
/* 30 E> */ B(StackCheck),
/* 34 S> */ B(LdaUndefined),
/* 46 S> */ B(Return),
......
......@@ -19,13 +19,11 @@ snippet: "
"
frame size: 4
parameter count: 1
bytecode array length: 24
bytecode array length: 19
bytecodes: [
B(CreateRestParameter),
B(Star), R(2),
B(Mov), R(closure), R(1),
B(Mov), R(new_target), R(0),
B(Ldar), R(0),
/* 93 E> */ B(StackCheck),
/* 93 S> */ B(Ldar), R(1),
B(GetSuperConstructor), R(3),
......@@ -53,16 +51,14 @@ snippet: "
"
frame size: 7
parameter count: 1
bytecode array length: 45
bytecode array length: 40
bytecodes: [
B(CreateRestParameter),
B(Star), R(2),
B(Mov), R(closure), R(1),
B(Mov), R(new_target), R(0),
B(Ldar), R(0),
/* 128 E> */ B(StackCheck),
B(Mov), R(2), R(3),
/* 140 S> */ B(Ldar), R(1),
/* 140 S> */ B(Ldar), R(closure),
B(GetSuperConstructor), R(4),
B(LdaSmi), I8(1),
B(Star), R(5),
......@@ -97,18 +93,16 @@ snippet: "
"
frame size: 10
parameter count: 1
bytecode array length: 77
bytecode array length: 72
bytecodes: [
B(CreateRestParameter),
B(Star), R(2),
B(Mov), R(closure), R(1),
B(Mov), R(new_target), R(0),
B(Ldar), R(0),
/* 128 E> */ B(StackCheck),
B(Mov), R(2), R(3),
/* 140 S> */ B(LdaUndefined),
B(Star), R(4),
/* 140 E> */ B(CallRuntime), U16(Runtime::k_GetSuperConstructor), R(1), U8(1),
/* 140 E> */ B(CallRuntime), U16(Runtime::k_GetSuperConstructor), R(closure), U8(1),
B(Star), R(5),
B(LdaUndefined),
B(Star), R(6),
......
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