Author: [EMAIL PROTECTED]
Date: Wed Nov 19 01:06:36 2008
New Revision: 788
Modified:
branches/experimental/toiger/src/codegen-ia32.cc
branches/experimental/toiger/src/jump-target-ia32.cc
branches/experimental/toiger/src/virtual-frame-ia32.cc
branches/experimental/toiger/src/virtual-frame-ia32.h
Log:
First step toward allowing constants to appear in the virtual frame
without being materialized on the actual frame.
Currently constants are materialized almost immediately: as soon as we
call the runtime; push any non-constant value on top of them; jump,
branch, or bind a jump target; or generate code for any AST node.
Review URL: http://codereview.chromium.org/11232
Modified: branches/experimental/toiger/src/codegen-ia32.cc
==============================================================================
--- branches/experimental/toiger/src/codegen-ia32.cc (original)
+++ branches/experimental/toiger/src/codegen-ia32.cc Wed Nov 19 01:06:36
2008
@@ -158,6 +158,7 @@
frame_->AllocateStackSlots(scope_->num_stack_slots());
if (scope_->num_heap_slots() > 0) {
+ frame_->SpillAll();
Comment cmnt(masm_, "[ allocate local context");
// Save the arguments object pointer, if any.
if (arguments_object_allocated && !arguments_object_saved) {
@@ -200,17 +201,12 @@
Variable* par = scope_->parameter(i);
Slot* slot = par->slot();
if (slot != NULL && slot->type() == Slot::CONTEXT) {
- // Save the arguments object pointer, if any.
- if (arguments_object_allocated && !arguments_object_saved) {
- frame_->EmitPush(ecx);
- arguments_object_saved = true;
- }
ASSERT(!scope_->is_global_scope()); // no parameters in global
scope
__ mov(eax, frame_->ParameterAt(i));
// Loads ecx with context; used below in RecordWrite.
- __ mov(SlotOperand(slot, ecx), eax);
+ __ mov(SlotOperand(slot, edx), eax);
int offset = FixedArray::kHeaderSize + slot->index() *
kPointerSize;
- __ RecordWrite(ecx, offset, eax, ebx);
+ __ RecordWrite(edx, offset, eax, ebx);
}
}
}
@@ -240,6 +236,7 @@
// the stack, we rely on the property that loading a
// zero-sized reference will not clobber the ecx register.
if (!arguments_object_saved) {
+ frame_->SpillAll();
frame_->EmitPush(ecx);
}
arguments_ref.SetValue(NOT_CONST_INIT);
@@ -524,10 +521,10 @@
Comment cmnt(masm_, "[ UnloadReference");
int size = ref->size();
if (size == 1) {
- frame_->Pop(eax);
+ frame_->EmitPop(eax);
__ mov(frame_->Top(), eax);
} else if (size > 1) {
- frame_->Pop(eax);
+ frame_->EmitPop(eax);
frame_->Drop(size);
frame_->EmitPush(eax);
}
@@ -553,7 +550,7 @@
Comment cmnt(masm_, "[ ToBoolean");
// The value to convert should be popped from the stack.
- frame_->Pop(eax);
+ frame_->EmitPop(eax);
// Fast case checks.
@@ -711,7 +708,7 @@
if (op == Token::COMMA) {
// Simply discard left value.
- frame_->Pop(eax);
+ frame_->EmitPop(eax);
frame_->Drop();
frame_->EmitPush(eax);
return;
@@ -747,7 +744,7 @@
DeferredInlineBinaryOperation* deferred =
new DeferredInlineBinaryOperation(this, op, overwrite_mode, flags);
// Fetch the operands from the stack.
- frame_->Pop(ebx); // get y
+ frame_->EmitPop(ebx); // get y
__ mov(eax, frame_->Top()); // get x
// Generate the inline part of the code.
deferred->GenerateInlineCode();
@@ -938,7 +935,7 @@
deferred = new DeferredInlinedSmiAddReversed(this, int_value,
overwrite_mode);
}
- frame_->Pop(eax);
+ frame_->EmitPop(eax);
__ add(Operand(eax), Immediate(value));
__ j(overflow, deferred->enter(), not_taken);
__ test(eax, Immediate(kSmiTagMask));
@@ -950,7 +947,7 @@
case Token::SUB: {
DeferredCode* deferred = NULL;
- frame_->Pop(eax);
+ frame_->EmitPop(eax);
if (!reversed) {
deferred = new DeferredInlinedSmiSub(this, int_value,
overwrite_mode);
__ sub(Operand(eax), Immediate(value));
@@ -970,7 +967,7 @@
case Token::SAR: {
if (reversed) {
- frame_->Pop(eax);
+ frame_->EmitPop(eax);
frame_->EmitPush(Immediate(value));
frame_->EmitPush(eax);
GenericBinaryOperation(op, type, overwrite_mode);
@@ -979,7 +976,7 @@
DeferredCode* deferred =
new DeferredInlinedSmiOperation(this, Token::SAR, shift_value,
overwrite_mode);
- frame_->Pop(eax);
+ frame_->EmitPop(eax);
__ test(eax, Immediate(kSmiTagMask));
__ j(not_zero, deferred->enter(), not_taken);
__ sar(eax, shift_value);
@@ -992,7 +989,7 @@
case Token::SHR: {
if (reversed) {
- frame_->Pop(eax);
+ frame_->EmitPop(eax);
frame_->EmitPush(Immediate(value));
frame_->EmitPush(eax);
GenericBinaryOperation(op, type, overwrite_mode);
@@ -1001,7 +998,7 @@
DeferredCode* deferred =
new DeferredInlinedSmiOperation(this, Token::SHR, shift_value,
overwrite_mode);
- frame_->Pop(eax);
+ frame_->EmitPop(eax);
__ test(eax, Immediate(kSmiTagMask));
__ mov(ebx, Operand(eax));
__ j(not_zero, deferred->enter(), not_taken);
@@ -1020,7 +1017,7 @@
case Token::SHL: {
if (reversed) {
- frame_->Pop(eax);
+ frame_->EmitPop(eax);
frame_->EmitPush(Immediate(value));
frame_->EmitPush(eax);
GenericBinaryOperation(op, type, overwrite_mode);
@@ -1029,7 +1026,7 @@
DeferredCode* deferred =
new DeferredInlinedSmiOperation(this, Token::SHL, shift_value,
overwrite_mode);
- frame_->Pop(eax);
+ frame_->EmitPop(eax);
__ test(eax, Immediate(kSmiTagMask));
__ mov(ebx, Operand(eax));
__ j(not_zero, deferred->enter(), not_taken);
@@ -1058,7 +1055,7 @@
deferred = new DeferredInlinedSmiOperationReversed(this, op,
int_value,
overwrite_mode);
}
- frame_->Pop(eax);
+ frame_->EmitPop(eax);
__ test(eax, Immediate(kSmiTagMask));
__ j(not_zero, deferred->enter(), not_taken);
if (op == Token::BIT_AND) {
@@ -1078,7 +1075,7 @@
if (!reversed) {
frame_->EmitPush(Immediate(value));
} else {
- frame_->Pop(eax);
+ frame_->EmitPop(eax);
frame_->EmitPush(Immediate(value));
frame_->EmitPush(eax);
}
@@ -1124,11 +1121,11 @@
// Implement '>' and '<=' by reversal to obtain ECMA-262 conversion
order.
if (cc == greater || cc == less_equal) {
cc = ReverseCondition(cc);
- frame_->Pop(edx);
- frame_->Pop(eax);
+ frame_->EmitPop(edx);
+ frame_->EmitPop(eax);
} else {
- frame_->Pop(eax);
- frame_->Pop(edx);
+ frame_->EmitPop(eax);
+ frame_->EmitPop(edx);
}
// Check for the smi case.
@@ -1200,7 +1197,7 @@
SmiComparisonDeferred* deferred =
new SmiComparisonDeferred(this, cc, strict, int_value);
- frame_->Pop(eax);
+ frame_->EmitPop(eax);
__ test(eax, Immediate(kSmiTagMask));
__ j(not_zero, deferred->enter(), not_taken);
// Test smi equality by pointer comparison.
@@ -1281,6 +1278,7 @@
void CodeGenerator::VisitBlock(Block* node) {
+ frame_->SpillAll();
Comment cmnt(masm_, "[ Block");
RecordStatementPosition(node);
node->set_break_stack_height(break_stack_height_);
@@ -1293,6 +1291,7 @@
void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
+ frame_->SpillAll();
frame_->EmitPush(Immediate(pairs));
frame_->EmitPush(esi);
frame_->EmitPush(Immediate(Smi::FromInt(is_eval() ? 1 : 0)));
@@ -1302,6 +1301,8 @@
void CodeGenerator::VisitDeclaration(Declaration* node) {
+ frame_->SpillAll();
+
Comment cmnt(masm_, "[ Declaration");
Variable* var = node->proxy()->var();
ASSERT(var != NULL); // must have been resolved
@@ -1363,6 +1364,7 @@
void CodeGenerator::VisitExpressionStatement(ExpressionStatement* node) {
+ frame_->SpillAll();
Comment cmnt(masm_, "[ ExpressionStatement");
RecordStatementPosition(node);
Expression* expression = node->expression();
@@ -1374,12 +1376,14 @@
void CodeGenerator::VisitEmptyStatement(EmptyStatement* node) {
+ frame_->SpillAll();
Comment cmnt(masm_, "// EmptyStatement");
// nothing to do
}
void CodeGenerator::VisitIfStatement(IfStatement* node) {
+ frame_->SpillAll();
Comment cmnt(masm_, "[ IfStatement");
// Generate different code depending on which parts of the if statement
// are present or not.
@@ -1477,6 +1481,7 @@
void CodeGenerator::VisitContinueStatement(ContinueStatement* node) {
+ frame_->SpillAll();
Comment cmnt(masm_, "[ ContinueStatement");
RecordStatementPosition(node);
CleanStack(break_stack_height_ - node->target()->break_stack_height());
@@ -1485,6 +1490,7 @@
void CodeGenerator::VisitBreakStatement(BreakStatement* node) {
+ frame_->SpillAll();
Comment cmnt(masm_, "[ BreakStatement");
RecordStatementPosition(node);
CleanStack(break_stack_height_ - node->target()->break_stack_height());
@@ -1493,12 +1499,13 @@
void CodeGenerator::VisitReturnStatement(ReturnStatement* node) {
+ frame_->SpillAll();
Comment cmnt(masm_, "[ ReturnStatement");
RecordStatementPosition(node);
Load(node->expression());
// Move the function result into eax
- frame_->Pop(eax);
+ frame_->EmitPop(eax);
// If we're inside a try statement or the return instruction
// sequence has been generated, we just jump to that
@@ -1532,6 +1539,7 @@
void CodeGenerator::VisitWithEnterStatement(WithEnterStatement* node) {
+ frame_->SpillAll();
Comment cmnt(masm_, "[ WithEnterStatement");
RecordStatementPosition(node);
Load(node->expression());
@@ -1552,6 +1560,7 @@
void CodeGenerator::VisitWithExitStatement(WithExitStatement* node) {
+ frame_->SpillAll();
Comment cmnt(masm_, "[ WithExitStatement");
// Pop context.
__ mov(esi, ContextOperand(esi, Context::PREVIOUS_INDEX));
@@ -1586,7 +1595,7 @@
// placeholders, and fill in the addresses after the labels have been
// bound.
- frame_->Pop(eax); // supposed Smi
+ frame_->EmitPop(eax); // supposed Smi
// check range of value, if outside [0..length-1] jump to default/end
label.
ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
@@ -1638,6 +1647,7 @@
void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) {
+ frame_->SpillAll();
Comment cmnt(masm_, "[ SwitchStatement");
RecordStatementPosition(node);
node->set_break_stack_height(break_stack_height_);
@@ -1727,6 +1737,7 @@
void CodeGenerator::VisitLoopStatement(LoopStatement* node) {
+ frame_->SpillAll();
Comment cmnt(masm_, "[ LoopStatement");
RecordStatementPosition(node);
node->set_break_stack_height(break_stack_height_);
@@ -1905,6 +1916,7 @@
void CodeGenerator::VisitForInStatement(ForInStatement* node) {
+ frame_->SpillAll();
Comment cmnt(masm_, "[ ForInStatement");
RecordStatementPosition(node);
@@ -1930,7 +1942,7 @@
// Both SpiderMonkey and kjs ignore null and undefined in contrast
// to the specification. 12.6.4 mandates a call to ToObject.
- frame_->Pop(eax);
+ frame_->EmitPop(eax);
// eax: value to be iterated over
__ cmp(eax, Factory::undefined_value());
@@ -2072,7 +2084,7 @@
// Next.
node->continue_target()->Bind();
- frame_->Pop(eax);
+ frame_->EmitPop(eax);
__ add(Operand(eax), Immediate(Smi::FromInt(1)));
frame_->EmitPush(eax);
entry.Jump();
@@ -2090,6 +2102,7 @@
void CodeGenerator::VisitTryCatch(TryCatch* node) {
+ frame_->SpillAll();
Comment cmnt(masm_, "[ TryCatch");
JumpTarget try_block(this);
@@ -2169,7 +2182,7 @@
// If we can fall off the end of the try block, unlink from try chain.
if (frame_ != NULL) {
- frame_->Pop(eax);
+ frame_->EmitPop(eax);
__ mov(Operand::StaticVariable(handler_address), eax); // TOS ==
next_sp
frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1);
// next_sp popped.
@@ -2193,7 +2206,7 @@
__ lea(esp, Operand(edx, kNextOffset));
frame_->Forget(frame_->height() - handler_height);
- frame_->Pop(Operand::StaticVariable(handler_address));
+ frame_->EmitPop(Operand::StaticVariable(handler_address));
frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1);
// next_sp popped.
shadows[i]->original_target()->Jump();
@@ -2205,6 +2218,7 @@
void CodeGenerator::VisitTryFinally(TryFinally* node) {
+ frame_->SpillAll();
Comment cmnt(masm_, "[ TryFinally");
// State: Used to keep track of reason for entering the finally
@@ -2295,7 +2309,7 @@
// Reload sp from the top handler, because some statements that we
// break from (eg, for...in) may have left stuff on the stack.
// Preserve the TOS in a register across stack manipulation.
- frame_->Pop(eax);
+ frame_->EmitPop(eax);
ExternalReference handler_address(Top::k_handler_address);
__ mov(edx, Operand::StaticVariable(handler_address));
const int kNextOffset = StackHandlerConstants::kNextOffset +
@@ -2303,7 +2317,7 @@
__ lea(esp, Operand(edx, kNextOffset));
frame_->Forget(frame_->height() - handler_height);
- frame_->Pop(Operand::StaticVariable(handler_address));
+ frame_->EmitPop(Operand::StaticVariable(handler_address));
frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1);
// Next_sp popped.
frame_->EmitPush(eax);
@@ -2328,8 +2342,8 @@
if (frame_ != NULL) {
JumpTarget exit(this);
// Restore state and return value or faked TOS.
- frame_->Pop(ecx);
- frame_->Pop(eax);
+ frame_->EmitPop(ecx);
+ frame_->EmitPop(eax);
// Generate code to jump to the right destination for all used
// (formerly) shadowing targets.
@@ -2355,6 +2369,7 @@
void CodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) {
+ frame_->SpillAll();
Comment cmnt(masm_, "[ DebuggerStatement");
RecordStatementPosition(node);
frame_->CallRuntime(Runtime::kDebugBreak, 0);
@@ -2376,6 +2391,7 @@
void CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) {
+ frame_->SpillAll();
Comment cmnt(masm_, "[ FunctionLiteral");
// Build the function boilerplate and instantiate it.
@@ -2388,12 +2404,14 @@
void CodeGenerator::VisitFunctionBoilerplateLiteral(
FunctionBoilerplateLiteral* node) {
+ frame_->SpillAll();
Comment cmnt(masm_, "[ FunctionBoilerplateLiteral");
InstantiateBoilerplate(node->boilerplate());
}
void CodeGenerator::VisitConditional(Conditional* node) {
+ frame_->SpillAll();
Comment cmnt(masm_, "[ Conditional");
JumpTarget then(this);
JumpTarget else_(this);
@@ -2454,12 +2472,14 @@
void CodeGenerator::VisitSlot(Slot* node) {
+ frame_->SpillAll();
Comment cmnt(masm_, "[ Slot");
LoadFromSlot(node, typeof_state());
}
void CodeGenerator::VisitVariableProxy(VariableProxy* node) {
+ frame_->SpillAll();
Comment cmnt(masm_, "[ VariableProxy");
Variable* var = node->var();
Expression* expr = var->rewrite();
@@ -2482,6 +2502,7 @@
void CodeGenerator::VisitLiteral(Literal* node) {
+ frame_->SpillAll();
Comment cmnt(masm_, "[ Literal");
if (node->handle()->IsSmi() && !IsInlineSmi(node)) {
// To prevent long attacker-controlled byte sequences in code, larger
@@ -2526,6 +2547,7 @@
void CodeGenerator::VisitRegExpLiteral(RegExpLiteral* node) {
+ frame_->SpillAll();
Comment cmnt(masm_, "[ RegExp Literal");
RegExpDeferred* deferred = new RegExpDeferred(this, node);
@@ -2586,6 +2608,7 @@
void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) {
+ frame_->SpillAll();
Comment cmnt(masm_, "[ ObjectLiteral");
ObjectLiteralDeferred* deferred = new ObjectLiteralDeferred(this, node);
@@ -2627,7 +2650,7 @@
__ mov(eax, frame_->Top());
frame_->EmitPush(eax);
Load(property->value());
- frame_->Pop(eax);
+ frame_->EmitPop(eax);
__ Set(ecx, Immediate(key));
frame_->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0);
frame_->Drop();
@@ -2676,6 +2699,7 @@
void CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) {
+ frame_->SpillAll();
Comment cmnt(masm_, "[ ArrayLiteral");
// Call runtime to create the array literal.
@@ -2702,7 +2726,7 @@
Load(value);
// Get the value off the stack.
- frame_->Pop(eax);
+ frame_->EmitPop(eax);
// Fetch the object literal while leaving on the stack.
__ mov(ecx, frame_->Top());
// Get the elements array.
@@ -2727,6 +2751,7 @@
void CodeGenerator::VisitAssignment(Assignment* node) {
+ frame_->SpillAll();
Comment cmnt(masm_, "[ Assignment");
RecordStatementPosition(node);
@@ -2776,6 +2801,7 @@
void CodeGenerator::VisitThrow(Throw* node) {
+ frame_->SpillAll();
Comment cmnt(masm_, "[ Throw");
Load(node->exception());
@@ -2786,6 +2812,7 @@
void CodeGenerator::VisitProperty(Property* node) {
+ frame_->SpillAll();
Comment cmnt(masm_, "[ Property");
Reference property(this, node);
property.GetValue(typeof_state());
@@ -2793,6 +2820,7 @@
void CodeGenerator::VisitCall(Call* node) {
+ frame_->SpillAll();
Comment cmnt(masm_, "[ Call");
ZoneList<Expression*>* args = node->arguments();
@@ -2924,6 +2952,7 @@
void CodeGenerator::VisitCallNew(CallNew* node) {
+ frame_->SpillAll();
Comment cmnt(masm_, "[ CallNew");
// According to ECMA-262, section 11.2.2, page 44, the function
@@ -2967,7 +2996,7 @@
void CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) {
ASSERT(args->length() == 1);
Load(args->at(0));
- frame_->Pop(eax);
+ frame_->EmitPop(eax);
__ test(eax, Immediate(kSmiTagMask));
cc_reg_ = zero;
}
@@ -2976,7 +3005,7 @@
void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) {
ASSERT(args->length() == 1);
Load(args->at(0));
- frame_->Pop(eax);
+ frame_->EmitPop(eax);
__ test(eax, Immediate(kSmiTagMask | 0x80000000));
cc_reg_ = zero;
}
@@ -3001,7 +3030,7 @@
// Load the string into eax.
Load(args->at(0));
- frame_->Pop(eax);
+ frame_->EmitPop(eax);
// If the receiver is a smi return undefined.
ASSERT(kSmiTag == 0);
__ test(eax, Immediate(kSmiTagMask));
@@ -3009,7 +3038,7 @@
// Load the index into ebx.
Load(args->at(1));
- frame_->Pop(ebx);
+ frame_->EmitPop(ebx);
// Check for negative or non-smi index.
ASSERT(kSmiTag == 0);
@@ -3109,7 +3138,7 @@
// object is a smi. This can't be done with the usual test opcode so
// we copy the object to ecx and do some destructive ops on it that
// result in the right CC bits.
- frame_->Pop(eax);
+ frame_->EmitPop(eax);
__ mov(ecx, Operand(eax));
__ and_(ecx, kSmiTagMask);
__ xor_(ecx, kSmiTagMask);
@@ -3208,14 +3237,15 @@
// Load the two objects into registers and perform the comparison.
Load(args->at(0));
Load(args->at(1));
- frame_->Pop(eax);
- frame_->Pop(ecx);
+ frame_->EmitPop(eax);
+ frame_->EmitPop(ecx);
__ cmp(eax, Operand(ecx));
cc_reg_ = equal;
}
void CodeGenerator::VisitCallRuntime(CallRuntime* node) {
+ frame_->SpillAll();
if (CheckForInlineRuntimeCall(node)) {
return;
}
@@ -3254,6 +3284,7 @@
void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) {
+ frame_->SpillAll();
// Note that because of NOT and an optimization in comparison of a typeof
// expression to a literal string, this function can fail to leave a
value
// on top of the frame or in the cc register.
@@ -3328,7 +3359,7 @@
case Token::SUB: {
UnarySubStub stub;
// TODO(1222589): remove dependency of TOS being cached inside stub
- frame_->Pop(eax);
+ frame_->EmitPop(eax);
frame_->CallStub(&stub, 0);
frame_->EmitPush(eax);
break;
@@ -3338,7 +3369,7 @@
// Smi check.
JumpTarget smi_label(this);
JumpTarget continue_label(this);
- frame_->Pop(eax);
+ frame_->EmitPop(eax);
__ test(eax, Immediate(kSmiTagMask));
smi_label.Branch(zero, taken);
@@ -3361,7 +3392,7 @@
case Token::ADD: {
// Smi check.
JumpTarget continue_label(this);
- frame_->Pop(eax);
+ frame_->EmitPop(eax);
__ test(eax, Immediate(kSmiTagMask));
continue_label.Branch(zero);
@@ -3466,6 +3497,7 @@
void CodeGenerator::VisitCountOperation(CountOperation* node) {
+ frame_->SpillAll();
Comment cmnt(masm_, "[ CountOperation");
bool is_postfix = node->is_postfix();
@@ -3494,7 +3526,7 @@
new CountOperationDeferred(this, is_postfix, is_increment,
target.size() * kPointerSize);
- frame_->Pop(eax); // Load TOS into eax for calculations below
+ frame_->EmitPop(eax); // Load TOS into eax for calculations below
// Postfix: Store the old value as the result.
if (is_postfix) {
@@ -3529,6 +3561,7 @@
void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
+ frame_->SpillAll();
// Note that due to an optimization in comparison operations (typeof
// compared to a string literal), we can evaluate a binary expression
such
// as AND or OR and not leave a value on the frame or in the cc register.
@@ -3668,6 +3701,7 @@
void CodeGenerator::VisitThisFunction(ThisFunction* node) {
+ frame_->SpillAll();
frame_->EmitPush(frame_->Function());
}
@@ -3685,6 +3719,7 @@
void CodeGenerator::VisitCompareOperation(CompareOperation* node) {
+ frame_->SpillAll();
Comment cmnt(masm_, "[ CompareOperation");
// Get the expressions from the node.
@@ -3704,7 +3739,7 @@
// The 'null' value can only be equal to 'null' or 'undefined'.
if (left_is_null || right_is_null) {
Load(left_is_null ? right : left);
- frame_->Pop(eax);
+ frame_->EmitPop(eax);
__ cmp(eax, Factory::null_value());
// The 'null' value is only equal to 'undefined' if using non-strict
@@ -3742,7 +3777,7 @@
// Load the operand and move it to register edx.
LoadTypeofExpression(operation->expression());
- frame_->Pop(edx);
+ frame_->EmitPop(edx);
if (check->Equals(Heap::number_symbol())) {
__ test(edx, Immediate(kSmiTagMask));
@@ -4051,7 +4086,7 @@
// Variable::CONST because of const declarations which will
// initialize consts to 'the hole' value and by doing so, end up
// calling this code.
- frame->Pop(eax);
+ frame->EmitPop(eax);
__ mov(cgen_->SlotOperand(slot, ecx), eax);
frame->EmitPush(eax); // RecordWrite may destroy the value in eax.
if (slot->type() == Slot::CONTEXT) {
@@ -4075,7 +4110,7 @@
Handle<String> name(GetName());
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
// TODO(1222589): Make the IC grab the values from the stack.
- frame->Pop(eax);
+ frame->EmitPop(eax);
// Setup the name register.
__ mov(ecx, name);
frame->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0);
@@ -4091,7 +4126,7 @@
// Call IC code.
Handle<Code>
ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
// TODO(1222589): Make the IC grab the values from the stack.
- frame->Pop(eax);
+ frame->EmitPop(eax);
frame->CallCodeObject(ic, RelocInfo::CODE_TARGET, 0);
frame->EmitPush(eax); // IC call leaves result in eax, push it out
break;
Modified: branches/experimental/toiger/src/jump-target-ia32.cc
==============================================================================
--- branches/experimental/toiger/src/jump-target-ia32.cc (original)
+++ branches/experimental/toiger/src/jump-target-ia32.cc Wed Nov 19
01:06:36 2008
@@ -69,11 +69,12 @@
if (expected_frame_ == NULL) {
expected_frame_ = current_frame;
- code_generator_->set_frame(NULL);
+ expected_frame_->EnsureMergable();
// The frame at the actual function return will always have height
zero.
if (code_generator_->IsActualFunctionReturn(this)) {
expected_frame_->Forget(expected_frame_->height());
}
+ code_generator_->set_frame(NULL);
} else {
// No code needs to be emitted to merge to the expected frame at the
// actual function return.
@@ -100,6 +101,7 @@
if (expected_frame_ == NULL) {
expected_frame_ = new VirtualFrame(current_frame);
+ expected_frame_->EnsureMergable();
// The frame at the actual function return will always have height
zero.
if (code_generator_->IsActualFunctionReturn(this)) {
expected_frame_->Forget(expected_frame_->height());
@@ -130,6 +132,7 @@
ASSERT(expected_frame_ == NULL);
expected_frame_ = new VirtualFrame(current_frame);
+ expected_frame_->EnsureMergable();
// Adjust the expected frame's height to account for the return address
// pushed by the call instruction.
expected_frame_->Adjust(1);
@@ -153,6 +156,7 @@
if (expected_frame_ == NULL) {
expected_frame_ = new VirtualFrame(current_frame);
+ expected_frame_->EnsureMergable();
// The frame at the actual function return will always have height
zero.
if (code_generator_->IsActualFunctionReturn(this)) {
expected_frame_->Forget(expected_frame_->height());
Modified: branches/experimental/toiger/src/virtual-frame-ia32.cc
==============================================================================
--- branches/experimental/toiger/src/virtual-frame-ia32.cc (original)
+++ branches/experimental/toiger/src/virtual-frame-ia32.cc Wed Nov 19
01:06:36 2008
@@ -33,77 +33,147 @@
namespace v8 { namespace internal {
+#define __ masm_->
+
//
-------------------------------------------------------------------------
// VirtualFrame implementation.
-#define __ masm_->
-
+// On entry to a function, the virtual frame already contains the receiver,
+// the parameters, and a return address. All frame elements are in memory.
VirtualFrame::VirtualFrame(CodeGenerator* cgen)
: masm_(cgen->masm()),
elements_(0),
parameter_count_(cgen->scope()->num_parameters()),
local_count_(0),
- frame_pointer_(-1) {
- // The virtual frame contains a receiver, the parameters, and a return
- // address (all in memory) when it is created.
- Adjust(parameter_count_ + 2);
+ stack_pointer_(parameter_count_ + 1), // 0-based index of TOS.
+ frame_pointer_(kIllegalIndex) {
+ for (int i = 0; i < parameter_count_ + 2; i++) {
+ elements_.Add(FrameElement());
+ }
}
+// When cloned, a frame is a deep copy of the original.
VirtualFrame::VirtualFrame(VirtualFrame* original)
: masm_(original->masm_),
elements_(original->elements_.length()),
parameter_count_(original->parameter_count_),
local_count_(original->local_count_),
+ stack_pointer_(original->stack_pointer_),
frame_pointer_(original->frame_pointer_) {
- // Copy all the elements.
+ // Copy all the elements from the original.
for (int i = 0; i < original->elements_.length(); i++) {
elements_.Add(original->elements_[i]);
}
}
+// Modify the state of the virtual frame to match the actual frame by
adding
+// extra in-memory elements to the top of the virtual frame. The extra
+// elements will be externally materialized on the actual frame (eg, by
+// pushing an exception handler). No code is emitted.
void VirtualFrame::Adjust(int count) {
ASSERT(count >= 0);
+ ASSERT(stack_pointer_ == elements_.length() - 1);
+
for (int i = 0; i < count; i++) {
- elements_.Add(Element());
+ elements_.Add(FrameElement());
}
+ stack_pointer_ += count;
}
+// Modify the state of the virtual frame to match the actual frame by
+// removing elements from the top of the virtual frame. The elements will
+// be externally popped from the actual frame (eg, by a runtime call). No
+// code is emitted.
void VirtualFrame::Forget(int count) {
ASSERT(count >= 0);
+ ASSERT(stack_pointer_ == elements_.length() - 1);
ASSERT(elements_.length() >= count);
+
+ stack_pointer_ -= count;
for (int i = 0; i < count; i++) {
elements_.RemoveLast();
}
}
+void VirtualFrame::SpillAll() {
+ int i = 0;
+
+ // Spill dirty constants below the stack pointer.
+ for (; i <= stack_pointer_; i++) {
+ if (elements_[i].type() == FrameElement::CONSTANT &&
+ elements_[i].is_dirty()) {
+ __ mov(Operand(ebp, fp_relative(i)),
Immediate(elements_[i].handle()));
+ elements_[i] = FrameElement(); // The element is now in memory.
+ }
+ }
+
+ // Spill all constants above the stack pointer.
+ for (; i < elements_.length(); i++) {
+ ASSERT(elements_[i].type() == FrameElement::CONSTANT);
+ ASSERT(elements_[i].is_dirty());
+ stack_pointer_++;
+ __ push(Immediate(elements_[i].handle()));
+ elements_[i] = FrameElement(); // The element is now in memory.
+ }
+}
+
+
+void VirtualFrame::PrepareForCall(int frame_arg_count) {
+ ASSERT(height() >= frame_arg_count);
+
+ // The only non-memory elements of the frame are constants. Push all of
+ // them above the stack pointer to allocate space for them and to ensure
+ // the arguments are flushed to memory.
+ for (int i = stack_pointer_ + 1; i < elements_.length(); i++) {
+ ASSERT(elements_[i].type() == FrameElement::CONSTANT);
+ ASSERT(elements_[i].is_dirty());
+ stack_pointer_++;
+ elements_[i].clear_dirty();
+ __ push(Immediate(elements_[i].handle()));
+ }
+
+ // Forget the ones that will be popped by the call.
+ Forget(frame_arg_count);
+}
+
+
+void VirtualFrame::EnsureMergable() {
+ // We cannot merge to a frame that has constants as elements, because an
+ // arbitrary frame may not have constants in those locations.
+ SpillAll();
+}
+
+
void VirtualFrame::MergeTo(VirtualFrame* expected) {
ASSERT(masm_ == expected->masm_);
ASSERT(elements_.length() == expected->elements_.length());
ASSERT(parameter_count_ == expected->parameter_count_);
ASSERT(local_count_ == expected->local_count_);
ASSERT(frame_pointer_ == expected->frame_pointer_);
- for (int i = 0; i < elements_.length(); i++) {
- ASSERT(elements_[i].matches(expected->elements_[i]));
- }
+
+ // The expected frame is one we can merge to (ie, currently that means
+ // that all elements are in memory). The only thing we need to do to
+ // merge is make this one mergable too.
+ SpillAll();
+
+ ASSERT(stack_pointer_ == expected->stack_pointer_);
}
void VirtualFrame::Enter() {
Comment cmnt(masm_, "[ Enter JS frame");
- Adjust(1);
- __ push(ebp);
+ EmitPush(ebp);
- frame_pointer_ = elements_.length() - 1;
+ frame_pointer_ = stack_pointer_;
__ mov(ebp, Operand(esp));
// Store the context and the function in the frame.
- Adjust(2);
- __ push(esi);
- __ push(edi);
+ EmitPush(esi);
+ EmitPush(edi);
// Clear the function slot when generating debug code.
if (FLAG_debug_code) {
@@ -123,20 +193,21 @@
// call instruction to support patching the exit code in the
// debugger. See VisitReturnStatement for the full return sequence.
__ mov(esp, Operand(ebp));
- __ pop(ebp);
+ stack_pointer_ = frame_pointer_;
+ for (int i = elements_.length() - 1; i > stack_pointer_; i--) {
+ elements_.RemoveLast();
+ }
+
+ frame_pointer_ = kIllegalIndex;
+ EmitPop(ebp);
}
void VirtualFrame::AllocateStackSlots(int count) {
ASSERT(height() == 0);
local_count_ = count;
- Adjust(count);
- if (count > 0) {
- Comment cmnt(masm_, "[ Allocate space for locals");
- __ Set(eax, Immediate(Factory::undefined_value()));
- for (int i = 0; i < count; i++) {
- __ push(eax);
- }
+ for (int i = 0; i < count; i++) {
+ elements_.Add(FrameElement(Factory::undefined_value()));
}
}
@@ -154,22 +225,19 @@
void VirtualFrame::CallStub(CodeStub* stub, int frame_arg_count) {
- ASSERT(height() >= frame_arg_count);
- Forget(frame_arg_count);
+ PrepareForCall(frame_arg_count);
__ CallStub(stub);
}
void VirtualFrame::CallRuntime(Runtime::Function* f, int frame_arg_count) {
- ASSERT(height() >= frame_arg_count);
- Forget(frame_arg_count);
+ PrepareForCall(frame_arg_count);
__ CallRuntime(f, frame_arg_count);
}
void VirtualFrame::CallRuntime(Runtime::FunctionId id, int
frame_arg_count) {
- ASSERT(height() >= frame_arg_count);
- Forget(frame_arg_count);
+ PrepareForCall(frame_arg_count);
__ CallRuntime(id, frame_arg_count);
}
@@ -177,8 +245,7 @@
void VirtualFrame::InvokeBuiltin(Builtins::JavaScript id,
InvokeFlag flag,
int frame_arg_count) {
- ASSERT(height() >= frame_arg_count);
- Forget(frame_arg_count);
+ PrepareForCall(frame_arg_count);
__ InvokeBuiltin(id, flag);
}
@@ -186,14 +253,20 @@
void VirtualFrame::CallCodeObject(Handle<Code> code,
RelocInfo::Mode rmode,
int frame_arg_count) {
- ASSERT(height() >= frame_arg_count);
- Forget(frame_arg_count);
+ PrepareForCall(frame_arg_count);
__ call(code, rmode);
}
void VirtualFrame::Drop(int count) {
ASSERT(height() >= count);
+
+ // Discard elements above the stack pointer.
+ while (count > 0 && stack_pointer_ < elements_.length() - 1) {
+ elements_.RemoveLast();
+ }
+
+ // Discard the rest of the elements and lower the stack pointer.
Forget(count);
if (count > 0) {
__ add(Operand(esp), Immediate(count * kPointerSize));
@@ -204,34 +277,45 @@
void VirtualFrame::Drop() { Drop(1); }
-void VirtualFrame::Pop(Register reg) {
- Forget(1);
+void VirtualFrame::EmitPop(Register reg) {
+ ASSERT(stack_pointer_ == elements_.length() - 1);
+ stack_pointer_--;
+ elements_.RemoveLast();
__ pop(reg);
}
-void VirtualFrame::Pop(Operand operand) {
- Forget(1);
+void VirtualFrame::EmitPop(Operand operand) {
+ ASSERT(stack_pointer_ == elements_.length() - 1);
+ stack_pointer_--;
+ elements_.RemoveLast();
__ pop(operand);
}
void VirtualFrame::EmitPush(Register reg) {
- Adjust(1);
+ ASSERT(stack_pointer_ == elements_.length() - 1);
+ elements_.Add(FrameElement());
+ stack_pointer_++;
__ push(reg);
}
void VirtualFrame::EmitPush(Operand operand) {
- Adjust(1);
+ ASSERT(stack_pointer_ == elements_.length() - 1);
+ elements_.Add(FrameElement());
+ stack_pointer_++;
__ push(operand);
}
void VirtualFrame::EmitPush(Immediate immediate) {
- Adjust(1);
+ ASSERT(stack_pointer_ == elements_.length() - 1);
+ elements_.Add(FrameElement());
+ stack_pointer_++;
__ push(immediate);
}
+
#undef __
Modified: branches/experimental/toiger/src/virtual-frame-ia32.h
==============================================================================
--- branches/experimental/toiger/src/virtual-frame-ia32.h (original)
+++ branches/experimental/toiger/src/virtual-frame-ia32.h Wed Nov 19
01:06:36 2008
@@ -39,11 +39,50 @@
// only one kind, in-memory. Their actual location is given by their
// position in the virtual frame.
-class Element BASE_EMBEDDED {
+class FrameElement BASE_EMBEDDED {
public:
- Element() {}
+ enum Type { MEMORY, CONSTANT, LAST_TYPE = CONSTANT };
- bool matches(const Element& other) { return true; }
+ FrameElement() : type_(MEMORY) {}
+
+ explicit FrameElement(Handle<Object> value) : type_(CONSTANT |
kDirtyBit) {
+ data_.handle_ = value.location();
+ }
+
+ Type type() const { return static_cast<Type>(type_ & kTypeMask); }
+
+ bool is_dirty() const {
+ STATIC_ASSERT(kDirtyBit > LAST_TYPE);
+ return (type_ & kDirtyBit) != 0;
+ }
+
+ void set_dirty() {
+ ASSERT(type() != MEMORY);
+ type_ = type_ | kDirtyBit;
+ }
+
+ void clear_dirty() {
+ ASSERT(type() != MEMORY);
+ type_ = type_ & ~kDirtyBit;
+ }
+
+ Handle<Object> handle() const {
+ ASSERT(type() == CONSTANT);
+ return Handle<Object>(data_.handle_);
+ }
+
+ private:
+ static const int kDirtyBit = 1 << 8;
+ static const int kTypeMask = kDirtyBit - 1;
+
+ // The element's type and a dirty bit. The dirty bit can be cleared
+ // for non-memory elements to indicate that the element agrees with
+ // the value in memory in the actual frame.
+ int type_;
+
+ union {
+ Object** handle_;
+ } data_;
};
@@ -58,12 +97,10 @@
class VirtualFrame : public Malloced {
public:
- // Construct a virtual frame with the given code generator used to
- // generate code.
+ // Construct an initial virtual frame on entry to a JS function.
explicit VirtualFrame(CodeGenerator* cgen);
- // Construct a virtual frame that is a clone of an existing one,
initially
- // with an identical state.
+ // Construct a virtual frame as a clone of an existing one.
explicit VirtualFrame(VirtualFrame* original);
// The height of the virtual expression stack.
@@ -71,13 +108,22 @@
return elements_.length() - expression_base_index();
}
- // Add extra in-memory elements to the top of the frame without
generating
- // code.
+ // Add extra in-memory elements to the top of the frame to match an
actual
+ // frame (eg, the frame after an exception handler is pushed). No code
is
+ // emitted.
void Adjust(int count);
- // Forget frame elements without generating code.
+ // Forget elements from the top of the frame to match an actual frame
(eg,
+ // the frame after a runtime call). No code is emitted.
void Forget(int count);
+ // Spill all values from the frame to memory.
+ void SpillAll();
+
+ // Ensure that this frame is in a state where an arbitrary frame of the
+ // right size could be merged to it. May emit code.
+ void EnsureMergable();
+
// Make this virtual frame have a state identical to an expected virtual
// frame. As a side effect, code may be emitted to make this frame match
// the expected one.
@@ -158,10 +204,10 @@
// Drop one element.
void Drop();
- // Pop and save an element from the top of the expression stack. May
emit
- // code.
- void Pop(Register reg);
- void Pop(Operand operand);
+ // Pop and save an element from the top of the expression stack and emit
a
+ // corresponding pop instruction.
+ void EmitPop(Register reg);
+ void EmitPop(Operand operand);
// Push an element on top of the expression stack and emit a
corresponding
// push instruction.
@@ -170,6 +216,9 @@
void EmitPush(Immediate immediate);
private:
+ // An illegal index into the virtual frame.
+ static const int kIllegalIndex = -1;
+
static const int kLocal0Offset = JavaScriptFrameConstants::kLocal0Offset;
static const int kFunctionOffset =
JavaScriptFrameConstants::kFunctionOffset;
static const int kContextOffset = StandardFrameConstants::kContextOffset;
@@ -178,11 +227,17 @@
MacroAssembler* masm_;
- List<Element> elements_;
+ List<FrameElement> elements_;
int parameter_count_;
int local_count_;
+ // The index of the element that is at the processor's stack pointer
+ // (the esp register).
+ int stack_pointer_;
+
+ // The index of the element that is at the processor's frame pointer
+ // (the ebp register).
int frame_pointer_;
// The index of the first parameter. The receiver lies below the first
@@ -196,6 +251,16 @@
// The index of the base of the expression stack.
int expression_base_index() const { return local0_index() +
local_count_; }
+
+ // Convert a frame index into a frame pointer relative offset into the
+ // actual stack.
+ int fp_relative(int index) const {
+ return (frame_pointer_ - index) * kPointerSize;
+ }
+
+ // Spill the topmost elements of the frame to memory (eg, they are the
+ // arguments to a call) and all registers.
+ void PrepareForCall(int count);
};
--~--~---------~--~----~------------~-------~--~----~
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
-~----------~----~----~----~------~----~------~--~---