Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(126)

Unified Diff: runtime/vm/flow_graph_compiler_ia32.cc

Issue 10458027: Started new compiler for ia32. Getters and setters can be intrinsified within the new compiler. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: runtime/vm/flow_graph_compiler_ia32.cc
===================================================================
--- runtime/vm/flow_graph_compiler_ia32.cc (revision 8082)
+++ runtime/vm/flow_graph_compiler_ia32.cc (working copy)
@@ -7,13 +7,114 @@
#include "vm/flow_graph_compiler.h"
+#include "vm/ast_printer.h"
#include "vm/compiler_stats.h"
+#include "vm/debugger.h"
+#include "vm/il_printer.h"
+#include "vm/intrinsifier.h"
+#include "vm/locations.h"
#include "vm/longjump.h"
+#include "vm/stub_code.h"
namespace dart {
+DECLARE_FLAG(bool, code_comments);
DECLARE_FLAG(bool, compiler_stats);
+DECLARE_FLAG(bool, enable_type_checks);
+DECLARE_FLAG(bool, intrinsify);
+DECLARE_FLAG(bool, optimization_counter_threshold);
+DECLARE_FLAG(bool, print_ast);
+DECLARE_FLAG(bool, print_scopes);
+DECLARE_FLAG(bool, report_usage_count);
+DECLARE_FLAG(bool, trace_functions);
+
+class DeoptimizationStub : public ZoneAllocated {
+ public:
+ DeoptimizationStub(intptr_t deopt_id,
+ intptr_t deopt_token_index,
+ intptr_t try_index,
+ DeoptReasonId reason)
+ : deopt_id_(deopt_id),
+ deopt_token_index_(deopt_token_index),
+ try_index_(try_index),
+ reason_(reason),
+ registers_(2),
+ entry_label_() {}
+
+ void Push(Register reg) { registers_.Add(reg); }
+ Label* entry_label() { return &entry_label_; }
+
+ void GenerateCode(FlowGraphCompiler* compiler);
+
+ private:
+ const intptr_t deopt_id_;
+ const intptr_t deopt_token_index_;
+ const intptr_t try_index_;
+ const DeoptReasonId reason_;
+ GrowableArray<Register> registers_;
+ Label entry_label_;
+
+ DISALLOW_COPY_AND_ASSIGN(DeoptimizationStub);
+};
+
+
+void DeoptimizationStub::GenerateCode(FlowGraphCompiler* compiler) {
+ Assembler* assem = compiler->assembler();
+#define __ assem->
+ __ Comment("Deopt stub for id %d", deopt_id_);
+ __ Bind(entry_label());
+ for (intptr_t i = 0; i < registers_.length(); i++) {
+ __ pushl(registers_[i]);
+ }
+ __ movl(EAX, Immediate(Smi::RawValue(reason_)));
+ __ call(&StubCode::DeoptimizeLabel());
+ compiler->AddCurrentDescriptor(PcDescriptors::kOther,
+ deopt_id_,
+ deopt_token_index_,
+ try_index_);
+#undef __
+}
+
+
+FlowGraphCompiler::FlowGraphCompiler(
+ Assembler* assembler,
+ const ParsedFunction& parsed_function,
+ const GrowableArray<BlockEntryInstr*>& block_order,
+ bool is_optimizing)
+ : FlowGraphVisitor(block_order),
+ assembler_(assembler),
+ parsed_function_(parsed_function),
+ block_info_(block_order.length()),
+ current_block_(NULL),
+ pc_descriptors_list_(NULL),
+ stackmap_builder_(NULL),
+ exception_handlers_list_(NULL),
+ deopt_stubs_(),
+ is_optimizing_(is_optimizing) {
+}
+
+
+FlowGraphCompiler::~FlowGraphCompiler() {
+ // BlockInfos are zone-allocated, so their destructors are not called.
+ // Verify the labels explicitly here.
+ for (int i = 0; i < block_info_.length(); ++i) {
+ ASSERT(!block_info_[i]->label.IsLinked());
+ ASSERT(!block_info_[i]->label.HasNear());
+ }
+}
+
+
+void FlowGraphCompiler::InitCompiler() {
+ pc_descriptors_list_ = new DescriptorList();
+ exception_handlers_list_ = new ExceptionHandlerList();
+ block_info_.Clear();
+ for (int i = 0; i < block_order_.length(); ++i) {
+ block_info_.Add(new BlockInfo());
+ }
+}
+
+
void FlowGraphCompiler::Bailout(const char* reason) {
const char* kFormat = "FlowGraphCompiler Bailout: %s.";
intptr_t len = OS::SNPrint(NULL, 0, kFormat, reason) + 1;
@@ -26,35 +127,313 @@
}
+// Uses current pc position and try-index.
+void FlowGraphCompiler::AddCurrentDescriptor(PcDescriptors::Kind kind,
+ intptr_t cid,
+ intptr_t token_index,
+ intptr_t try_index) {
+ pc_descriptors_list_->AddDescriptor(kind,
+ assembler_->CodeSize(),
+ cid,
+ token_index,
+ try_index);
+}
+
+#define __ assembler_->
+
+void FlowGraphCompiler::IntrinsifyGetter() {
+ // TOS: return address.
+ // +1 : receiver.
+ // Sequence node has one return node, its input is load field node.
+ const SequenceNode& sequence_node = *parsed_function_.node_sequence();
+ ASSERT(sequence_node.length() == 1);
+ ASSERT(sequence_node.NodeAt(0)->IsReturnNode());
+ const ReturnNode& return_node = *sequence_node.NodeAt(0)->AsReturnNode();
+ ASSERT(return_node.value()->IsLoadInstanceFieldNode());
+ const LoadInstanceFieldNode& load_node =
+ *return_node.value()->AsLoadInstanceFieldNode();
+ __ movl(EAX, Address(ESP, 1 * kWordSize));
+ __ movl(EAX, FieldAddress(EAX, load_node.field().Offset()));
+ __ ret();
+}
+
+
+void FlowGraphCompiler::IntrinsifySetter() {
+ // TOS: return address.
+ // +1 : value
+ // +2 : receiver.
+ // Sequence node has one store node and one return NULL node.
+ const SequenceNode& sequence_node = *parsed_function_.node_sequence();
+ ASSERT(sequence_node.length() == 2);
+ ASSERT(sequence_node.NodeAt(0)->IsStoreInstanceFieldNode());
+ ASSERT(sequence_node.NodeAt(1)->IsReturnNode());
+ const StoreInstanceFieldNode& store_node =
+ *sequence_node.NodeAt(0)->AsStoreInstanceFieldNode();
+ __ movl(EAX, Address(ESP, 2 * kWordSize)); // Receiver.
+ __ movl(EBX, Address(ESP, 1 * kWordSize)); // Value.
+ __ StoreIntoObject(EAX, FieldAddress(EAX, store_node.field().Offset()), EBX);
+ const Immediate raw_null =
+ Immediate(reinterpret_cast<intptr_t>(Object::null()));
+ __ movl(EAX, raw_null);
+ __ ret();
+}
+
+
+intptr_t FlowGraphCompiler::StackSize() const {
+ return parsed_function_.stack_local_count() +
+ parsed_function_.copied_parameter_count();
+}
+
+
+bool FlowGraphCompiler::CanOptimize() {
+ return
+ !FLAG_report_usage_count &&
+ (FLAG_optimization_counter_threshold >= 0) &&
+ !Isolate::Current()->debugger()->IsActive();
+}
+
+
+// Returns 'true' if code generation for this function is complete, i.e.,
+// no fall-through to regular code is needed.
+bool FlowGraphCompiler::TryIntrinsify() {
+ if (!CanOptimize()) return false;
+ // Intrinsification skips arguments checks, therefore disable if in checked
+ // mode.
+ if (FLAG_intrinsify && !FLAG_trace_functions && !FLAG_enable_type_checks) {
+ if ((parsed_function_.function().kind() == RawFunction::kImplicitGetter)) {
+ IntrinsifyGetter();
+ return true;
+ }
+ if ((parsed_function_.function().kind() == RawFunction::kImplicitSetter)) {
+ IntrinsifySetter();
+ return true;
+ }
+ }
+ // Even if an intrinsified version of the function was successfully
+ // generated, it may fall through to the non-intrinsified method body.
+ if (!FLAG_trace_functions) {
+ return Intrinsifier::Intrinsify(parsed_function_.function(), assembler_);
+ }
+ return false;
+}
+
+
+void FlowGraphCompiler::GenerateCallRuntime(intptr_t cid,
+ intptr_t token_index,
+ intptr_t try_index,
+ const RuntimeEntry& entry) {
+ __ CallRuntime(entry);
+ AddCurrentDescriptor(PcDescriptors::kOther, cid, token_index, try_index);
+}
+
+
+void FlowGraphCompiler::CopyParameters() {
+ Bailout("Copy Parameters");
+}
+
+
void FlowGraphCompiler::CompileGraph() {
- Bailout("CompileGraph");
+ InitCompiler();
+ if (TryIntrinsify()) {
+ __ int3();
+ __ jmp(&StubCode::FixCallersTargetLabel());
+ return;
+ }
+ // Specialized version of entry code from CodeGenerator::GenerateEntryCode.
+ const Function& function = parsed_function_.function();
+
+ const int parameter_count = function.num_fixed_parameters();
+ const int num_copied_params = parsed_function_.copied_parameter_count();
+ const int local_count = parsed_function_.stack_local_count();
+ AssemblerMacros::EnterDartFrame(assembler_, (StackSize() * kWordSize));
+ // We check the number of passed arguments when we have to copy them due to
+ // the presence of optional named parameters.
+ // No such checking code is generated if only fixed parameters are declared,
+ // unless we are debug mode or unless we are compiling a closure.
+ if (num_copied_params == 0) {
+#ifdef DEBUG
+ const bool check_arguments = true;
+#else
+ const bool check_arguments = function.IsClosureFunction();
+#endif
+ if (check_arguments) {
+ // Check that num_fixed <= argc <= num_params.
+ Label argc_in_range;
+ // Total number of args is the first Smi in args descriptor array (R10).
regis 2012/05/30 08:58:20 R10 -> EDX
srdjan 2012/05/30 16:20:39 Done.
+ __ movl(EAX, FieldAddress(EDX, Array::data_offset()));
+ __ cmpl(EAX, Immediate(Smi::RawValue(parameter_count)));
+ __ j(EQUAL, &argc_in_range, Assembler::kNearJump);
+ if (function.IsClosureFunction()) {
+ GenerateCallRuntime(AstNode::kNoId,
+ function.token_index(),
+ CatchClauseNode::kInvalidTryIndex,
+ kClosureArgumentMismatchRuntimeEntry);
+ } else {
+ __ Stop("Wrong number of arguments");
+ }
+ __ Bind(&argc_in_range);
+ }
+ } else {
+ CopyParameters();
+ }
+ // Initialize (non-argument) stack allocated locals to null.
+ if (local_count > 0) {
+ const Immediate raw_null =
+ Immediate(reinterpret_cast<intptr_t>(Object::null()));
+ __ movl(EAX, raw_null);
+ const int base = parsed_function_.first_stack_local_index();
+ for (int i = 0; i < local_count; ++i) {
+ // Subtract index i (locals lie at lower addresses than EBP).
+ __ movl(Address(EBP, (base - i) * kWordSize), EAX);
+ }
+ }
+
+ // Generate stack overflow check.
+ __ cmpl(ESP,
+ Address::Absolute(Isolate::Current()->stack_limit_address()));
+ Label no_stack_overflow;
+ __ j(ABOVE, &no_stack_overflow, Assembler::kNearJump);
+ GenerateCallRuntime(AstNode::kNoId,
+ function.token_index(),
+ CatchClauseNode::kInvalidTryIndex,
+ kStackOverflowRuntimeEntry);
+ __ Bind(&no_stack_overflow);
+
+ if (FLAG_print_scopes) {
+ // Print the function scope (again) after generating the prologue in order
+ // to see annotations such as allocation indices of locals.
+ if (FLAG_print_ast) {
+ // Second printing.
+ OS::Print("Annotated ");
+ }
+ AstPrinter::PrintFunctionScope(parsed_function_);
+ }
+
+ VisitBlocks();
+
+ __ int3();
+ GenerateDeferredCode();
+ // Emit function patching code. This will be swapped with the first 13 bytes
regis 2012/05/30 08:58:20 13 bytes? Isn't it just 5 bytes in 32-bit mode?
srdjan 2012/05/30 16:20:39 Done.
+ // at entry point.
+ pc_descriptors_list_->AddDescriptor(PcDescriptors::kPatchCode,
+ assembler_->CodeSize(),
+ AstNode::kNoId,
+ 0,
+ -1);
+ __ jmp(&StubCode::FixCallersTargetLabel());
}
+void FlowGraphCompiler::GenerateDeferredCode() {
+ for (intptr_t i = 0; i < deopt_stubs_.length(); i++) {
+ deopt_stubs_[i]->GenerateCode(this);
+ }
+}
+
+
+void FlowGraphCompiler::EmitComment(Instruction* instr) {
+ char buffer[80];
+ BufferFormatter f(buffer, sizeof(buffer));
+ instr->PrintTo(&f);
+ __ Comment("@%d: %s", instr->cid(), buffer);
+}
+
+
+void FlowGraphCompiler::BailoutOnInstruction(Instruction* instr) {
+ char buffer[80];
+ BufferFormatter f(buffer, sizeof(buffer));
+ instr->PrintTo(&f);
+ Bailout(buffer);
+}
+
+
+void FlowGraphCompiler::EmitInstructionPrologue(Instruction* instr) {
+ LocationSummary* locs = instr->locs();
+ ASSERT(locs != NULL);
+
+ locs->AllocateRegisters();
+
+ // Load instruction inputs into allocated registers.
+ for (intptr_t i = locs->input_count() - 1; i >= 0; i--) {
+ Location loc = locs->in(i);
+ ASSERT(loc.kind() == Location::kRegister);
+ __ popl(loc.reg());
+ }
+}
+
+
+void FlowGraphCompiler::VisitBlocks() {
+ for (intptr_t i = 0; i < block_order_.length(); ++i) {
+ __ Comment("B%d", i);
+ // Compile the block entry.
+ current_block_ = block_order_[i];
+ Instruction* instr = current_block()->Accept(this);
+ // Compile all successors until an exit, branch, or a block entry.
+ while ((instr != NULL) && !instr->IsBlockEntry()) {
+ if (FLAG_code_comments) EmitComment(instr);
+ if (instr->locs() == NULL) {
+ BailoutOnInstruction(instr);
+ } else {
+ EmitInstructionPrologue(instr);
+ instr->EmitNativeCode(this);
+ instr = instr->StraightLineSuccessor();
+ }
+ }
+ BlockEntryInstr* successor =
+ (instr == NULL) ? NULL : instr->AsBlockEntry();
+ if (successor != NULL) {
+ // Block ended with a "goto". We can fall through if it is the
+ // next block in the list. Otherwise, we need a jump.
+ if ((i == block_order_.length() - 1) ||
+ (block_order_[i + 1] != successor)) {
+ __ jmp(&block_info_[successor->postorder_number()]->label);
+ }
+ }
+ }
+}
+
+
void FlowGraphCompiler::FinalizePcDescriptors(const Code& code) {
- UNIMPLEMENTED();
+ ASSERT(pc_descriptors_list_ != NULL);
+ const PcDescriptors& descriptors = PcDescriptors::Handle(
+ pc_descriptors_list_->FinalizePcDescriptors(code.EntryPoint()));
+ descriptors.Verify(parsed_function_.function().is_optimizable());
+ code.set_pc_descriptors(descriptors);
}
void FlowGraphCompiler::FinalizeStackmaps(const Code& code) {
- UNIMPLEMENTED();
+ if (stackmap_builder_ == NULL) {
+ // The unoptimizing compiler has no stack maps.
+ code.set_stackmaps(Array::Handle());
+ } else {
+ // Finalize the stack map array and add it to the code object.
+ code.set_stackmaps(
+ Array::Handle(stackmap_builder_->FinalizeStackmaps(code)));
+ }
}
void FlowGraphCompiler::FinalizeVarDescriptors(const Code& code) {
- UNIMPLEMENTED();
+ const LocalVarDescriptors& var_descs = LocalVarDescriptors::Handle(
+ parsed_function_.node_sequence()->scope()->GetVarDescriptors());
+ code.set_var_descriptors(var_descs);
}
void FlowGraphCompiler::FinalizeExceptionHandlers(const Code& code) {
- UNIMPLEMENTED();
+ ASSERT(exception_handlers_list_ != NULL);
+ const ExceptionHandlers& handlers = ExceptionHandlers::Handle(
+ exception_handlers_list_->FinalizeExceptionHandlers(code.EntryPoint()));
+ code.set_exception_handlers(handlers);
}
void FlowGraphCompiler::FinalizeComments(const Code& code) {
- UNIMPLEMENTED();
+ code.set_comments(assembler_->GetCodeComments());
}
+#undef __
} // namespace dart

Powered by Google App Engine
This is Rietveld 408576698