Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(621)

Unified Diff: src/codegen-ia32.cc

Issue 40290: Experimental: Merge 1395:1441 from bleeding_edge branch to the... (Closed) Base URL: http://v8.googlecode.com/svn/branches/experimental/global/
Patch Set: Created 11 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/codegen-arm.cc ('k') | src/compilation-cache.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/codegen-ia32.cc
===================================================================
--- src/codegen-ia32.cc (revision 1441)
+++ src/codegen-ia32.cc (working copy)
@@ -154,18 +154,14 @@
// Get outer context and create a new context based on it.
frame_->PushFunction();
Result context = frame_->CallRuntime(Runtime::kNewContext, 1);
+
// Update context local.
frame_->SaveContextRegister();
- if (kDebug) {
- JumpTarget verified_true(this);
- // Verify eax and esi are the same in debug mode
+ // Verify that the runtime call result and esi agree.
+ if (FLAG_debug_code) {
__ cmp(context.reg(), Operand(esi));
- context.Unuse();
- verified_true.Branch(equal);
- frame_->SpillAll();
- __ int3();
- verified_true.Bind();
+ __ Assert(equal, "Runtime::NewContext should end up in esi");
}
}
@@ -736,17 +732,17 @@
const char* GenericBinaryOpStub::GetName() {
switch (op_) {
- case Token::ADD: return "GenericBinaryOpStub_ADD";
- case Token::SUB: return "GenericBinaryOpStub_SUB";
- case Token::MUL: return "GenericBinaryOpStub_MUL";
- case Token::DIV: return "GenericBinaryOpStub_DIV";
- case Token::BIT_OR: return "GenericBinaryOpStub_BIT_OR";
- case Token::BIT_AND: return "GenericBinaryOpStub_BIT_AND";
- case Token::BIT_XOR: return "GenericBinaryOpStub_BIT_XOR";
- case Token::SAR: return "GenericBinaryOpStub_SAR";
- case Token::SHL: return "GenericBinaryOpStub_SHL";
- case Token::SHR: return "GenericBinaryOpStub_SHR";
- default: return "GenericBinaryOpStub";
+ case Token::ADD: return "GenericBinaryOpStub_ADD";
+ case Token::SUB: return "GenericBinaryOpStub_SUB";
+ case Token::MUL: return "GenericBinaryOpStub_MUL";
+ case Token::DIV: return "GenericBinaryOpStub_DIV";
+ case Token::BIT_OR: return "GenericBinaryOpStub_BIT_OR";
+ case Token::BIT_AND: return "GenericBinaryOpStub_BIT_AND";
+ case Token::BIT_XOR: return "GenericBinaryOpStub_BIT_XOR";
+ case Token::SAR: return "GenericBinaryOpStub_SAR";
+ case Token::SHL: return "GenericBinaryOpStub_SHL";
+ case Token::SHR: return "GenericBinaryOpStub_SHR";
+ default: return "GenericBinaryOpStub";
}
}
@@ -840,9 +836,9 @@
class DeferredInlineSmiOperation: public DeferredCode {
public:
DeferredInlineSmiOperation(CodeGenerator* generator,
- Token::Value op,
- Smi* value,
- OverwriteMode overwrite_mode)
+ Token::Value op,
+ Smi* value,
+ OverwriteMode overwrite_mode)
: DeferredCode(generator),
op_(op),
value_(value),
@@ -1123,8 +1119,8 @@
// In the slow case, this masking is done inside the runtime call.
int shift_value = int_value & 0x1f;
DeferredCode* deferred =
- new DeferredInlineSmiOperation(this, Token::SAR, smi_value,
- overwrite_mode);
+ new DeferredInlineSmiOperation(this, Token::SAR, smi_value,
+ overwrite_mode);
Result result = frame_->Pop();
result.ToRegister();
__ test(result.reg(), Immediate(kSmiTagMask));
@@ -1149,8 +1145,8 @@
// In the slow case, this masking is done inside the runtime call.
int shift_value = int_value & 0x1f;
DeferredCode* deferred =
- new DeferredInlineSmiOperation(this, Token::SHR, smi_value,
- overwrite_mode);
+ new DeferredInlineSmiOperation(this, Token::SHR, smi_value,
+ overwrite_mode);
Result operand = frame_->Pop();
operand.ToRegister();
__ test(operand.reg(), Immediate(kSmiTagMask));
@@ -1186,8 +1182,8 @@
// In the slow case, this masking is done inside the runtime call.
int shift_value = int_value & 0x1f;
DeferredCode* deferred =
- new DeferredInlineSmiOperation(this, Token::SHL, smi_value,
- overwrite_mode);
+ new DeferredInlineSmiOperation(this, Token::SHL, smi_value,
+ overwrite_mode);
Result operand = frame_->Pop();
operand.ToRegister();
__ test(operand.reg(), Immediate(kSmiTagMask));
@@ -1310,6 +1306,8 @@
right_side = frame_->Pop();
left_side = frame_->Pop();
}
+ ASSERT(cc == less || cc == equal || cc == greater_equal);
+
// If either side is a constant smi, optimize the comparison.
bool left_side_constant_smi =
left_side.is_constant() && left_side.handle()->IsSmi();
@@ -1325,17 +1323,18 @@
// Trivial case, comparing two constants.
int left_value = Smi::cast(*left_side.handle())->value();
int right_value = Smi::cast(*right_side.handle())->value();
- if (left_value < right_value &&
- (cc == less || cc == less_equal || cc == not_equal) ||
- left_value == right_value &&
- (cc == less_equal || cc == equal || cc == greater_equal) ||
- left_value > right_value &&
- (cc == greater || cc == greater_equal || cc == not_equal)) {
- // The comparison is unconditionally true.
- dest->Goto(true);
- } else {
- // The comparison is unconditionally false.
- dest->Goto(false);
+ switch (cc) {
+ case less:
+ dest->Goto(left_value < right_value);
+ break;
+ case equal:
+ dest->Goto(left_value == right_value);
+ break;
+ case greater_equal:
+ dest->Goto(left_value >= right_value);
+ break;
+ default:
+ UNREACHABLE();
}
} else { // Only one side is a constant Smi.
// If left side is a constant Smi, reverse the operands.
@@ -1376,7 +1375,7 @@
ASSERT(right_side.is_valid());
__ cmp(left_side.reg(), Operand(right_side.reg()));
} else {
- __ cmp(Operand(left_side.reg()), Immediate(right_side.handle()));
+ __ cmp(Operand(left_side.reg()), Immediate(right_side.handle()));
}
left_side.Unuse();
right_side.Unuse();
@@ -1421,8 +1420,8 @@
} else { // Neither side is a constant Smi or null.
// If either side is a non-smi constant, skip the smi check.
bool known_non_smi =
- left_side.is_constant() && !left_side.handle()->IsSmi() ||
- right_side.is_constant() && !right_side.handle()->IsSmi();
+ (left_side.is_constant() && !left_side.handle()->IsSmi()) ||
+ (right_side.is_constant() && !right_side.handle()->IsSmi());
left_side.ToRegister();
right_side.ToRegister();
JumpTarget is_smi(this);
@@ -1870,16 +1869,10 @@
// Update context local.
frame_->SaveContextRegister();
- if (kDebug) {
- JumpTarget verified_true(this);
- // Verify that the result of the runtime call and the esi register are
- // the same in debug mode.
+ // Verify that the runtime call result and esi agree.
+ if (FLAG_debug_code) {
__ cmp(context.reg(), Operand(esi));
- context.Unuse();
- verified_true.Branch(equal);
- frame_->SpillAll();
- __ int3();
- verified_true.Bind();
+ __ Assert(equal, "Runtime::NewContext should end up in esi");
}
}
@@ -2031,199 +2024,121 @@
node->set_break_stack_height(break_stack_height_);
node->break_target()->Initialize(this);
+ // Compile the switch value.
Load(node->tag());
+
if (TryGenerateFastCaseSwitchStatement(node)) {
return;
}
- JumpTarget next_test(this);
- JumpTarget fall_through(this);
- JumpTarget default_entry(this);
- JumpTarget default_exit(this, JumpTarget::BIDIRECTIONAL);
ZoneList<CaseClause*>* cases = node->cases();
int length = cases->length();
CaseClause* default_clause = NULL;
- // Loop over the cases, compiling tests and bodies. Skip the
- // default if found and compile it at the end. Exit early if an
- // unconditionally true match occurs (which can happen, eg, in the
- // event the switch value is a compile-time constant).
- //
- // Bind the next_test target before entering the loop so we can use
- // its state to detect whether the switch value needs to be dropped
- // from the frame.
+ JumpTarget next_test(this);
+ // Compile the case label expressions and comparisons. Exit early
+ // if a comparison is unconditionally true. The target next_test is
+ // bound before the loop in order to indicate control flow to the
+ // first comparison.
next_test.Bind();
- int index = 0;
- for (; index < length; index++) {
- CaseClause* clause = cases->at(index);
+ for (int i = 0; i < length && !next_test.is_unused(); i++) {
+ CaseClause* clause = cases->at(i);
+ clause->body_target()->Initialize(this);
+ // The default is not a test, but remember it for later.
if (clause->is_default()) {
- // Remember the default clause and compile it at the end.
default_clause = clause;
continue;
}
- // Compile each non-default clause.
- Comment cmnt(masm_, "[ Case clause");
- // Recycle the same target for each test.
- if (!next_test.is_unused()) {
- // The next test target may be linked (as the target of a
- // previous match failure) or bound (if the previous comparison
- // was unconditionally false or this is the first non-default
- // comparison).
- if (next_test.is_linked()) {
- next_test.Bind();
- }
- next_test.Unuse();
+ Comment cmnt(masm_, "[ Case comparison");
+ // We recycle the same target next_test for each test. Bind it if
+ // the previous test has not done so and then unuse it for the
+ // loop.
+ if (next_test.is_linked()) {
+ next_test.Bind();
}
+ next_test.Unuse();
// Duplicate the switch value.
frame_->Dup();
- // Compile the clause's label expression.
+ // Compile the label expression.
Load(clause->label());
- // Compare and branch to the body if true and to the next test if
- // false.
- JumpTarget enter_body(this);
- ControlDestination dest(&enter_body, &next_test, true);
+ // Compare and branch to the body if true or the next test if
+ // false. Prefer the next test as a fall through.
+ ControlDestination dest(clause->body_target(), &next_test, false);
Comparison(equal, true, &dest);
- bool previous_was_default =
- index > 0 && cases->at(index - 1)->is_default();
- if (dest.false_was_fall_through()) {
- // The false target next_test was bound as the fall-through.
- // This may indicate that the comparison was unconditionally
- // false if there are no dangling jumps to enter_body. Even
- // then we may still need to compile the body if it is reachable
- // as a fall through.
-
- // We do not need to compile the body if control cannot reach
- // it. Control could reach the body (1) from the comparison by
- // a branch to enter_body, (2) as the fall through of some
- // previous case, or (3) possibly via a backward jump from the
- // default.
- if (!enter_body.is_linked() &&
- !fall_through.is_linked() &&
- !previous_was_default) {
- continue;
- }
-
- // We will compile the body and we have to jump around it on
- // this path where the comparison failed.
- next_test.Unuse();
- next_test.Jump();
- if (enter_body.is_linked()) {
- enter_body.Bind();
- }
+ // If the comparison fell through to the true target, jump to the
+ // actual body.
+ if (dest.true_was_fall_through()) {
+ clause->body_target()->Unuse();
+ clause->body_target()->Jump();
}
+ }
- // The body entry target may have been bound, indicating control
- // flow can reach the body via the comparison.
- if (enter_body.is_bound()) {
- // The switch value is no longer needed.
- frame_->Drop();
- } else {
- // The test was unconditionally false but we will compile the
- // body as a fall through.
- ASSERT(!has_valid_frame());
+ // If there was control flow to a next test from the last one
+ // compiled, compile a jump to the default or break target.
+ if (!next_test.is_unused()) {
+ if (next_test.is_linked()) {
+ next_test.Bind();
}
-
- // Label the body if needed for fall through.
- if (previous_was_default) {
- // Because the default is compiled last, there is always a potential
- // backwards edge to here, falling through from the default.
- default_exit.Bind();
+ // Drop the switch value.
+ frame_->Drop();
+ if (default_clause != NULL) {
+ default_clause->body_target()->Jump();
} else {
- // Recycle the same target for each fall through.
- fall_through.Bind();
- fall_through.Unuse();
+ node->break_target()->Jump();
}
-
- // Compile the body.
- ASSERT(has_valid_frame());
- { Comment body_cmnt(masm_, "[ Case body");
- VisitStatements(clause->statements());
- }
-
- // The test may have been unconditionally true, which is indicated
- // by the absence of any control flow to the next_test target. In
- // that case, exit this loop and stop compiling both tests and
- // bodies (and begin compiling only bodies if necessary).
-
- // Otherwise, if control flow can fall off the end of the body
- // jump to the body of the next case as fall through unless this
- // is the last non-default case.
- if (!next_test.is_linked()) {
- index++;
- break;
- } else if (has_valid_frame()) {
- if (index < length - 2 && // There are at least two cases after this
- cases->at(index + 1)->is_default()) { // The next is the default.
- default_entry.Jump();
- } else if (index < length - 1) { // This is not the last case.
- fall_through.Jump();
- }
- }
}
- // If we did not compile all the cases then we must have hit one
- // that was unconditionally true. We do not need to compile any
- // more tests but we may have (and continue to have) fall through.
- for (; index < length && has_valid_frame(); index++) {
- Comment cmnt(masm_, "[ Case fall-through");
- VisitStatements(cases->at(index)->statements());
- }
- // Complete the switch statement based on the compilation state of
- // the last case that was compiled.
- if (next_test.is_unused()) {
- // The last test compiled was unconditionally true. We still need
- // to compile the default if we found one and it can be targeted
- // by fall through.
- if (default_clause != NULL) {
- bool was_only_clause = length == 1 && cases->at(0) == default_clause;
- if (was_only_clause || default_entry.is_linked()) {
- Comment cmnt(masm_, "[ Default clause");
- default_entry.Bind();
- VisitStatements(default_clause->statements());
- // If control flow can fall off the end of the default and there
- // was a case after it, jump to that case's body.
- if (has_valid_frame() && default_exit.is_bound()) {
- default_exit.Jump();
- }
- }
- }
- } else {
- // The switch value is still on the frame. We have to drop it and
- // possibly compile a default case.
- if (next_test.is_linked()) {
- if (has_valid_frame()) {
- // We have fall through and thus need to jump around the code
- // to drop the switch value.
- fall_through.Jump();
- }
- next_test.Bind();
- }
- frame_->Drop();
+ // The last instruction emitted was a jump, either to the default
+ // clause or the break target, or else to a case body from the loop
+ // that compiles the tests.
+ ASSERT(!has_valid_frame());
+ // Compile case bodies as needed.
+ for (int i = 0; i < length; i++) {
+ CaseClause* clause = cases->at(i);
- // If there was a default clause, compile it now.
- if (default_clause != NULL) {
- Comment cmnt(masm_, "[ Default clause");
- if (default_entry.is_linked()) {
- default_entry.Bind();
+ // There are two ways to reach the body: from the corresponding
+ // test or as the fall through of the previous body.
+ if (!clause->body_target()->is_linked() && !has_valid_frame()) {
+ // If we have neither, skip this body.
+ continue;
+ } else if (clause->body_target()->is_linked() && has_valid_frame()) {
+ // If we have both, put a jump on the fall through path to avoid
+ // the dropping of the switch value on the test path. The
+ // exception is the default which has already had the switch
+ // value dropped.
+ if (clause->is_default()) {
+ clause->body_target()->Bind();
+ } else {
+ JumpTarget body(this);
+ body.Jump();
+ clause->body_target()->Bind();
+ frame_->Drop();
+ body.Bind();
}
- VisitStatements(default_clause->statements());
- // If control flow can fall off the end of the default and there
- // was a case after it, jump to that case's body.
- if (has_valid_frame() && default_exit.is_bound()) {
- default_exit.Jump();
+ } else if (clause->body_target()->is_linked()) {
+ // No fall through to worry about.
+ clause->body_target()->Bind();
+ if (!clause->is_default()) {
+ frame_->Drop();
}
+ } else {
+ // Otherwise, we have only fall through.
+ ASSERT(has_valid_frame());
}
- }
- if (fall_through.is_linked()) {
- fall_through.Bind();
+ // We are now prepared to compile the body.
+ Comment cmnt(masm_, "[ Case body");
+ VisitStatements(clause->statements());
}
+
+ // We may not have a valid frame here so bind the break target only
+ // if needed.
if (node->break_target()->is_linked()) {
node->break_target()->Bind();
}
@@ -2915,23 +2830,30 @@
}
// Unlink from try chain; be careful not to destroy the TOS.
- unlink.Bind();
- // 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_->EmitPop(eax);
- ExternalReference handler_address(Top::k_handler_address);
- __ mov(edx, Operand::StaticVariable(handler_address));
- const int kNextOffset = StackHandlerConstants::kNextOffset +
- StackHandlerConstants::kAddressDisplacement;
- __ lea(esp, Operand(edx, kNextOffset));
- frame_->Forget(frame_->height() - handler_height);
+ if (unlink.is_linked()) {
+ unlink.Bind();
+ }
- frame_->EmitPop(Operand::StaticVariable(handler_address));
- frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1);
- // Next_sp popped.
- frame_->EmitPush(eax);
+ // Control can reach here via a jump to unlink or by falling off the
+ // end of the try block (with no unlinks).
+ if (has_valid_frame()) {
+ // 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_->EmitPop(eax);
+ ExternalReference handler_address(Top::k_handler_address);
+ __ mov(edx, Operand::StaticVariable(handler_address));
+ const int kNextOffset = StackHandlerConstants::kNextOffset +
+ StackHandlerConstants::kAddressDisplacement;
+ __ lea(esp, Operand(edx, kNextOffset));
+ frame_->Forget(frame_->height() - handler_height);
+ frame_->EmitPop(Operand::StaticVariable(handler_address));
+ frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1);
+ // Next_sp popped.
+ frame_->EmitPush(eax);
+ }
+
// --- Finally block ---
finally_block.Bind();
@@ -3517,7 +3439,10 @@
for (int i = 0; i < node->properties()->length(); i++) {
ObjectLiteral::Property* property = node->properties()->at(i);
switch (property->kind()) {
- case ObjectLiteral::Property::CONSTANT: break;
+ case ObjectLiteral::Property::CONSTANT:
+ break;
+ case ObjectLiteral::Property::OBJECT_LITERAL:
+ if (property->value()->AsObjectLiteral()->is_simple()) break;
case ObjectLiteral::Property::COMPUTED: {
Handle<Object> key(property->key()->handle());
Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
« no previous file with comments | « src/codegen-arm.cc ('k') | src/compilation-cache.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698