Reland "Enable map dependency to in-flight compilation info."
authoryangguo@chromium.org <yangguo@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 12 Jun 2013 09:43:22 +0000 (09:43 +0000)
committeryangguo@chromium.org <yangguo@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 12 Jun 2013 09:43:22 +0000 (09:43 +0000)
BUG=248076
R=ulan@chromium.org

Review URL: https://chromiumcodereview.appspot.com/16782004

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@15077 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

24 files changed:
src/arm/lithium-codegen-arm.cc
src/arm/lithium-codegen-arm.h
src/compiler.cc
src/compiler.h
src/hydrogen-instructions.h
src/hydrogen.cc
src/hydrogen.h
src/ia32/lithium-codegen-ia32.cc
src/ia32/lithium-codegen-ia32.h
src/mark-compact.cc
src/mips/lithium-codegen-mips.cc
src/mips/lithium-codegen-mips.h
src/objects-inl.h
src/objects.cc
src/objects.h
src/runtime.cc
src/runtime.h
src/x64/lithium-codegen-x64.cc
src/x64/lithium-codegen-x64.h
test/mjsunit/compiler/parallel-proto-change.js
test/mjsunit/manual-parallel-recompile.js
test/mjsunit/parallel-initial-prototype-change.js [new file with mode: 0644]
test/mjsunit/parallel-invalidate-transition-map.js [new file with mode: 0644]
test/mjsunit/parallel-optimize-disabled.js

index 96befb0..ed7e779 100644 (file)
@@ -87,20 +87,7 @@ void LCodeGen::FinishCode(Handle<Code> code) {
     RegisterDependentCodeForEmbeddedMaps(code);
   }
   PopulateDeoptimizationData(code);
-  for (int i = 0 ; i < prototype_maps_.length(); i++) {
-    prototype_maps_.at(i)->AddDependentCode(
-        DependentCode::kPrototypeCheckGroup, code);
-  }
-  for (int i = 0 ; i < transition_maps_.length(); i++) {
-    transition_maps_.at(i)->AddDependentCode(
-        DependentCode::kTransitionGroup, code);
-  }
-  if (graph()->depends_on_empty_array_proto_elements()) {
-    isolate()->initial_object_prototype()->map()->AddDependentCode(
-        DependentCode::kElementsCantBeAddedGroup, code);
-    isolate()->initial_array_prototype()->map()->AddDependentCode(
-        DependentCode::kElementsCantBeAddedGroup, code);
-  }
+  info()->CommitDependentMaps(code);
 }
 
 
