}
+void MacroAssembler::Push(Handle<Object> handle) {
+ mov(ip, Operand(handle));
+ push(ip);
+}
+
+
void MacroAssembler::Move(Register dst, Handle<Object> value) {
mov(dst, Operand(value));
}
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));
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);
}
}
-bool CatchExtensionObject::IsInlineable() const {
- return false;
-}
-
-
bool DebuggerStatement::IsInlineable() const {
return false;
}
V(RegExpLiteral) \
V(ObjectLiteral) \
V(ArrayLiteral) \
- V(CatchExtensionObject) \
V(Assignment) \
V(Throw) \
V(Property) \
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_;
};
// 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
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_;
};
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_;
};
};
-// 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);
}
-void BreakableStatementChecker::VisitCatchExtensionObject(
- CatchExtensionObject* expr) {
-}
-
-
void BreakableStatementChecker::VisitAssignment(Assignment* expr) {
// If assigning to a property (including a global property) the assignment is
// breakable.
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());
}
__ 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());
}
-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());
}
-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,
}
+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);
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);
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_;
}
-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_++;
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);
Expression* expr = ParseExpression(true, CHECK_OK);
Expect(Token::RPAREN, CHECK_OK);
- return WithHelper(expr, labels, false, CHECK_OK);
+ return WithHelper(expr, labels, CHECK_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());
}
// 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());
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);
}
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;
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;
}
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);
-// 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:
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());
}
}
-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:
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());
}
}
-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);
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());
}
}
-void JsonAstBuilder::VisitCatchExtensionObject(CatchExtensionObject* expr) {
- TagScope tag(this, "CatchExtensionObject");
- Visit(expr->key());
- Visit(expr->value());
-}
-
-
void JsonAstBuilder::VisitAssignment(Assignment* expr) {
TagScope tag(this, "Assignment");
{
}
-void Processor::VisitCatchExtensionObject(CatchExtensionObject* node) {
- USE(node);
- UNREACHABLE();
-}
-
-
void Processor::VisitAssignment(Assignment* node) {
USE(node);
UNREACHABLE();
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);