Stop using with explicitly to implement try/catch.

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
This commit is contained in:
kmillikin@chromium.org 2011-06-08 13:55:33 +00:00
parent 699d17c3b9
commit e9a1ffde92
14 changed files with 100 additions and 173 deletions

View 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));
}

View 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));

View 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;
}

View File

@ -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);

View 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());

View 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,

View 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);

View 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);

View 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_;

View 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;
}

View 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);

View 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");
{

View 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();

View 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);