| OLD | NEW | 
|     1 // Copyright 2006-2008 the V8 project authors. All rights reserved. |     1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 
|     2 // Redistribution and use in source and binary forms, with or without |     2 // Redistribution and use in source and binary forms, with or without | 
|     3 // modification, are permitted provided that the following conditions are |     3 // modification, are permitted provided that the following conditions are | 
|     4 // met: |     4 // met: | 
|     5 // |     5 // | 
|     6 //     * Redistributions of source code must retain the above copyright |     6 //     * Redistributions of source code must retain the above copyright | 
|     7 //       notice, this list of conditions and the following disclaimer. |     7 //       notice, this list of conditions and the following disclaimer. | 
|     8 //     * Redistributions in binary form must reproduce the above |     8 //     * Redistributions in binary form must reproduce the above | 
|     9 //       copyright notice, this list of conditions and the following |     9 //       copyright notice, this list of conditions and the following | 
|    10 //       disclaimer in the documentation and/or other materials provided |    10 //       disclaimer in the documentation and/or other materials provided | 
|    11 //       with the distribution. |    11 //       with the distribution. | 
|    12 //     * Neither the name of Google Inc. nor the names of its |    12 //     * Neither the name of Google Inc. nor the names of its | 
|    13 //       contributors may be used to endorse or promote products derived |    13 //       contributors may be used to endorse or promote products derived | 
|    14 //       from this software without specific prior written permission. |    14 //       from this software without specific prior written permission. | 
|    15 // |    15 // | 
|    16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |    16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 
|    17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |    17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 
|    18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |    18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 
|    19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |    19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 
|    20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |    20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 
|    21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |    21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 
|    22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |    22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 
|    23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |    23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 
|    24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |    24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
|    25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |    25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
|    26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |    26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
|    27  |    27  | 
|    28 #include "v8.h" |    28 #include "v8.h" | 
|    29  |    29  | 
 |    30 #include "compilation-cache.h" | 
