| Index: src/compiler/instruction-selector.cc
|
| diff --git a/src/compiler/instruction-selector.cc b/src/compiler/instruction-selector.cc
|
| index 78bcc96cc67177e778eb19c7eae9b624e6a40887..587afd72453e068ce165942682a21740fbc4d64c 100644
|
| --- a/src/compiler/instruction-selector.cc
|
| +++ b/src/compiler/instruction-selector.cc
|
| @@ -251,20 +251,19 @@ void InstructionSelector::MarkAsRepresentation(MachineType rep, Node* node) {
|
|
|
| // TODO(bmeurer): Get rid of the CallBuffer business and make
|
| // InstructionSelector::VisitCall platform independent instead.
|
| -CallBuffer::CallBuffer(Zone* zone, CallDescriptor* d)
|
| - : output_count(0),
|
| - descriptor(d),
|
| - output_nodes(zone->NewArray<Node*>(d->ReturnCount())),
|
| - outputs(zone->NewArray<InstructionOperand*>(d->ReturnCount())),
|
| - fixed_and_control_args(
|
| - zone->NewArray<InstructionOperand*>(input_count() + control_count())),
|
| - fixed_count(0),
|
| - pushed_nodes(zone->NewArray<Node*>(input_count())),
|
| - pushed_count(0) {
|
| - if (d->ReturnCount() > 1) {
|
| - memset(output_nodes, 0, sizeof(Node*) * d->ReturnCount()); // NOLINT
|
| - }
|
| - memset(pushed_nodes, 0, sizeof(Node*) * input_count()); // NOLINT
|
| +CallBuffer::CallBuffer(Zone* zone, CallDescriptor* d,
|
| + FrameStateDescriptor* frame_desc)
|
| + : descriptor(d),
|
| + frame_state_descriptor(frame_desc),
|
| + output_nodes(NodeVector::allocator_type(zone)),
|
| + outputs(InstructionOperandVector::allocator_type(zone)),
|
| + instruction_args(InstructionOperandVector::allocator_type(zone)),
|
| + pushed_nodes(NodeVector::allocator_type(zone)) {
|
| + output_nodes.reserve(d->ReturnCount());
|
| + outputs.reserve(d->ReturnCount());
|
| + pushed_nodes.reserve(input_count());
|
| + instruction_args.reserve(input_count() + control_count() +
|
| + frame_state_value_count());
|
| }
|
|
|
|
|
| @@ -278,90 +277,114 @@ void InstructionSelector::InitializeCallBuffer(Node* call, CallBuffer* buffer,
|
| OperandGenerator g(this);
|
| DCHECK_EQ(call->op()->OutputCount(), buffer->descriptor->ReturnCount());
|
| DCHECK_EQ(OperatorProperties::GetValueInputCount(call->op()),
|
| - buffer->input_count());
|
| + buffer->input_count() + buffer->frame_state_count());
|
|
|
| if (buffer->descriptor->ReturnCount() > 0) {
|
| // Collect the projections that represent multiple outputs from this call.
|
| if (buffer->descriptor->ReturnCount() == 1) {
|
| - buffer->output_nodes[0] = call;
|
| + buffer->output_nodes.push_back(call);
|
| } else {
|
| - call->CollectProjections(buffer->descriptor->ReturnCount(),
|
| - buffer->output_nodes);
|
| + call->CollectProjections(&buffer->output_nodes);
|
| + DCHECK(buffer->output_nodes.size() <=
|
| + static_cast<size_t>(buffer->descriptor->ReturnCount()));
|
| }
|
|
|
| // Filter out the outputs that aren't live because no projection uses them.
|
| - for (int i = 0; i < buffer->descriptor->ReturnCount(); i++) {
|
| + for (size_t i = 0; i < buffer->output_nodes.size(); i++) {
|
| if (buffer->output_nodes[i] != NULL) {
|
| Node* output = buffer->output_nodes[i];
|
| - LinkageLocation location = buffer->descriptor->GetReturnLocation(i);
|
| + LinkageLocation location =
|
| + buffer->descriptor->GetReturnLocation(static_cast<int>(i));
|
| MarkAsRepresentation(location.representation(), output);
|
| - buffer->outputs[buffer->output_count++] =
|
| - g.DefineAsLocation(output, location);
|
| + buffer->outputs.push_back(g.DefineAsLocation(output, location));
|
| }
|
| }
|
| }
|
|
|
| - buffer->fixed_count = 1; // First argument is always the callee.
|
| + // The first argument is always the callee code.
|
| Node* callee = call->InputAt(0);
|
| switch (buffer->descriptor->kind()) {
|
| case CallDescriptor::kCallCodeObject:
|
| - buffer->fixed_and_control_args[0] =
|
| + buffer->instruction_args.push_back(
|
| (call_code_immediate && callee->opcode() == IrOpcode::kHeapConstant)
|
| ? g.UseImmediate(callee)
|
| - : g.UseRegister(callee);
|
| + : g.UseRegister(callee));
|
| break;
|
| case CallDescriptor::kCallAddress:
|
| - buffer->fixed_and_control_args[0] =
|
| + buffer->instruction_args.push_back(
|
| (call_address_immediate &&
|
| (callee->opcode() == IrOpcode::kInt32Constant ||
|
| callee->opcode() == IrOpcode::kInt64Constant))
|
| ? g.UseImmediate(callee)
|
| - : g.UseRegister(callee);
|
| + : g.UseRegister(callee));
|
| break;
|
| case CallDescriptor::kCallJSFunction:
|
| - buffer->fixed_and_control_args[0] =
|
| - g.UseLocation(callee, buffer->descriptor->GetInputLocation(0));
|
| + buffer->instruction_args.push_back(
|
| + g.UseLocation(callee, buffer->descriptor->GetInputLocation(0)));
|
| break;
|
| }
|
| + DCHECK_EQ(1, buffer->instruction_args.size());
|
| +
|
| + // If the call needs a frame state, we insert the state information as
|
| + // follows (n is the number of value inputs to the frame state):
|
| + // arg 1 : deoptimization id.
|
| + // arg 2 - arg (n + 1) : value inputs to the frame state.
|
| + if (buffer->frame_state_descriptor != NULL) {
|
| + int deoptimization_id =
|
| + sequence()->AddDeoptimizationEntry(buffer->frame_state_descriptor);
|
| + buffer->instruction_args.push_back(g.TempImmediate(deoptimization_id));
|
| +
|
| + Node* frame_state = call->InputAt(buffer->descriptor->InputCount());
|
| + AddFrameStateInputs(frame_state, &buffer->instruction_args,
|
| + buffer->frame_state_descriptor);
|
| + }
|
| + DCHECK_EQ(1 + buffer->frame_state_value_count(),
|
| + buffer->instruction_args.size());
|
|
|
| int input_count = buffer->input_count();
|
|
|
| - // Split the arguments into pushed_nodes and fixed_args. Pushed arguments
|
| - // require an explicit push instruction before the call and do not appear
|
| - // as arguments to the call. Everything else ends up as an InstructionOperand
|
| - // argument to the call.
|
| + // Split the arguments into pushed_nodes and instruction_args. Pushed
|
| + // arguments require an explicit push instruction before the call and do
|
| + // not appear as arguments to the call. Everything else ends up
|
| + // as an InstructionOperand argument to the call.
|
| InputIter iter(call->inputs().begin());
|
| + int pushed_count = 0;
|
| for (int index = 0; index < input_count; ++iter, ++index) {
|
| DCHECK(iter != call->inputs().end());
|
| DCHECK(index == iter.index());
|
| + DCHECK((*iter)->op()->opcode() != IrOpcode::kFrameState);
|
| if (index == 0) continue; // The first argument (callee) is already done.
|
| InstructionOperand* op =
|
| g.UseLocation(*iter, buffer->descriptor->GetInputLocation(index));
|
| if (UnallocatedOperand::cast(op)->HasFixedSlotPolicy()) {
|
| int stack_index = -UnallocatedOperand::cast(op)->fixed_slot_index() - 1;
|
| - DCHECK(buffer->pushed_nodes[stack_index] == NULL);
|
| + if (static_cast<size_t>(stack_index) >= buffer->pushed_nodes.size()) {
|
| + buffer->pushed_nodes.resize(stack_index + 1, NULL);
|
| + }
|
| + DCHECK_EQ(NULL, buffer->pushed_nodes[stack_index]);
|
| buffer->pushed_nodes[stack_index] = *iter;
|
| - buffer->pushed_count++;
|
| + pushed_count++;
|
| } else {
|
| - buffer->fixed_and_control_args[buffer->fixed_count] = op;
|
| - buffer->fixed_count++;
|
| + buffer->instruction_args.push_back(op);
|
| }
|
| }
|
| + CHECK_EQ(pushed_count, static_cast<int>(buffer->pushed_nodes.size()));
|
|
|
| // If the call can deoptimize, we add the continuation and deoptimization
|
| // block labels.
|
| if (buffer->descriptor->CanLazilyDeoptimize()) {
|
| DCHECK(cont_node != NULL);
|
| DCHECK(deopt_node != NULL);
|
| - buffer->fixed_and_control_args[buffer->fixed_count] = g.Label(cont_node);
|
| - buffer->fixed_and_control_args[buffer->fixed_count + 1] =
|
| - g.Label(deopt_node);
|
| + buffer->instruction_args.push_back(g.Label(cont_node));
|
| + buffer->instruction_args.push_back(g.Label(deopt_node));
|
| } else {
|
| DCHECK(cont_node == NULL);
|
| DCHECK(deopt_node == NULL);
|
| }
|
|
|
| - DCHECK(input_count == (buffer->fixed_count + buffer->pushed_count));
|
| + DCHECK(input_count ==
|
| + (buffer->instruction_args.size() - buffer->control_count() +
|
| + buffer->pushed_nodes.size() - buffer->frame_state_value_count()));
|
| }
|
|
|
|
|
| @@ -994,6 +1017,20 @@ void InstructionSelector::VisitThrow(Node* value) {
|
| }
|
|
|
|
|
| +FrameStateDescriptor* InstructionSelector::GetFrameStateDescriptor(
|
| + Node* state) {
|
| + DCHECK(state->op()->opcode() == IrOpcode::kFrameState);
|
| + BailoutId ast_id = OpParameter<BailoutId>(state);
|
| + Node* parameters = state->InputAt(0);
|
| + Node* locals = state->InputAt(1);
|
| + Node* stack = state->InputAt(2);
|
| +
|
| + return new (instruction_zone())
|
| + FrameStateDescriptor(ast_id, OpParameter<int>(parameters),
|
| + OpParameter<int>(locals), OpParameter<int>(stack));
|
| +}
|
| +
|
| +
|
| static InstructionOperand* UseOrImmediate(OperandGenerator* g, Node* input) {
|
| switch (input->opcode()) {
|
| case IrOpcode::kInt32Constant:
|
| @@ -1007,37 +1044,42 @@ static InstructionOperand* UseOrImmediate(OperandGenerator* g, Node* input) {
|
| }
|
|
|
|
|
| -void InstructionSelector::VisitDeoptimize(Node* deopt) {
|
| - DCHECK(deopt->op()->opcode() == IrOpcode::kDeoptimize);
|
| - Node* state = deopt->InputAt(0);
|
| - DCHECK(state->op()->opcode() == IrOpcode::kFrameState);
|
| - BailoutId ast_id = OpParameter<BailoutId>(state);
|
| +void InstructionSelector::AddFrameStateInputs(
|
| + Node* state, InstructionOperandVector* inputs,
|
| + FrameStateDescriptor* descriptor) {
|
| + DCHECK_EQ(IrOpcode::kFrameState, state->op()->opcode());
|
|
|
| - // Add the inputs.
|
| Node* parameters = state->InputAt(0);
|
| - int parameters_count = OpParameter<int>(parameters);
|
| -
|
| Node* locals = state->InputAt(1);
|
| - int locals_count = OpParameter<int>(locals);
|
| -
|
| Node* stack = state->InputAt(2);
|
| - int stack_count = OpParameter<int>(stack);
|
| +
|
| + DCHECK_EQ(descriptor->parameters_count(), parameters->InputCount());
|
| + DCHECK_EQ(descriptor->locals_count(), locals->InputCount());
|
| + DCHECK_EQ(descriptor->stack_count(), stack->InputCount());
|
|
|
| OperandGenerator g(this);
|
| - std::vector<InstructionOperand*> inputs;
|
| - inputs.reserve(parameters_count + locals_count + stack_count);
|
| - for (int i = 0; i < parameters_count; i++) {
|
| - inputs.push_back(UseOrImmediate(&g, parameters->InputAt(i)));
|
| + for (int i = 0; i < descriptor->parameters_count(); i++) {
|
| + inputs->push_back(UseOrImmediate(&g, parameters->InputAt(i)));
|
| }
|
| - for (int i = 0; i < locals_count; i++) {
|
| - inputs.push_back(UseOrImmediate(&g, locals->InputAt(i)));
|
| + for (int i = 0; i < descriptor->locals_count(); i++) {
|
| + inputs->push_back(UseOrImmediate(&g, locals->InputAt(i)));
|
| }
|
| - for (int i = 0; i < stack_count; i++) {
|
| - inputs.push_back(UseOrImmediate(&g, stack->InputAt(i)));
|
| + for (int i = 0; i < descriptor->stack_count(); i++) {
|
| + inputs->push_back(UseOrImmediate(&g, stack->InputAt(i)));
|
| }
|
| +}
|
| +
|
| +
|
| +void InstructionSelector::VisitDeoptimize(Node* deopt) {
|
| + DCHECK(deopt->op()->opcode() == IrOpcode::kDeoptimize);
|
| + Node* state = deopt->InputAt(0);
|
| + FrameStateDescriptor* descriptor = GetFrameStateDescriptor(state);
|
| +
|
| + InstructionOperandVector inputs(
|
| + (InstructionOperandVector::allocator_type(zone())));
|
| + inputs.reserve(descriptor->size());
|
|
|
| - FrameStateDescriptor* descriptor = new (instruction_zone())
|
| - FrameStateDescriptor(ast_id, parameters_count, locals_count, stack_count);
|
| + AddFrameStateInputs(state, &inputs, descriptor);
|
|
|
| DCHECK_EQ(descriptor->size(), inputs.size());
|
|
|
|
|