diff options
| author | Ben Murdoch <benm@google.com> | 2012-03-05 11:04:45 +0000 |
|---|---|---|
| committer | Ben Murdoch <benm@google.com> | 2012-04-11 15:39:56 +0100 |
| commit | 592a9fc1d8ea420377a2e7efd0600e20b058be2b (patch) | |
| tree | 23fe22995f4f9056a96266d169d49426a5e745d7 /src/full-codegen.cc | |
| parent | e25ed7434cc3a061dd965ad25b923bca153aed94 (diff) | |
| download | android_external_v8-592a9fc1d8ea420377a2e7efd0600e20b058be2b.tar.gz android_external_v8-592a9fc1d8ea420377a2e7efd0600e20b058be2b.tar.bz2 android_external_v8-592a9fc1d8ea420377a2e7efd0600e20b058be2b.zip | |
Merge V8 at 3.7.12.28
Bug: 5688872
Change-Id: Iddb40cae44d51a2b449f2858951e0472771f5981
Diffstat (limited to 'src/full-codegen.cc')
| -rw-r--r-- | src/full-codegen.cc | 248 |
1 files changed, 106 insertions, 142 deletions
diff --git a/src/full-codegen.cc b/src/full-codegen.cc index 80738741..04086d48 100644 --- a/src/full-codegen.cc +++ b/src/full-codegen.cc @@ -244,11 +244,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()); @@ -291,12 +286,16 @@ bool FullCodeGenerator::MakeCode(CompilationInfo* info) { code->set_optimizable(info->IsOptimizable()); cgen.PopulateDeoptimizationData(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. #ifdef ENABLE_GDB_JIT_INTERFACE if (FLAG_gdbjit && !code.is_null()) { GDBJITLineInfo* lineinfo = @@ -363,7 +362,7 @@ 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; @@ -384,10 +383,11 @@ void FullCodeGenerator::PrepareForBailoutForId(int id, State state) { } -void FullCodeGenerator::RecordStackCheck(int ast_id) { +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 +412,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 +440,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); } @@ -523,8 +519,8 @@ void FullCodeGenerator::VisitDeclarations( 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. + if (var->binding_needs_init()) { + // In case this binding needs initialization use the hole. array->set_the_hole(j++); } else { array->set_undefined(j++); @@ -549,11 +545,10 @@ void FullCodeGenerator::VisitDeclarations( 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 +654,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 +677,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 +717,6 @@ void FullCodeGenerator::VisitLogicalExpression(BinaryOperation* expr) { } PrepareForBailoutForId(right_id, NO_REGISTERS); __ bind(&eval_right); - ForwardBailoutToChild(expr); } else if (context()->IsAccumulatorValue()) { VisitForAccumulatorValue(left); @@ -717,7 +724,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 +742,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 +763,7 @@ void FullCodeGenerator::VisitLogicalExpression(BinaryOperation* expr) { __ bind(&eval_right); } - VisitInCurrentContext(right); + VisitInDuplicateContext(right); __ bind(&done); } @@ -785,34 +790,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 +800,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 +958,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 +1088,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 +1112,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(IN_JAVASCRIPT, TRY_CATCH_HANDLER, stmt->index()); + { TryCatch try_body(this); Visit(stmt->try_block()); - __ PopTryHandler(); - decrement_stack_height(delta); } - __ bind(&done); + __ PopTryHandler(); + __ bind(&exit); } @@ -1162,12 +1140,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 +1156,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); + // Setup try handler. + __ bind(&try_entry); + __ PushTryHandler(IN_JAVASCRIPT, TRY_FINALLY_HANDLER, 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 +1214,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 +1221,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 +1266,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 +1283,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; } |