|    30 #include "execution.h" |    31 #include "execution.h" | 
|    31 #include "heap-profiler.h" |    32 #include "heap-profiler.h" | 
|    32 #include "global-handles.h" |    33 #include "global-handles.h" | 
|    33 #include "ic-inl.h" |    34 #include "ic-inl.h" | 
|    34 #include "mark-compact.h" |    35 #include "mark-compact.h" | 
|    35 #include "objects-visiting.h" |    36 #include "objects-visiting.h" | 
|    36 #include "stub-cache.h" |    37 #include "stub-cache.h" | 
|    37  |    38  | 
|    38 namespace v8 { |    39 namespace v8 { | 
|    39 namespace internal { |    40 namespace internal { | 
| (...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   245   return HeapObject::cast(first); |   246   return HeapObject::cast(first); | 
|   246 } |   247 } | 
|   247  |   248  | 
|   248  |   249  | 
|   249 class StaticMarkingVisitor : public StaticVisitorBase { |   250 class StaticMarkingVisitor : public StaticVisitorBase { | 
|   250  public: |   251  public: | 
|   251   static inline void IterateBody(Map* map, HeapObject* obj) { |   252   static inline void IterateBody(Map* map, HeapObject* obj) { | 
|   252     table_.GetVisitor(map)(map, obj); |   253     table_.GetVisitor(map)(map, obj); | 
|   253   } |   254   } | 
|   254  |   255  | 
 |   256   static void EnableCodeFlushing(bool enabled) { | 
 |   257     if (enabled) { | 
 |   258       table_.Register(kVisitJSFunction, &VisitJSFunction); | 
 |   259     } else { | 
 |   260       table_.Register(kVisitJSFunction, | 
 |   261                       &JSObjectVisitor::VisitSpecialized<JSFunction::kSize>); | 
 |   262     } | 
 |   263   } | 
 |   264  | 
|   255   static void Initialize() { |   265   static void Initialize() { | 
|   256     table_.Register(kVisitShortcutCandidate, |   266     table_.Register(kVisitShortcutCandidate, | 
|   257                     &FixedBodyVisitor<StaticMarkingVisitor, |   267                     &FixedBodyVisitor<StaticMarkingVisitor, | 
|   258                                       ConsString::BodyDescriptor, |   268                                       ConsString::BodyDescriptor, | 
|   259                                       void>::Visit); |   269                                       void>::Visit); | 
|   260  |   270  | 
|   261     table_.Register(kVisitConsString, |   271     table_.Register(kVisitConsString, | 
|   262                     &FixedBodyVisitor<StaticMarkingVisitor, |   272                     &FixedBodyVisitor<StaticMarkingVisitor, | 
|   263                                       ConsString::BodyDescriptor, |   273                                       ConsString::BodyDescriptor, | 
|   264                                       void>::Visit); |   274                                       void>::Visit); | 
| (...skipping 17 matching lines...) Expand all  Loading... | 
|   282                     &FixedBodyVisitor<StaticMarkingVisitor, |   292                     &FixedBodyVisitor<StaticMarkingVisitor, | 
|   283                                       Oddball::BodyDescriptor, |   293                                       Oddball::BodyDescriptor, | 
|   284                                       void>::Visit); |   294                                       void>::Visit); | 
|   285     table_.Register(kVisitMap, |   295     table_.Register(kVisitMap, | 
|   286                     &FixedBodyVisitor<StaticMarkingVisitor, |   296                     &FixedBodyVisitor<StaticMarkingVisitor, | 
|   287                                       Map::BodyDescriptor, |   297                                       Map::BodyDescriptor, | 
|   288                                       void>::Visit); |   298                                       void>::Visit); | 
|   289  |   299  | 
|   290     table_.Register(kVisitCode, &VisitCode); |   300     table_.Register(kVisitCode, &VisitCode); | 
|   291  |   301  | 
 |   302     table_.Register(kVisitJSFunction, &VisitJSFunction); | 
 |   303  | 
|   292     table_.Register(kVisitPropertyCell, |   304     table_.Register(kVisitPropertyCell, | 
|   293                     &FixedBodyVisitor<StaticMarkingVisitor, |   305                     &FixedBodyVisitor<StaticMarkingVisitor, | 
|   294                                       JSGlobalPropertyCell::BodyDescriptor, |   306                                       JSGlobalPropertyCell::BodyDescriptor, | 
|   295                                       void>::Visit); |   307                                       void>::Visit); | 
|   296  |   308  | 
|   297     table_.RegisterSpecializations<DataObjectVisitor, |   309     table_.RegisterSpecializations<DataObjectVisitor, | 
|   298                                    kVisitDataObject, |   310                                    kVisitDataObject, | 
|   299                                    kVisitDataObjectGeneric>(); |   311                                    kVisitDataObjectGeneric>(); | 
|   300  |   312  | 
|   301     table_.RegisterSpecializations<JSObjectVisitor, |   313     table_.RegisterSpecializations<JSObjectVisitor, | 
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   398                               void> JSObjectVisitor; |   410                               void> JSObjectVisitor; | 
|   399  |   411  | 
|   400   typedef FlexibleBodyVisitor<StaticMarkingVisitor, |   412   typedef FlexibleBodyVisitor<StaticMarkingVisitor, | 
|   401                               StructBodyDescriptor, |   413                               StructBodyDescriptor, | 
|   402                               void> StructObjectVisitor; |   414                               void> StructObjectVisitor; | 
|   403  |   415  | 
|   404   static void VisitCode(Map* map, HeapObject* object) { |   416   static void VisitCode(Map* map, HeapObject* object) { | 
|   405     reinterpret_cast<Code*>(object)->CodeIterateBody<StaticMarkingVisitor>(); |   417     reinterpret_cast<Code*>(object)->CodeIterateBody<StaticMarkingVisitor>(); | 
|   406   } |   418   } | 
|   407  |   419  | 
 |   420   // Code flushing support. | 
 |   421  | 
 |   422   // How many collections newly compiled code object will survive before being | 
 |   423   // flushed. | 
 |   424   static const int kCodeAgeThreshold = 5; | 
 |   425  | 
 |   426   inline static bool HasSourceCode(SharedFunctionInfo* info) { | 
 |   427     Object* undefined = Heap::raw_unchecked_undefined_value(); | 
 |   428     return (info->script() != undefined) && | 
 |   429         (reinterpret_cast<Script*>(info->script())->source() != undefined); | 
 |   430   } | 
 |   431  | 
 |   432  | 
 |   433   inline static bool IsCompiled(JSFunction* function) { | 
 |   434     return | 
 |   435         function->unchecked_code() != Builtins::builtin(Builtins::LazyCompile); | 
 |   436   } | 
 |   437  | 
 |   438  | 
 |   439   inline static bool IsCompiled(SharedFunctionInfo* function) { | 
 |   440     return | 
 |   441         function->unchecked_code() != Builtins::builtin(Builtins::LazyCompile); | 
 |   442   } | 
 |   443  | 
 |   444  | 
 |   445   static void FlushCodeForFunction(JSFunction* function) { | 
 |   446     SharedFunctionInfo* shared_info = function->unchecked_shared(); | 
 |   447  | 
 |   448     if (shared_info->IsMarked()) return; | 
 |   449  | 
 |   450     // Special handling if the function and shared info objects | 
 |   451     // have different code objects. | 
 |   452     if (function->unchecked_code() != shared_info->unchecked_code()) { | 
 |   453       // If the shared function has been flushed but the function has not, | 
 |   454       // we flush the function if possible. | 
 |   455       if (!IsCompiled(shared_info) && | 
 |   456           IsCompiled(function) && | 
 |   457           !function->unchecked_code()->IsMarked()) { | 
 |   458         function->set_code(shared_info->unchecked_code()); | 
 |   459       } | 
 |   460       return; | 
 |   461     } | 
 |   462  | 
 |   463     // Code is either on stack or in compilation cache. | 
 |   464     if (shared_info->unchecked_code()->IsMarked()) { | 
 |   465       shared_info->set_code_age(0); | 
 |   466       return; | 
 |   467     } | 
 |   468  | 
 |   469     // The function must be compiled and have the source code available, | 
 |   470     // to be able to recompile it in case we need the function again. | 
 |   471     if (!(shared_info->is_compiled() && HasSourceCode(shared_info))) return; | 
 |   472  | 
 |   473     // We never flush code for Api functions. | 
 |   474     Object* function_data = shared_info->function_data(); | 
 |   475     if (function_data->IsHeapObject() && | 
 |   476         (SafeMap(function_data)->instance_type() == | 
 |   477          FUNCTION_TEMPLATE_INFO_TYPE)) { | 
 |   478       return; | 
 |   479     } | 
 |   480  | 
 |   481     // Only flush code for functions. | 
 |   482     if (shared_info->code()->kind() != Code::FUNCTION) return; | 
 |   483  | 
 |   484     // Function must be lazy compilable. | 
 |   485     if (!shared_info->allows_lazy_compilation()) return; | 
 |   486  | 
 |   487     // If this is a full script wrapped in a function we do no flush the code. | 
 |   488     if (shared_info->is_toplevel()) return; | 
 |   489  | 
 |   490     // Age this shared function info. | 
 |   491     if (shared_info->code_age() < kCodeAgeThreshold) { | 
 |   492       shared_info->set_code_age(shared_info->code_age() + 1); | 
 |   493       return; | 
 |   494     } | 
 |   495  | 
 |   496     // Compute the lazy compilable version of the code. | 
 |   497     Code* code = Builtins::builtin(Builtins::LazyCompile); | 
 |   498     shared_info->set_code(code); | 
 |   499     function->set_code(code); | 
 |   500   } | 
 |   501  | 
 |   502  | 
 |   503   static inline Map* SafeMap(Object* obj) { | 
 |   504     MapWord map_word = HeapObject::cast(obj)->map_word(); | 
 |   505     map_word.ClearMark(); | 
 |   506     map_word.ClearOverflow(); | 
 |   507     return map_word.ToMap(); | 
 |   508   } | 
 |   509  | 
 |   510  | 
 |   511   static inline bool IsJSBuiltinsObject(Object* obj) { | 
 |   512     return obj->IsHeapObject() && | 
 |   513         (SafeMap(obj)->instance_type() == JS_BUILTINS_OBJECT_TYPE); | 
 |   514   } | 
 |   515  | 
 |   516  | 
 |   517   static inline bool IsValidNotBuiltinContext(Object* ctx) { | 
 |   518     if (!ctx->IsHeapObject()) return false; | 
 |   519  | 
 |   520     Map* map = SafeMap(ctx); | 
 |   521     if(!(map == Heap::raw_unchecked_context_map() || | 
 |   522          map == Heap::raw_unchecked_catch_context_map() || | 
 |   523          map == Heap::raw_unchecked_global_context_map())) { | 
 |   524       return false; | 
 |   525     } | 
 |   526  | 
 |   527     Context* context = reinterpret_cast<Context*>(ctx); | 
 |   528  | 
 |   529     if(IsJSBuiltinsObject(context->global())) { | 
 |   530       return false; | 
 |   531     } | 
 |   532  | 
 |   533     return true; | 
 |   534   } | 
 |   535  | 
 |   536  | 
 |   537   static void VisitJSFunction(Map* map, HeapObject* object) { | 
 |   538     JSFunction* jsfunction = reinterpret_cast<JSFunction*>(object); | 
 |   539  | 
 |   540     // The function must have a valid context and not be a builtin. | 
 |   541     if (IsValidNotBuiltinContext(jsfunction->unchecked_context())) { | 
 |   542       FlushCodeForFunction(jsfunction); | 
 |   543     } | 
 |   544  | 
 |   545     JSObjectVisitor::VisitSpecialized<JSFunction::kSize>(map, object); | 
 |   546   } | 
 |   547  | 
|   408   typedef void (*Callback)(Map* map, HeapObject* object); |   548   typedef void (*Callback)(Map* map, HeapObject* object); | 
|   409  |   549  | 
|   410   static VisitorDispatchTable<Callback> table_; |   550   static VisitorDispatchTable<Callback> table_; | 
|   411 }; |   551 }; | 
|   412  |   552  | 
|   413  |   553  | 
|   414 VisitorDispatchTable<StaticMarkingVisitor::Callback> |   554 VisitorDispatchTable<StaticMarkingVisitor::Callback> | 
|   415   StaticMarkingVisitor::table_; |   555   StaticMarkingVisitor::table_; | 
|   416  |   556  | 
|   417  |   557  | 
| (...skipping 10 matching lines...) Expand all  Loading... | 
|   428   void VisitCodeTarget(RelocInfo* rinfo) { |   568   void VisitCodeTarget(RelocInfo* rinfo) { | 
|   429     StaticMarkingVisitor::VisitCodeTarget(rinfo); |   569     StaticMarkingVisitor::VisitCodeTarget(rinfo); | 
|   430   } |   570   } | 
|   431  |   571  | 
|   432   void VisitDebugTarget(RelocInfo* rinfo) { |   572   void VisitDebugTarget(RelocInfo* rinfo) { | 
|   433     StaticMarkingVisitor::VisitDebugTarget(rinfo); |   573     StaticMarkingVisitor::VisitDebugTarget(rinfo); | 
|   434   } |   574   } | 
|   435 }; |   575 }; | 
|   436  |   576  | 
|   437  |   577  | 
 |   578 class CodeMarkingVisitor : public ThreadVisitor { | 
 |   579  public: | 
 |   580   void VisitThread(ThreadLocalTop* top) { | 
 |   581     for (StackFrameIterator it(top); !it.done(); it.Advance()) { | 
 |   582       MarkCompactCollector::MarkObject(it.frame()->unchecked_code()); | 
 |   583     } | 
 |   584   } | 
 |   585 }; | 
 |   586  | 
 |   587  | 
 |   588 class SharedFunctionInfoMarkingVisitor : public ObjectVisitor { | 
 |   589  public: | 
 |   590   void VisitPointers(Object** start, Object** end) { | 
 |   591     for (Object** p = start; p < end; p++) VisitPointer(p); | 
 |   592   } | 
 |   593  | 
 |   594   void VisitPointer(Object** slot) { | 
 |   595     Object* obj = *slot; | 
 |   596     if (obj->IsHeapObject()) { | 
 |   597       MarkCompactCollector::MarkObject(HeapObject::cast(obj)); | 
 |   598     } | 
 |   599   } | 
 |   600 }; | 
 |   601  | 
 |   602  | 
 |   603 void MarkCompactCollector::PrepareForCodeFlushing() { | 
 |   604   if (!FLAG_flush_code) { | 
 |   605     StaticMarkingVisitor::EnableCodeFlushing(false); | 
 |   606     return; | 
 |   607   } | 
 |   608  | 
 |   609 #ifdef ENABLE_DEBUGGER_SUPPORT | 
 |   610   if (Debug::IsLoaded() || Debug::has_break_points()) { | 
 |   611     StaticMarkingVisitor::EnableCodeFlushing(false); | 
 |   612     return; | 
 |   613   } | 
 |   614 #endif | 
 |   615   StaticMarkingVisitor::EnableCodeFlushing(true); | 
 |   616  | 
 |   617   // Make sure we are not referencing the code from the stack. | 
 |   618   for (StackFrameIterator it; !it.done(); it.Advance()) { | 
 |   619     MarkCompactCollector::MarkObject(it.frame()->unchecked_code()); | 
 |   620   } | 
 |   621  | 
 |   622   // Iterate the archived stacks in all threads to check if | 
 |   623   // the code is referenced. | 
 |   624   CodeMarkingVisitor code_marking_visitor; | 
 |   625   ThreadManager::IterateArchivedThreads(&code_marking_visitor); | 
 |   626  | 
 |   627   SharedFunctionInfoMarkingVisitor visitor; | 
 |   628   CompilationCache::IterateFunctions(&visitor); | 
 |   629  | 
 |   630   MarkCompactCollector::ProcessMarkingStack(); | 
 |   631 } | 
 |   632  | 
 |   633  | 
|   438 // Visitor class for marking heap roots. |   634 // Visitor class for marking heap roots. | 
|   439 class RootMarkingVisitor : public ObjectVisitor { |   635 class RootMarkingVisitor : public ObjectVisitor { | 
|   440  public: |   636  public: | 
|   441   void VisitPointer(Object** p) { |   637   void VisitPointer(Object** p) { | 
|   442     MarkObjectByPointer(p); |   638     MarkObjectByPointer(p); | 
|   443   } |   639   } | 
|   444  |   640  | 
|   445   void VisitPointers(Object** start, Object** end) { |   641   void VisitPointers(Object** start, Object** end) { | 
|   446     for (Object** p = start; p < end; p++) MarkObjectByPointer(p); |   642     for (Object** p = start; p < end; p++) MarkObjectByPointer(p); | 
|   447   } |   643   } | 
| (...skipping 338 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   786   ASSERT(state_ == PREPARE_GC); |   982   ASSERT(state_ == PREPARE_GC); | 
|   787   state_ = MARK_LIVE_OBJECTS; |   983   state_ = MARK_LIVE_OBJECTS; | 
|   788 #endif |   984 #endif | 
|   789   // The to space contains live objects, the from space is used as a marking |   985   // The to space contains live objects, the from space is used as a marking | 
|   790   // stack. |   986   // stack. | 
|   791   marking_stack.Initialize(Heap::new_space()->FromSpaceLow(), |   987   marking_stack.Initialize(Heap::new_space()->FromSpaceLow(), | 
|   792                            Heap::new_space()->FromSpaceHigh()); |   988                            Heap::new_space()->FromSpaceHigh()); | 
|   793  |   989  | 
|   794   ASSERT(!marking_stack.overflowed()); |   990   ASSERT(!marking_stack.overflowed()); | 
|   795  |   991  | 
 |   992   PrepareForCodeFlushing(); | 
 |   993  | 
|   796   RootMarkingVisitor root_visitor; |   994   RootMarkingVisitor root_visitor; | 
|   797   MarkRoots(&root_visitor); |   995   MarkRoots(&root_visitor); | 
|   798  |   996  | 
|   799   // The objects reachable from the roots are marked, yet unreachable |   997   // The objects reachable from the roots are marked, yet unreachable | 
|   800   // objects are unmarked.  Mark objects reachable from object groups |   998   // objects are unmarked.  Mark objects reachable from object groups | 
|   801   // containing at least one marked object, and continue until no new |   999   // containing at least one marked object, and continue until no new | 
|   802   // objects are reachable from the object groups. |  1000   // objects are reachable from the object groups. | 
|   803   ProcessObjectGroups(); |  1001   ProcessObjectGroups(); | 
|   804  |  1002  | 
|   805   // The objects reachable from the roots or object groups are marked, |  1003   // The objects reachable from the roots or object groups are marked, | 
| (...skipping 1635 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  2441 } |  2639 } | 
|  2442  |  2640  | 
|  2443  |  2641  | 
|  2444 void MarkCompactCollector::Initialize() { |  2642 void MarkCompactCollector::Initialize() { | 
|  2445   StaticPointersToNewGenUpdatingVisitor::Initialize(); |  2643   StaticPointersToNewGenUpdatingVisitor::Initialize(); | 
|  2446   StaticMarkingVisitor::Initialize(); |  2644   StaticMarkingVisitor::Initialize(); | 
|  2447 } |  2645 } | 
|  2448  |  2646  | 
|  2449  |  2647  | 
|  2450 } }  // namespace v8::internal |  2648 } }  // namespace v8::internal | 
| OLD | NEW |