Stop using with explicitly to implement try/catch.
authorkmillikin@chromium.org <kmillikin@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 8 Jun 2011 13:55:33 +0000 (13:55 +0000)
committerkmillikin@chromium.org <kmillikin@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 8 Jun 2011 13:55:33 +0000 (13:55 +0000)
The AST for TryCatch gives us enough structure that we do not need to expand
it to explicitly include a with.  Try/catch is still handled the same as
before at runtime.

R=ager@chromium.org
BUG=
TEST=

Review URL: http://codereview.chromium.org/7134014

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@8224 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

14 files changed:
src/arm/macro-assembler-arm.cc
src/arm/macro-assembler-arm.h
src/ast.cc
src/ast.h
src/full-codegen.cc
src/hydrogen.cc
src/ia32/assembler-ia32.cc
src/ia32/assembler-ia32.h
src/ia32/macro-assembler-ia32.h
src/parser.cc
src/parser.h
src/prettyprinter.cc
src/rewriter.cc
src/x64/assembler-x64.h

index d250f94..464478a 100644 (file)
@@ -298,6 +298,12 @@ void MacroAssembler::Call(Label* target) {
 }
 
 
+void MacroAssembler::Push(Handle<Object> handle) {
+  mov(ip, Operand(handle));
+  push(ip);
+}
+
+
 void MacroAssembler::Move(Register dst, Handle<Object> value) {
   mov(dst, Operand(value));
 }
index 2dda57d..0802d7c 100644 (file)
@@ -192,6 +192,9 @@ class MacroAssembler: public Assembler {
                    Register address,
                    Register scratch);
 
+  // Push a handle.
+  void Push(Handle<Object> handle);
+
   // Push two registers.  Pushes leftmost register first (to highest address).
   void Push(Register src1, Register src2, Condition cond = al) {
     ASSERT(!src1.is(src2));
index 436fb69..21d7007 100644 (file)
@@ -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;
 }
index 6c9ac8b..7ed3579 100644 (file)
--- 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<Label*>* 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<Label*>* targets() { return targets_; }
+  ZoneList<Label*>* targets() { return &targets_; }
   virtual bool IsInlineable() const;
 
  private:
-  ZoneList<Label*>* targets_;
+  ZoneList<Label*> 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<String> 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<String> name() const { return name_; }
   virtual bool IsInlineable() const;
 
  private:
-  VariableProxy* catch_var_;
+  Handle<String> 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);
index 6604e41..972bdf0 100644 (file)
@@ -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());
index 3ce4a5b..48c27c9 100644 (file)
@@ -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<Map> type,
                                Handle<String> name,
index a7602e7..0dc5194 100644 (file)
@@ -449,6 +449,13 @@ void Assembler::push(const Operand& src) {
 }
 
 
+void Assembler::push(Handle<Object> 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);
index e933102..6609b4f 100644 (file)
@@ -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<Object> handle);
 
   void pop(Register dst);
   void pop(const Operand& dst);
index 93d7e2e..d491131 100644 (file)
@@ -591,6 +591,9 @@ class MacroAssembler: public Assembler {
 
   void Move(Register target, Handle<Object> value);
 
+  // Push a handle value.
+  void Push(Handle<Object> handle) { push(handle); }
+
   Handle<Object> CodeObject() {
     ASSERT(!code_object_.is_null());
     return code_object_;
index cce337f..70d7be4 100644 (file)
@@ -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<Label*>* target_list = new(zone()) ZoneList<Label*>(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<Label*>* target_list = new(zone()) ZoneList<Label*>(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<const char*>::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<Label*>* catch_target_list = new(zone()) ZoneList<Label*>(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<String> name;
   if (tok == Token::CATCH) {
-    has_catch = true;
     Consume(Token::CATCH);
 
     Expect(Token::LPAREN, CHECK_OK);
-    Handle<String> name = ParseIdentifier(CHECK_OK);
+    name = ParseIdentifier(CHECK_OK);
 
     if (top_scope_->is_strict_mode() && IsEvalOrArguments(name)) {
       ReportMessage("strict_catch_variable", Vector<const char*>::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;
 }
 
index a7132ce..fe11bc9 100644 (file)
@@ -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);
index 60288a9..0149ed5 100644 (file)
@@ -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");
   {
index efe8044..7ed19d5 100644 (file)
@@ -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();
index 7769b03..2971db8 100644 (file)
@@ -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<Object> handle);
 
   void pop(Register dst);
   void pop(const Operand& dst);