| Index: runtime/vm/flow_graph_compiler_x64.cc
|
| ===================================================================
|
| --- runtime/vm/flow_graph_compiler_x64.cc (revision 6659)
|
| +++ runtime/vm/flow_graph_compiler_x64.cc (working copy)
|
| @@ -11,7 +11,9 @@
|
| #include "vm/ast_printer.h"
|
| #include "vm/code_descriptors.h"
|
| #include "vm/code_generator.h"
|
| +#include "vm/debugger.h"
|
| #include "vm/disassembler.h"
|
| +#include "vm/intrinsifier.h"
|
| #include "vm/longjump.h"
|
| #include "vm/object_store.h"
|
| #include "vm/parser.h"
|
| @@ -20,10 +22,14 @@
|
| namespace dart {
|
|
|
| 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);
|
|
|
| +
|
| FlowGraphCompiler::FlowGraphCompiler(
|
| Assembler* assembler,
|
| const ParsedFunction& parsed_function,
|
| @@ -1519,9 +1525,88 @@
|
| }
|
|
|
|
|
| +bool FlowGraphCompiler::CanOptimize() {
|
| + return
|
| + !FLAG_report_usage_count &&
|
| + (FLAG_optimization_counter_threshold >= 0) &&
|
| + !Isolate::Current()->debugger()->IsActive();
|
| +}
|
| +
|
| +
|
| +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();
|
| + __ movq(RAX, Address(RSP, 1 * kWordSize));
|
| + __ movq(RAX, FieldAddress(RAX, 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();
|
| + __ movq(RAX, Address(RSP, 2 * kWordSize)); // Receiver.
|
| + __ movq(RBX, Address(RSP, 1 * kWordSize)); // Value.
|
| + __ StoreIntoObject(RAX, FieldAddress(RAX, store_node.field().Offset()), RBX);
|
| + const Immediate raw_null =
|
| + Immediate(reinterpret_cast<intptr_t>(Object::null()));
|
| + __ movq(RAX, raw_null);
|
| + __ ret();
|
| +}
|
| +
|
| +
|
| +// 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;
|
| +}
|
| +
|
| +
|
| // TODO(srdjan): Investigate where to put the argument type checks for
|
| // checked mode.
|
| void FlowGraphCompiler::CompileGraph() {
|
| + if (TryIntrinsify()) {
|
| + // Make it patchable: code must have a minimum code size, nop(2) increases
|
| + // the minimum code size appropriately.
|
| + __ nop(2);
|
| + __ int3();
|
| + __ jmp(&StubCode::FixCallersTargetLabel());
|
| + return;
|
| + }
|
| // Specialized version of entry code from CodeGenerator::GenerateEntryCode.
|
| const Function& function = parsed_function_.function();
|
|
|
|
|