@@ -4267,9 +4254,6 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
   }
 
   if (!transition.is_null()) {
-    if (transition->CanBeDeprecated()) {
-      transition_maps_.Add(transition, info()->zone());
-    }
     __ mov(scratch, Operand(transition));
     __ str(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
     if (instr->hydrogen()->NeedsWriteBarrierForMap()) {
@@ -5382,11 +5366,7 @@ void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
 
   ASSERT(prototypes->length() == maps->length());
 
-  if (instr->hydrogen()->CanOmitPrototypeChecks()) {
-    for (int i = 0; i < maps->length(); i++) {
-      prototype_maps_.Add(maps->at(i), info()->zone());
-    }
-  } else {
+  if (!instr->hydrogen()->CanOmitPrototypeChecks()) {
     for (int i = 0; i < prototypes->length(); i++) {
       __ LoadHeapObject(prototype_reg, prototypes->at(i));
       __ ldr(map_reg, FieldMemOperand(prototype_reg, HeapObject::kMapOffset));
index f264259..cecf152 100644 (file)
@@ -56,8 +56,6 @@ class LCodeGen BASE_EMBEDDED {
         deoptimizations_(4, info->zone()),
         deopt_jump_table_(4, info->zone()),
         deoptimization_literals_(8, info->zone()),
-        prototype_maps_(0, info->zone()),
-        transition_maps_(0, info->zone()),
         inlined_function_count_(0),
         scope_(info->scope()),
         status_(UNUSED),
@@ -406,8 +404,6 @@ class LCodeGen BASE_EMBEDDED {
   ZoneList<LEnvironment*> deoptimizations_;
   ZoneList<Deoptimizer::JumpTableEntry> deopt_jump_table_;
   ZoneList<Handle<Object> > deoptimization_literals_;
-  ZoneList<Handle<Map> > prototype_maps_;
-  ZoneList<Handle<Map> > transition_maps_;
   int inlined_function_count_;
   Scope* const scope_;
   Status status_;
index b1f8234..e8781c7 100644 (file)
@@ -106,6 +106,9 @@ void CompilationInfo::Initialize(Isolate* isolate, Mode mode, Zone* zone) {
   opt_count_ = shared_info().is_null() ? 0 : shared_info()->opt_count();
   no_frame_ranges_ = isolate->cpu_profiler()->is_profiling()
                    ? new List<OffsetRange>(2) : NULL;
+  for (int i = 0; i < DependentCode::kGroupCount; i++) {
+    dependent_maps_[i] = NULL;
+  }
   if (mode == STUB) {
     mode_ = STUB;
     return;
@@ -125,6 +128,41 @@ void CompilationInfo::Initialize(Isolate* isolate, Mode mode, Zone* zone) {
 CompilationInfo::~CompilationInfo() {
   delete deferred_handles_;
   delete no_frame_ranges_;
+#ifdef DEBUG
+  // Check that no dependent maps have been added or added dependent maps have
+  // been rolled back or committed.
+  for (int i = 0; i < DependentCode::kGroupCount; i++) {
+    ASSERT_EQ(NULL, dependent_maps_[i]);
+  }
+#endif  // DEBUG
+}
+
+
+void CompilationInfo::CommitDependentMaps(Handle<Code> code) {
+  for (int i = 0; i < DependentCode::kGroupCount; i++) {
+    ZoneList<Handle<Map> >* group_maps = dependent_maps_[i];
+    if (group_maps == NULL) continue;
+    ASSERT(!object_wrapper_.is_null());
+    for (int j = 0; j < group_maps->length(); j++) {
+      group_maps->at(j)->dependent_code()->UpdateToFinishedCode(
+          static_cast<DependentCode::DependencyGroup>(i), this, *code);
+    }
+    dependent_maps_[i] = NULL;  // Zone-allocated, no need to delete.
+  }
+}
+
+
+void CompilationInfo::RollbackDependentMaps() {
+  // Unregister from all dependent maps if not yet committed.
+  for (int i = 0; i < DependentCode::kGroupCount; i++) {
+    ZoneList<Handle<Map> >* group_maps = dependent_maps_[i];
+    if (group_maps == NULL) continue;
+    for (int j = 0; j < group_maps->length(); j++) {
+      group_maps->at(j)->dependent_code()->RemoveCompilationInfo(
+          static_cast<DependentCode::DependencyGroup>(i), this);
+    }
+    dependent_maps_[i] = NULL;  // Zone-allocated, no need to delete.
+  }
 }
 
 
@@ -982,7 +1020,7 @@ void Compiler::InstallOptimizedCode(OptimizingCompiler* optimizing_compiler) {
   // The function may have already been optimized by OSR.  Simply continue.
   // Except when OSR already disabled optimization for some reason.
   if (info->shared_info()->optimization_disabled()) {
-    info->SetCode(Handle<Code>(info->shared_info()->code()));
+    info->AbortOptimization();
     InstallFullCode(*info);
     if (FLAG_trace_parallel_recompilation) {
       PrintF("  ** aborting optimization for ");
@@ -1000,9 +1038,11 @@ void Compiler::InstallOptimizedCode(OptimizingCompiler* optimizing_compiler) {
   // If crankshaft succeeded, install the optimized code else install
   // the unoptimized code.
   OptimizingCompiler::Status status = optimizing_compiler->last_status();
-  if (status != OptimizingCompiler::SUCCEEDED) {
-    optimizing_compiler->info()->set_bailout_reason(
-        "failed/bailed out last time");
+  if (info->HasAbortedDueToDependentMap()) {
+    info->set_bailout_reason("bailed out due to dependent map");
+    status = optimizing_compiler->AbortOptimization();
+  } else if (status != OptimizingCompiler::SUCCEEDED) {
+    info->set_bailout_reason("failed/bailed out last time");
     status = optimizing_compiler->AbortOptimization();
   } else {
     status = optimizing_compiler->GenerateAndInstallCode();
index 8e6d295..f53feb9 100644 (file)
@@ -57,12 +57,8 @@ struct OffsetRange {
 // is constructed based on the resources available at compile-time.
 class CompilationInfo {
  public:
-  CompilationInfo(Handle<Script> script, Zone* zone);
-  CompilationInfo(Handle<SharedFunctionInfo> shared_info, Zone* zone);
   CompilationInfo(Handle<JSFunction> closure, Zone* zone);
-  CompilationInfo(HydrogenCodeStub* stub, Isolate* isolate, Zone* zone);
-
-  ~CompilationInfo();
+  virtual ~CompilationInfo();
 
   Isolate* isolate() {
     ASSERT(Isolate::Current() == isolate_);
@@ -243,6 +239,17 @@ class CompilationInfo {
     deferred_handles_ = deferred_handles;
   }
 
+  ZoneList<Handle<Map> >* dependent_maps(DependentCode::DependencyGroup group) {
+    if (dependent_maps_[group] == NULL) {
+      dependent_maps_[group] = new(zone_) ZoneList<Handle<Map> >(2, zone_);
+    }
+    return dependent_maps_[group];
+  }
+
+  void CommitDependentMaps(Handle<Code> code);
+
+  void RollbackDependentMaps();
+
   void SaveHandles() {
     SaveHandle(&closure_);
     SaveHandle(&shared_info_);
@@ -276,6 +283,26 @@ class CompilationInfo {
     return result;
   }
 
+  Handle<Foreign> object_wrapper() {
+    if (object_wrapper_.is_null()) {
+      object_wrapper_ =
+          isolate()->factory()->NewForeign(reinterpret_cast<Address>(this));
+    }
+    return object_wrapper_;
+  }
+
+  void AbortDueToDependentMap() {
+    mode_ = DEPENDENT_MAP_ABORT;
+  }
+
+  bool HasAbortedDueToDependentMap() {
+    return mode_ == DEPENDENT_MAP_ABORT;
+  }
+
+ protected:
+  CompilationInfo(Handle<Script> script, Zone* zone);
+  CompilationInfo(Handle<SharedFunctionInfo> shared_info, Zone* zone);
+  CompilationInfo(HydrogenCodeStub* stub, Isolate* isolate, Zone* zone);
 
  private:
   Isolate* isolate_;
@@ -289,7 +316,8 @@ class CompilationInfo {
     BASE,
     OPTIMIZE,
     NONOPT,
-    STUB
+    STUB,
+    DEPENDENT_MAP_ABORT
   };
 
   void Initialize(Isolate* isolate, Mode mode, Zone* zone);
@@ -369,6 +397,8 @@ class CompilationInfo {
 
   DeferredHandles* deferred_handles_;
 
+  ZoneList<Handle<Map> >* dependent_maps_[DependentCode::kGroupCount];
+
   template<typename T>
   void SaveHandle(Handle<T> *object) {
     if (!object->is_null()) {
@@ -387,6 +417,8 @@ class CompilationInfo {
   // during graph optimization.
   int opt_count_;
 
+  Handle<Foreign> object_wrapper_;
+
   DISALLOW_COPY_AND_ASSIGN(CompilationInfo);
 };
 
@@ -407,11 +439,18 @@ class CompilationInfoWithZone: public CompilationInfo {
       : CompilationInfo(closure, &zone_),
         zone_(closure->GetIsolate()),
         zone_scope_(&zone_, DELETE_ON_EXIT) {}
-  explicit CompilationInfoWithZone(HydrogenCodeStub* stub, Isolate* isolate)
+  CompilationInfoWithZone(HydrogenCodeStub* stub, Isolate* isolate)
       : CompilationInfo(stub, isolate, &zone_),
         zone_(isolate),
         zone_scope_(&zone_, DELETE_ON_EXIT) {}
 
+  // Virtual destructor because a CompilationInfoWithZone has to exit the
+  // zone scope and get rid of dependent maps even when the destructor is
+  // called when cast as a CompilationInfo.
+  virtual ~CompilationInfoWithZone() {
+    RollbackDependentMaps();
+  }
+
  private:
   Zone zone_;
   ZoneScope zone_scope_;
index 82ed261..e4186d3 100644 (file)
@@ -2977,21 +2977,33 @@ class HCheckPrototypeMaps: public HTemplateInstruction<0> {
  public:
   HCheckPrototypeMaps(Handle<JSObject> prototype,
                       Handle<JSObject> holder,
-                      Zone* zone)
+                      Zone* zone,
+                      CompilationInfo* info)
       : prototypes_(2, zone),
         maps_(2, zone),
         first_prototype_unique_id_(),
-        last_prototype_unique_id_() {
+        last_prototype_unique_id_(),
+        can_omit_prototype_maps_(true) {
     SetFlag(kUseGVN);
     SetGVNFlag(kDependsOnMaps);
     // Keep a list of all objects on the prototype chain up to the holder
     // and the expected maps.
     while (true) {
       prototypes_.Add(prototype, zone);
-      maps_.Add(Handle<Map>(prototype->map()), zone);
+      Handle<Map> map(prototype->map());
+      maps_.Add(map, zone);
+      can_omit_prototype_maps_ &= map->CanOmitPrototypeChecks();
       if (prototype.is_identical_to(holder)) break;
       prototype = Handle<JSObject>(JSObject::cast(prototype->GetPrototype()));
     }
+    if (can_omit_prototype_maps_) {
+      // Mark in-flight compilation as dependent on those maps.
+      for (int i = 0; i < maps()->length(); i++) {
+        Handle<Map> map = maps()->at(i);
+        map->AddDependentCompilationInfo(DependentCode::kPrototypeCheckGroup,
+                                         info);
+      }
+    }
   }
 
   ZoneList<Handle<JSObject> >* prototypes() { return &prototypes_; }
@@ -3016,12 +3028,7 @@ class HCheckPrototypeMaps: public HTemplateInstruction<0> {
     last_prototype_unique_id_ = UniqueValueId(prototypes_.last());
   }
 
-  bool CanOmitPrototypeChecks() {
-    for (int i = 0; i < maps()->length(); i++) {
-      if (!maps()->at(i)->CanOmitPrototypeChecks()) return false;
-    }
-    return true;
-  }
+  bool CanOmitPrototypeChecks() { return can_omit_prototype_maps_; }
 
  protected:
   virtual bool DataEquals(HValue* other) {
@@ -3035,6 +3042,7 @@ class HCheckPrototypeMaps: public HTemplateInstruction<0> {
   ZoneList<Handle<Map> > maps_;
   UniqueValueId first_prototype_unique_id_;
   UniqueValueId last_prototype_unique_id_;
+  bool can_omit_prototype_maps_;
 };
 
 
@@ -5691,6 +5699,7 @@ class HStoreNamedField: public HTemplateInstruction<2> {
                        = Representation::Tagged())
       : access_(access),
         field_representation_(field_representation),
+        transition_(),
         transition_unique_id_(),
         new_space_dominator_(NULL) {
     SetOperandAt(0, obj);
@@ -5722,7 +5731,13 @@ class HStoreNamedField: public HTemplateInstruction<2> {
   HObjectAccess access() const { return access_; }
   Handle<Map> transition() const { return transition_; }
   UniqueValueId transition_unique_id() const { return transition_unique_id_; }
-  void set_transition(Handle<Map> map) { transition_ = map; }
+  void SetTransition(Handle<Map> map, CompilationInfo* info) {
+    ASSERT(transition_.is_null());  // Only set once.
+    if (map->CanBeDeprecated()) {
+      map->AddDependentCompilationInfo(DependentCode::kTransitionGroup, info);
+    }
+    transition_ = map;
+  }
   HValue* new_space_dominator() const { return new_space_dominator_; }
 
   bool NeedsWriteBarrier() {
index b2badcd..b3ffac7 100644 (file)
@@ -3823,7 +3823,7 @@ void TestContext::BuildBranch(HValue* value) {
 
 
 void HOptimizedGraphBuilder::Bailout(const char* reason) {
-  info()->set_bailout_reason(reason);
+  current_info()->set_bailout_reason(reason);
   SetStackOverflow();
 }
 
@@ -3880,11 +3880,11 @@ void HOptimizedGraphBuilder::VisitExpressions(
 
 
 bool HOptimizedGraphBuilder::BuildGraph() {
-  if (info()->function()->is_generator()) {
+  if (current_info()->function()->is_generator()) {
     Bailout("function is a generator");
     return false;
   }
-  Scope* scope = info()->scope();
+  Scope* scope = current_info()->scope();
   if (scope->HasIllegalRedeclaration()) {
     Bailout("function with illegal redeclaration");
     return false;
@@ -3928,7 +3928,7 @@ bool HOptimizedGraphBuilder::BuildGraph() {
   AddInstruction(
       new(zone()) HStackCheck(context, HStackCheck::kFunctionEntry));
 
-  VisitStatements(info()->function()->body());
+  VisitStatements(current_info()->function()->body());
   if (HasStackOverflow()) return false;
 
   if (current_block() != NULL) {
@@ -3940,7 +3940,7 @@ bool HOptimizedGraphBuilder::BuildGraph() {
   // last time this function was compiled, then this recompile is likely not
   // due to missing/inadequate type feedback, but rather too aggressive
   // optimization. Disable optimistic LICM in that case.
-  Handle<Code> unoptimized_code(info()->shared_info()->code());
+  Handle<Code> unoptimized_code(current_info()->shared_info()->code());
   ASSERT(unoptimized_code->kind() == Code::FUNCTION);
   Handle<TypeFeedbackInfo> type_info(
       TypeFeedbackInfo::cast(unoptimized_code->type_feedback_info()));
@@ -5129,7 +5129,7 @@ void HOptimizedGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) {
 
 
 bool HOptimizedGraphBuilder::HasOsrEntryAt(IterationStatement* statement) {
-  return statement->OsrEntryId() == info()->osr_ast_id();
+  return statement->OsrEntryId() == current_info()->osr_ast_id();
 }
 
 
@@ -5516,9 +5516,9 @@ void HOptimizedGraphBuilder::VisitFunctionLiteral(FunctionLiteral* expr) {
   ASSERT(current_block() != NULL);
   ASSERT(current_block()->HasPredecessor());
   Handle<SharedFunctionInfo> shared_info =
-      SearchSharedFunctionInfo(info()->shared_info()->code(), expr);
+      SearchSharedFunctionInfo(current_info()->shared_info()->code(), expr);
   if (shared_info.is_null()) {
-    shared_info = Compiler::BuildFunctionInfo(expr, info()->script());
+    shared_info = Compiler::BuildFunctionInfo(expr, current_info()->script());
   }
   // We also have a stack overflow if the recursive compilation did.
   if (HasStackOverflow()) return;
@@ -5579,10 +5579,10 @@ void HOptimizedGraphBuilder::VisitConditional(Conditional* expr) {
 HOptimizedGraphBuilder::GlobalPropertyAccess
     HOptimizedGraphBuilder::LookupGlobalProperty(
         Variable* var, LookupResult* lookup, bool is_store) {
-  if (var->is_this() || !info()->has_global_object()) {
+  if (var->is_this() || !current_info()->has_global_object()) {
     return kUseGeneric;
   }
-  Handle<GlobalObject> global(info()->global_object());
+  Handle<GlobalObject> global(current_info()->global_object());
   global->Lookup(*var->name(), lookup);
   if (!lookup->IsNormal() ||
       (is_store && lookup->IsReadOnly()) ||
@@ -5597,7 +5597,7 @@ HOptimizedGraphBuilder::GlobalPropertyAccess
 HValue* HOptimizedGraphBuilder::BuildContextChainWalk(Variable* var) {
   ASSERT(var->IsContextSlot());
   HValue* context = environment()->LookupContext();
-  int length = info()->scope()->ContextChainLength(var->scope());
+  int length = current_info()->scope()->ContextChainLength(var->scope());
   while (length-- > 0) {
     HInstruction* context_instruction = new(zone()) HOuterContext(context);
     AddInstruction(context_instruction);
@@ -5633,12 +5633,12 @@ void HOptimizedGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
           LookupGlobalProperty(variable, &lookup, false);
 
       if (type == kUseCell &&
-          info()->global_object()->IsAccessCheckNeeded()) {
+          current_info()->global_object()->IsAccessCheckNeeded()) {
         type = kUseGeneric;
       }
 
       if (type == kUseCell) {
-        Handle<GlobalObject> global(info()->global_object());
+        Handle<GlobalObject> global(current_info()->global_object());
         Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup));
         HLoadGlobalCell* instr =
             new(zone()) HLoadGlobalCell(cell, lookup.GetPropertyDetails());
@@ -6229,7 +6229,8 @@ HInstruction* HOptimizedGraphBuilder::BuildStoreNamedField(
     AddInstruction(new(zone()) HCheckPrototypeMaps(
         Handle<JSObject>(JSObject::cast(map->prototype())),
         Handle<JSObject>(JSObject::cast(proto)),
-        zone()));
+        zone(),
+        top_info()));
   }
 
   HObjectAccess field_access = HObjectAccess::ForField(map, lookup, name);
@@ -6265,7 +6266,7 @@ HInstruction* HOptimizedGraphBuilder::BuildStoreNamedField(
 
   if (transition_to_field) {
     Handle<Map> transition(lookup->GetTransitionMapFromMap(*map));
-    instr->set_transition(transition);
+    instr->SetTransition(transition, top_info());
     // TODO(fschneider): Record the new map type of the object in the IR to
     // enable elimination of redundant checks after the transition store.
     instr->SetGVNFlag(kChangesMaps);
@@ -6568,7 +6569,7 @@ void HOptimizedGraphBuilder::HandleGlobalVariableAssignment(
   LookupResult lookup(isolate());
   GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup, true);
   if (type == kUseCell) {
-    Handle<GlobalObject> global(info()->global_object());
+    Handle<GlobalObject> global(current_info()->global_object());
     Handle<JSGlobalPropertyCell> cell(global->GetPropertyCell(&lookup));
     HInstruction* instr =
         new(zone()) HStoreGlobalCell(value, cell, lookup.GetPropertyDetails());
@@ -6633,13 +6634,13 @@ void HOptimizedGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
         // Bail out if we try to mutate a parameter value in a function
         // using the arguments object.  We do not (yet) correctly handle the
         // arguments property of the function.
-        if (info()->scope()->arguments() != NULL) {
+        if (current_info()->scope()->arguments() != NULL) {
           // Parameters will be allocated to context slots.  We have no
           // direct way to detect that the variable is a parameter so we do
           // a linear search of the parameter variables.
-          int count = info()->scope()->num_parameters();
+          int count = current_info()->scope()->num_parameters();
           for (int i = 0; i < count; ++i) {
-            if (var == info()->scope()->parameter(i)) {
+            if (var == current_info()->scope()->parameter(i)) {
               Bailout(
                   "assignment to parameter, function uses arguments object");
             }
@@ -6859,12 +6860,12 @@ void HOptimizedGraphBuilder::VisitAssignment(Assignment* expr) {
         // Bail out if we try to mutate a parameter value in a function using
         // the arguments object.  We do not (yet) correctly handle the
         // arguments property of the function.
-        if (info()->scope()->arguments() != NULL) {
+        if (current_info()->scope()->arguments() != NULL) {
           // Parameters will rewrite to context slots.  We have no direct way
           // to detect that the variable is a parameter.
-          int count = info()->scope()->num_parameters();
+          int count = current_info()->scope()->num_parameters();
           for (int i = 0; i < count; ++i) {
-            if (var == info()->scope()->parameter(i)) {
+            if (var == current_info()->scope()->parameter(i)) {
               return Bailout("assignment to parameter in arguments object");
             }
           }
@@ -7026,8 +7027,8 @@ HInstruction* HOptimizedGraphBuilder::BuildLoadNamedMonomorphic(
     Handle<JSObject> holder(lookup.holder());
     Handle<Map> holder_map(holder->map());
     AddCheckMap(object, map);
-    AddInstruction(
-        new(zone()) HCheckPrototypeMaps(prototype, holder, zone()));
+    AddInstruction(new(zone()) HCheckPrototypeMaps(
+        prototype, holder, zone(), top_info()));
     HValue* holder_value = AddInstruction(new(zone())
         HConstant(holder, Representation::Tagged()));
     return BuildLoadNamedField(holder_value,
@@ -7041,7 +7042,8 @@ HInstruction* HOptimizedGraphBuilder::BuildLoadNamedMonomorphic(
     Handle<JSObject> holder(lookup.holder());
     Handle<Map> holder_map(holder->map());
     AddCheckMap(object, map);
-    AddInstruction(new(zone()) HCheckPrototypeMaps(prototype, holder, zone()));
+    AddInstruction(new(zone()) HCheckPrototypeMaps(
+        prototype, holder, zone(), top_info()));
     Handle<JSFunction> function(lookup.GetConstantFunctionFromMap(*holder_map));
     return new(zone()) HConstant(function, Representation::Tagged());
   }
@@ -7078,8 +7080,8 @@ HInstruction* HOptimizedGraphBuilder::BuildMonomorphicElementAccess(
       isolate()->IsFastArrayConstructorPrototypeChainIntact()) {
     Handle<JSObject> prototype(JSObject::cast(map->prototype()), isolate());
     Handle<JSObject> object_prototype = isolate()->initial_object_prototype();
-    AddInstruction(
-        new(zone()) HCheckPrototypeMaps(prototype, object_prototype, zone()));
+    AddInstruction(new(zone()) HCheckPrototypeMaps(
+        prototype, object_prototype, zone(), top_info()));
     load_mode = ALLOW_RETURN_HOLE;
     graph()->MarkDependsOnEmptyArrayProtoElements();
   }
@@ -7594,8 +7596,8 @@ void HOptimizedGraphBuilder::AddCheckPrototypeMaps(Handle<JSObject> holder,
                                                    Handle<Map> receiver_map) {
   if (!holder.is_null()) {
     Handle<JSObject> prototype(JSObject::cast(receiver_map->prototype()));
-    AddInstruction(
-        new(zone()) HCheckPrototypeMaps(prototype, holder, zone()));
+    AddInstruction(new(zone()) HCheckPrototypeMaps(
+        prototype, holder, zone(), top_info()));
   }
 }
 
@@ -7740,7 +7742,7 @@ void HOptimizedGraphBuilder::HandlePolymorphicCallNamed(
     expr->ComputeTarget(map, name);
     AddCheckPrototypeMaps(expr->holder(), map);
     if (FLAG_trace_inlining && FLAG_polymorphic_inlining) {
-      Handle<JSFunction> caller = info()->closure();
+      Handle<JSFunction> caller = current_info()->closure();
       SmartArrayPointer<char> caller_name =
           caller->shared()->DebugName()->ToCString();
       PrintF("Trying to inline the polymorphic call to %s from %s\n",
@@ -7824,7 +7826,7 @@ int HOptimizedGraphBuilder::InliningAstSize(Handle<JSFunction> target) {
 
   // Precondition: call is monomorphic and we have found a target with the
   // appropriate arity.
-  Handle<JSFunction> caller = info()->closure();
+  Handle<JSFunction> caller = current_info()->closure();
   Handle<SharedFunctionInfo> target_shared(target->shared());
 
   // Do a quick check on source code length to avoid parsing large
@@ -7860,7 +7862,7 @@ bool HOptimizedGraphBuilder::TryInline(CallKind call_kind,
   int nodes_added = InliningAstSize(target);
   if (nodes_added == kNotInlinable) return false;
 
-  Handle<JSFunction> caller = info()->closure();
+  Handle<JSFunction> caller = current_info()->closure();
 
   if (nodes_added > Min(FLAG_max_inlined_nodes, kUnlimitedMaxInlinedNodes)) {
     TraceInline(target, caller, "target AST is too large [early]");
@@ -7869,7 +7871,7 @@ bool HOptimizedGraphBuilder::TryInline(CallKind call_kind,
 
 #if !defined(V8_TARGET_ARCH_IA32)
   // Target must be able to use caller's context.
-  CompilationInfo* outer_info = info();
+  CompilationInfo* outer_info = current_info();
   if (target->context() != outer_info->closure()->context() ||
       outer_info->scope()->contains_with() ||
       outer_info->scope()->num_heap_slots() > 0) {
@@ -8304,7 +8306,8 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall(
             Call::GetPrototypeForPrimitiveCheck(STRING_CHECK,
                 expr->holder()->GetIsolate()),
             expr->holder(),
-            zone()));
+            zone(),
+            top_info()));
         HInstruction* char_code =
             BuildStringCharCodeAt(context, string, index);
         if (id == kStringCharCodeAt) {
@@ -8455,7 +8458,7 @@ bool HOptimizedGraphBuilder::TryCallApply(Call* expr) {
     return false;
   }
 
-  if (info()->scope()->arguments() == NULL) return false;
+  if (current_info()->scope()->arguments() == NULL) return false;
 
   ZoneList<Expression*>* args = expr->arguments();
   if (args->length() != 2) return false;
@@ -8696,8 +8699,8 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) {
       LookupResult lookup(isolate());
       GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup, false);
       if (type == kUseCell &&
-          !info()->global_object()->IsAccessCheckNeeded()) {
-        Handle<GlobalObject> global(info()->global_object());
+          !current_info()->global_object()->IsAccessCheckNeeded()) {
+        Handle<GlobalObject> global(current_info()->global_object());
         known_global_function = expr->ComputeGlobalTarget(global, &lookup);
       }
       if (known_global_function) {
@@ -8732,7 +8735,7 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) {
         }
         if (TryInlineCall(expr)) return;
 
-        if (expr->target().is_identical_to(info()->closure())) {
+        if (expr->target().is_identical_to(current_info()->closure())) {
           graph()->MarkRecursive();
         }
 
@@ -9231,13 +9234,13 @@ void HOptimizedGraphBuilder::VisitCountOperation(CountOperation* expr) {
         // Bail out if we try to mutate a parameter value in a function
         // using the arguments object.  We do not (yet) correctly handle the
         // arguments property of the function.
-        if (info()->scope()->arguments() != NULL) {
+        if (current_info()->scope()->arguments() != NULL) {
           // Parameters will rewrite to context slots.  We have no direct
           // way to detect that the variable is a parameter so we use a
           // linear search of the parameter list.
-          int count = info()->scope()->num_parameters();
+          int count = current_info()->scope()->num_parameters();
           for (int i = 0; i < count; ++i) {
-            if (var == info()->scope()->parameter(i)) {
+            if (var == current_info()->scope()->parameter(i)) {
               return Bailout("assignment to parameter in arguments object");
             }
           }
@@ -9836,10 +9839,10 @@ void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
     VariableProxy* proxy = expr->right()->AsVariableProxy();
     bool global_function = (proxy != NULL) && proxy->var()->IsUnallocated();
     if (global_function &&
-        info()->has_global_object() &&
-        !info()->global_object()->IsAccessCheckNeeded()) {
+        current_info()->has_global_object() &&
+        !current_info()->global_object()->IsAccessCheckNeeded()) {
       Handle<String> name = proxy->name();
-      Handle<GlobalObject> global(info()->global_object());
+      Handle<GlobalObject> global(current_info()->global_object());
       LookupResult lookup(isolate());
       global->Lookup(*name, &lookup);
       if (lookup.IsNormal() && lookup.GetValue()->IsJSFunction()) {
@@ -10282,9 +10285,9 @@ void HOptimizedGraphBuilder::VisitDeclarations(
     Handle<FixedArray> array =
        isolate()->factory()->NewFixedArray(globals_.length(), TENURED);
     for (int i = 0; i < globals_.length(); ++i) array->set(i, *globals_.at(i));
-    int flags = DeclareGlobalsEvalFlag::encode(info()->is_eval()) |
-                DeclareGlobalsNativeFlag::encode(info()->is_native()) |
-                DeclareGlobalsLanguageMode::encode(info()->language_mode());
+    int flags = DeclareGlobalsEvalFlag::encode(current_info()->is_eval()) |
+        DeclareGlobalsNativeFlag::encode(current_info()->is_native()) |
+        DeclareGlobalsLanguageMode::encode(current_info()->language_mode());
     HInstruction* result = new(zone()) HDeclareGlobals(
         environment()->LookupContext(), array, flags);
     AddInstruction(result);
@@ -10338,8 +10341,8 @@ void HOptimizedGraphBuilder::VisitFunctionDeclaration(
   switch (variable->location()) {
     case Variable::UNALLOCATED: {
       globals_.Add(variable->name(), zone());
-      Handle<SharedFunctionInfo> function =
-          Compiler::BuildFunctionInfo(declaration->fun(), info()->script());
+      Handle<SharedFunctionInfo> function = Compiler::BuildFunctionInfo(
+          declaration->fun(), current_info()->script());
       // Check for stack-overflow exception.
       if (function.is_null()) return SetStackOverflow();
       globals_.Add(function, zone());
index ad89e50..160ffef 100644 (file)
@@ -402,13 +402,15 @@ class HGraph: public ZoneObject {
   }
 
   void MarkDependsOnEmptyArrayProtoElements() {
+    // Add map dependency if not already added.
+    if (depends_on_empty_array_proto_elements_) return;
+    isolate()->initial_object_prototype()->map()->AddDependentCompilationInfo(
+        DependentCode::kElementsCantBeAddedGroup, info());
+    isolate()->initial_array_prototype()->map()->AddDependentCompilationInfo(
+        DependentCode::kElementsCantBeAddedGroup, info());
     depends_on_empty_array_proto_elements_ = true;
   }
 
-  bool depends_on_empty_array_proto_elements() {
-    return depends_on_empty_array_proto_elements_;
-  }
-
   void RecordUint32Instruction(HInstruction* instr) {
     if (uint32_instructions_ == NULL) {
       uint32_instructions_ = new(zone()) ZoneList<HInstruction*>(4, zone());
@@ -968,6 +970,7 @@ class HGraphBuilder {
   Zone* zone() const { return info_->zone(); }
   HGraph* graph() const { return graph_; }
   Isolate* isolate() const { return graph_->isolate(); }
+  CompilationInfo* top_info() { return info_; }
 
   HGraph* CreateGraph();
 
@@ -1488,7 +1491,7 @@ class HOptimizedGraphBuilder: public HGraphBuilder, public AstVisitor {
   void set_ast_context(AstContext* context) { ast_context_ = context; }
 
   // Accessors forwarded to the function state.
-  CompilationInfo* info() const {
+  CompilationInfo* current_info() const {
     return function_state()->compilation_info();
   }
   AstContext* call_context() const {
index 7d685bf..fead96e 100644 (file)
@@ -109,20 +109,7 @@ void LCodeGen::FinishCode(Handle<Code> code) {
   if (!info()->IsStub()) {
     Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(code);
   }
-  for (int i = 0 ; i < prototype_maps_.length(); i++) {
-    prototype_maps_.at(i)->AddDependentCode(
-        DependentCode::kPrototypeCheckGroup, code);
-  }
-  for (int i = 0 ; i < transition_maps_.length(); i++) {
-    transition_maps_.at(i)->AddDependentCode(
-        DependentCode::kTransitionGroup, code);
-  }
-  if (graph()->depends_on_empty_array_proto_elements()) {
-    isolate()->initial_object_prototype()->map()->AddDependentCode(
-        DependentCode::kElementsCantBeAddedGroup, code);
-    isolate()->initial_array_prototype()->map()->AddDependentCode(
-        DependentCode::kElementsCantBeAddedGroup, code);
-  }
+  info()->CommitDependentMaps(code);
 }
 
 
@@ -4331,9 +4318,6 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
   }
 
   if (!transition.is_null()) {
-    if (transition->CanBeDeprecated()) {
-      transition_maps_.Add(transition, info()->zone());
-    }
     if (!instr->hydrogen()->NeedsWriteBarrierForMap()) {
       __ mov(FieldOperand(object, HeapObject::kMapOffset), transition);
     } else {
@@ -6009,11 +5993,7 @@ void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
 
   ASSERT(prototypes->length() == maps->length());
 
-  if (instr->hydrogen()->CanOmitPrototypeChecks()) {
-    for (int i = 0; i < maps->length(); i++) {
-      prototype_maps_.Add(maps->at(i), info()->zone());
-    }
-  } else {
+  if (!instr->hydrogen()->CanOmitPrototypeChecks()) {
     for (int i = 0; i < prototypes->length(); i++) {
       __ LoadHeapObject(reg, prototypes->at(i));
       DoCheckMapCommon(reg, maps->at(i), instr);
index 647dd0e..33f0eda 100644 (file)
@@ -58,8 +58,6 @@ class LCodeGen BASE_EMBEDDED {
         deoptimizations_(4, info->zone()),
         jump_table_(4, info->zone()),
         deoptimization_literals_(8, info->zone()),
-        prototype_maps_(0, info->zone()),
-        transition_maps_(0, info->zone()),
         inlined_function_count_(0),
         scope_(info->scope()),
         status_(UNUSED),
@@ -409,8 +407,6 @@ class LCodeGen BASE_EMBEDDED {
   ZoneList<LEnvironment*> deoptimizations_;
   ZoneList<Deoptimizer::JumpTableEntry> jump_table_;
   ZoneList<Handle<Object> > deoptimization_literals_;
-  ZoneList<Handle<Map> > prototype_maps_;
-  ZoneList<Handle<Map> > transition_maps_;
   int inlined_function_count_;
   Scope* const scope_;
   Status status_;
index dc2db4b..c2ab501 100644 (file)
@@ -2504,11 +2504,14 @@ void MarkCompactCollector::ClearAndDeoptimizeDependentCode(Map* map) {
   int number_of_entries = starts.number_of_entries();
   if (number_of_entries == 0) return;
   for (int i = 0; i < number_of_entries; i++) {
+    // If the entry is compilation info then the map must be alive,
+    // and ClearAndDeoptimizeDependentCode shouldn't be called.
+    ASSERT(entries->is_code_at(i));
     Code* code = entries->code_at(i);
     if (IsMarked(code) && !code->marked_for_deoptimization()) {
       code->set_marked_for_deoptimization(true);
     }
-    entries->clear_code_at(i);
+    entries->clear_at(i);
   }
   map->set_dependent_code(DependentCode::cast(heap()->empty_fixed_array()));
 }
@@ -2525,15 +2528,17 @@ void MarkCompactCollector::ClearNonLiveDependentCode(Map* map) {
   for (int g = 0; g < DependentCode::kGroupCount; g++) {
     int group_number_of_entries = 0;
     for (int i = starts.at(g); i < starts.at(g + 1); i++) {
-      Code* code = entries->code_at(i);
-      if (IsMarked(code) && !code->marked_for_deoptimization()) {
+      Object* obj = entries->object_at(i);
+      ASSERT(obj->IsCode() || IsMarked(obj));
+      if (IsMarked(obj) &&
+          (!obj->IsCode() || !Code::cast(obj)->marked_for_deoptimization())) {
         if (new_number_of_entries + group_number_of_entries != i) {
-          entries->set_code_at(new_number_of_entries +
-                               group_number_of_entries, code);
+          entries->set_object_at(
+              new_number_of_entries + group_number_of_entries, obj);
         }
-        Object** slot = entries->code_slot_at(new_number_of_entries +
-                                              group_number_of_entries);
-        RecordSlot(slot, slot, code);
+        Object** slot = entries->slot_at(new_number_of_entries +
+                                         group_number_of_entries);
+        RecordSlot(slot, slot, obj);
         group_number_of_entries++;
       }
     }
@@ -2543,7 +2548,7 @@ void MarkCompactCollector::ClearNonLiveDependentCode(Map* map) {
     new_number_of_entries += group_number_of_entries;
   }
   for (int i = new_number_of_entries; i < number_of_entries; i++) {
-    entries->clear_code_at(i);
+    entries->clear_at(i);
   }
 }
 
index 3c583e3..4e56937 100644 (file)
@@ -87,20 +87,7 @@ void LCodeGen::FinishCode(Handle<Code> code) {
     RegisterDependentCodeForEmbeddedMaps(code);
   }
   PopulateDeoptimizationData(code);
-  for (int i = 0 ; i < prototype_maps_.length(); i++) {
-    prototype_maps_.at(i)->AddDependentCode(
-        DependentCode::kPrototypeCheckGroup, code);
-  }
-  for (int i = 0 ; i < transition_maps_.length(); i++) {
-    transition_maps_.at(i)->AddDependentCode(
-        DependentCode::kTransitionGroup, code);
-  }
-  if (graph()->depends_on_empty_array_proto_elements()) {
-    isolate()->initial_object_prototype()->map()->AddDependentCode(
-        DependentCode::kElementsCantBeAddedGroup, code);
-    isolate()->initial_array_prototype()->map()->AddDependentCode(
-        DependentCode::kElementsCantBeAddedGroup, code);
-  }
+  info()->CommitDependentMaps(code);
 }
 
 
@@ -3991,9 +3978,6 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
   }
 
   if (!transition.is_null()) {
-    if (transition->CanBeDeprecated()) {
-      transition_maps_.Add(transition, info()->zone());
-    }
     __ li(scratch, Operand(transition));
     __ sw(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
     if (instr->hydrogen()->NeedsWriteBarrierForMap()) {
@@ -5144,11 +5128,7 @@ void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
 
   ASSERT(prototypes->length() == maps->length());
 
-  if (instr->hydrogen()->CanOmitPrototypeChecks()) {
-    for (int i = 0; i < maps->length(); i++) {
-      prototype_maps_.Add(maps->at(i), info()->zone());
-    }
-  } else {
+  if (!instr->hydrogen()->CanOmitPrototypeChecks()) {
     for (int i = 0; i < prototypes->length(); i++) {
       __ LoadHeapObject(prototype_reg, prototypes->at(i));
       __ lw(map_reg, FieldMemOperand(prototype_reg, HeapObject::kMapOffset));
index a208c40..ee01383 100644 (file)
@@ -55,8 +55,6 @@ class LCodeGen BASE_EMBEDDED {
         deoptimizations_(4, info->zone()),
         deopt_jump_table_(4, info->zone()),
         deoptimization_literals_(8, info->zone()),
-        prototype_maps_(0, info->zone()),
-        transition_maps_(0, info->zone()),
         inlined_function_count_(0),
         scope_(info->scope()),
         status_(UNUSED),
@@ -412,8 +410,6 @@ class LCodeGen BASE_EMBEDDED {
   ZoneList<LEnvironment*> deoptimizations_;
   ZoneList<Deoptimizer::JumpTableEntry> deopt_jump_table_;
   ZoneList<Handle<Object> > deoptimization_literals_;
-  ZoneList<Handle<Map> > prototype_maps_;
-  ZoneList<Handle<Map> > transition_maps_;
   int inlined_function_count_;
   Scope* const scope_;
   Status status_;
index e60f0f3..581935f 100644 (file)
@@ -3659,17 +3659,6 @@ bool Map::CanOmitPrototypeChecks() {
 }
 
 
-void Map::AddDependentCode(DependentCode::DependencyGroup group,
-                           Handle<Code> code) {
-  Handle<DependentCode> codes =
-      DependentCode::Insert(Handle<DependentCode>(dependent_code()),
-                             group, code);
-  if (*codes != dependent_code()) {
-    set_dependent_code(*codes);
-  }
-}
-
-
 int DependentCode::number_of_entries(DependencyGroup group) {
   if (length() == 0) return 0;
   return Smi::cast(get(group))->value();
@@ -3681,32 +3670,52 @@ void DependentCode::set_number_of_entries(DependencyGroup group, int value) {
 }
 
 
+bool DependentCode::is_code_at(int i) {
+  return get(kCodesStartIndex + i)->IsCode();
+}
+
 Code* DependentCode::code_at(int i) {
   return Code::cast(get(kCodesStartIndex + i));
 }
 
 
-void DependentCode::set_code_at(int i, Code* value) {
-  set(kCodesStartIndex + i, value);
+CompilationInfo* DependentCode::compilation_info_at(int i) {
+  return reinterpret_cast<CompilationInfo*>(
+      Foreign::cast(get(kCodesStartIndex + i))->foreign_address());
 }
 
 
-Object** DependentCode::code_slot_at(int i) {
+void DependentCode::set_object_at(int i, Object* object) {
+  set(kCodesStartIndex + i, object);
+}
+
+
+Object* DependentCode::object_at(int i) {
+  return get(kCodesStartIndex + i);
+}
+
+
+Object** DependentCode::slot_at(int i) {
   return HeapObject::RawField(
       this, FixedArray::OffsetOfElementAt(kCodesStartIndex + i));
 }
 
 
-void DependentCode::clear_code_at(int i) {
+void DependentCode::clear_at(int i) {
   set_undefined(kCodesStartIndex + i);
 }
 
 
+void DependentCode::copy(int from, int to) {
+  set(kCodesStartIndex + to, get(kCodesStartIndex + from));
+}
+
+
 void DependentCode::ExtendGroup(DependencyGroup group) {
   GroupStartIndexes starts(this);
   for (int g = kGroupCount - 1; g > group; g--) {
     if (starts.at(g) < starts.at(g + 1)) {
-      set_code_at(starts.at(g + 1), code_at(starts.at(g)));
+      copy(starts.at(g), starts.at(g + 1));
     }
   }
 }
index 6512c60..bdd0818 100644 (file)
@@ -11091,6 +11091,24 @@ void Map::ZapPrototypeTransitions() {
 }
 
 
+void Map::AddDependentCompilationInfo(DependentCode::DependencyGroup group,
+                                      CompilationInfo* info) {
+  Handle<DependentCode> dep(dependent_code());
+  Handle<DependentCode> codes =
+      DependentCode::Insert(dep, group, info->object_wrapper());
+  if (*codes != dependent_code()) set_dependent_code(*codes);
+  info->dependent_maps(group)->Add(Handle<Map>(this), info->zone());
+}
+
+
+void Map::AddDependentCode(DependentCode::DependencyGroup group,
+                           Handle<Code> code) {
+  Handle<DependentCode> codes = DependentCode::Insert(
+      Handle<DependentCode>(dependent_code()), group, code);
+  if (*codes != dependent_code()) set_dependent_code(*codes);
+}
+
+
 DependentCode::GroupStartIndexes::GroupStartIndexes(DependentCode* entries) {
   Recompute(entries);
 }
@@ -11107,13 +11125,13 @@ void DependentCode::GroupStartIndexes::Recompute(DependentCode* entries) {
 
 Handle<DependentCode> DependentCode::Insert(Handle<DependentCode> entries,
                                             DependencyGroup group,
-                                            Handle<Code> value) {
+                                            Handle<Object> object) {
   GroupStartIndexes starts(*entries);
   int start = starts.at(group);
   int end = starts.at(group + 1);
   int number_of_entries = starts.number_of_entries();
-  if (start < end && entries->code_at(end - 1) == *value) {
-    // Do not append the code if it is already in the array.
+  if (start < end && entries->object_at(end - 1) == *object) {
+    // Do not append the compilation info if it is already in the array.
     // It is sufficient to just check only the last element because
     // we process embedded maps of an optimized code in one batch.
     return entries;
@@ -11130,7 +11148,7 @@ Handle<DependentCode> DependentCode::Insert(Handle<DependentCode> entries,
     end = starts.at(group + 1);
     number_of_entries = starts.number_of_entries();
     for (int i = 0; i < number_of_entries; i++) {
-      entries->clear_code_at(i);
+      entries->clear_at(i);
     }
     // If the old fixed array was empty, we need to reset counters of the
     // new array.
@@ -11142,17 +11160,79 @@ Handle<DependentCode> DependentCode::Insert(Handle<DependentCode> entries,
     entries = new_entries;
   }
   entries->ExtendGroup(group);
-  entries->set_code_at(end, *value);
+  entries->set_object_at(end, *object);
   entries->set_number_of_entries(group, end + 1 - start);
   return entries;
 }
 
 
+void DependentCode::UpdateToFinishedCode(DependencyGroup group,
+                                         CompilationInfo* info,
+                                         Code* code) {
+  DisallowHeapAllocation no_gc;
+  AllowDeferredHandleDereference get_object_wrapper;
+  Foreign* info_wrapper = *info->object_wrapper();
+  GroupStartIndexes starts(this);
+  int start = starts.at(group);
+  int end = starts.at(group + 1);
+  for (int i = start; i < end; i++) {
+    if (object_at(i) == info_wrapper) {
+      set_object_at(i, code);
+      break;
+    }
+  }
+
+#ifdef DEBUG
+  for (int i = start; i < end; i++) {
+    ASSERT(is_code_at(i) || compilation_info_at(i) != info);
+  }
+#endif
+}
+
+
+void DependentCode::RemoveCompilationInfo(DependentCode::DependencyGroup group,
+                                          CompilationInfo* info) {
+  DisallowHeapAllocation no_allocation;
+  AllowDeferredHandleDereference get_object_wrapper;
+  Foreign* info_wrapper = *info->object_wrapper();
+  GroupStartIndexes starts(this);
+  int start = starts.at(group);
+  int end = starts.at(group + 1);
+  // Find compilation info wrapper.
+  int info_pos = -1;
+  for (int i = start; i < end; i++) {
+    if (object_at(i) == info_wrapper) {
+      info_pos = i;
+      break;
+    }
+  }
+  if (info_pos == -1) return;  // Not found.
+  int gap = info_pos;
+  // Use the last of each group to fill the gap in the previous group.
+  for (int i = group; i < kGroupCount; i++) {
+    int last_of_group = starts.at(i + 1) - 1;
+    ASSERT(last_of_group >= gap);
+    if (last_of_group == gap) continue;
+    copy(last_of_group, gap);
+    gap = last_of_group;
+  }
+  ASSERT(gap == starts.number_of_entries() - 1);
+  clear_at(gap);  // Clear last gap.
+  set_number_of_entries(group, end - start - 1);
+
+#ifdef DEBUG
+  for (int i = start; i < end - 1; i++) {
+    ASSERT(is_code_at(i) || compilation_info_at(i) != info);
+  }
+#endif
+}
+
+
 bool DependentCode::Contains(DependencyGroup group, Code* code) {
   GroupStartIndexes starts(this);
-  int number_of_entries = starts.at(kGroupCount);
+  int number_of_entries = starts.number_of_entries();
   for (int i = 0; i < number_of_entries; i++) {
-    if (code_at(i) == code) return true;
+    if (object_at(i) == code) return true;
   }
   return false;
 }
@@ -11173,20 +11253,25 @@ void DependentCode::DeoptimizeDependentCodeGroup(
   DependentCode::GroupStartIndexes starts(this);
   int start = starts.at(group);
   int end = starts.at(group + 1);
-  int number_of_entries = starts.at(DependentCode::kGroupCount);
+  int code_entries = starts.number_of_entries();
   if (start == end) return;
   for (int i = start; i < end; i++) {
-    Code* code = code_at(i);
-    code->set_marked_for_deoptimization(true);
+    if (is_code_at(i)) {
+      Code* code = code_at(i);
+      code->set_marked_for_deoptimization(true);
+    } else {
+      CompilationInfo* info = compilation_info_at(i);
+      info->AbortDueToDependentMap();
+    }
   }
   // Compact the array by moving all subsequent groups to fill in the new holes.
-  for (int src = end, dst = start; src < number_of_entries; src++, dst++) {
-    set_code_at(dst, code_at(src));
+  for (int src = end, dst = start; src < code_entries; src++, dst++) {
+    copy(src, dst);
   }
   // Now the holes are at the end of the array, zap them for heap-verifier.
   int removed = end - start;
-  for (int i = number_of_entries - removed; i < number_of_entries; i++) {
-    clear_code_at(i);
+  for (int i = code_entries - removed; i < code_entries; i++) {
+    clear_at(i);
   }
   set_number_of_entries(group, 0);
   DeoptimizeDependentCodeFilter filter;
index 1ee31b6..6c3b732 100644 (file)
@@ -4980,6 +4980,8 @@ class Code: public HeapObject {
 };
 
 
+class CompilationInfo;
+
 // This class describes the layout of dependent codes array of a map. The
 // array is partitioned into several groups of dependent codes. Each group
 // contains codes with the same dependency on the map. The array has the
@@ -5033,8 +5035,14 @@ class DependentCode: public FixedArray {
 
   bool Contains(DependencyGroup group, Code* code);
   static Handle<DependentCode> Insert(Handle<DependentCode> entries,
-                                       DependencyGroup group,
-                                       Handle<Code> value);
+                                      DependencyGroup group,
+                                      Handle<Object> object);
+  void UpdateToFinishedCode(DependencyGroup group,
+                            CompilationInfo* info,
+                            Code* code);
+  void RemoveCompilationInfo(DependentCode::DependencyGroup group,
+                             CompilationInfo* info);
+
   void DeoptimizeDependentCodeGroup(Isolate* isolate,
                                     DependentCode::DependencyGroup group);
 
@@ -5042,10 +5050,14 @@ class DependentCode: public FixedArray {
   // and the mark compact collector.
   inline int number_of_entries(DependencyGroup group);
   inline void set_number_of_entries(DependencyGroup group, int value);
+  inline bool is_code_at(int i);
   inline Code* code_at(int i);
-  inline void set_code_at(int i, Code* value);
-  inline Object** code_slot_at(int i);
-  inline void clear_code_at(int i);
+  inline CompilationInfo* compilation_info_at(int i);
+  inline void set_object_at(int i, Object* object);
+  inline Object** slot_at(int i);
+  inline Object* object_at(int i);
+  inline void clear_at(int i);
+  inline void copy(int from, int to);
   static inline DependentCode* cast(Object* object);
 
  private:
@@ -5554,8 +5566,11 @@ class Map: public HeapObject {
 
   inline bool CanOmitPrototypeChecks();
 
-  inline void AddDependentCode(DependentCode::DependencyGroup group,
-                               Handle<Code> code);
+  void AddDependentCompilationInfo(DependentCode::DependencyGroup group,
+                                        CompilationInfo* info);
+
+  void AddDependentCode(DependentCode::DependencyGroup group,
+                        Handle<Code> code);
 
   bool IsMapInArrayPrototypeChain();
 
index 83b3688..e462972 100644 (file)
@@ -8097,13 +8097,15 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
 }
 
 
-RUNTIME_FUNCTION(MaybeObject*, Runtime_WaitUntilOptimized) {
+RUNTIME_FUNCTION(MaybeObject*, Runtime_CompleteOptimization) {
   HandleScope scope(isolate);
   ASSERT(args.length() == 1);
   CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
-  if (FLAG_parallel_recompilation) {
-    if (V8::UseCrankshaft() && function->IsOptimizable()) {
-      while (!function->IsOptimized()) OS::Sleep(50);
+  if (FLAG_parallel_recompilation && V8::UseCrankshaft()) {
+    // While function is in optimization pipeline, it is marked with builtins.
+    while (function->code()->kind() == Code::BUILTIN) {
+      isolate->optimizing_compiler_thread()->InstallOptimizedFunctions();
+      OS::Sleep(50);
     }
   }
   return isolate->heap()->undefined_value();
index ef54016..c52bbe7 100644 (file)
@@ -96,7 +96,7 @@ namespace internal {
   F(ClearFunctionTypeFeedback, 1, 1) \
   F(RunningInSimulator, 0, 1) \
   F(OptimizeFunctionOnNextCall, -1, 1) \
-  F(WaitUntilOptimized, 1, 1) \
+  F(CompleteOptimization, 1, 1) \
   F(GetOptimizationStatus, 1, 1) \
   F(GetOptimizationCount, 1, 1) \
   F(CompileForOnStackReplacement, 1, 1) \
index f423133..497dc76 100644 (file)
@@ -92,20 +92,7 @@ void LCodeGen::FinishCode(Handle<Code> code) {
     RegisterDependentCodeForEmbeddedMaps(code);
   }
   PopulateDeoptimizationData(code);
-  for (int i = 0 ; i < prototype_maps_.length(); i++) {
-    prototype_maps_.at(i)->AddDependentCode(
-        DependentCode::kPrototypeCheckGroup, code);
-  }
-  for (int i = 0 ; i < transition_maps_.length(); i++) {
-    transition_maps_.at(i)->AddDependentCode(
-        DependentCode::kTransitionGroup, code);
-  }
-  if (graph()->depends_on_empty_array_proto_elements()) {
-    isolate()->initial_object_prototype()->map()->AddDependentCode(
-        DependentCode::kElementsCantBeAddedGroup, code);
-    isolate()->initial_array_prototype()->map()->AddDependentCode(
-        DependentCode::kElementsCantBeAddedGroup, code);
-  }
+  info()->CommitDependentMaps(code);
 }
 
 
@@ -4025,9 +4012,6 @@ void LCodeGen::DoStoreNamedField(LStoreNamedField* instr) {
   }
 
   if (!transition.is_null()) {
-    if (transition->CanBeDeprecated()) {
-      transition_maps_.Add(transition, info()->zone());
-    }
     if (!instr->hydrogen()->NeedsWriteBarrierForMap()) {
       __ Move(FieldOperand(object, HeapObject::kMapOffset), transition);
     } else {
@@ -5100,11 +5084,7 @@ void LCodeGen::DoCheckPrototypeMaps(LCheckPrototypeMaps* instr) {
 
   ASSERT(prototypes->length() == maps->length());
 
-  if (instr->hydrogen()->CanOmitPrototypeChecks()) {
-    for (int i = 0; i < maps->length(); i++) {
-      prototype_maps_.Add(maps->at(i), info()->zone());
-    }
-  } else {
+  if (!instr->hydrogen()->CanOmitPrototypeChecks()) {
     for (int i = 0; i < prototypes->length(); i++) {
       __ LoadHeapObject(reg, prototypes->at(i));
       DoCheckMapCommon(reg, maps->at(i), instr);
index 07a948c..c3f99c4 100644 (file)
@@ -57,8 +57,6 @@ class LCodeGen BASE_EMBEDDED {
         deoptimizations_(4, info->zone()),
         jump_table_(4, info->zone()),
         deoptimization_literals_(8, info->zone()),
-        prototype_maps_(0, info->zone()),
-        transition_maps_(0, info->zone()),
         inlined_function_count_(0),
         scope_(info->scope()),
         status_(UNUSED),
@@ -362,8 +360,6 @@ class LCodeGen BASE_EMBEDDED {
   ZoneList<LEnvironment*> deoptimizations_;
   ZoneList<Deoptimizer::JumpTableEntry> jump_table_;
   ZoneList<Handle<Object> > deoptimization_literals_;
-  ZoneList<Handle<Map> > prototype_maps_;
-  ZoneList<Handle<Map> > transition_maps_;
   int inlined_function_count_;
   Scope* const scope_;
   Status status_;
index 74e6d86..aa1ac6d 100644 (file)
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-// Flags: --allow-natives-syntax --parallel-recompilation
+// Flags: --allow-natives-syntax
+// Flags: --parallel-recompilation --parallel-recompilation-delay=50
+
+function assertUnoptimized(fun) {
+  assertTrue(%GetOptimizationStatus(fun) != 1);
+}
 
 function f(foo) { return foo.bar(); }
 
@@ -36,10 +41,10 @@ assertEquals(1, f(o));
 assertEquals(1, f(o));
 
 %OptimizeFunctionOnNextCall(f, "parallel");
-assertEquals(1, f(o));
-// Change the prototype chain during optimization.
+assertEquals(1, f(o));     // Trigger optimization.
+assertUnoptimized(f);      // Optimization not yet done.
+// Change the prototype chain during optimization to trigger map invalidation.
 o.__proto__.__proto__ = { bar: function() { return 2; } };
-
-%WaitUntilOptimized(f);
-
+%CompleteOptimization(f);  // Conclude optimization with...
+assertUnoptimized(f);      // ... bailing out due to map dependency.
 assertEquals(2, f(o));
index 8d660e0..f090ff4 100644 (file)
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-// Flags: --allow-natives-syntax --expose-gc --parallel-recompilation
+// Flags: --allow-natives-syntax --expose-gc
+// Flags: --parallel-recompilation --parallel-recompilation-delay=50
 
 function assertUnoptimized(fun) {
   assertTrue(%GetOptimizationStatus(fun) != 1);
 }
 
+function assertOptimized(fun) {
+  assertTrue(%GetOptimizationStatus(fun) != 2);
+}
+
 function f(x) {
   var xx = x * x;
   var xxstr = xx.toString();
@@ -53,10 +58,13 @@ assertUnoptimized(g);
 
 %OptimizeFunctionOnNextCall(f, "parallel");
 %OptimizeFunctionOnNextCall(g, "parallel");
-f(g(2));
+f(g(2));  // Trigger optimization.
 
-assertUnoptimized(f);
+assertUnoptimized(f);  // Not yet optimized.
 assertUnoptimized(g);
 
-%WaitUntilOptimized(f);
-%WaitUntilOptimized(g);
+%CompleteOptimization(f);  // Wait till optimized code is installed.
+%CompleteOptimization(g);
+
+assertOptimized(f);  // Optimized now.
+assertOptimized(g);
diff --git a/test/mjsunit/parallel-initial-prototype-change.js b/test/mjsunit/parallel-initial-prototype-change.js
new file mode 100644 (file)
index 0000000..5544beb
--- /dev/null
@@ -0,0 +1,50 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --allow-natives-syntax
+// Flags: --parallel-recompilation --parallel-recompilation-delay=50
+
+function assertUnoptimized(fun) {
+  assertTrue(%GetOptimizationStatus(fun) != 1);
+}
+
+function f1(a, i) {
+  return a[i] + 0.5;
+}
+
+var arr = [0.0,,2.5];
+assertEquals(0.5, f1(arr, 0));
+assertEquals(0.5, f1(arr, 0));
+
+// Optimized code of f1 depends on initial object and array maps.
+%OptimizeFunctionOnNextCall(f1, "parallel");
+assertEquals(0.5, f1(arr, 0));
+assertUnoptimized(f1);      // Not yet optimized.
+Object.prototype[1] = 1.5;  // Invalidate current initial object map.
+assertEquals(2, f1(arr, 1));
+%CompleteOptimization(f1);  // Conclude optimization with...
+assertUnoptimized(f1);      // ... bailing out due to map dependency.
diff --git a/test/mjsunit/parallel-invalidate-transition-map.js b/test/mjsunit/parallel-invalidate-transition-map.js
new file mode 100644 (file)
index 0000000..42a266f
--- /dev/null
@@ -0,0 +1,56 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --track-fields --track-double-fields --allow-natives-syntax
+// Flags: --parallel-recompilation --parallel-recompilation-delay=50
+
+function assertUnoptimized(fun) {
+  assertTrue(%GetOptimizationStatus(fun) != 1);
+}
+
+function new_object() {
+  var o = {};
+  o.a = 1;
+  o.b = 2;
+  return o;
+}
+
+function add_field(obj) {
+  obj.c = 3;
+}
+
+add_field(new_object());
+add_field(new_object());
+%OptimizeFunctionOnNextCall(add_field, "parallel");
+
+var o = new_object();
+add_field(o);                      // Trigger optimization.
+assertUnoptimized(add_field);      // Not yet optimized.
+o.c = 2.2;                         // Invalidate transition map.
+%CompleteOptimization(add_field);  // Conclude optimization with...
+assertUnoptimized(add_field);      // ... bailing out due to map dependency.
+
index 86b375c..479684d 100644 (file)
@@ -43,4 +43,4 @@ f();
 %OptimizeFunctionOnNextCall(g, "parallel");
 f(0);  // g() is disabled for optimization on inlining attempt.
 // Attempt to optimize g() should not run into any assertion.
-%WaitUntilOptimized(g);
+%CompleteOptimization(g);