Move more nodes to the optimizing code generator.
Review URL: http://codereview.chromium.org//8678033 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@1829 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
@@ -33,80 +33,28 @@ DECLARE_FLAG(bool, trace_compiler);
|
||||
#define __ assembler_->
|
||||
|
||||
|
||||
class CodeGeneratorState : public StackResource {
|
||||
public:
|
||||
explicit CodeGeneratorState(CodeGenerator* codegen)
|
||||
: StackResource(Isolate::Current()),
|
||||
codegen_(codegen),
|
||||
parent_(codegen->state()) {
|
||||
if (parent_ != NULL) {
|
||||
root_node_ = parent_->root_node_;
|
||||
loop_level_ = parent_->loop_level_;
|
||||
context_level_ = parent_->context_level_;
|
||||
current_try_index_ = parent_->current_try_index_;
|
||||
} else {
|
||||
root_node_ = NULL;
|
||||
loop_level_ = 0;
|
||||
context_level_ = 0;
|
||||
current_try_index_ = CatchClauseNode::kInvalidTryIndex;
|
||||
}
|
||||
codegen_->set_state(this);
|
||||
}
|
||||
virtual ~CodeGeneratorState() {
|
||||
codegen_->set_state(parent_);
|
||||
CodeGeneratorState::CodeGeneratorState(CodeGenerator* codegen)
|
||||
: StackResource(Isolate::Current()),
|
||||
codegen_(codegen),
|
||||
parent_(codegen->state()) {
|
||||
if (parent_ != NULL) {
|
||||
root_node_ = parent_->root_node_;
|
||||
loop_level_ = parent_->loop_level_;
|
||||
context_level_ = parent_->context_level_;
|
||||
current_try_index_ = parent_->current_try_index_;
|
||||
} else {
|
||||
root_node_ = NULL;
|
||||
loop_level_ = 0;
|
||||
context_level_ = 0;
|
||||
current_try_index_ = CatchClauseNode::kInvalidTryIndex;
|
||||
}
|
||||
codegen_->set_state(this);
|
||||
}
|
||||
|
||||
CodeGeneratorState* parent() const { return parent_; }
|
||||
|
||||
AstNode* root_node() const { return root_node_; }
|
||||
void set_root_node(AstNode* value) { root_node_ = value; }
|
||||
bool IsRootNode(AstNode* node) const {
|
||||
return root_node_ == node;
|
||||
}
|
||||
|
||||
int loop_level() const { return loop_level_; }
|
||||
void set_loop_level(int loop_level) {
|
||||
loop_level_ = loop_level;
|
||||
}
|
||||
|
||||
int context_level() const { return context_level_; }
|
||||
void set_context_level(int context_level) {
|
||||
context_level_ = context_level;
|
||||
}
|
||||
|
||||
int try_index() const { return current_try_index_; }
|
||||
void set_try_index(int value) {
|
||||
current_try_index_ = value;
|
||||
}
|
||||
|
||||
private:
|
||||
CodeGenerator* codegen_;
|
||||
CodeGeneratorState* parent_;
|
||||
AstNode* root_node_;
|
||||
|
||||
// The loop level reflects the lexical nesting of loop statements, regardless
|
||||
// of the presence of captured variables.
|
||||
int loop_level_;
|
||||
|
||||
// The runtime context level is only incremented when a new context is
|
||||
// allocated and chained to the list of contexts. This occurs when the scopes
|
||||
// at the current loop level contain captured variables.
|
||||
int context_level_;
|
||||
|
||||
// We identify each try block in this function with an unique 'try index'
|
||||
// value.
|
||||
// The 'try index' is used to match the try blocks with the corresponding
|
||||
// catch block (if one exists). The PC descriptors generated for
|
||||
// statements in the try block use this index so that it can be matched
|
||||
// to the appropriate catch block.
|
||||
// The 'try index' value is generated by incrementing the try_index_
|
||||
// variable in the CodeGenerator object.
|
||||
// We store the 'try index' of the block of code that we are
|
||||
// currently generating code for in the current_try_index_ variable.
|
||||
int current_try_index_;
|
||||
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(CodeGeneratorState);
|
||||
};
|
||||
CodeGeneratorState::~CodeGeneratorState() {
|
||||
codegen_->set_state(parent_);
|
||||
}
|
||||
|
||||
|
||||
class CodeGenerator::DescriptorList : public ZoneAllocated {
|
||||
@@ -767,6 +715,45 @@ void CodeGenerator::GenerateEntryCode() {
|
||||
}
|
||||
|
||||
|
||||
void CodeGenerator::GenerateReturnEpilog() {
|
||||
// Unchain the context(s) up to context level 0.
|
||||
int context_level = state()->context_level();
|
||||
ASSERT(context_level >= 0);
|
||||
while (context_level-- > 0) {
|
||||
__ movl(CTX, FieldAddress(CTX, Context::parent_offset()));
|
||||
}
|
||||
#ifdef DEBUG
|
||||
// Check that the entry stack size matches the exit stack size.
|
||||
__ movl(EDX, EBP);
|
||||
__ subl(EDX, ESP);
|
||||
ASSERT(locals_space_size() >= 0);
|
||||
__ cmpl(EDX, Immediate(locals_space_size()));
|
||||
Label wrong_stack;
|
||||
__ j(NOT_EQUAL, &wrong_stack, Assembler::kNearJump);
|
||||
#endif // DEBUG.
|
||||
|
||||
if (FLAG_trace_functions) {
|
||||
__ pushl(EAX); // Preserve result.
|
||||
const Function& function =
|
||||
Function::ZoneHandle(parsed_function_.function().raw());
|
||||
__ LoadObject(EBX, function);
|
||||
__ pushl(EBX);
|
||||
GenerateCallRuntime(AstNode::kNoId,
|
||||
0,
|
||||
kTraceFunctionExitRuntimeEntry);
|
||||
__ popl(EAX); // Remove argument.
|
||||
__ popl(EAX); // Restore result.
|
||||
}
|
||||
__ LeaveFrame();
|
||||
__ ret();
|
||||
|
||||
#ifdef DEBUG
|
||||
__ Bind(&wrong_stack);
|
||||
__ Stop("Exit stack size does not match the entry stack size.");
|
||||
#endif // DEBUG.
|
||||
}
|
||||
|
||||
|
||||
void CodeGenerator::VisitReturnNode(ReturnNode* node) {
|
||||
ASSERT(!IsResultNeeded(node));
|
||||
ASSERT(node->value() != NULL);
|
||||
@@ -808,41 +795,7 @@ void CodeGenerator::VisitReturnNode(ReturnNode* node) {
|
||||
String::ZoneHandle(String::NewSymbol("function result")));
|
||||
}
|
||||
}
|
||||
// Unchain the context(s) up to context level 0.
|
||||
int context_level = state()->context_level();
|
||||
ASSERT(context_level >= 0);
|
||||
while (context_level-- > 0) {
|
||||
__ movl(CTX, FieldAddress(CTX, Context::parent_offset()));
|
||||
}
|
||||
#ifdef DEBUG
|
||||
// Check that the entry stack size matches the exit stack size.
|
||||
__ movl(EDX, EBP);
|
||||
__ subl(EDX, ESP);
|
||||
ASSERT(locals_space_size() >= 0);
|
||||
__ cmpl(EDX, Immediate(locals_space_size()));
|
||||
Label wrong_stack;
|
||||
__ j(NOT_EQUAL, &wrong_stack, Assembler::kNearJump);
|
||||
#endif // DEBUG.
|
||||
|
||||
if (FLAG_trace_functions) {
|
||||
__ pushl(EAX); // Preserve result.
|
||||
const Function& function =
|
||||
Function::ZoneHandle(parsed_function_.function().raw());
|
||||
__ LoadObject(EBX, function);
|
||||
__ pushl(EBX);
|
||||
GenerateCallRuntime(AstNode::kNoId,
|
||||
0,
|
||||
kTraceFunctionExitRuntimeEntry);
|
||||
__ popl(EAX); // Remove argument.
|
||||
__ popl(EAX); // Restore result.
|
||||
}
|
||||
__ LeaveFrame();
|
||||
__ ret();
|
||||
|
||||
#ifdef DEBUG
|
||||
__ Bind(&wrong_stack);
|
||||
__ Stop("Exit stack size does not match the entry stack size.");
|
||||
#endif // DEBUG.
|
||||
GenerateReturnEpilog();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -19,9 +19,68 @@ namespace dart {
|
||||
// Forward Declarations.
|
||||
class Assembler;
|
||||
class AstNode;
|
||||
class CodeGeneratorState;
|
||||
class CodeGenerator;
|
||||
class SourceLabel;
|
||||
|
||||
|
||||
class CodeGeneratorState : public StackResource {
|
||||
public:
|
||||
explicit CodeGeneratorState(CodeGenerator* codegen);
|
||||
virtual ~CodeGeneratorState();
|
||||
|
||||
CodeGeneratorState* parent() const { return parent_; }
|
||||
|
||||
AstNode* root_node() const { return root_node_; }
|
||||
void set_root_node(AstNode* value) { root_node_ = value; }
|
||||
bool IsRootNode(AstNode* node) const {
|
||||
return root_node_ == node;
|
||||
}
|
||||
|
||||
int loop_level() const { return loop_level_; }
|
||||
void set_loop_level(int loop_level) {
|
||||
loop_level_ = loop_level;
|
||||
}
|
||||
|
||||
int context_level() const { return context_level_; }
|
||||
void set_context_level(int context_level) {
|
||||
context_level_ = context_level;
|
||||
}
|
||||
|
||||
int try_index() const { return current_try_index_; }
|
||||
void set_try_index(int value) {
|
||||
current_try_index_ = value;
|
||||
}
|
||||
|
||||
private:
|
||||
CodeGenerator* codegen_;
|
||||
CodeGeneratorState* parent_;
|
||||
AstNode* root_node_;
|
||||
|
||||
// The loop level reflects the lexical nesting of loop statements, regardless
|
||||
// of the presence of captured variables.
|
||||
int loop_level_;
|
||||
|
||||
// The runtime context level is only incremented when a new context is
|
||||
// allocated and chained to the list of contexts. This occurs when the scopes
|
||||
// at the current loop level contain captured variables.
|
||||
int context_level_;
|
||||
|
||||
// We identify each try block in this function with an unique 'try index'
|
||||
// value.
|
||||
// The 'try index' is used to match the try blocks with the corresponding
|
||||
// catch block (if one exists). The PC descriptors generated for
|
||||
// statements in the try block use this index so that it can be matched
|
||||
// to the appropriate catch block.
|
||||
// The 'try index' value is generated by incrementing the try_index_
|
||||
// variable in the CodeGenerator object.
|
||||
// We store the 'try index' of the block of code that we are
|
||||
// currently generating code for in the current_try_index_ variable.
|
||||
int current_try_index_;
|
||||
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(CodeGeneratorState);
|
||||
};
|
||||
|
||||
|
||||
class CodeGenerator : public AstNodeVisitor {
|
||||
public:
|
||||
CodeGenerator(Assembler* assembler, const ParsedFunction& parsed_function);
|
||||
@@ -63,6 +122,8 @@ NODE_LIST(DEFINE_VISITOR_FUNCTION)
|
||||
|
||||
virtual void CountBackwardLoop();
|
||||
|
||||
void GenerateReturnEpilog();
|
||||
|
||||
private:
|
||||
// TODO(srdjan): Remove the friendship once the two compilers are properly
|
||||
// structured.
|
||||
|
||||
@@ -2554,6 +2554,51 @@ void OptimizingCodeGenerator::VisitStaticCallNode(StaticCallNode* node) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void OptimizingCodeGenerator::VisitReturnNode(ReturnNode* node) {
|
||||
if ((node->inlined_finally_list_length() > 0) || FLAG_enable_type_checks) {
|
||||
CodeGenerator::VisitReturnNode(node);
|
||||
return;
|
||||
}
|
||||
ASSERT(!IsResultNeeded(node));
|
||||
ASSERT(node->value() != NULL);
|
||||
VisitLoadOne(node->value(), EAX);
|
||||
GenerateReturnEpilog();
|
||||
}
|
||||
|
||||
|
||||
void OptimizingCodeGenerator::VisitSequenceNode(SequenceNode* node_sequence) {
|
||||
if (FLAG_enable_type_checks ||
|
||||
(node_sequence->scope()->num_context_variables() > 0)) {
|
||||
CodeGenerator::VisitSequenceNode(node_sequence);
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < node_sequence->length(); i++) {
|
||||
AstNode* child_node = node_sequence->NodeAt(i);
|
||||
state()->set_root_node(child_node);
|
||||
child_node->Visit(this);
|
||||
}
|
||||
if (node_sequence->label() != NULL) {
|
||||
__ Bind(node_sequence->label()->break_label());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void OptimizingCodeGenerator::VisitStoreInstanceFieldNode(
|
||||
StoreInstanceFieldNode* node) {
|
||||
if (FLAG_enable_type_checks) {
|
||||
CodeGenerator::VisitStoreInstanceFieldNode(node);
|
||||
return;
|
||||
}
|
||||
VisitLoadTwo(node->instance(), node->value(), EDX, EAX);
|
||||
__ StoreIntoObject(EDX, FieldAddress(EDX, node->field().Offset()), EAX);
|
||||
if (IsResultNeeded(node)) {
|
||||
// The result is the input value.
|
||||
__ pushl(EAX);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace dart
|
||||
|
||||
#endif // defined TARGET_ARCH_IA32
|
||||
|
||||
@@ -40,6 +40,9 @@ class OptimizingCodeGenerator : public CodeGenerator {
|
||||
virtual void VisitIfNode(IfNode* node);
|
||||
virtual void VisitInstanceCallNode(InstanceCallNode* node);
|
||||
virtual void VisitStaticCallNode(StaticCallNode* node);
|
||||
virtual void VisitReturnNode(ReturnNode* node);
|
||||
virtual void VisitSequenceNode(SequenceNode* node_sequence);
|
||||
virtual void VisitStoreInstanceFieldNode(StoreInstanceFieldNode* node);
|
||||
|
||||
// Return true if intrinsification succeeded and no more code is needed.
|
||||
// Returns false if either no intrinsification occured or if intrinsified
|
||||
|
||||
Reference in New Issue
Block a user