Index: src/full-codegen/full-codegen.cc |
diff --git a/src/full-codegen/full-codegen.cc b/src/full-codegen/full-codegen.cc |
index bd0ca46f5eb3c27eb316bbc4c29948c839cc8569..8255089f7ef0ede6f612983fb70bdefb73a9f631 100644 |
--- a/src/full-codegen/full-codegen.cc |
+++ b/src/full-codegen/full-codegen.cc |
@@ -272,7 +272,7 @@ void FullCodeGenerator::AccumulatorValueContext::Plug(Register reg) const { |
void FullCodeGenerator::StackValueContext::Plug(Register reg) const { |
- __ Push(reg); |
+ codegen()->PushOperand(reg); |
} |
@@ -286,14 +286,36 @@ void FullCodeGenerator::TestContext::Plug(Register reg) const { |
void FullCodeGenerator::EffectContext::Plug(bool flag) const {} |
+void FullCodeGenerator::EffectContext::DropAndPlug(int count, |
+ Register reg) const { |
+ DCHECK(count > 0); |
+ codegen()->DropOperands(count); |
+} |
+ |
+void FullCodeGenerator::AccumulatorValueContext::DropAndPlug( |
+ int count, Register reg) const { |
+ DCHECK(count > 0); |
+ codegen()->DropOperands(count); |
+ __ Move(result_register(), reg); |
+} |
+ |
+void FullCodeGenerator::TestContext::DropAndPlug(int count, |
+ Register reg) const { |
+ DCHECK(count > 0); |
+ // For simplicity we always test the accumulator register. |
+ codegen()->DropOperands(count); |
+ __ Move(result_register(), reg); |
+ codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL); |
+ codegen()->DoTest(this); |
+} |
void FullCodeGenerator::EffectContext::PlugTOS() const { |
- __ Drop(1); |
+ codegen()->DropOperands(1); |
} |
void FullCodeGenerator::AccumulatorValueContext::PlugTOS() const { |
- __ Pop(result_register()); |
+ codegen()->PopOperand(result_register()); |
} |
@@ -303,7 +325,7 @@ void FullCodeGenerator::StackValueContext::PlugTOS() const { |
void FullCodeGenerator::TestContext::PlugTOS() const { |
// For simplicity we always test the accumulator register. |
- __ Pop(result_register()); |
+ codegen()->PopOperand(result_register()); |
codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL); |
codegen()->DoTest(this); |
} |
@@ -433,6 +455,47 @@ int FullCodeGenerator::DeclareGlobalsFlags() { |
DeclareGlobalsLanguageMode::encode(language_mode()); |
} |
+void FullCodeGenerator::PushOperand(Handle<Object> handle) { |
+ OperandStackDepthIncrement(1); |
+ __ Push(handle); |
+} |
+ |
+void FullCodeGenerator::PushOperand(Smi* smi) { |
+ OperandStackDepthIncrement(1); |
+ __ Push(smi); |
+} |
+ |
+void FullCodeGenerator::PushOperand(Register reg) { |
+ OperandStackDepthIncrement(1); |
+ __ Push(reg); |
+} |
+ |
+void FullCodeGenerator::PopOperand(Register reg) { |
+ OperandStackDepthDecrement(1); |
+ __ Pop(reg); |
+} |
+ |
+void FullCodeGenerator::DropOperands(int count) { |
+ OperandStackDepthDecrement(count); |
+ __ Drop(count); |
+} |
+ |
+void FullCodeGenerator::CallRuntimeWithOperands(Runtime::FunctionId id) { |
+ OperandStackDepthDecrement(Runtime::FunctionForId(id)->nargs); |
+ __ CallRuntime(id); |
+} |
+ |
+void FullCodeGenerator::OperandStackDepthIncrement(int count) { |
+ DCHECK_GE(count, 0); |
+ DCHECK_GE(operand_stack_depth_, 0); |
+ operand_stack_depth_ += count; |
+} |
+ |
+void FullCodeGenerator::OperandStackDepthDecrement(int count) { |
+ DCHECK_GE(count, 0); |
+ DCHECK_GE(operand_stack_depth_, count); |
+ operand_stack_depth_ -= count; |
+} |
void FullCodeGenerator::EmitSubString(CallRuntime* expr) { |
// Load the arguments on the stack and call the stub. |
@@ -443,6 +506,7 @@ void FullCodeGenerator::EmitSubString(CallRuntime* expr) { |
VisitForStackValue(args->at(1)); |
VisitForStackValue(args->at(2)); |
__ CallStub(&stub); |
+ OperandStackDepthDecrement(3); |
context()->Plug(result_register()); |
} |
@@ -457,19 +521,20 @@ void FullCodeGenerator::EmitRegExpExec(CallRuntime* expr) { |
VisitForStackValue(args->at(2)); |
VisitForStackValue(args->at(3)); |
__ CallStub(&stub); |
+ OperandStackDepthDecrement(4); |
context()->Plug(result_register()); |
} |
void FullCodeGenerator::EmitMathPow(CallRuntime* expr) { |
// Load the arguments on the stack and call the runtime function. |
+ MathPowStub stub(isolate(), MathPowStub::ON_STACK); |
ZoneList<Expression*>* args = expr->arguments(); |
DCHECK(args->length() == 2); |
VisitForStackValue(args->at(0)); |
VisitForStackValue(args->at(1)); |
- |
- MathPowStub stub(isolate(), MathPowStub::ON_STACK); |
__ CallStub(&stub); |
+ OperandStackDepthDecrement(2); |
context()->Plug(result_register()); |
} |
@@ -493,7 +558,7 @@ void FullCodeGenerator::EmitIntrinsicAsStubCall(CallRuntime* expr, |
__ Move(callable.descriptor().GetRegisterParameter(last), |
result_register()); |
for (int i = last; i-- > 0;) { |
- __ Pop(callable.descriptor().GetRegisterParameter(i)); |
+ PopOperand(callable.descriptor().GetRegisterParameter(i)); |
} |
} |
__ Call(callable.code(), RelocInfo::CODE_TARGET); |
@@ -943,13 +1008,37 @@ void FullCodeGenerator::EmitUnwindAndReturn() { |
EmitReturnSequence(); |
} |
+void FullCodeGenerator::EmitNamedSuperPropertyLoad(Property* prop) { |
+ // Stack: receiver, home_object |
+ SetExpressionPosition(prop); |
+ Literal* key = prop->key()->AsLiteral(); |
+ DCHECK(!key->value()->IsSmi()); |
+ DCHECK(prop->IsSuperAccess()); |
+ |
+ PushOperand(key->value()); |
+ CallRuntimeWithOperands(Runtime::kLoadFromSuper); |
+} |
+ |
+void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) { |
+ SetExpressionPosition(prop); |
+ Handle<Code> ic = CodeFactory::KeyedLoadIC(isolate()).code(); |
+ __ Move(LoadDescriptor::SlotRegister(), |
+ SmiFromSlot(prop->PropertyFeedbackSlot())); |
+ CallIC(ic); |
+} |
+ |
+void FullCodeGenerator::EmitKeyedSuperPropertyLoad(Property* prop) { |
+ // Stack: receiver, home_object, key. |
+ SetExpressionPosition(prop); |
+ CallRuntimeWithOperands(Runtime::kLoadKeyedFromSuper); |
+} |
void FullCodeGenerator::EmitPropertyKey(ObjectLiteralProperty* property, |
BailoutId bailout_id) { |
VisitForStackValue(property->key()); |
- __ CallRuntime(Runtime::kToName); |
+ CallRuntimeWithOperands(Runtime::kToName); |
PrepareForBailoutForId(bailout_id, NO_REGISTERS); |
- __ Push(result_register()); |
+ PushOperand(result_register()); |
} |
@@ -971,9 +1060,9 @@ void FullCodeGenerator::VisitWithStatement(WithStatement* stmt) { |
__ Move(callable.descriptor().GetRegisterParameter(0), result_register()); |
__ Call(callable.code(), RelocInfo::CODE_TARGET); |
PrepareForBailoutForId(stmt->ToObjectId(), NO_REGISTERS); |
- __ Push(result_register()); |
+ PushOperand(result_register()); |
PushFunctionArgumentForContextAllocation(); |
- __ CallRuntime(Runtime::kPushWithContext); |
+ CallRuntimeWithOperands(Runtime::kPushWithContext); |
StoreToFrameField(StandardFrameConstants::kContextOffset, context_register()); |
PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS); |
@@ -1166,10 +1255,10 @@ void FullCodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) { |
// Exception handler code, the exception is in the result register. |
// Extend the context before executing the catch block. |
{ Comment cmnt(masm_, "[ Extend catch context"); |
- __ Push(stmt->variable()->name()); |
- __ Push(result_register()); |
+ PushOperand(stmt->variable()->name()); |
+ PushOperand(result_register()); |
PushFunctionArgumentForContextAllocation(); |
- __ CallRuntime(Runtime::kPushCatchContext); |
+ CallRuntimeWithOperands(Runtime::kPushCatchContext); |
StoreToFrameField(StandardFrameConstants::kContextOffset, |
context_register()); |
} |
@@ -1257,16 +1346,18 @@ void FullCodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) { |
// Finally block implementation. |
__ bind(&finally_entry); |
Comment cmnt_finally(masm(), "[ Finally block"); |
+ OperandStackDepthIncrement(2); // Token and accumulator are on stack. |
EnterFinallyBlock(); |
{ |
Finally finally_body(this); |
Visit(stmt->finally_block()); |
} |
- ExitFinallyBlock(); // Return to the calling code. |
+ ExitFinallyBlock(); |
+ OperandStackDepthDecrement(2); // Token and accumulator were on stack. |
{ |
Comment cmnt_deferred(masm(), "[ Post-finally dispatch"); |
- deferred.EmitCommands(); |
+ deferred.EmitCommands(); // Return to the calling code. |
} |
} |
@@ -1292,6 +1383,7 @@ void FullCodeGenerator::VisitConditional(Conditional* expr) { |
Label true_case, false_case, done; |
VisitForControl(expr->condition(), &true_case, &false_case, &true_case); |
+ int original_stack_depth = operand_stack_depth_; |
PrepareForBailoutForId(expr->ThenId(), NO_REGISTERS); |
__ bind(&true_case); |
SetExpressionPosition(expr->then_expression()); |
@@ -1306,6 +1398,7 @@ void FullCodeGenerator::VisitConditional(Conditional* expr) { |
__ jmp(&done); |
} |
+ operand_stack_depth_ = original_stack_depth; |
PrepareForBailoutForId(expr->ElseId(), NO_REGISTERS); |
__ bind(&false_case); |
SetExpressionPosition(expr->else_expression()); |
@@ -1347,17 +1440,17 @@ void FullCodeGenerator::VisitClassLiteral(ClassLiteral* lit) { |
if (lit->extends() != NULL) { |
VisitForStackValue(lit->extends()); |
} else { |
- __ Push(isolate()->factory()->the_hole_value()); |
+ PushOperand(isolate()->factory()->the_hole_value()); |
} |
VisitForStackValue(lit->constructor()); |
- __ Push(Smi::FromInt(lit->start_position())); |
- __ Push(Smi::FromInt(lit->end_position())); |
+ PushOperand(Smi::FromInt(lit->start_position())); |
+ PushOperand(Smi::FromInt(lit->end_position())); |
- __ CallRuntime(Runtime::kDefineClass); |
+ CallRuntimeWithOperands(Runtime::kDefineClass); |
PrepareForBailoutForId(lit->CreateLiteralId(), TOS_REG); |
- __ Push(result_register()); |
+ PushOperand(result_register()); |
// Load the "prototype" from the constructor. |
__ Move(LoadDescriptor::ReceiverRegister(), result_register()); |
@@ -1366,13 +1459,13 @@ void FullCodeGenerator::VisitClassLiteral(ClassLiteral* lit) { |
__ Move(LoadDescriptor::SlotRegister(), SmiFromSlot(lit->PrototypeSlot())); |
CallLoadIC(NOT_INSIDE_TYPEOF); |
PrepareForBailoutForId(lit->PrototypeId(), TOS_REG); |
- __ Push(result_register()); |
+ PushOperand(result_register()); |
EmitClassDefineProperties(lit); |
// Set both the prototype and constructor to have fast properties, and also |
// freeze them in strong mode. |
- __ CallRuntime(Runtime::kFinalizeClassDefinition); |
+ CallRuntimeWithOperands(Runtime::kFinalizeClassDefinition); |
if (lit->class_variable_proxy() != nullptr) { |
EmitVariableAssignment(lit->class_variable_proxy()->var(), Token::INIT, |
@@ -1397,8 +1490,12 @@ void FullCodeGenerator::VisitThrow(Throw* expr) { |
Comment cmnt(masm_, "[ Throw"); |
VisitForStackValue(expr->exception()); |
SetExpressionPosition(expr); |
- __ CallRuntime(Runtime::kThrow); |
+ CallRuntimeWithOperands(Runtime::kThrow); |
// Never returns here. |
+ |
+ // Even though this expression doesn't produce a value, we need to simulate |
+ // plugging of the value context to ensure stack depth tracking is in sync. |
+ if (context()->IsStackValue()) OperandStackDepthIncrement(1); |
} |
@@ -1407,17 +1504,14 @@ void FullCodeGenerator::EnterTryBlock(int handler_index, Label* handler) { |
entry->range_start = masm()->pc_offset(); |
entry->handler_offset = handler->pos(); |
entry->try_catch_depth = try_catch_depth_; |
+ entry->stack_depth = operand_stack_depth_; |
- // Determine expression stack depth of try statement. |
- int stack_depth = info_->scope()->num_stack_slots(); // Include stack locals. |
- for (NestedStatement* current = nesting_stack_; current != NULL; /*nop*/) { |
- current = current->AccumulateDepth(&stack_depth); |
- } |
- entry->stack_depth = stack_depth; |
+ // We are using the operand stack depth, check for accuracy. |
+ EmitOperandStackDepthCheck(); |
// Push context onto operand stack. |
STATIC_ASSERT(TryBlockConstant::kElementCount == 1); |
- __ Push(context_register()); |
+ PushOperand(context_register()); |
} |
@@ -1426,7 +1520,7 @@ void FullCodeGenerator::ExitTryBlock(int handler_index) { |
entry->range_end = masm()->pc_offset(); |
// Drop context from operand stack. |
- __ Drop(TryBlockConstant::kElementCount); |
+ DropOperands(TryBlockConstant::kElementCount); |
} |
@@ -1479,6 +1573,7 @@ void FullCodeGenerator::VisitCall(Call* expr) { |
case Call::OTHER_CALL: |
// Call to an arbitrary expression not handled specially above. |
VisitForStackValue(callee); |
+ OperandStackDepthIncrement(1); |
__ PushRoot(Heap::kUndefinedValueRootIndex); |
// Emit function call. |
EmitCall(expr); |
@@ -1694,9 +1789,9 @@ FullCodeGenerator::EnterBlockScopeIfNeeded::EnterBlockScopeIfNeeded( |
{ |
if (needs_block_context_) { |
Comment cmnt(masm(), "[ Extend block context"); |
- __ Push(scope->GetScopeInfo(codegen->isolate())); |
+ codegen_->PushOperand(scope->GetScopeInfo(codegen->isolate())); |
codegen_->PushFunctionArgumentForContextAllocation(); |
- __ CallRuntime(Runtime::kPushBlockContext); |
+ codegen_->CallRuntimeWithOperands(Runtime::kPushBlockContext); |
// Replace the context stored in the frame. |
codegen_->StoreToFrameField(StandardFrameConstants::kContextOffset, |