diff --git a/src/arm/macro-assembler-arm.cc b/src/arm/macro-assembler-arm.cc index d250f944f3..464478a310 100644 --- a/src/arm/macro-assembler-arm.cc +++ b/src/arm/macro-assembler-arm.cc @@ -298,6 +298,12 @@ void MacroAssembler::Call(Label* target) { } +void MacroAssembler::Push(Handle handle) { + mov(ip, Operand(handle)); + push(ip); +} + + void MacroAssembler::Move(Register dst, Handle value) { mov(dst, Operand(value)); } diff --git a/src/arm/macro-assembler-arm.h b/src/arm/macro-assembler-arm.h index 2dda57dbf9..0802d7ca6f 100644 --- a/src/arm/macro-assembler-arm.h +++ b/src/arm/macro-assembler-arm.h @@ -192,6 +192,9 @@ class MacroAssembler: public Assembler { Register address, Register scratch); + // Push a handle. + void Push(Handle handle); + // Push two registers. Pushes leftmost register first (to highest address). void Push(Register src1, Register src2, Condition cond = al) { ASSERT(!src1.is(src2)); diff --git a/src/ast.cc b/src/ast.cc index 436fb69b36..21d7007c64 100644 --- a/src/ast.cc +++ b/src/ast.cc @@ -293,11 +293,11 @@ void ObjectLiteral::CalculateEmitStore() { void TargetCollector::AddTarget(Label* target) { // Add the label to the collector, but discard duplicates. - int length = targets_->length(); + int length = targets_.length(); for (int i = 0; i < length; i++) { - if (targets_->at(i) == target) return; + if (targets_[i] == target) return; } - targets_->Add(target); + targets_.Add(target); } @@ -392,11 +392,6 @@ bool TryFinallyStatement::IsInlineable() const { } -bool CatchExtensionObject::IsInlineable() const { - return false; -} - - bool DebuggerStatement::IsInlineable() const { return false; } diff --git a/src/ast.h b/src/ast.h index 6c9ac8bcc0..7ed3579edd 100644 --- a/src/ast.h +++ b/src/ast.h @@ -80,7 +80,6 @@ namespace internal { V(RegExpLiteral) \ V(ObjectLiteral) \ V(ArrayLiteral) \ - V(CatchExtensionObject) \ V(Assignment) \ V(Throw) \ V(Property) \ @@ -614,19 +613,17 @@ class ReturnStatement: public Statement { class WithEnterStatement: public Statement { public: - explicit WithEnterStatement(Expression* expression, bool is_catch_block) - : expression_(expression), is_catch_block_(is_catch_block) { } + explicit WithEnterStatement(Expression* expression) + : expression_(expression) { } DECLARE_NODE_TYPE(WithEnterStatement) Expression* expression() const { return expression_; } - bool is_catch_block() const { return is_catch_block_; } virtual bool IsInlineable() const; private: Expression* expression_; - bool is_catch_block_; }; @@ -743,9 +740,7 @@ class IfStatement: public Statement { // stack in the compiler; this should probably be reworked. class TargetCollector: public AstNode { public: - explicit TargetCollector(ZoneList* targets) - : targets_(targets) { - } + TargetCollector(): targets_(0) { } // Adds a jump target to the collector. The collector stores a pointer not // a copy of the target to make binding work, so make sure not to pass in @@ -756,11 +751,11 @@ class TargetCollector: public AstNode { virtual void Accept(AstVisitor* v) { UNREACHABLE(); } virtual TargetCollector* AsTargetCollector() { return this; } - ZoneList* targets() { return targets_; } + ZoneList* targets() { return &targets_; } virtual bool IsInlineable() const; private: - ZoneList* targets_; + ZoneList targets_; }; @@ -785,22 +780,20 @@ class TryStatement: public Statement { class TryCatchStatement: public TryStatement { public: - TryCatchStatement(Block* try_block, - VariableProxy* catch_var, - Block* catch_block) + TryCatchStatement(Block* try_block, Handle name, Block* catch_block) : TryStatement(try_block), - catch_var_(catch_var), + name_(name), catch_block_(catch_block) { } DECLARE_NODE_TYPE(TryCatchStatement) - VariableProxy* catch_var() const { return catch_var_; } Block* catch_block() const { return catch_block_; } + Handle name() const { return name_; } virtual bool IsInlineable() const; private: - VariableProxy* catch_var_; + Handle name_; Block* catch_block_; }; @@ -1040,27 +1033,6 @@ class ArrayLiteral: public MaterializedLiteral { }; -// Node for constructing a context extension object for a catch block. -// The catch context extension object has one property, the catch -// variable, which should be DontDelete. -class CatchExtensionObject: public Expression { - public: - CatchExtensionObject(Literal* key, VariableProxy* value) - : key_(key), value_(value) { - } - - DECLARE_NODE_TYPE(CatchExtensionObject) - - Literal* key() const { return key_; } - VariableProxy* value() const { return value_; } - virtual bool IsInlineable() const; - - private: - Literal* key_; - VariableProxy* value_; -}; - - class VariableProxy: public Expression { public: explicit VariableProxy(Variable* var); diff --git a/src/full-codegen.cc b/src/full-codegen.cc index 6604e41401..972bdf05e2 100644 --- a/src/full-codegen.cc +++ b/src/full-codegen.cc @@ -187,11 +187,6 @@ void BreakableStatementChecker::VisitArrayLiteral(ArrayLiteral* expr) { } -void BreakableStatementChecker::VisitCatchExtensionObject( - CatchExtensionObject* expr) { -} - - void BreakableStatementChecker::VisitAssignment(Assignment* expr) { // If assigning to a property (including a global property) the assignment is // breakable. @@ -962,15 +957,7 @@ void FullCodeGenerator::VisitWithEnterStatement(WithEnterStatement* stmt) { SetStatementPosition(stmt); VisitForStackValue(stmt->expression()); - if (stmt->is_catch_block()) { - __ CallRuntime(Runtime::kPushCatchContext, 1); - } else { - __ CallRuntime(Runtime::kPushContext, 1); - } - // Both runtime calls return the new context in both the context and the - // result registers. - - // Update local stack frame context field. + __ CallRuntime(Runtime::kPushContext, 1); StoreToFrameField(StandardFrameConstants::kContextOffset, context_register()); } @@ -1117,15 +1104,15 @@ void FullCodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) { __ Call(&try_handler_setup); // Try handler code, exception in result register. - // Store exception in local .catch variable before executing catch block. - { - // The catch variable is *always* a variable proxy for a local variable. - Variable* catch_var = stmt->catch_var()->AsVariableProxy()->AsVariable(); - ASSERT_NOT_NULL(catch_var); - Slot* variable_slot = catch_var->AsSlot(); - ASSERT_NOT_NULL(variable_slot); - ASSERT_EQ(Slot::LOCAL, variable_slot->type()); - StoreToFrameField(SlotOffset(variable_slot), result_register()); + // Extend the context before executing the catch block. + { Comment cmnt(masm_, "[ Extend catch context"); + __ Push(stmt->name()); + __ push(result_register()); + __ CallRuntime(Runtime::kCreateCatchExtensionObject, 2); + __ push(result_register()); + __ CallRuntime(Runtime::kPushCatchContext, 1); + StoreToFrameField(StandardFrameConstants::kContextOffset, + context_register()); } Visit(stmt->catch_block()); @@ -1281,18 +1268,6 @@ void FullCodeGenerator::VisitSharedFunctionInfoLiteral( } -void FullCodeGenerator::VisitCatchExtensionObject(CatchExtensionObject* expr) { - // Call runtime routine to allocate the catch extension object and - // assign the exception value to the catch variable. - Comment cmnt(masm_, "[ CatchExtensionObject"); - VisitForStackValue(expr->key()); - VisitForStackValue(expr->value()); - // Create catch extension object. - __ CallRuntime(Runtime::kCreateCatchExtensionObject, 2); - context()->Plug(result_register()); -} - - void FullCodeGenerator::VisitThrow(Throw* expr) { Comment cmnt(masm_, "[ Throw"); VisitForStackValue(expr->exception()); diff --git a/src/hydrogen.cc b/src/hydrogen.cc index 3ce4a5b179..48c27c93c6 100644 --- a/src/hydrogen.cc +++ b/src/hydrogen.cc @@ -3187,14 +3187,6 @@ void HGraphBuilder::VisitArrayLiteral(ArrayLiteral* expr) { } -void HGraphBuilder::VisitCatchExtensionObject(CatchExtensionObject* expr) { - ASSERT(!HasStackOverflow()); - ASSERT(current_block() != NULL); - ASSERT(current_block()->HasPredecessor()); - return Bailout("CatchExtensionObject"); -} - - // Sets the lookup result and returns true if the store can be inlined. static bool ComputeStoredField(Handle type, Handle name, diff --git a/src/ia32/assembler-ia32.cc b/src/ia32/assembler-ia32.cc index a7602e7d8e..0dc519407c 100644 --- a/src/ia32/assembler-ia32.cc +++ b/src/ia32/assembler-ia32.cc @@ -449,6 +449,13 @@ void Assembler::push(const Operand& src) { } +void Assembler::push(Handle handle) { + EnsureSpace ensure_space(this); + EMIT(0x68); + emit(handle); +} + + void Assembler::pop(Register dst) { ASSERT(reloc_info_writer.last_pc() != NULL); EnsureSpace ensure_space(this); diff --git a/src/ia32/assembler-ia32.h b/src/ia32/assembler-ia32.h index e933102cd9..6609b4fed9 100644 --- a/src/ia32/assembler-ia32.h +++ b/src/ia32/assembler-ia32.h @@ -659,6 +659,7 @@ class Assembler : public AssemblerBase { void push_imm32(int32_t imm32); void push(Register src); void push(const Operand& src); + void push(Handle handle); void pop(Register dst); void pop(const Operand& dst); diff --git a/src/ia32/macro-assembler-ia32.h b/src/ia32/macro-assembler-ia32.h index 93d7e2e2ec..d49113127f 100644 --- a/src/ia32/macro-assembler-ia32.h +++ b/src/ia32/macro-assembler-ia32.h @@ -591,6 +591,9 @@ class MacroAssembler: public Assembler { void Move(Register target, Handle value); + // Push a handle value. + void Push(Handle handle) { push(handle); } + Handle CodeObject() { ASSERT(!code_object_.is_null()); return code_object_; diff --git a/src/parser.cc b/src/parser.cc index cce337fb46..70d7be449b 100644 --- a/src/parser.cc +++ b/src/parser.cc @@ -1906,13 +1906,9 @@ Statement* Parser::ParseReturnStatement(bool* ok) { } -Block* Parser::WithHelper(Expression* obj, - ZoneStringList* labels, - bool is_catch_block, - bool* ok) { +Block* Parser::WithHelper(Expression* obj, ZoneStringList* labels, bool* ok) { // Parse the statement and collect escaping labels. - ZoneList* target_list = new(zone()) ZoneList(0); - TargetCollector collector(target_list); + TargetCollector collector; Statement* stat; { Target target(&this->target_stack_, &collector); with_nesting_level_++; @@ -1926,7 +1922,7 @@ Block* Parser::WithHelper(Expression* obj, Block* result = new(zone()) Block(NULL, 2, false); if (result != NULL) { - result->AddStatement(new(zone()) WithEnterStatement(obj, is_catch_block)); + result->AddStatement(new(zone()) WithEnterStatement(obj)); // Create body block. Block* body = new(zone()) Block(NULL, 1, false); @@ -1961,7 +1957,7 @@ Statement* Parser::ParseWithStatement(ZoneStringList* labels, bool* ok) { Expression* expr = ParseExpression(true, CHECK_OK); Expect(Token::RPAREN, CHECK_OK); - return WithHelper(expr, labels, false, CHECK_OK); + return WithHelper(expr, labels, CHECK_OK); } @@ -2057,18 +2053,13 @@ TryStatement* Parser::ParseTryStatement(bool* ok) { Expect(Token::TRY, CHECK_OK); - ZoneList* target_list = new(zone()) ZoneList(0); - TargetCollector collector(target_list); + TargetCollector try_collector; Block* try_block; - { Target target(&this->target_stack_, &collector); + { Target target(&this->target_stack_, &try_collector); try_block = ParseBlock(NULL, CHECK_OK); } - Block* catch_block = NULL; - Variable* catch_var = NULL; - Block* finally_block = NULL; - Token::Value tok = peek(); if (tok != Token::CATCH && tok != Token::FINALLY) { ReportMessage("no_catch_or_finally", Vector::empty()); @@ -2077,18 +2068,17 @@ TryStatement* Parser::ParseTryStatement(bool* ok) { } // If we can break out from the catch block and there is a finally block, - // then we will need to collect jump targets from the catch block. Since - // we don't know yet if there will be a finally block, we always collect - // the jump targets. - ZoneList* catch_target_list = new(zone()) ZoneList(0); - TargetCollector catch_collector(catch_target_list); - bool has_catch = false; + // then we will need to collect escaping targets from the catch + // block. Since we don't know yet if there will be a finally block, we + // always collect the targets. + TargetCollector catch_collector; + Block* catch_block = NULL; + Handle name; if (tok == Token::CATCH) { - has_catch = true; Consume(Token::CATCH); Expect(Token::LPAREN, CHECK_OK); - Handle name = ParseIdentifier(CHECK_OK); + name = ParseIdentifier(CHECK_OK); if (top_scope_->is_strict_mode() && IsEvalOrArguments(name)) { ReportMessage("strict_catch_variable", Vector::empty()); @@ -2099,17 +2089,33 @@ TryStatement* Parser::ParseTryStatement(bool* ok) { Expect(Token::RPAREN, CHECK_OK); if (peek() == Token::LBRACE) { - // Allocate a temporary for holding the finally state while - // executing the finally block. - catch_var = - top_scope_->NewTemporary(isolate()->factory()->catch_var_symbol()); - Literal* name_literal = new(zone()) Literal(name); - VariableProxy* catch_var_use = new(zone()) VariableProxy(catch_var); - Expression* obj = - new(zone()) CatchExtensionObject(name_literal, catch_var_use); + // Rewrite the catch body B to a single statement block + // { try B finally { PopContext }}. + Block* inner_body; + // We need to collect escapes from the body for both the inner + // try/finally used to pop the catch context and any possible outer + // try/finally. + TargetCollector inner_collector; { Target target(&this->target_stack_, &catch_collector); - catch_block = WithHelper(obj, NULL, true, CHECK_OK); + { Target target(&this->target_stack_, &inner_collector); + ++with_nesting_level_; + top_scope_->RecordWithStatement(); + inner_body = ParseBlock(NULL, CHECK_OK); + --with_nesting_level_; + } } + + // Create exit block. + Block* inner_finally = new(zone()) Block(NULL, 1, false); + inner_finally->AddStatement(new(zone()) WithExitStatement()); + + // Create a try/finally statement. + TryFinallyStatement* inner_try_finally = + new(zone()) TryFinallyStatement(inner_body, inner_finally); + inner_try_finally->set_escaping_targets(inner_collector.targets()); + + catch_block = new (zone()) Block(NULL, 1, false); + catch_block->AddStatement(inner_try_finally); } else { Expect(Token::LBRACE, CHECK_OK); } @@ -2117,23 +2123,21 @@ TryStatement* Parser::ParseTryStatement(bool* ok) { tok = peek(); } - if (tok == Token::FINALLY || !has_catch) { + Block* finally_block = NULL; + if (tok == Token::FINALLY || catch_block == NULL) { Consume(Token::FINALLY); - // Declare a variable for holding the finally state while - // executing the finally block. finally_block = ParseBlock(NULL, CHECK_OK); } // Simplify the AST nodes by converting: - // 'try { } catch { } finally { }' + // 'try B0 catch B1 finally B2' // to: - // 'try { try { } catch { } } finally { }' + // 'try { try B0 catch B1 } finally B2' if (catch_block != NULL && finally_block != NULL) { - VariableProxy* catch_var_defn = new(zone()) VariableProxy(catch_var); TryCatchStatement* statement = - new(zone()) TryCatchStatement(try_block, catch_var_defn, catch_block); - statement->set_escaping_targets(collector.targets()); + new(zone()) TryCatchStatement(try_block, name, catch_block); + statement->set_escaping_targets(try_collector.targets()); try_block = new(zone()) Block(NULL, 1, false); try_block->AddStatement(statement); catch_block = NULL; @@ -2142,20 +2146,16 @@ TryStatement* Parser::ParseTryStatement(bool* ok) { TryStatement* result = NULL; if (catch_block != NULL) { ASSERT(finally_block == NULL); - VariableProxy* catch_var_defn = new(zone()) VariableProxy(catch_var); result = - new(zone()) TryCatchStatement(try_block, catch_var_defn, catch_block); - result->set_escaping_targets(collector.targets()); + new(zone()) TryCatchStatement(try_block, name, catch_block); } else { ASSERT(finally_block != NULL); result = new(zone()) TryFinallyStatement(try_block, finally_block); - // Add the jump targets of the try block and the catch block. - for (int i = 0; i < collector.targets()->length(); i++) { - catch_collector.AddTarget(collector.targets()->at(i)); - } - result->set_escaping_targets(catch_collector.targets()); + // Combine the jump targets of the try block and the possible catch block. + try_collector.targets()->AddAll(*catch_collector.targets()); } + result->set_escaping_targets(try_collector.targets()); return result; } diff --git a/src/parser.h b/src/parser.h index a7132ce240..fe11bc9b51 100644 --- a/src/parser.h +++ b/src/parser.h @@ -498,10 +498,7 @@ class Parser { Statement* ParseContinueStatement(bool* ok); Statement* ParseBreakStatement(ZoneStringList* labels, bool* ok); Statement* ParseReturnStatement(bool* ok); - Block* WithHelper(Expression* obj, - ZoneStringList* labels, - bool is_catch_block, - bool* ok); + Block* WithHelper(Expression* obj, ZoneStringList* labels, bool* ok); Statement* ParseWithStatement(ZoneStringList* labels, bool* ok); CaseClause* ParseCaseClause(bool* default_seen_ptr, bool* ok); SwitchStatement* ParseSwitchStatement(ZoneStringList* labels, bool* ok); diff --git a/src/prettyprinter.cc b/src/prettyprinter.cc index 60288a969b..0149ed51e2 100644 --- a/src/prettyprinter.cc +++ b/src/prettyprinter.cc @@ -1,4 +1,4 @@ -// Copyright 2006-2008 the V8 project authors. All rights reserved. +// Copyright 2011 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: @@ -201,7 +201,8 @@ void PrettyPrinter::VisitTryCatchStatement(TryCatchStatement* node) { Print("try "); Visit(node->try_block()); Print(" catch ("); - Visit(node->catch_var()); + const bool quote = false; + PrintLiteral(node->name(), quote); Print(") "); Visit(node->catch_block()); } @@ -282,15 +283,6 @@ void PrettyPrinter::VisitArrayLiteral(ArrayLiteral* node) { } -void PrettyPrinter::VisitCatchExtensionObject(CatchExtensionObject* node) { - Print("{ "); - Visit(node->key()); - Print(": "); - Visit(node->value()); - Print(" }"); -} - - void PrettyPrinter::VisitSlot(Slot* node) { switch (node->type()) { case Slot::PARAMETER: @@ -862,7 +854,8 @@ void AstPrinter::VisitForInStatement(ForInStatement* node) { void AstPrinter::VisitTryCatchStatement(TryCatchStatement* node) { IndentedScope indent(this, "TRY CATCH"); PrintIndentedVisit("TRY", node->try_block()); - PrintIndentedVisit("CATCHVAR", node->catch_var()); + const bool quote = false; + PrintLiteralIndented("CATCHVAR", node->name(), quote); PrintIndentedVisit("CATCH", node->catch_block()); } @@ -962,13 +955,6 @@ void AstPrinter::VisitArrayLiteral(ArrayLiteral* node) { } -void AstPrinter::VisitCatchExtensionObject(CatchExtensionObject* node) { - IndentedScope indent(this, "CatchExtensionObject"); - PrintIndentedVisit("KEY", node->key()); - PrintIndentedVisit("VALUE", node->value()); -} - - void AstPrinter::VisitSlot(Slot* node) { PrintIndented("SLOT "); PrettyPrinter::VisitSlot(node); @@ -1254,8 +1240,10 @@ void JsonAstBuilder::VisitForInStatement(ForInStatement* stmt) { void JsonAstBuilder::VisitTryCatchStatement(TryCatchStatement* stmt) { TagScope tag(this, "TryCatchStatement"); + { AttributesScope attributes(this); + AddAttribute("variable", stmt->name()); + } Visit(stmt->try_block()); - Visit(stmt->catch_var()); Visit(stmt->catch_block()); } @@ -1360,13 +1348,6 @@ void JsonAstBuilder::VisitArrayLiteral(ArrayLiteral* expr) { } -void JsonAstBuilder::VisitCatchExtensionObject(CatchExtensionObject* expr) { - TagScope tag(this, "CatchExtensionObject"); - Visit(expr->key()); - Visit(expr->value()); -} - - void JsonAstBuilder::VisitAssignment(Assignment* expr) { TagScope tag(this, "Assignment"); { diff --git a/src/rewriter.cc b/src/rewriter.cc index efe80447d4..7ed19d576e 100644 --- a/src/rewriter.cc +++ b/src/rewriter.cc @@ -252,12 +252,6 @@ void Processor::VisitObjectLiteral(ObjectLiteral* node) { } -void Processor::VisitCatchExtensionObject(CatchExtensionObject* node) { - USE(node); - UNREACHABLE(); -} - - void Processor::VisitAssignment(Assignment* node) { USE(node); UNREACHABLE(); diff --git a/src/x64/assembler-x64.h b/src/x64/assembler-x64.h index 7769b032ea..2971db845e 100644 --- a/src/x64/assembler-x64.h +++ b/src/x64/assembler-x64.h @@ -640,6 +640,7 @@ class Assembler : public AssemblerBase { void push_imm32(int32_t imm32); void push(Register src); void push(const Operand& src); + void push(Handle handle); void pop(Register dst); void pop(const Operand& dst);