summaryrefslogtreecommitdiff
path: root/deps/v8/src/full-codegen.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/full-codegen.cc')
-rw-r--r--deps/v8/src/full-codegen.cc398
1 files changed, 220 insertions, 178 deletions
diff --git a/deps/v8/src/full-codegen.cc b/deps/v8/src/full-codegen.cc
index 8073874132..5c5ba6b256 100644
--- a/deps/v8/src/full-codegen.cc
+++ b/deps/v8/src/full-codegen.cc
@@ -1,4 +1,4 @@
-// Copyright 2011 the V8 project authors. All rights reserved.
+// Copyright 2012 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -51,7 +51,25 @@ void BreakableStatementChecker::Check(Expression* expr) {
}
-void BreakableStatementChecker::VisitDeclaration(Declaration* decl) {
+void BreakableStatementChecker::VisitVariableDeclaration(
+ VariableDeclaration* decl) {
+}
+
+void BreakableStatementChecker::VisitModuleDeclaration(
+ ModuleDeclaration* decl) {
+}
+
+
+void BreakableStatementChecker::VisitModuleLiteral(ModuleLiteral* module) {
+}
+
+void BreakableStatementChecker::VisitModuleVariable(ModuleVariable* module) {
+}
+
+void BreakableStatementChecker::VisitModulePath(ModulePath* module) {
+}
+
+void BreakableStatementChecker::VisitModuleUrl(ModuleUrl* module) {
}
@@ -244,11 +262,6 @@ void BreakableStatementChecker::VisitBinaryOperation(BinaryOperation* expr) {
}
-void BreakableStatementChecker::VisitCompareToNull(CompareToNull* expr) {
- Visit(expr->expression());
-}
-
-
void BreakableStatementChecker::VisitCompareOperation(CompareOperation* expr) {
Visit(expr->left());
Visit(expr->right());
@@ -290,13 +303,21 @@ bool FullCodeGenerator::MakeCode(CompilationInfo* info) {
Handle<Code> code = CodeGenerator::MakeCodeEpilogue(&masm, flags, info);
code->set_optimizable(info->IsOptimizable());
cgen.PopulateDeoptimizationData(code);
+ cgen.PopulateTypeFeedbackCells(code);
code->set_has_deoptimization_support(info->HasDeoptimizationSupport());
+ code->set_handler_table(*cgen.handler_table());
+#ifdef ENABLE_DEBUGGER_SUPPORT
code->set_has_debug_break_slots(
info->isolate()->debugger()->IsDebuggerActive());
+ code->set_compiled_optimizable(info->IsOptimizable());
+#endif // ENABLE_DEBUGGER_SUPPORT
code->set_allow_osr_at_loop_nesting_level(0);
code->set_stack_check_table_offset(table_offset);
CodeGenerator::PrintCode(code, info);
- info->SetCode(code); // may be an empty handle.
+ info->SetCode(code); // May be an empty handle.
+ if (!code.is_null()) {
+ isolate->runtime_profiler()->NotifyCodeGenerated(code->instruction_size());
+ }
#ifdef ENABLE_GDB_JIT_INTERFACE
if (FLAG_gdbjit && !code.is_null()) {
GDBJITLineInfo* lineinfo =
@@ -330,8 +351,7 @@ void FullCodeGenerator::PopulateDeoptimizationData(Handle<Code> code) {
ASSERT(info_->HasDeoptimizationSupport() || bailout_entries_.is_empty());
if (!info_->HasDeoptimizationSupport()) return;
int length = bailout_entries_.length();
- Handle<DeoptimizationOutputData> data =
- isolate()->factory()->
+ Handle<DeoptimizationOutputData> data = isolate()->factory()->
NewDeoptimizationOutputData(length, TENURED);
for (int i = 0; i < length; i++) {
data->SetAstId(i, Smi::FromInt(bailout_entries_[i].id));
@@ -341,6 +361,21 @@ void FullCodeGenerator::PopulateDeoptimizationData(Handle<Code> code) {
}
+void FullCodeGenerator::PopulateTypeFeedbackCells(Handle<Code> code) {
+ if (type_feedback_cells_.is_empty()) return;
+ int length = type_feedback_cells_.length();
+ int array_size = TypeFeedbackCells::LengthOfFixedArray(length);
+ Handle<TypeFeedbackCells> cache = Handle<TypeFeedbackCells>::cast(
+ isolate()->factory()->NewFixedArray(array_size, TENURED));
+ for (int i = 0; i < length; i++) {
+ cache->SetAstId(i, Smi::FromInt(type_feedback_cells_[i].ast_id));
+ cache->SetCell(i, *type_feedback_cells_[i].cell);
+ }
+ code->set_type_feedback_cells(*cache);
+}
+
+
+
void FullCodeGenerator::PrepareForBailout(Expression* node, State state) {
PrepareForBailoutForId(node->id(), state);
}
@@ -363,20 +398,22 @@ void FullCodeGenerator::RecordJSReturnSite(Call* call) {
}
-void FullCodeGenerator::PrepareForBailoutForId(int id, State state) {
+void FullCodeGenerator::PrepareForBailoutForId(unsigned id, State state) {
// There's no need to prepare this code for bailouts from already optimized
// code or code that can't be optimized.
- if (!FLAG_deopt || !info_->HasDeoptimizationSupport()) return;
+ if (!info_->HasDeoptimizationSupport()) return;
unsigned pc_and_state =
StateField::encode(state) | PcField::encode(masm_->pc_offset());
BailoutEntry entry = { id, pc_and_state };
#ifdef DEBUG
- // Assert that we don't have multiple bailout entries for the same node.
- for (int i = 0; i < bailout_entries_.length(); i++) {
- if (bailout_entries_.at(i).id == entry.id) {
- AstPrinter printer;
- PrintF("%s", printer.PrintProgram(info_->function()));
- UNREACHABLE();
+ if (FLAG_enable_slow_asserts) {
+ // Assert that we don't have multiple bailout entries for the same node.
+ for (int i = 0; i < bailout_entries_.length(); i++) {
+ if (bailout_entries_.at(i).id == entry.id) {
+ AstPrinter printer;
+ PrintF("%s", printer.PrintProgram(info_->function()));
+ UNREACHABLE();
+ }
}
}
#endif // DEBUG
@@ -384,10 +421,18 @@ void FullCodeGenerator::PrepareForBailoutForId(int id, State state) {
}
-void FullCodeGenerator::RecordStackCheck(int ast_id) {
+void FullCodeGenerator::RecordTypeFeedbackCell(
+ unsigned id, Handle<JSGlobalPropertyCell> cell) {
+ TypeFeedbackCellEntry entry = { id, cell };
+ type_feedback_cells_.Add(entry);
+}
+
+
+void FullCodeGenerator::RecordStackCheck(unsigned ast_id) {
// The pc offset does not need to be encoded and packed together with a
// state.
- BailoutEntry entry = { ast_id, masm_->pc_offset() };
+ ASSERT(masm_->pc_offset() > 0);
+ BailoutEntry entry = { ast_id, static_cast<unsigned>(masm_->pc_offset()) };
stack_checks_.Add(entry);
}
@@ -412,27 +457,24 @@ void FullCodeGenerator::AccumulatorValueContext::Plug(Register reg) const {
void FullCodeGenerator::StackValueContext::Plug(Register reg) const {
__ push(reg);
- codegen()->increment_stack_height();
}
void FullCodeGenerator::TestContext::Plug(Register reg) const {
// For simplicity we always test the accumulator register.
__ Move(result_register(), reg);
- codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
+ codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL);
codegen()->DoTest(this);
}
void FullCodeGenerator::EffectContext::PlugTOS() const {
__ Drop(1);
- codegen()->decrement_stack_height();
}
void FullCodeGenerator::AccumulatorValueContext::PlugTOS() const {
__ pop(result_register());
- codegen()->decrement_stack_height();
}
@@ -443,8 +485,7 @@ void FullCodeGenerator::StackValueContext::PlugTOS() const {
void FullCodeGenerator::TestContext::PlugTOS() const {
// For simplicity we always test the accumulator register.
__ pop(result_register());
- codegen()->decrement_stack_height();
- codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
+ codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL);
codegen()->DoTest(this);
}
@@ -505,39 +546,40 @@ void FullCodeGenerator::DoTest(const TestContext* context) {
void FullCodeGenerator::VisitDeclarations(
ZoneList<Declaration*>* declarations) {
- int length = declarations->length();
- int global_count = 0;
- for (int i = 0; i < length; i++) {
- Declaration* decl = declarations->at(i);
- EmitDeclaration(decl->proxy(), decl->mode(), decl->fun(), &global_count);
- }
+ int save_global_count = global_count_;
+ global_count_ = 0;
+
+ AstVisitor::VisitDeclarations(declarations);
// Batch declare global functions and variables.
- if (global_count > 0) {
+ if (global_count_ > 0) {
Handle<FixedArray> array =
- isolate()->factory()->NewFixedArray(2 * global_count, TENURED);
+ isolate()->factory()->NewFixedArray(2 * global_count_, TENURED);
+ int length = declarations->length();
for (int j = 0, i = 0; i < length; i++) {
- Declaration* decl = declarations->at(i);
- Variable* var = decl->proxy()->var();
-
- if (var->IsUnallocated()) {
- array->set(j++, *(var->name()));
- if (decl->fun() == NULL) {
- if (var->mode() == Variable::CONST) {
- // In case this is const property use the hole.
- array->set_the_hole(j++);
+ VariableDeclaration* decl = declarations->at(i)->AsVariableDeclaration();
+ if (decl != NULL) {
+ Variable* var = decl->proxy()->var();
+
+ if (var->IsUnallocated()) {
+ array->set(j++, *(var->name()));
+ if (decl->fun() == NULL) {
+ if (var->binding_needs_init()) {
+ // In case this binding needs initialization use the hole.
+ array->set_the_hole(j++);
+ } else {
+ array->set_undefined(j++);
+ }
} else {
- array->set_undefined(j++);
+ Handle<SharedFunctionInfo> function =
+ Compiler::BuildFunctionInfo(decl->fun(), script());
+ // Check for stack-overflow exception.
+ if (function.is_null()) {
+ SetStackOverflow();
+ return;
+ }
+ array->set(j++, *function);
}
- } else {
- Handle<SharedFunctionInfo> function =
- Compiler::BuildFunctionInfo(decl->fun(), script());
- // Check for stack-overflow exception.
- if (function.is_null()) {
- SetStackOverflow();
- return;
- }
- array->set(j++, *function);
}
}
}
@@ -545,15 +587,46 @@ void FullCodeGenerator::VisitDeclarations(
// declaration the global functions and variables.
DeclareGlobals(array);
}
+
+ global_count_ = save_global_count;
+}
+
+
+void FullCodeGenerator::VisitVariableDeclaration(VariableDeclaration* decl) {
+ EmitDeclaration(decl->proxy(), decl->mode(), decl->fun());
+}
+
+
+void FullCodeGenerator::VisitModuleDeclaration(ModuleDeclaration* decl) {
+ // TODO(rossberg)
+}
+
+
+void FullCodeGenerator::VisitModuleLiteral(ModuleLiteral* module) {
+ // TODO(rossberg)
+}
+
+
+void FullCodeGenerator::VisitModuleVariable(ModuleVariable* module) {
+ // TODO(rossberg)
+}
+
+
+void FullCodeGenerator::VisitModulePath(ModulePath* module) {
+ // TODO(rossberg)
+}
+
+
+void FullCodeGenerator::VisitModuleUrl(ModuleUrl* decl) {
+ // TODO(rossberg)
}
int FullCodeGenerator::DeclareGlobalsFlags() {
- int flags = 0;
- if (is_eval()) flags |= kDeclareGlobalsEvalFlag;
- if (is_strict_mode()) flags |= kDeclareGlobalsStrictModeFlag;
- if (is_native()) flags |= kDeclareGlobalsNativeFlag;
- return flags;
+ ASSERT(DeclareGlobalsLanguageMode::is_valid(language_mode()));
+ return DeclareGlobalsEvalFlag::encode(is_eval()) |
+ DeclareGlobalsNativeFlag::encode(is_native()) |
+ DeclareGlobalsLanguageMode::encode(language_mode());
}
@@ -659,14 +732,13 @@ FullCodeGenerator::InlineFunctionGenerator
}
-void FullCodeGenerator::EmitInlineRuntimeCall(CallRuntime* node) {
- ZoneList<Expression*>* args = node->arguments();
- const Runtime::Function* function = node->function();
+void FullCodeGenerator::EmitInlineRuntimeCall(CallRuntime* expr) {
+ const Runtime::Function* function = expr->function();
ASSERT(function != NULL);
ASSERT(function->intrinsic_type == Runtime::INLINE);
InlineFunctionGenerator generator =
FindInlineFunctionGenerator(function->function_id);
- ((*this).*(generator))(args);
+ ((*this).*(generator))(expr);
}
@@ -683,11 +755,25 @@ void FullCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
}
+void FullCodeGenerator::VisitInDuplicateContext(Expression* expr) {
+ if (context()->IsEffect()) {
+ VisitForEffect(expr);
+ } else if (context()->IsAccumulatorValue()) {
+ VisitForAccumulatorValue(expr);
+ } else if (context()->IsStackValue()) {
+ VisitForStackValue(expr);
+ } else if (context()->IsTest()) {
+ const TestContext* test = TestContext::cast(context());
+ VisitForControl(expr, test->true_label(), test->false_label(),
+ test->fall_through());
+ }
+}
+
+
void FullCodeGenerator::VisitComma(BinaryOperation* expr) {
Comment cmnt(masm_, "[ Comma");
VisitForEffect(expr->left());
- if (context()->IsTest()) ForwardBailoutToChild(expr);
- VisitInCurrentContext(expr->right());
+ VisitInDuplicateContext(expr->right());
}
@@ -709,7 +795,6 @@ void FullCodeGenerator::VisitLogicalExpression(BinaryOperation* expr) {
}
PrepareForBailoutForId(right_id, NO_REGISTERS);
__ bind(&eval_right);
- ForwardBailoutToChild(expr);
} else if (context()->IsAccumulatorValue()) {
VisitForAccumulatorValue(left);
@@ -717,7 +802,6 @@ void FullCodeGenerator::VisitLogicalExpression(BinaryOperation* expr) {
// case we need it.
__ push(result_register());
Label discard, restore;
- PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
if (is_logical_and) {
DoTest(left, &discard, &restore, &restore);
} else {
@@ -736,7 +820,6 @@ void FullCodeGenerator::VisitLogicalExpression(BinaryOperation* expr) {
// case we need it.
__ push(result_register());
Label discard;
- PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
if (is_logical_and) {
DoTest(left, &discard, &done, &discard);
} else {
@@ -758,7 +841,7 @@ void FullCodeGenerator::VisitLogicalExpression(BinaryOperation* expr) {
__ bind(&eval_right);
}
- VisitInCurrentContext(right);
+ VisitInDuplicateContext(right);
__ bind(&done);
}
@@ -785,34 +868,6 @@ void FullCodeGenerator::VisitArithmeticExpression(BinaryOperation* expr) {
}
-void FullCodeGenerator::ForwardBailoutToChild(Expression* expr) {
- if (!info_->HasDeoptimizationSupport()) return;
- ASSERT(context()->IsTest());
- ASSERT(expr == forward_bailout_stack_->expr());
- forward_bailout_pending_ = forward_bailout_stack_;
-}
-
-
-void FullCodeGenerator::VisitInCurrentContext(Expression* expr) {
- if (context()->IsTest()) {
- ForwardBailoutStack stack(expr, forward_bailout_pending_);
- ForwardBailoutStack* saved = forward_bailout_stack_;
- forward_bailout_pending_ = NULL;
- forward_bailout_stack_ = &stack;
- Visit(expr);
- forward_bailout_stack_ = saved;
- } else {
- ASSERT(forward_bailout_pending_ == NULL);
- Visit(expr);
- State state = context()->IsAccumulatorValue() ? TOS_REG : NO_REGISTERS;
- PrepareForBailout(expr, state);
- // Forwarding bailouts to children is a one shot operation. It should have
- // been processed at this point.
- ASSERT(forward_bailout_pending_ == NULL);
- }
-}
-
-
void FullCodeGenerator::VisitBlock(Block* stmt) {
Comment cmnt(masm_, "[ Block");
NestedBlock nested_block(this, stmt);
@@ -823,9 +878,18 @@ void FullCodeGenerator::VisitBlock(Block* stmt) {
if (stmt->block_scope() != NULL) {
{ Comment cmnt(masm_, "[ Extend block context");
scope_ = stmt->block_scope();
- __ Push(scope_->GetSerializedScopeInfo());
+ Handle<ScopeInfo> scope_info = scope_->GetScopeInfo();
+ int heap_slots = scope_info->ContextLength() - Context::MIN_CONTEXT_SLOTS;
+ __ Push(scope_info);
PushFunctionArgumentForContextAllocation();
- __ CallRuntime(Runtime::kPushBlockContext, 2);
+ if (heap_slots <= FastNewBlockContextStub::kMaximumSlots) {
+ FastNewBlockContextStub stub(heap_slots);
+ __ CallStub(&stub);
+ } else {
+ __ CallRuntime(Runtime::kPushBlockContext, 2);
+ }
+
+ // Replace the context stored in the frame.
StoreToFrameField(StandardFrameConstants::kContextOffset,
context_register());
}
@@ -972,7 +1036,6 @@ void FullCodeGenerator::VisitWithStatement(WithStatement* stmt) {
VisitForStackValue(stmt->expression());
PushFunctionArgumentForContextAllocation();
__ CallRuntime(Runtime::kPushWithContext, 2);
- decrement_stack_height();
StoreToFrameField(StandardFrameConstants::kContextOffset, context_register());
{ WithOrCatch body(this);
@@ -1103,20 +1166,17 @@ void FullCodeGenerator::VisitForStatement(ForStatement* stmt) {
void FullCodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) {
Comment cmnt(masm_, "[ TryCatchStatement");
SetStatementPosition(stmt);
- // The try block adds a handler to the exception handler chain
- // before entering, and removes it again when exiting normally.
- // If an exception is thrown during execution of the try block,
- // control is passed to the handler, which also consumes the handler.
- // At this point, the exception is in a register, and store it in
- // the temporary local variable (prints as ".catch-var") before
- // executing the catch block. The catch block has been rewritten
- // to introduce a new scope to bind the catch variable and to remove
- // that scope again afterwards.
-
- Label try_handler_setup, done;
- __ Call(&try_handler_setup);
- // Try handler code, exception in result register.
-
+ // The try block adds a handler to the exception handler chain before
+ // entering, and removes it again when exiting normally. If an exception
+ // is thrown during execution of the try block, the handler is consumed
+ // and control is passed to the catch block with the exception in the
+ // result register.
+
+ Label try_entry, handler_entry, exit;
+ __ jmp(&try_entry);
+ __ bind(&handler_entry);
+ handler_table()->set(stmt->index(), Smi::FromInt(handler_entry.pos()));
+ // 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());
@@ -1130,27 +1190,23 @@ void FullCodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) {
Scope* saved_scope = scope();
scope_ = stmt->scope();
ASSERT(scope_->declarations()->is_empty());
- { WithOrCatch body(this);
+ { WithOrCatch catch_body(this);
Visit(stmt->catch_block());
}
// Restore the context.
LoadContextField(context_register(), Context::PREVIOUS_INDEX);
StoreToFrameField(StandardFrameConstants::kContextOffset, context_register());
scope_ = saved_scope;
- __ jmp(&done);
+ __ jmp(&exit);
// Try block code. Sets up the exception handler chain.
- __ bind(&try_handler_setup);
- {
- const int delta = StackHandlerConstants::kSize / kPointerSize;
- TryCatch try_block(this);
- __ PushTryHandler(IN_JAVASCRIPT, TRY_CATCH_HANDLER);
- increment_stack_height(delta);
+ __ bind(&try_entry);
+ __ PushTryHandler(StackHandler::CATCH, stmt->index());
+ { TryCatch try_body(this);
Visit(stmt->try_block());
- __ PopTryHandler();
- decrement_stack_height(delta);
}
- __ bind(&done);
+ __ PopTryHandler();
+ __ bind(&exit);
}
@@ -1162,12 +1218,12 @@ void FullCodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
//
// The try-finally construct can enter the finally block in three ways:
// 1. By exiting the try-block normally. This removes the try-handler and
- // calls the finally block code before continuing.
+ // calls the finally block code before continuing.
// 2. By exiting the try-block with a function-local control flow transfer
// (break/continue/return). The site of the, e.g., break removes the
// try handler and calls the finally block code before continuing
// its outward control transfer.
- // 3. by exiting the try-block with a thrown exception.
+ // 3. By exiting the try-block with a thrown exception.
// This can happen in nested function calls. It traverses the try-handler
// chain and consumes the try-handler entry before jumping to the
// handler code. The handler code then calls the finally-block before
@@ -1178,49 +1234,39 @@ void FullCodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
// exception) in the result register (rax/eax/r0), both of which must
// be preserved. The return address isn't GC-safe, so it should be
// cooked before GC.
- Label finally_entry;
- Label try_handler_setup;
- const int original_stack_height = stack_height();
-
- // Setup the try-handler chain. Use a call to
- // Jump to try-handler setup and try-block code. Use call to put try-handler
- // address on stack.
- __ Call(&try_handler_setup);
- // Try handler code. Return address of call is pushed on handler stack.
- {
- // This code is only executed during stack-handler traversal when an
- // exception is thrown. The exception is in the result register, which
- // is retained by the finally block.
- // Call the finally block and then rethrow the exception if it returns.
- __ Call(&finally_entry);
- __ push(result_register());
- __ CallRuntime(Runtime::kReThrow, 1);
- }
+ Label try_entry, handler_entry, finally_entry;
+
+ // Jump to try-handler setup and try-block code.
+ __ jmp(&try_entry);
+ __ bind(&handler_entry);
+ handler_table()->set(stmt->index(), Smi::FromInt(handler_entry.pos()));
+ // Exception handler code. This code is only executed when an exception
+ // is thrown. The exception is in the result register, and must be
+ // preserved by the finally block. Call the finally block and then
+ // rethrow the exception if it returns.
+ __ Call(&finally_entry);
+ __ push(result_register());
+ __ CallRuntime(Runtime::kReThrow, 1);
+ // Finally block implementation.
__ bind(&finally_entry);
- {
- // Finally block implementation.
- Finally finally_block(this);
- EnterFinallyBlock();
- set_stack_height(original_stack_height + Finally::kElementCount);
+ EnterFinallyBlock();
+ { Finally finally_body(this);
Visit(stmt->finally_block());
- ExitFinallyBlock(); // Return to the calling code.
}
+ ExitFinallyBlock(); // Return to the calling code.
- __ bind(&try_handler_setup);
- {
- // Setup try handler (stack pointer registers).
- const int delta = StackHandlerConstants::kSize / kPointerSize;
- TryFinally try_block(this, &finally_entry);
- __ PushTryHandler(IN_JAVASCRIPT, TRY_FINALLY_HANDLER);
- set_stack_height(original_stack_height + delta);
+ // Set up try handler.
+ __ bind(&try_entry);
+ __ PushTryHandler(StackHandler::FINALLY, stmt->index());
+ { TryFinally try_body(this, &finally_entry);
Visit(stmt->try_block());
- __ PopTryHandler();
- set_stack_height(original_stack_height);
}
+ __ PopTryHandler();
// Execute the finally block on the way out. Clobber the unpredictable
- // value in the accumulator with one that's safe for GC. The finally
- // block will unconditionally preserve the accumulator on the stack.
+ // value in the result register with one that's safe for GC because the
+ // finally block will unconditionally preserve the result register on the
+ // stack.
ClearAccumulator();
__ Call(&finally_entry);
}
@@ -1246,7 +1292,6 @@ void FullCodeGenerator::VisitConditional(Conditional* expr) {
__ bind(&true_case);
SetExpressionPosition(expr->then_expression(),
expr->then_expression_position());
- int start_stack_height = stack_height();
if (context()->IsTest()) {
const TestContext* for_test = TestContext::cast(context());
VisitForControl(expr->then_expression(),
@@ -1254,17 +1299,15 @@ void FullCodeGenerator::VisitConditional(Conditional* expr) {
for_test->false_label(),
NULL);
} else {
- VisitInCurrentContext(expr->then_expression());
+ VisitInDuplicateContext(expr->then_expression());
__ jmp(&done);
}
PrepareForBailoutForId(expr->ElseId(), NO_REGISTERS);
__ bind(&false_case);
- set_stack_height(start_stack_height);
- if (context()->IsTest()) ForwardBailoutToChild(expr);
SetExpressionPosition(expr->else_expression(),
expr->else_expression_position());
- VisitInCurrentContext(expr->else_expression());
+ VisitInDuplicateContext(expr->else_expression());
// If control flow falls through Visit, merge it with true case here.
if (!context()->IsTest()) {
__ bind(&done);
@@ -1301,11 +1344,8 @@ void FullCodeGenerator::VisitSharedFunctionInfoLiteral(
void FullCodeGenerator::VisitThrow(Throw* expr) {
Comment cmnt(masm_, "[ Throw");
- // Throw has no effect on the stack height or the current expression context.
- // Usually the expression context is null, because throw is a statement.
VisitForStackValue(expr->exception());
__ CallRuntime(Runtime::kThrow, 1);
- decrement_stack_height();
// Never returns here.
}
@@ -1321,19 +1361,21 @@ FullCodeGenerator::NestedStatement* FullCodeGenerator::TryCatch::Exit(
}
-bool FullCodeGenerator::TryLiteralCompare(CompareOperation* compare,
- Label* if_true,
- Label* if_false,
- Label* fall_through) {
- Expression *expr;
+bool FullCodeGenerator::TryLiteralCompare(CompareOperation* expr) {
+ Expression* sub_expr;
Handle<String> check;
- if (compare->IsLiteralCompareTypeof(&expr, &check)) {
- EmitLiteralCompareTypeof(expr, check, if_true, if_false, fall_through);
+ if (expr->IsLiteralCompareTypeof(&sub_expr, &check)) {
+ EmitLiteralCompareTypeof(expr, sub_expr, check);
+ return true;
+ }
+
+ if (expr->IsLiteralCompareUndefined(&sub_expr)) {
+ EmitLiteralCompareNil(expr, sub_expr, kUndefinedValue);
return true;
}
- if (compare->IsLiteralCompareUndefined(&expr)) {
- EmitLiteralCompareUndefined(expr, if_true, if_false, fall_through);
+ if (expr->IsLiteralCompareNull(&sub_expr)) {
+ EmitLiteralCompareNil(expr, sub_expr, kNullValue);
return true;
}