From 35faa6aaa96cabf1d2d5538f61e66fabb133d00a Mon Sep 17 00:00:00 2001 From: "srdjan@google.com" Date: Thu, 24 Nov 2011 01:14:15 +0000 Subject: [PATCH] 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 --- runtime/vm/code_generator_ia32.cc | 165 +++++++++----------------- runtime/vm/code_generator_ia32.h | 63 +++++++++- runtime/vm/opt_code_generator_ia32.cc | 45 +++++++ runtime/vm/opt_code_generator_ia32.h | 3 + 4 files changed, 169 insertions(+), 107 deletions(-) diff --git a/runtime/vm/code_generator_ia32.cc b/runtime/vm/code_generator_ia32.cc index 5d1fb3f98cf..18cbb96c689 100644 --- a/runtime/vm/code_generator_ia32.cc +++ b/runtime/vm/code_generator_ia32.cc @@ -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(); } diff --git a/runtime/vm/code_generator_ia32.h b/runtime/vm/code_generator_ia32.h index ebb908da823..e9b91241135 100644 --- a/runtime/vm/code_generator_ia32.h +++ b/runtime/vm/code_generator_ia32.h @@ -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. diff --git a/runtime/vm/opt_code_generator_ia32.cc b/runtime/vm/opt_code_generator_ia32.cc index 68f40e4d5de..b9e413d895f 100644 --- a/runtime/vm/opt_code_generator_ia32.cc +++ b/runtime/vm/opt_code_generator_ia32.cc @@ -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 diff --git a/runtime/vm/opt_code_generator_ia32.h b/runtime/vm/opt_code_generator_ia32.h index fe5ea059459..d7c4c84f462 100644 --- a/runtime/vm/opt_code_generator_ia32.h +++ b/runtime/vm/opt_code_generator_ia32.h @@ -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