| Index: runtime/vm/precompiler.cc
|
| diff --git a/runtime/vm/precompiler.cc b/runtime/vm/precompiler.cc
|
| index e2eb627d851bc1181963771fa1b785313261bdb7..e45c04cf08662ca5dcda050f1196e28a4b9b0bce 100644
|
| --- a/runtime/vm/precompiler.cc
|
| +++ b/runtime/vm/precompiler.cc
|
| @@ -33,6 +33,7 @@
|
| #include "vm/object_store.h"
|
| #include "vm/os.h"
|
| #include "vm/parser.h"
|
| +#include "vm/program_visitor.h"
|
| #include "vm/redundancy_elimination.h"
|
| #include "vm/regexp_assembler.h"
|
| #include "vm/regexp_parser.h"
|
| @@ -42,10 +43,11 @@
|
| #include "vm/timeline.h"
|
| #include "vm/timer.h"
|
| #include "vm/type_table.h"
|
| +#include "vm/version.h"
|
| +#include "vm/json_parser.h"
|
|
|
| namespace dart {
|
|
|
| -
|
| #define T (thread())
|
| #define I (isolate())
|
| #define Z (zone())
|
| @@ -76,6 +78,15 @@ DECLARE_FLAG(bool, huge_method_cutoff_in_code_size);
|
| DECLARE_FLAG(bool, trace_failed_optimization_attempts);
|
| DECLARE_FLAG(bool, trace_inlining_intervals);
|
| DECLARE_FLAG(bool, trace_irregexp);
|
| +DECLARE_FLAG(int, inlining_hotness);
|
| +DECLARE_FLAG(int, inlining_size_threshold);
|
| +DECLARE_FLAG(int, inlining_callee_size_threshold);
|
| +DECLARE_FLAG(int, inline_getters_setters_smaller_than);
|
| +DECLARE_FLAG(int, inlining_depth_threshold);
|
| +DECLARE_FLAG(int, inlining_caller_size_threshold);
|
| +DECLARE_FLAG(int, inlining_constant_arguments_max_size_threshold);
|
| +DECLARE_FLAG(int, inlining_constant_arguments_min_size_threshold);
|
| +
|
|
|
| #ifdef DART_PRECOMPILER
|
|
|
| @@ -185,12 +196,37 @@ static void Jump(const Error& error) {
|
| }
|
|
|
|
|
| +TypeRangeCache::TypeRangeCache(Precompiler* precompiler,
|
| + Thread* thread,
|
| + intptr_t num_cids)
|
| + : precompiler_(precompiler),
|
| + thread_(thread),
|
| + lower_limits_(thread->zone()->Alloc<intptr_t>(num_cids)),
|
| + upper_limits_(thread->zone()->Alloc<intptr_t>(num_cids)) {
|
| + for (intptr_t i = 0; i < num_cids; i++) {
|
| + lower_limits_[i] = kNotComputed;
|
| + upper_limits_[i] = kNotComputed;
|
| + }
|
| + ASSERT(precompiler->type_range_cache() == NULL);
|
| + precompiler->set_type_range_cache(this);
|
| +}
|
| +
|
| +
|
| +TypeRangeCache::~TypeRangeCache() {
|
| + ASSERT(precompiler_->type_range_cache() == this);
|
| + precompiler_->set_type_range_cache(NULL);
|
| +}
|
| +
|
| +
|
| RawError* Precompiler::CompileAll(
|
| Dart_QualifiedFunctionName embedder_entry_points[],
|
| - bool reset_fields) {
|
| + bool reset_fields,
|
| + uint8_t* jit_feedback,
|
| + intptr_t jit_feedback_length) {
|
| LongJumpScope jump;
|
| if (setjmp(*jump.Set()) == 0) {
|
| Precompiler precompiler(Thread::Current(), reset_fields);
|
| + precompiler.LoadFeedback(jit_feedback, jit_feedback_length);
|
| precompiler.DoCompileAll(embedder_entry_points);
|
| return Error::null();
|
| } else {
|
| @@ -294,6 +330,7 @@ Precompiler::Precompiler(Thread* thread, bool reset_fields)
|
| zone_(NULL),
|
| isolate_(thread->isolate()),
|
| reset_fields_(reset_fields),
|
| + jit_feedback_(NULL),
|
| changed_(false),
|
| function_count_(0),
|
| class_count_(0),
|
| @@ -316,10 +353,52 @@ Precompiler::Precompiler(Thread* thread, bool reset_fields)
|
| types_to_retain_(),
|
| consts_to_retain_(),
|
| field_type_map_(),
|
| + type_range_cache_(NULL),
|
| error_(Error::Handle()),
|
| get_runtime_type_is_unique_(false) {}
|
|
|
|
|
| +void Precompiler::LoadFeedback(uint8_t* buffer, intptr_t length) {
|
| + if (buffer == NULL) {
|
| + if (FLAG_trace_precompiler) {
|
| + THR_Print("Precompiler running without JIT feedback\n");
|
| + }
|
| +
|
| + // Flags affecting compilation only:
|
| + // There is no counter feedback in precompilation, so ignore the counter
|
| + // when making inlining decisions.
|
| + FLAG_inlining_hotness = 0;
|
| + // Use smaller thresholds in precompilation as we are compiling everything
|
| + // with the optimizing compiler instead of only hot functions.
|
| + FLAG_inlining_size_threshold = 5;
|
| + FLAG_inline_getters_setters_smaller_than = 5;
|
| + FLAG_inlining_callee_size_threshold = 20;
|
| + FLAG_inlining_depth_threshold = 4;
|
| + FLAG_inlining_caller_size_threshold = 1000;
|
| + FLAG_inlining_constant_arguments_max_size_threshold = 100;
|
| + FLAG_inlining_constant_arguments_min_size_threshold = 30;
|
| + return;
|
| + }
|
| +
|
| + if (FLAG_trace_precompiler) {
|
| + THR_Print("Loading JIT feedback\n");
|
| + }
|
| +
|
| + JSONParser parser(reinterpret_cast<const char*>(buffer), length,
|
| + Thread::Current()->zone());
|
| + ParsedJSONValue* root = parser.ParseValue();
|
| + if (root->IsError()) {
|
| + ParsedJSONError* error = static_cast<ParsedJSONError*>(root);
|
| + THR_Print("Error parsing JIT feedback: %s:%" Pd "\n", error->message(),
|
| + error->position());
|
| + } else if (!root->IsObject()) {
|
| + THR_Print("Error parsing JIT feedback: object expected\n");
|
| + } else {
|
| + jit_feedback_ = static_cast<ParsedJSONObject*>(root);
|
| + }
|
| +}
|
| +
|
| +
|
| void Precompiler::DoCompileAll(
|
| Dart_QualifiedFunctionName embedder_entry_points[]) {
|
| ASSERT(I->compilation_allowed());
|
| @@ -336,7 +415,8 @@ void Precompiler::DoCompileAll(
|
| FinalizeAllClasses();
|
|
|
| SortClasses();
|
| - TypeRangeCache trc(T, I->class_table()->NumCids());
|
| + TypeRangeCache trc(this, T, I->class_table()->NumCids());
|
| + VerifyJITFeedback();
|
|
|
| // Precompile static initializers to compute result type information.
|
| PrecompileStaticInitializers();
|
| @@ -478,7 +558,7 @@ void Precompiler::PrecompileStaticInitializers() {
|
|
|
| HANDLESCOPE(T);
|
| StaticInitializerVisitor visitor(Z);
|
| - VisitClasses(&visitor);
|
| + ProgramVisitor::VisitClasses(&visitor);
|
| }
|
|
|
|
|
| @@ -508,7 +588,7 @@ void Precompiler::PrecompileConstructors() {
|
|
|
| HANDLESCOPE(T);
|
| ConstructorVisitor visitor(this, zone_);
|
| - VisitFunctions(&visitor);
|
| + ProgramVisitor::VisitFunctions(&visitor);
|
|
|
| FieldTypeMap::Iterator it(field_type_map_.GetIterator());
|
| for (FieldTypePair* current = it.Next(); current != NULL;
|
| @@ -533,13 +613,13 @@ void Precompiler::ClearAllCode() {
|
| }
|
| };
|
| ClearCodeFunctionVisitor function_visitor;
|
| - VisitFunctions(&function_visitor);
|
| + ProgramVisitor::VisitFunctions(&function_visitor);
|
|
|
| class ClearCodeClassVisitor : public ClassVisitor {
|
| void Visit(const Class& cls) { cls.DisableAllocationStub(); }
|
| };
|
| ClearCodeClassVisitor class_visitor;
|
| - VisitClasses(&class_visitor);
|
| + ProgramVisitor::VisitClasses(&class_visitor);
|
| }
|
|
|
|
|
| @@ -2081,7 +2161,7 @@ void Precompiler::BindStaticCalls() {
|
| };
|
|
|
| BindStaticCallsVisitor visitor(Z);
|
| - VisitFunctions(&visitor);
|
| + ProgramVisitor::VisitFunctions(&visitor);
|
| }
|
|
|
|
|
| @@ -2170,7 +2250,7 @@ void Precompiler::SwitchICCalls() {
|
|
|
| ASSERT(!I->compilation_allowed());
|
| SwitchICCallsVisitor visitor(Z);
|
| - VisitFunctions(&visitor);
|
| + ProgramVisitor::VisitFunctions(&visitor);
|
| #endif
|
| }
|
|
|
| @@ -2243,7 +2323,7 @@ void Precompiler::DedupStackMaps() {
|
| };
|
|
|
| DedupStackMapsVisitor visitor(Z);
|
| - VisitFunctions(&visitor);
|
| + ProgramVisitor::VisitFunctions(&visitor);
|
| }
|
|
|
|
|
| @@ -2310,7 +2390,7 @@ void Precompiler::DedupLists() {
|
| };
|
|
|
| DedupListsVisitor visitor(Z);
|
| - VisitFunctions(&visitor);
|
| + ProgramVisitor::VisitFunctions(&visitor);
|
| }
|
|
|
|
|
| @@ -2356,81 +2436,7 @@ void Precompiler::DedupInstructions() {
|
| };
|
|
|
| DedupInstructionsVisitor visitor(Z);
|
| - VisitFunctions(&visitor);
|
| -}
|
| -
|
| -
|
| -void Precompiler::VisitClasses(ClassVisitor* visitor) {
|
| - Library& lib = Library::Handle(Z);
|
| - Class& cls = Class::Handle(Z);
|
| -
|
| - for (intptr_t i = 0; i < libraries_.Length(); i++) {
|
| - lib ^= libraries_.At(i);
|
| - ClassDictionaryIterator it(lib, ClassDictionaryIterator::kIteratePrivate);
|
| - while (it.HasNext()) {
|
| - cls = it.GetNextClass();
|
| - if (cls.IsDynamicClass()) {
|
| - continue; // class 'dynamic' is in the read-only VM isolate.
|
| - }
|
| - visitor->Visit(cls);
|
| - }
|
| - }
|
| -}
|
| -
|
| -
|
| -void Precompiler::VisitFunctions(FunctionVisitor* visitor) {
|
| - Library& lib = Library::Handle(Z);
|
| - Class& cls = Class::Handle(Z);
|
| - Array& functions = Array::Handle(Z);
|
| - Array& fields = Array::Handle(Z);
|
| - Field& field = Field::Handle(Z);
|
| - Object& object = Object::Handle(Z);
|
| - Function& function = Function::Handle(Z);
|
| - GrowableObjectArray& closures = GrowableObjectArray::Handle(Z);
|
| -
|
| - for (intptr_t i = 0; i < libraries_.Length(); i++) {
|
| - lib ^= libraries_.At(i);
|
| - ClassDictionaryIterator it(lib, ClassDictionaryIterator::kIteratePrivate);
|
| - while (it.HasNext()) {
|
| - cls = it.GetNextClass();
|
| - if (cls.IsDynamicClass()) {
|
| - continue; // class 'dynamic' is in the read-only VM isolate.
|
| - }
|
| -
|
| - functions = cls.functions();
|
| - for (intptr_t j = 0; j < functions.Length(); j++) {
|
| - function ^= functions.At(j);
|
| - visitor->Visit(function);
|
| - if (function.HasImplicitClosureFunction()) {
|
| - function = function.ImplicitClosureFunction();
|
| - visitor->Visit(function);
|
| - }
|
| - }
|
| -
|
| - functions = cls.invocation_dispatcher_cache();
|
| - for (intptr_t j = 0; j < functions.Length(); j++) {
|
| - object = functions.At(j);
|
| - if (object.IsFunction()) {
|
| - function ^= functions.At(j);
|
| - visitor->Visit(function);
|
| - }
|
| - }
|
| - fields = cls.fields();
|
| - for (intptr_t j = 0; j < fields.Length(); j++) {
|
| - field ^= fields.At(j);
|
| - if (field.is_static() && field.HasPrecompiledInitializer()) {
|
| - function ^= field.PrecompiledInitializer();
|
| - visitor->Visit(function);
|
| - }
|
| - }
|
| - }
|
| - }
|
| - closures = isolate()->object_store()->closure_functions();
|
| - for (intptr_t j = 0; j < closures.Length(); j++) {
|
| - function ^= closures.At(j);
|
| - visitor->Visit(function);
|
| - ASSERT(!function.HasImplicitClosureFunction());
|
| - }
|
| + ProgramVisitor::VisitFunctions(&visitor);
|
| }
|
|
|
|
|
| @@ -2607,6 +2613,342 @@ void Precompiler::RemapClassIds(intptr_t* old_to_new_cid) {
|
| }
|
|
|
|
|
| +void Precompiler::VerifyJITFeedback() {
|
| + if (jit_feedback_ == NULL) return;
|
| +
|
| + ParsedJSONString* js_vmversion = jit_feedback_->StringAt("vmVersion");
|
| + if ((js_vmversion == NULL) ||
|
| + strcmp(js_vmversion->value(), Version::CommitString()) != 0) {
|
| + THR_Print(
|
| + "JIT feedback contains invalid vm version "
|
| + "(saw %s, expected %s).\n",
|
| + js_vmversion->value(), Version::CommitString());
|
| + jit_feedback_ = NULL;
|
| + return;
|
| + }
|
| + ParsedJSONBoolean* js_asserts = jit_feedback_->BooleanAt("asserts");
|
| + if ((js_asserts == NULL) || (FLAG_enable_asserts != js_asserts->value())) {
|
| + THR_Print("JIT feedback contains invalid FLAG_enable_asserts\n");
|
| + jit_feedback_ = NULL;
|
| + return;
|
| + }
|
| + ParsedJSONBoolean* js_typechecks = jit_feedback_->BooleanAt("typeChecks");
|
| + if ((js_typechecks == NULL) ||
|
| + (FLAG_enable_type_checks != js_typechecks->value())) {
|
| + THR_Print("JIT feedback contains invalid FLAG_enable_type_checks\n");
|
| + jit_feedback_ = NULL;
|
| + return;
|
| + }
|
| +
|
| + ParsedJSONArray* js_scripts = jit_feedback_->ArrayAt("scripts");
|
| + ASSERT(js_scripts != NULL);
|
| + Script& script = Script::Handle(Z);
|
| + for (intptr_t i = 0; i < js_scripts->Length(); i++) {
|
| + ParsedJSONObject* js_script = js_scripts->ObjectAt(i);
|
| + ASSERT(js_script != NULL);
|
| + ParsedJSONString* js_uri = js_script->StringAt("uri");
|
| + ASSERT(js_uri != NULL);
|
| + ParsedJSONNumber* js_fp = js_script->NumberAt("checksum");
|
| + ASSERT(js_fp != NULL);
|
| + script = LookupScript(js_uri->value());
|
| + if (script.IsNull()) {
|
| + THR_Print("Cannot find script %s\n", js_uri->value());
|
| + continue;
|
| + }
|
| + intptr_t fp = script.SourceFingerprint();
|
| + if (fp != js_fp->value()) {
|
| + THR_Print(
|
| + "Fingerprint has changed for %s. Continuing without JIT "
|
| + "feedback.\n",
|
| + js_uri->value());
|
| + jit_feedback_ = NULL;
|
| + return;
|
| + }
|
| + }
|
| +
|
| + ParsedJSONArray* js_classes = jit_feedback_->ArrayAt("classes");
|
| + ASSERT(js_classes != NULL);
|
| + Library& lib = Library::Handle(Z);
|
| + Class& cls = Class::Handle(Z);
|
| + String& str = String::Handle(Z);
|
| + for (intptr_t i = 0; i < js_classes->Length(); i++) {
|
| + ParsedJSONObject* js_class = js_classes->ObjectAt(i);
|
| + ASSERT(js_class != NULL);
|
| + ParsedJSONString* js_uri = js_class->StringAt("uri");
|
| + ASSERT(js_uri != NULL);
|
| + ParsedJSONString* js_name = js_class->StringAt("name");
|
| + ASSERT(js_name != NULL);
|
| + ParsedJSONNumber* js_cid = js_class->NumberAt("cid");
|
| + ASSERT(js_cid != NULL);
|
| +
|
| + str = String::New(js_uri->value());
|
| + lib = Library::LookupLibrary(T, str);
|
| + if (lib.IsNull()) {
|
| + THR_Print("Cannot find library %s\n", js_uri->value());
|
| + continue;
|
| + }
|
| + str = String::New(js_name->value());
|
| + if (str.Equals(Symbols::TopLevel())) {
|
| + cls = lib.toplevel_class();
|
| + } else {
|
| + cls = lib.LookupClassAllowPrivate(str);
|
| + }
|
| + if (cls.IsNull()) {
|
| + THR_Print("Missing class %s\n", js_name->value());
|
| + continue;
|
| + }
|
| +
|
| + feedback_cid_map_.Insert(IntptrPair(js_cid->value(), cls.id()));
|
| + }
|
| +
|
| + ParsedJSONArray* js_functions = jit_feedback_->ArrayAt("functions");
|
| + ASSERT(js_functions != NULL);
|
| + for (intptr_t i = 0; i < js_functions->Length(); i++) {
|
| + ParsedJSONObject* js_function = js_functions->ObjectAt(i);
|
| + ASSERT(js_function != NULL);
|
| + ParsedJSONString* js_name = js_function->StringAt("name");
|
| + ASSERT(js_name != NULL);
|
| + ParsedJSONNumber* js_cid = js_function->NumberAt("class");
|
| + ASSERT(js_cid != NULL);
|
| + ParsedJSONNumber* js_token = js_function->NumberAt("tokenPos");
|
| + ASSERT(js_token != NULL);
|
| + ParsedJSONNumber* js_kind = js_function->NumberAt("kind");
|
| + ASSERT(js_kind != NULL);
|
| + function_feedback_map_.Insert(FunctionFeedbackPair(
|
| + FunctionFeedbackKey(MapCid(js_cid->value()), js_token->value(),
|
| + js_kind->value()),
|
| + js_function));
|
| + }
|
| +
|
| + class ApplyUsageVisitor : public FunctionVisitor {
|
| + public:
|
| + explicit ApplyUsageVisitor(Precompiler* precompiler)
|
| + : precompiler_(precompiler) {}
|
| + void Visit(const Function& function) {
|
| + ParsedJSONObject* js_function = precompiler_->LookupFeedback(function);
|
| + if (js_function == NULL) {
|
| + function.set_usage_counter(0);
|
| + } else {
|
| + ParsedJSONNumber* js_usage = js_function->NumberAt("usageCounter");
|
| + ASSERT(js_usage != NULL);
|
| + function.set_usage_counter(js_usage->value());
|
| + }
|
| + }
|
| +
|
| + private:
|
| + Precompiler* precompiler_;
|
| + };
|
| +
|
| + ApplyUsageVisitor visitor(this);
|
| + ProgramVisitor::VisitFunctions(&visitor);
|
| +}
|
| +
|
| +
|
| +ParsedJSONObject* Precompiler::LookupFeedback(const Function& function) {
|
| + const Class& owner = Class::Handle(Z, function.Owner());
|
| +
|
| + FunctionFeedbackKey key(owner.id(), function.token_pos().value(),
|
| + function.kind());
|
| + FunctionFeedbackPair* pair = function_feedback_map_.Lookup(key);
|
| + if (pair == NULL) {
|
| + return NULL;
|
| + }
|
| + return pair->value_;
|
| +}
|
| +
|
| +
|
| +RawScript* Precompiler::LookupScript(const char* uri) {
|
| + String& dart_uri = String::Handle(Z, String::New(uri));
|
| + Library& lib = Library::Handle(Z);
|
| + Script& script = Script::Handle(Z);
|
| + for (intptr_t i = 0; i < libraries_.Length(); i++) {
|
| + lib ^= libraries_.At(i);
|
| + script = lib.LookupScript(dart_uri);
|
| + if (!script.IsNull()) {
|
| + return script.raw();
|
| + }
|
| + }
|
| + return Script::null();
|
| +}
|
| +
|
| +
|
| +intptr_t Precompiler::MapCid(intptr_t feedback_cid) {
|
| + if (feedback_cid < kNumPredefinedCids) {
|
| + return feedback_cid;
|
| + }
|
| + IntptrPair* pair = feedback_cid_map_.Lookup(feedback_cid);
|
| + if (pair == NULL) return kIllegalCid;
|
| + return pair->value_;
|
| +}
|
| +
|
| +
|
| +void Precompiler::PopulateWithICData(const Function& function,
|
| + FlowGraph* graph) {
|
| + Zone* zone = Thread::Current()->zone();
|
| +
|
| + for (BlockIterator block_it = graph->reverse_postorder_iterator();
|
| + !block_it.Done(); block_it.Advance()) {
|
| + ForwardInstructionIterator it(block_it.Current());
|
| + for (; !it.Done(); it.Advance()) {
|
| + Instruction* instr = it.Current();
|
| + if (instr->IsInstanceCall()) {
|
| + InstanceCallInstr* call = instr->AsInstanceCall();
|
| + if (!call->HasICData()) {
|
| + const Array& arguments_descriptor = Array::Handle(
|
| + zone, ArgumentsDescriptor::New(call->ArgumentCount(),
|
| + call->argument_names()));
|
| + const ICData& ic_data = ICData::ZoneHandle(
|
| + zone, ICData::New(function, call->function_name(),
|
| + arguments_descriptor, call->deopt_id(),
|
| + call->checked_argument_count(), false));
|
| + call->set_ic_data(&ic_data);
|
| + }
|
| + } else if (instr->IsStaticCall()) {
|
| + StaticCallInstr* call = instr->AsStaticCall();
|
| + if (!call->HasICData()) {
|
| + const Array& arguments_descriptor = Array::Handle(
|
| + zone, ArgumentsDescriptor::New(call->ArgumentCount(),
|
| + call->argument_names()));
|
| + const Function& target = call->function();
|
| + MethodRecognizer::Kind recognized_kind =
|
| + MethodRecognizer::RecognizeKind(target);
|
| + int num_args_checked = 0;
|
| + switch (recognized_kind) {
|
| + case MethodRecognizer::kDoubleFromInteger:
|
| + case MethodRecognizer::kMathMin:
|
| + case MethodRecognizer::kMathMax:
|
| + num_args_checked = 2;
|
| + break;
|
| + default:
|
| + break;
|
| + }
|
| + const ICData& ic_data = ICData::ZoneHandle(
|
| + zone, ICData::New(function, String::Handle(zone, target.name()),
|
| + arguments_descriptor, call->deopt_id(),
|
| + num_args_checked, true));
|
| + ic_data.AddTarget(target);
|
| + call->set_ic_data(&ic_data);
|
| + }
|
| + }
|
| + }
|
| + }
|
| +}
|
| +
|
| +
|
| +void Precompiler::TryApplyFeedback(const Function& function, FlowGraph* graph) {
|
| + ParsedJSONObject* js_function = LookupFeedback(function);
|
| + if (js_function == NULL) {
|
| + if (FLAG_trace_precompiler) {
|
| + THR_Print("No feedback available for %s\n",
|
| + function.ToQualifiedCString());
|
| + }
|
| + return;
|
| + }
|
| +
|
| + ParsedJSONArray* js_icdatas = js_function->ArrayAt("ics");
|
| + ASSERT(js_icdatas != NULL);
|
| +
|
| + for (BlockIterator block_it = graph->reverse_postorder_iterator();
|
| + !block_it.Done(); block_it.Advance()) {
|
| + ForwardInstructionIterator it(block_it.Current());
|
| + for (; !it.Done(); it.Advance()) {
|
| + Instruction* instr = it.Current();
|
| + if (instr->IsInstanceCall()) {
|
| + InstanceCallInstr* call = instr->AsInstanceCall();
|
| + TryApplyFeedback(js_icdatas, *call->ic_data());
|
| + } else if (instr->IsStaticCall()) {
|
| + StaticCallInstr* call = instr->AsStaticCall();
|
| + TryApplyFeedback(js_icdatas, *call->ic_data());
|
| + }
|
| + }
|
| + }
|
| +}
|
| +
|
| +
|
| +void Precompiler::TryApplyFeedback(ParsedJSONArray* js_icdatas,
|
| + const ICData& ic) {
|
| + for (intptr_t j = 0; j < js_icdatas->Length(); j++) {
|
| + ParsedJSONObject* js_icdata = js_icdatas->ObjectAt(j);
|
| + ASSERT(js_icdata != NULL);
|
| +
|
| + ParsedJSONNumber* js_deoptid = js_icdata->NumberAt("deoptId");
|
| + ASSERT(js_deoptid != NULL);
|
| + if (js_deoptid->value() != ic.deopt_id()) continue;
|
| +
|
| + ParsedJSONBoolean* js_isstaticcall = js_icdata->BooleanAt("isStaticCall");
|
| + ASSERT(js_isstaticcall != NULL);
|
| + if (js_isstaticcall->value() != ic.is_static_call()) return;
|
| +
|
| + ParsedJSONNumber* js_argsTested = js_icdata->NumberAt("argsTested");
|
| + ASSERT(js_argsTested != NULL);
|
| + if (js_argsTested->value() != ic.NumArgsTested()) return;
|
| +
|
| + ParsedJSONString* js_selector = js_icdata->StringAt("selector");
|
| + ASSERT(js_selector != NULL);
|
| + const String& feedback_selector =
|
| + String::Handle(String::New(js_selector->value()));
|
| + const String& selector = String::Handle(ic.target_name());
|
| + // N.B.: EqualsIgnoringPrivateKey is not symmetric.
|
| + if (!String::EqualsIgnoringPrivateKey(selector, feedback_selector)) return;
|
| +
|
| + ParsedJSONArray* js_entries = js_icdata->ArrayAt("entries");
|
| + ASSERT(js_entries != NULL);
|
| + if (ic.is_static_call()) {
|
| + // [cid [cid]] target count
|
| + ParsedJSONNumber* entry = js_entries->NumberAt(js_entries->Length() - 1);
|
| + ASSERT(entry != NULL);
|
| + ic.SetCountAt(0, entry->value());
|
| + } else {
|
| + // [cid [cid [cid]]] target count
|
| + const Array& arguments_descriptor =
|
| + Array::Handle(ic.arguments_descriptor());
|
| + ArgumentsDescriptor args_desc(arguments_descriptor);
|
| +
|
| + intptr_t num_args_checked = ic.NumArgsTested();
|
| + for (intptr_t k = 0; k < js_entries->Length();
|
| + k += num_args_checked + 1) {
|
| + GrowableArray<intptr_t> class_ids(num_args_checked);
|
| + for (intptr_t arg = 0; arg < num_args_checked; arg++) {
|
| + ParsedJSONNumber* entry = js_entries->NumberAt(k + arg);
|
| + ASSERT(entry != NULL);
|
| + class_ids.Add(MapCid(entry->value()));
|
| + }
|
| + ParsedJSONNumber* entry = js_entries->NumberAt(k + num_args_checked);
|
| + ASSERT(entry != NULL);
|
| + intptr_t count = entry->value();
|
| +
|
| + bool has_missing_cid = false;
|
| + for (intptr_t arg = 0; arg < num_args_checked; arg++) {
|
| + if (class_ids[arg] == kIllegalCid) {
|
| + has_missing_cid = true;
|
| + }
|
| + }
|
| + if (has_missing_cid) continue;
|
| +
|
| + intptr_t receiver_cid = class_ids[0];
|
| + const Class& receiver_cls =
|
| + Class::Handle(I->class_table()->At(receiver_cid));
|
| + if (receiver_cls.IsClass()) {
|
| + const Function& target =
|
| + Function::Handle(Resolver::ResolveDynamicForReceiverClass(
|
| + receiver_cls, selector, args_desc, false));
|
| + // TODO(rmacnak): Create missing dispatchers.
|
| + if (!target.IsNull()) {
|
| + if (num_args_checked == 1) {
|
| + ic.AddReceiverCheck(receiver_cid, target, count);
|
| + } else {
|
| + ic.AddCheck(class_ids, target, count);
|
| + }
|
| + }
|
| + }
|
| + }
|
| + }
|
| +
|
| + return;
|
| + }
|
| +}
|
| +
|
| +
|
| void Precompiler::ResetPrecompilerState() {
|
| changed_ = false;
|
| function_count_ = 0;
|
| @@ -2757,6 +3099,15 @@ bool PrecompileParsedFunctionHelper::Compile(CompilationPipeline* pipeline) {
|
| zone, parsed_function(), *ic_data_array, Compiler::kNoOSRDeoptId);
|
| }
|
|
|
| + if (optimized()) {
|
| + Precompiler::PopulateWithICData(parsed_function()->function(),
|
| + flow_graph);
|
| + if (precompiler_ != NULL) {
|
| + precompiler_->TryApplyFeedback(parsed_function()->function(),
|
| + flow_graph);
|
| + }
|
| + }
|
| +
|
| const bool print_flow_graph =
|
| (FLAG_print_flow_graph ||
|
| (optimized() && FLAG_print_flow_graph_optimized)) &&
|
| @@ -2807,7 +3158,6 @@ bool PrecompileParsedFunctionHelper::Compile(CompilationPipeline* pipeline) {
|
|
|
| AotOptimizer optimizer(precompiler_, flow_graph,
|
| use_speculative_inlining, &inlining_black_list);
|
| - optimizer.PopulateWithICData();
|
|
|
| optimizer.ApplyClassIds();
|
| DEBUG_ASSERT(flow_graph->VerifyUseLists());
|
|
|