| Index: runtime/vm/flow_graph_compiler_shared.cc
|
| ===================================================================
|
| --- runtime/vm/flow_graph_compiler_shared.cc (revision 8249)
|
| +++ runtime/vm/flow_graph_compiler_shared.cc (working copy)
|
| @@ -4,11 +4,21 @@
|
|
|
| #include "vm/flow_graph_compiler_shared.h"
|
|
|
| +#include "vm/debugger.h"
|
| #include "vm/intermediate_language.h"
|
| +#include "vm/intrinsifier.h"
|
| +#include "vm/longjump.h"
|
| #include "vm/parser.h"
|
| +#include "vm/stub_code.h"
|
|
|
| namespace dart {
|
|
|
| +DECLARE_FLAG(bool, enable_type_checks);
|
| +DECLARE_FLAG(bool, intrinsify);
|
| +DECLARE_FLAG(int, optimization_counter_threshold);
|
| +DECLARE_FLAG(bool, trace_functions);
|
| +DECLARE_FLAG(bool, report_usage_count);
|
| +
|
| FlowGraphCompilerShared::FlowGraphCompilerShared(
|
| Assembler* assembler,
|
| const ParsedFunction& parsed_function,
|
| @@ -136,6 +146,11 @@
|
| }
|
|
|
|
|
| +void FlowGraphCompilerShared::FinalizeComments(const Code& code) {
|
| + code.set_comments(assembler()->GetCodeComments());
|
| +}
|
| +
|
| +
|
| void FlowGraphCompilerShared::GenerateDeferredCode() {
|
| for (intptr_t i = 0; i < deopt_stubs_.length(); i++) {
|
| deopt_stubs_[i]->GenerateCode(this);
|
| @@ -143,6 +158,125 @@
|
| }
|
|
|
|
|
| +void FlowGraphCompilerShared::GenerateInstanceCall(
|
| + intptr_t cid,
|
| + intptr_t token_index,
|
| + intptr_t try_index,
|
| + const String& function_name,
|
| + intptr_t argument_count,
|
| + const Array& argument_names,
|
| + intptr_t checked_argument_count) {
|
| + ICData& ic_data =
|
| + ICData::ZoneHandle(ICData::New(parsed_function().function(),
|
| + function_name,
|
| + cid,
|
| + checked_argument_count));
|
| + const Array& arguments_descriptor =
|
| + CodeGenerator::ArgumentsDescriptor(argument_count, argument_names);
|
| + uword label_address = 0;
|
| + switch (checked_argument_count) {
|
| + case 1:
|
| + label_address = StubCode::OneArgCheckInlineCacheEntryPoint();
|
| + break;
|
| + case 2:
|
| + label_address = StubCode::TwoArgsCheckInlineCacheEntryPoint();
|
| + break;
|
| + default:
|
| + UNIMPLEMENTED();
|
| + }
|
| + ExternalLabel target_label("InlineCache", label_address);
|
| +
|
| + const intptr_t descr_offset = EmitInstanceCall(&target_label,
|
| + ic_data,
|
| + arguments_descriptor,
|
| + argument_count);
|
| + pc_descriptors_list()->AddDescriptor(PcDescriptors::kIcCall,
|
| + descr_offset,
|
| + cid,
|
| + token_index,
|
| + try_index);
|
| +}
|
| +
|
| +
|
| +void FlowGraphCompilerShared::GenerateStaticCall(intptr_t cid,
|
| + intptr_t token_index,
|
| + intptr_t try_index,
|
| + const Function& function,
|
| + intptr_t argument_count,
|
| + const Array& argument_names) {
|
| + const Array& arguments_descriptor =
|
| + CodeGenerator::ArgumentsDescriptor(argument_count, argument_names);
|
| + const intptr_t descr_offset = EmitStaticCall(function,
|
| + arguments_descriptor,
|
| + argument_count);
|
| + pc_descriptors_list()->AddDescriptor(PcDescriptors::kFuncCall,
|
| + descr_offset,
|
| + cid,
|
| + token_index,
|
| + try_index);
|
| +}
|
| +
|
| +
|
| +void FlowGraphCompilerShared::Bailout(const char* reason) {
|
| + const char* kFormat = "FlowGraphCompiler Bailout: %s %s.";
|
| + const char* function_name = parsed_function().function().ToCString();
|
| + intptr_t len = OS::SNPrint(NULL, 0, kFormat, function_name, reason) + 1;
|
| + char* chars = reinterpret_cast<char*>(
|
| + Isolate::Current()->current_zone()->Allocate(len));
|
| + OS::SNPrint(chars, len, kFormat, function_name, reason);
|
| + const Error& error = Error::Handle(
|
| + LanguageError::New(String::Handle(String::New(chars))));
|
| + Isolate::Current()->long_jump_base()->Jump(1, error);
|
| +}
|
| +
|
| +
|
| +static bool 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 FlowGraphCompilerShared::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)) {
|
| + // An implicit getter must have a specific AST structure.
|
| + 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();
|
| + GenerateInlinedGetter(load_node.field().Offset());
|
| + return true;
|
| + }
|
| + if ((parsed_function().function().kind() == RawFunction::kImplicitSetter)) {
|
| + // An implicit setter must have a specific AST structure.
|
| + // 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();
|
| + GenerateInlinedSetter(store_node.field().Offset());
|
| + 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;
|
| +}
|
| +
|
| } // namespace dart
|
|
|
|
|
|
|