Author: [email protected]
Date: Tue Apr 14 06:38:25 2009
New Revision: 1702

Added:
    trunk/src/func-name-inferrer.cc
       - copied unchanged from r1701,  
/branches/bleeding_edge/src/func-name-inferrer.cc
    trunk/src/func-name-inferrer.h
       - copied unchanged from r1701,  
/branches/bleeding_edge/src/func-name-inferrer.h
    trunk/test/cctest/test-func-name-inference.cc
       - copied unchanged from r1701,  
/branches/bleeding_edge/test/cctest/test-func-name-inference.cc
Modified:
    trunk/   (props changed)
    trunk/ChangeLog
    trunk/src/SConscript
    trunk/src/api.cc
    trunk/src/ast.h
    trunk/src/codegen-arm.h
    trunk/src/codegen-ia32.h
    trunk/src/codegen.cc
    trunk/src/compiler.cc
    trunk/src/d8.cc
    trunk/src/d8.h
    trunk/src/frames-arm.cc
    trunk/src/frames-ia32.cc
    trunk/src/frames-inl.h
    trunk/src/frames.cc
    trunk/src/frames.h
    trunk/src/heap.cc
    trunk/src/mark-compact.cc
    trunk/src/objects-inl.h
    trunk/src/objects.cc
    trunk/src/objects.h
    trunk/src/prettyprinter.cc
    trunk/src/regexp-macro-assembler-irregexp-inl.h   (props changed)
    trunk/src/rewriter.cc
    trunk/src/runtime.cc
    trunk/src/runtime.h
    trunk/test/cctest/SConscript
    trunk/test/mjsunit/global-load-from-eval-in-with.js   (props changed)
    trunk/test/mjsunit/local-load-from-eval.js   (props changed)
    trunk/test/mjsunit/property-load-across-eval.js   (props changed)
    trunk/test/mjsunit/regress/regress-269.js   (props changed)
    trunk/tools/v8.xcodeproj/project.pbxproj
    trunk/tools/visual_studio/v8_base.vcproj
    trunk/tools/visual_studio/v8_base_arm.vcproj
    trunk/tools/visual_studio/v8_cctest.vcproj

Log:
Made the stack traversal code in the profiler robust by avoiding to look  
into the heap.

Added name inferencing for anonymous functions to facilitate debugging and  
profiling.

Re-enabled stats timers in the developer shell (d8).

Fixed issue 303 by avoiding to shortcut cons-symbols.


Modified: trunk/ChangeLog
==============================================================================
--- trunk/ChangeLog     (original)
+++ trunk/ChangeLog     Tue Apr 14 06:38:25 2009
@@ -1,3 +1,16 @@
+2009-04-14: Version 1.1.9
+
+        Made the stack traversal code in the profiler robust by avoiding
+        to look into the heap.
+
+        Added name inferencing for anonymous functions to facilitate
+        debugging and profiling.
+
+        Re-enabled stats timers in the developer shell (d8).
+
+        Fixed issue 303 by avoiding to shortcut cons-symbols.
+
+
  2009-04-11: Version 1.1.8

          Changed test-debug/ThreadedDebugging to be non-flaky (issue 96).

Modified: trunk/src/SConscript
==============================================================================
--- trunk/src/SConscript        (original)
+++ trunk/src/SConscript        Tue Apr 14 06:38:25 2009
@@ -40,7 +40,8 @@
      'codegen.cc', 'compilation-cache.cc', 'compiler.cc', 'contexts.cc',
      'conversions.cc', 'counters.cc', 'dateparser.cc', 'debug.cc',
      'debug-agent.cc', 'disassembler.cc', 'execution.cc', 'factory.cc',
-    'flags.cc', 'frames.cc', 'global-handles.cc', 'handles.cc', 'hashmap.cc',
+    'flags.cc', 'frames.cc', 'func-name-inferrer.cc',
+    'global-handles.cc', 'handles.cc', 'hashmap.cc',
      'heap.cc', 'ic.cc', 'interpreter-irregexp.cc', 'jsregexp.cc',
      'jump-target.cc', 'log.cc', 'mark-compact.cc', 'messages.cc', 
'objects.cc',
      'oprofile-agent.cc', 'parser.cc', 'property.cc', 
'regexp-macro-assembler.cc',

Modified: trunk/src/api.cc
==============================================================================
--- trunk/src/api.cc    (original)
+++ trunk/src/api.cc    Tue Apr 14 06:38:25 2009
@@ -2373,7 +2373,7 @@


  const char* v8::V8::GetVersion() {
-  return "1.1.8";
+  return "1.1.9";
  }



Modified: trunk/src/ast.h
==============================================================================
--- trunk/src/ast.h     (original)
+++ trunk/src/ast.h     Tue Apr 14 06:38:25 2009
@@ -1223,7 +1223,8 @@
          end_position_(end_position),
          is_expression_(is_expression),
          loop_nesting_(0),
-        function_token_position_(RelocInfo::kNoPosition) {
+        function_token_position_(RelocInfo::kNoPosition),
+        inferred_name_(Heap::empty_string()) {
  #ifdef DEBUG
      already_compiled_ = false;
  #endif
@@ -1253,6 +1254,11 @@
    bool loop_nesting() const { return loop_nesting_; }
    void set_loop_nesting(int nesting) { loop_nesting_ = nesting; }

+  Handle<String> inferred_name() const  { return inferred_name_; }
+  void set_inferred_name(Handle<String> inferred_name) {
+    inferred_name_ = inferred_name;
+  }
+
  #ifdef DEBUG
    void mark_as_compiled() {
      ASSERT(!already_compiled_);
@@ -1273,6 +1279,7 @@
    bool is_expression_;
    int loop_nesting_;
    int function_token_position_;
+  Handle<String> inferred_name_;
  #ifdef DEBUG
    bool already_compiled_;
  #endif

Modified: trunk/src/codegen-arm.h
==============================================================================
--- trunk/src/codegen-arm.h     (original)
+++ trunk/src/codegen-arm.h     Tue Apr 14 06:38:25 2009
@@ -160,7 +160,8 @@
                                int end_position,
                                bool is_expression,
                                bool is_toplevel,
-                              Handle<Script> script);
+                              Handle<Script> script,
+                              Handle<String> inferred_name);

    // Accessors
    MacroAssembler* masm() { return masm_; }

Modified: trunk/src/codegen-ia32.h
==============================================================================
--- trunk/src/codegen-ia32.h    (original)
+++ trunk/src/codegen-ia32.h    Tue Apr 14 06:38:25 2009
@@ -299,7 +299,8 @@
                                int end_position,
                                bool is_expression,
                                bool is_toplevel,
-                              Handle<Script> script);
+                              Handle<Script> script,
+                              Handle<String> inferred_name);

    // Accessors
    MacroAssembler* masm() { return masm_; }

Modified: trunk/src/codegen.cc
==============================================================================
--- trunk/src/codegen.cc        (original)
+++ trunk/src/codegen.cc        Tue Apr 14 06:38:25 2009
@@ -230,7 +230,8 @@
                                      int end_position,
                                      bool is_expression,
                                      bool is_toplevel,
-                                    Handle<Script> script) {
+                                    Handle<Script> script,
+                                    Handle<String> inferred_name) {
    fun->shared()->set_length(length);
    fun->shared()->set_formal_parameter_count(length);
    fun->shared()->set_script(*script);
@@ -239,6 +240,7 @@
    fun->shared()->set_end_position(end_position);
    fun->shared()->set_is_expression(is_expression);
    fun->shared()->set_is_toplevel(is_toplevel);
+  fun->shared()->set_inferred_name(*inferred_name);
  }


@@ -299,7 +301,8 @@
    CodeGenerator::SetFunctionInfo(function, node->num_parameters(),
                                   node->function_token_position(),
                                   node->start_position(),  
node->end_position(),
-                                 node->is_expression(), false, script_);
+                                 node->is_expression(), false, script_,
+                                 node->inferred_name());

    // Notify debugger that a new function has been added.
    Debugger::OnNewFunction(function);

Modified: trunk/src/compiler.cc
==============================================================================
--- trunk/src/compiler.cc       (original)
+++ trunk/src/compiler.cc       Tue Apr 14 06:38:25 2009
@@ -152,7 +152,8 @@
    CodeGenerator::SetFunctionInfo(fun, lit->scope()->num_parameters(),
                                   RelocInfo::kNoPosition,
                                   lit->start_position(),  
lit->end_position(),
-                                 lit->is_expression(), true, script);
+                                 lit->is_expression(), true, script,
+                                 lit->inferred_name());

    // Hint to the runtime system used when allocating space for initial
    // property space by setting the expected number of properties for
@@ -316,20 +317,22 @@
    // name and line number. Check explicit whether logging is enabled as  
finding
    // the line number is not for free.
    if (Logger::is_enabled() || OProfileAgent::is_enabled()) {
+    Handle<String> func_name(lit->name()->length() > 0 ?
+                             *lit->name() : shared->inferred_name());
      if (script->name()->IsString()) {
        int line_num = GetScriptLineNumber(script, start_position);
        if (line_num > 0) {
          line_num += script->line_offset()->value() + 1;
        }
-      LOG(CodeCreateEvent("LazyCompile", *code, *lit->name(),
+      LOG(CodeCreateEvent("LazyCompile", *code, *func_name,
                            String::cast(script->name()), line_num));
-      OProfileAgent::CreateNativeCodeRegion(*lit->name(),
+      OProfileAgent::CreateNativeCodeRegion(*func_name,
                                              String::cast(script->name()),
                                              line_num, code->address(),
                                              code->ExecutableSize());
      } else {
-      LOG(CodeCreateEvent("LazyCompile", *code, *lit->name()));
-      OProfileAgent::CreateNativeCodeRegion(*lit->name(), code->address(),
+      LOG(CodeCreateEvent("LazyCompile", *code, *func_name));
+      OProfileAgent::CreateNativeCodeRegion(*func_name, code->address(),
                                              code->ExecutableSize());
      }
    }

Modified: trunk/src/d8.cc
==============================================================================
--- trunk/src/d8.cc     (original)
+++ trunk/src/d8.cc     Tue Apr 14 06:38:25 2009
@@ -268,12 +268,19 @@
  }


-int32_t* Counter::Bind(const char* name) {
+int32_t* Counter::Bind(const char* name, bool is_histogram) {
    int i;
    for (i = 0; i < kMaxNameSize - 1 && name[i]; i++)
      name_[i] = static_cast<char>(name[i]);
    name_[i] = '\0';
-  return &counter_;
+  is_histogram_ = is_histogram;
+  return ptr();
+}
+
+
+void Counter::AddSample(int32_t sample) {
+  count_++;
+  sample_total_ += sample;
  }


@@ -302,6 +309,8 @@
    }
    counters_ = static_cast<CounterCollection*>(memory);
    V8::SetCounterFunction(LookupCounter);
+  V8::SetCreateHistogramFunction(CreateHistogram);
+  V8::SetAddHistogramSampleFunction(AddHistogramSample);
  }


@@ -316,15 +325,44 @@
  }


-int* Shell::LookupCounter(const char* name) {
+Counter* Shell::GetCounter(const char* name, bool is_histogram) {
    Counter* counter = counter_map_->Lookup(name);
+
+  if (counter == NULL) {
+    counter = counters_->GetNextCounter();
+    if (counter != NULL) {
+      counter_map_->Set(name, counter);
+      counter->Bind(name, is_histogram);
+    }
+  } else {
+    ASSERT(counter->is_histogram() == is_histogram);
+  }
+  return counter;
+}
+
+
+int* Shell::LookupCounter(const char* name) {
+  Counter* counter = GetCounter(name, false);
+
    if (counter != NULL) {
      return counter->ptr();
+  } else {
+    return NULL;
    }
-  Counter* result = counters_->GetNextCounter();
-  if (result == NULL) return NULL;
-  counter_map_->Set(name, result);
-  return result->Bind(name);
+}
+
+
+void* Shell::CreateHistogram(const char* name,
+                             int min,
+                             int max,
+                             size_t buckets) {
+  return GetCounter(name, true);
+}
+
+
+void Shell::AddHistogramSample(void* histogram, int sample) {
+  Counter* counter = reinterpret_cast<Counter*>(histogram);
+  counter->AddSample(sample);
  }


@@ -333,8 +371,12 @@
    // Set up counters
    if (i::FLAG_map_counters != NULL)
      MapCounters(i::FLAG_map_counters);
-  if (i::FLAG_dump_counters)
+  if (i::FLAG_dump_counters) {
      V8::SetCounterFunction(LookupCounter);
+    V8::SetCreateHistogramFunction(CreateHistogram);
+    V8::SetAddHistogramSampleFunction(AddHistogramSample);
+  }
+
    // Initialize the global objects
    HandleScope scope;
    Handle<ObjectTemplate> global_template = ObjectTemplate::New();
@@ -406,7 +448,14 @@
      ::printf("+----------------------------------------+-------------+\n");
      for (CounterMap::Iterator i(counter_map_); i.More(); i.Next()) {
        Counter* counter = i.CurrentValue();
-      ::printf("| %-38s | %11i |\n", i.CurrentKey(), counter->value());
+      if (counter->is_histogram()) {
+        ::printf("| c:%-36s | %11i |\n", i.CurrentKey(), counter->count());
+        ::printf("| t:%-36s | %11i |\n",
+                 i.CurrentKey(),
+                 counter->sample_total());
+      } else {
+        ::printf("| %-38s | %11i |\n", i.CurrentKey(), counter->count());
+      }
      }
      ::printf("+----------------------------------------+-------------+\n");
    }

Modified: trunk/src/d8.h
==============================================================================
--- trunk/src/d8.h      (original)
+++ trunk/src/d8.h      Tue Apr 14 06:38:25 2009
@@ -42,11 +42,16 @@
  class Counter {
   public:
    static const int kMaxNameSize = 64;
-  int32_t* Bind(const char* name);
-  int32_t* ptr() { return &counter_; }
-  int32_t value() { return counter_; }
+  int32_t* Bind(const char* name, bool histogram);
+  int32_t* ptr() { return &count_; }
+  int32_t count() { return count_; }
+  int32_t sample_total() { return sample_total_; }
+  bool is_histogram() { return is_histogram_; }
+  void AddSample(int32_t sample);
   private:
-  int32_t counter_;
+  int32_t count_;
+  int32_t sample_total_;
+  bool is_histogram_;
    uint8_t name_[kMaxNameSize];
  };

@@ -116,6 +121,11 @@
    static void Initialize();
    static void OnExit();
    static int* LookupCounter(const char* name);
+  static void* CreateHistogram(const char* name,
+                               int min,
+                               int max,
+                               size_t buckets);
+  static void AddHistogramSample(void* histogram, int sample);
    static void MapCounters(const char* name);
    static Handle<String> ReadFile(const char* name);
    static void RunShell();
@@ -179,6 +189,7 @@
    static CounterCollection local_counters_;
    static CounterCollection* counters_;
    static i::OS::MemoryMappedFile* counters_file_;
+  static Counter* GetCounter(const char* name, bool is_histogram);
  };



Modified: trunk/src/frames-arm.cc
==============================================================================
--- trunk/src/frames-arm.cc     (original)
+++ trunk/src/frames-arm.cc     Tue Apr 14 06:38:25 2009
@@ -80,7 +80,7 @@

  Address JavaScriptFrame::GetCallerStackPointer() const {
    int arguments;
-  if (Heap::gc_state() != Heap::NOT_IN_GC) {
+  if (Heap::gc_state() != Heap::NOT_IN_GC || disable_heap_access_) {
      // The arguments for cooked frames are traversed as if they were
      // expression stack elements of the calling frame. The reason for
      // this rather strange decision is that we cannot access the

Modified: trunk/src/frames-ia32.cc
==============================================================================
--- trunk/src/frames-ia32.cc    (original)
+++ trunk/src/frames-ia32.cc    Tue Apr 14 06:38:25 2009
@@ -78,7 +78,7 @@

  Address JavaScriptFrame::GetCallerStackPointer() const {
    int arguments;
-  if (Heap::gc_state() != Heap::NOT_IN_GC) {
+  if (Heap::gc_state() != Heap::NOT_IN_GC || disable_heap_access_) {
      // The arguments for cooked frames are traversed as if they were
      // expression stack elements of the calling frame. The reason for
      // this rather strange decision is that we cannot access the

Modified: trunk/src/frames-inl.h
==============================================================================
--- trunk/src/frames-inl.h      (original)
+++ trunk/src/frames-inl.h      Tue Apr 14 06:38:25 2009
@@ -169,19 +169,6 @@
  }


-inline bool JavaScriptFrame::is_at_function() const {
-  Object* result = function_slot_object();
-  // Verify that frame points at correct JS function object.
-  // We are verifying that function object address and
-  // the underlying map object address are valid, and that
-  // function is really a function.
-  return Heap::Contains(reinterpret_cast<Address>(result)) &&
-      result->IsHeapObject() &&
-      Heap::Contains(HeapObject::cast(result)->map()) &&
-      result->IsJSFunction();
-}
-
-
  inline Object* JavaScriptFrame::function() const {
    Object* result = function_slot_object();
    ASSERT(result->IsJSFunction());

Modified: trunk/src/frames.cc
==============================================================================
--- trunk/src/frames.cc (original)
+++ trunk/src/frames.cc Tue Apr 14 06:38:25 2009
@@ -86,6 +86,7 @@
    if (use_top || fp != NULL) {
      Reset();
    }
+  JavaScriptFrame_.DisableHeapAccess();
  }

  #undef INITIALIZE_SINGLETON
@@ -208,7 +209,9 @@
    StackFrame* last_frame = iterator_.frame();
    Address last_sp = last_frame->sp(), last_fp = last_frame->fp();
    // Before advancing to the next stack frame, perform pointer validity  
tests
-  iteration_done_ = !IsValidFrame(last_frame) | 
| !IsValidCaller(last_frame);
+  iteration_done_ = !IsValidFrame(last_frame) ||
+      !CanIterateHandles(last_frame, iterator_.handler()) ||
+      !IsValidCaller(last_frame);
    if (iteration_done_) return;

    iterator_.Advance();
@@ -219,12 +222,17 @@
  }


+bool SafeStackFrameIterator::CanIterateHandles(StackFrame* frame,
+                                               StackHandler* handler) {
+  // If StackIterator iterates over StackHandles, verify that
+  // StackHandlerIterator can be instantiated (see StackHandlerIterator
+  // constructor.)
+  return !is_valid_top_ || (frame->sp() <= handler->address());
+}
+
+
  bool SafeStackFrameIterator::IsValidFrame(StackFrame* frame) const {
-  return IsValidStackAddress(frame->sp()) &&  
IsValidStackAddress(frame->fp()) &&
-      // JavaScriptFrame uses function shared info to advance, hence it  
must
-      // point to a valid function object.
-      (!frame->is_java_script() ||
-       reinterpret_cast<JavaScriptFrame*>(frame)->is_at_function());
+  return IsValidStackAddress(frame->sp()) &&  
IsValidStackAddress(frame->fp());
  }


@@ -270,7 +278,7 @@
  SafeStackTraceFrameIterator::SafeStackTraceFrameIterator(
      Address fp, Address sp, Address low_bound, Address high_bound) :
      SafeJavaScriptFrameIterator(fp, sp, low_bound, high_bound) {
-  if (!done() && !frame()->is_at_function()) Advance();
+  if (!done() && !frame()->is_java_script()) Advance();
  }


@@ -278,7 +286,7 @@
    while (true) {
      SafeJavaScriptFrameIterator::Advance();
      if (done()) return;
-    if (frame()->is_at_function()) return;
+    if (frame()->is_java_script()) return;
    }
  }
  #endif

Modified: trunk/src/frames.h
==============================================================================
--- trunk/src/frames.h  (original)
+++ trunk/src/frames.h  Tue Apr 14 06:38:25 2009
@@ -373,7 +373,6 @@
    virtual Type type() const { return JAVA_SCRIPT; }

    // Accessors.
-  inline bool is_at_function() const;
    inline Object* function() const;
    inline Object* receiver() const;
    inline void set_receiver(Object* value);
@@ -414,11 +413,19 @@

   protected:
    explicit JavaScriptFrame(StackFrameIterator* iterator)
-      : StandardFrame(iterator) { }
+      : StandardFrame(iterator), disable_heap_access_(false) { }

    virtual Address GetCallerStackPointer() const;

+  // When this mode is enabled it is not allowed to access heap objects.
+  // This is a special mode used when gathering stack samples in profiler.
+  // A shortcoming is that caller's SP value will be calculated incorrectly
+  // (see GetCallerStackPointer implementation), but it is not used for  
stack
+  // sampling.
+  void DisableHeapAccess() { disable_heap_access_ = true; }
+
   private:
+  bool disable_heap_access_;
    inline Object* function_slot_object() const;

    friend class StackFrameIterator;
@@ -638,6 +645,7 @@
    bool IsValidStackAddress(Address addr) const {
      return IsWithinBounds(low_bound_, high_bound_, addr);
    }
+  bool CanIterateHandles(StackFrame* frame, StackHandler* handler);
    bool IsValidFrame(StackFrame* frame) const;
    bool IsValidCaller(StackFrame* frame);


Modified: trunk/src/heap.cc
==============================================================================
--- trunk/src/heap.cc   (original)
+++ trunk/src/heap.cc   Tue Apr 14 06:38:25 2009
@@ -374,9 +374,34 @@
  }


+static void VerifySymbolTable() {
+#ifdef DEBUG
+  // Helper class for verifying the symbol table.
+  class SymbolTableVerifier : public ObjectVisitor {
+   public:
+    SymbolTableVerifier() { }
+    void VisitPointers(Object** start, Object** end) {
+      // Visit all HeapObject pointers in [start, end).
+      for (Object** p = start; p < end; p++) {
+        if ((*p)->IsHeapObject()) {
+          // Check that the symbol is actually a symbol.
+          ASSERT((*p)->IsNull() || (*p)->IsUndefined() ||  
(*p)->IsSymbol());
+        }
+      }
+    }
+  };
+
+  SymbolTableVerifier verifier;
+  SymbolTable* symbol_table = SymbolTable::cast(Heap::symbol_table());
+  symbol_table->IterateElements(&verifier);
+#endif  // DEBUG
+}
+
+
  void Heap::PerformGarbageCollection(AllocationSpace space,
                                      GarbageCollector collector,
                                      GCTracer* tracer) {
+  VerifySymbolTable();
    if (collector == MARK_COMPACTOR && global_gc_prologue_callback_) {
      ASSERT(!allocation_allowed_);
      global_gc_prologue_callback_();
@@ -421,6 +446,7 @@
      ASSERT(!allocation_allowed_);
      global_gc_epilogue_callback_();
    }
+  VerifySymbolTable();
  }


@@ -813,12 +839,12 @@


  static inline bool IsShortcutCandidate(HeapObject* object, Map* map) {
-  // A ConsString object with Heap::empty_string() as the right side
-  // is a candidate for being shortcut by the scavenger.
+  STATIC_ASSERT(kNotStringTag != 0 && kSymbolTag != 0);
    ASSERT(object->map() == map);
-  if (map->instance_type() >= FIRST_NONSTRING_TYPE) return false;
-  return (StringShape(map).representation_tag() == kConsStringTag) &&
-         (ConsString::cast(object)->unchecked_second() ==  
Heap::empty_string());
+  InstanceType type = map->instance_type();
+  if ((type & kShortcutTypeMask) != kShortcutTypeTag) return false;
+  ASSERT(object->IsString() && !object->IsSymbol());
+  return ConsString::cast(object)->unchecked_second() ==  
Heap::empty_string();
  }


@@ -1384,6 +1410,7 @@
    share->set_script(undefined_value());
    share->set_start_position_and_type(0);
    share->set_debug_info(undefined_value());
+  share->set_inferred_name(empty_string());
    return result;
  }


Modified: trunk/src/mark-compact.cc
==============================================================================
--- trunk/src/mark-compact.cc   (original)
+++ trunk/src/mark-compact.cc   Tue Apr 14 06:38:25 2009
@@ -96,24 +96,6 @@
  }


-#ifdef DEBUG
-// Helper class for verifying the symbol table.
-class SymbolTableVerifier : public ObjectVisitor {
- public:
-  SymbolTableVerifier() { }
-  void VisitPointers(Object** start, Object** end) {
-    // Visit all HeapObject pointers in [start, end).
-    for (Object** p = start; p < end; p++) {
-      if ((*p)->IsHeapObject()) {
-        // Check that the symbol is actually a symbol.
-        ASSERT((*p)->IsNull() || (*p)->IsUndefined() || (*p)->IsSymbol());
-      }
-    }
-  }
-};
-#endif  // DEBUG
-
-
  void MarkCompactCollector::Prepare(GCTracer* tracer) {
    // Rather than passing the tracer around we stash it in a static member
    // variable.
@@ -166,10 +148,6 @@
    }

  #ifdef DEBUG
-  SymbolTable* symbol_table = SymbolTable::cast(Heap::symbol_table());
-  SymbolTableVerifier v;
-  symbol_table->IterateElements(&v);
-
    live_bytes_ = 0;
    live_young_objects_ = 0;
    live_old_pointer_objects_ = 0;
@@ -242,13 +220,7 @@
    MapWord map_word = object->map_word();
    map_word.ClearMark();
    InstanceType type = map_word.ToMap()->instance_type();
-  if (type >= FIRST_NONSTRING_TYPE || (type & kIsSymbolMask) != 0) {
-    return object;
-  }
-
-  StringRepresentationTag rep =
-      static_cast<StringRepresentationTag>(type &  
kStringRepresentationMask);
-  if (rep != kConsStringTag) return object;
+  if ((type & kShortcutTypeMask) != kShortcutTypeTag) return object;

    Object* second =  
reinterpret_cast<ConsString*>(object)->unchecked_second();
    if (reinterpret_cast<String*>(second) != Heap::empty_string()) return  
object;

Modified: trunk/src/objects-inl.h
==============================================================================
--- trunk/src/objects-inl.h     (original)
+++ trunk/src/objects-inl.h     Tue Apr 14 06:38:25 2009
@@ -2077,6 +2077,7 @@
  ACCESSORS(SharedFunctionInfo, lazy_load_data, Object, kLazyLoadDataOffset)
  ACCESSORS(SharedFunctionInfo, script, Object, kScriptOffset)
  ACCESSORS(SharedFunctionInfo, debug_info, Object, kDebugInfoOffset)
+ACCESSORS(SharedFunctionInfo, inferred_name, String, kInferredNameOffset)

  BOOL_ACCESSORS(FunctionTemplateInfo, flag, hidden_prototype,
                 kHiddenPrototypeBit)

Modified: trunk/src/objects.cc
==============================================================================
--- trunk/src/objects.cc        (original)
+++ trunk/src/objects.cc        Tue Apr 14 06:38:25 2009
@@ -679,7 +679,7 @@
      SmartPointer<uc16> smart_chars = this->ToWideCString();
      ASSERT(memcmp(*smart_chars,
                    resource->data(),
-                  resource->length()*sizeof(**smart_chars)) == 0);
+                  resource->length() * sizeof(**smart_chars)) == 0);
    }
  #endif  // DEBUG

@@ -4641,7 +4641,7 @@
  void SharedFunctionInfo::SharedFunctionInfoIterateBody(ObjectVisitor* v) {
    IteratePointers(v, kNameOffset, kCodeOffset + kPointerSize);
    IteratePointers(v, kInstanceClassNameOffset, kScriptOffset +  
kPointerSize);
-  IteratePointer(v, kDebugInfoOffset);
+  IteratePointers(v, kDebugInfoOffset, kInferredNameOffset + kPointerSize);
  }


@@ -6304,7 +6304,7 @@
      if (StringShape(string_).IsCons()) {
        ConsString* cons_string = ConsString::cast(string_);
        cons_string->TryFlatten();
-      if (cons_string->second() == Heap::empty_string()) {
+      if (cons_string->second()->length() == 0) {
          string_ = cons_string->first();
        }
      }
@@ -6312,6 +6312,7 @@
      Map* map = Heap::SymbolMapForString(string_);
      if (map != NULL) {
        string_->set_map(map);
+      ASSERT(string_->IsSymbol());
        return string_;
      }
      // Otherwise allocate a new symbol.

Modified: trunk/src/objects.h
==============================================================================
--- trunk/src/objects.h (original)
+++ trunk/src/objects.h Tue Apr 14 06:38:25 2009
@@ -441,6 +441,19 @@
    kExternalStringTag = 0x3
  };

+
+// A ConsString with an empty string as the right side is a candidate
+// for being shortcut by the garbage collector unless it is a
+// symbol. It's not common to have non-flat symbols, so we do not
+// shortcut them thereby avoiding turning symbols into strings. See
+// heap.cc and mark-compact.cc.
+const uint32_t kShortcutTypeMask =
+    kIsNotStringMask |
+    kIsSymbolMask |
+    kStringRepresentationMask;
+const uint32_t kShortcutTypeTag = kConsStringTag;
+
+
  enum InstanceType {
    SHORT_SYMBOL_TYPE = kShortStringTag | kSymbolTag | kSeqStringTag,
    MEDIUM_SYMBOL_TYPE = kMediumStringTag | kSymbolTag | kSeqStringTag,
@@ -2665,6 +2678,13 @@
    // [debug info]: Debug information.
    DECL_ACCESSORS(debug_info, Object)

+  // [inferred name]: Name inferred from variable or property
+  // assignment of this function. Used to facilitate debugging and
+  // profiling of JavaScript code written in OO style, where almost
+  // all functions are anonymous but are assigned to object
+  // properties.
+  DECL_ACCESSORS(inferred_name, String)
+
    // Position of the 'function' token in the script source.
    inline int function_token_position();
    inline void set_function_token_position(int function_token_position);
@@ -2724,7 +2744,8 @@
    static const int kEndPositionOffset = kStartPositionAndTypeOffset +  
kIntSize;
    static const int kFunctionTokenPositionOffset = kEndPositionOffset +  
kIntSize;
    static const int kDebugInfoOffset = kFunctionTokenPositionOffset +  
kIntSize;
-  static const int kSize = kDebugInfoOffset + kPointerSize;
+  static const int kInferredNameOffset = kDebugInfoOffset + kPointerSize;
+  static const int kSize = kInferredNameOffset + kPointerSize;

   private:
    // Bit positions in length_and_flg.

Modified: trunk/src/prettyprinter.cc
==============================================================================
--- trunk/src/prettyprinter.cc  (original)
+++ trunk/src/prettyprinter.cc  Tue Apr 14 06:38:25 2009
@@ -709,6 +709,7 @@
    Init();
    { IndentedScope indent("FUNC");
      PrintLiteralIndented("NAME", program->name(), true);
+    PrintLiteralIndented("INFERRED NAME", program->inferred_name(), true);
      PrintParameters(program->scope());
      PrintDeclarations(program->scope()->declarations());
      PrintStatements(program->body());
@@ -885,6 +886,7 @@
  void AstPrinter::VisitFunctionLiteral(FunctionLiteral* node) {
    IndentedScope indent("FUNC LITERAL");
    PrintLiteralIndented("NAME", node->name(), false);
+  PrintLiteralIndented("INFERRED NAME", node->inferred_name(), false);
    PrintParameters(node->scope());
    // We don't want to see the function literal in this case: it
    // will be printed via PrintProgram when the code for it is

Modified: trunk/src/rewriter.cc
==============================================================================
--- trunk/src/rewriter.cc       (original)
+++ trunk/src/rewriter.cc       Tue Apr 14 06:38:25 2009
@@ -28,6 +28,7 @@
  #include "v8.h"

  #include "ast.h"
+#include "func-name-inferrer.h"
  #include "scopes.h"
  #include "rewriter.h"

@@ -36,7 +37,9 @@

  class AstOptimizer: public AstVisitor {
   public:
-  explicit AstOptimizer() {
+  explicit AstOptimizer() {}
+  explicit AstOptimizer(Handle<String> enclosing_name) {
+    func_name_inferrer_.PushEnclosingName(enclosing_name);
    }

    void Optimize(ZoneList<Statement*>* statements);
@@ -45,6 +48,8 @@
    // Used for loop condition analysis.  Cleared before visiting a loop
    // condition, set when a function literal is visited.
    bool has_function_literal_;
+  // Helper object for function name inferring.
+  FuncNameInferrer func_name_inferrer_;

    // Helpers
    void OptimizeArguments(ZoneList<Expression*>* arguments);
@@ -185,8 +190,12 @@


  void AstOptimizer::VisitFunctionLiteral(FunctionLiteral* node) {
-  USE(node);
    has_function_literal_ = true;
+
+  if (node->name()->length() == 0) {
+    // Anonymous function.
+    func_name_inferrer_.SetFuncToInfer(node);
+  }
  }


@@ -216,6 +225,11 @@
      } else if (node->type()->IsLikelySmi()) {
        var->type()->SetAsLikelySmi();
      }
+
+    if (!var->is_this() &&
+        !Heap::result_symbol()->Equals(*var->name())) {
+      func_name_inferrer_.PushName(var->name());
+    }
    }
  }

@@ -224,6 +238,11 @@
    Handle<Object> literal = node->handle();
    if (literal->IsSmi()) {
      node->type()->SetAsLikelySmi();
+  } else if (literal->IsString()) {
+    Handle<String> lit_str(Handle<String>::cast(literal));
+    if (!Heap::prototype_symbol()->Equals(*lit_str)) {
+      func_name_inferrer_.PushName(lit_str);
+    }
    }
  }

@@ -239,9 +258,10 @@
    }
  }

-
  void AstOptimizer::VisitObjectLiteral(ObjectLiteral* node) {
    for (int i = 0; i < node->properties()->length(); i++) {
+    ScopedFuncNameInferrer scoped_fni(&func_name_inferrer_);
+    scoped_fni.Enter();
      Visit(node->properties()->at(i)->key());
      Visit(node->properties()->at(i)->value());
    }
@@ -255,11 +275,17 @@


  void AstOptimizer::VisitAssignment(Assignment* node) {
+  ScopedFuncNameInferrer scoped_fni(&func_name_inferrer_);
    switch (node->op()) {
      case Token::INIT_VAR:
      case Token::INIT_CONST:
      case Token::ASSIGN:
        // No type can be infered from the general assignment.
+
+      if (node->value()->AsFunctionLiteral() != NULL ||
+          node->value()->AsObjectLiteral() != NULL) {
+        scoped_fni.Enter();
+      }
        break;
      case Token::ASSIGN_BIT_OR:
      case Token::ASSIGN_BIT_XOR:
@@ -368,6 +394,12 @@


  void AstOptimizer::VisitCallRuntime(CallRuntime* node) {
+  ScopedFuncNameInferrer scoped_fni(&func_name_inferrer_);
+  if (Factory::InitializeVarGlobal_symbol()->Equals(*node->name()) &&
+      node->arguments()->length() >= 2 &&
+      node->arguments()->at(1)->AsFunctionLiteral() != NULL) {
+      scoped_fni.Enter();
+  }
    OptimizeArguments(node->arguments());
  }

@@ -794,13 +826,10 @@
    ZoneList<Statement*>* body = function->body();

    if (FLAG_optimize_ast && !body->is_empty()) {
-    Scope* scope = function->scope();
-    if (!scope->is_global_scope()) {
-      AstOptimizer optimizer;
-      optimizer.Optimize(body);
-      if (optimizer.HasStackOverflow()) {
-        return false;
-      }
+    AstOptimizer optimizer(function->name());
+    optimizer.Optimize(body);
+    if (optimizer.HasStackOverflow()) {
+      return false;
      }
    }
    return true;

Modified: trunk/src/runtime.cc
==============================================================================
--- trunk/src/runtime.cc        (original)
+++ trunk/src/runtime.cc        Tue Apr 14 06:38:25 2009
@@ -3391,6 +3391,13 @@
  }


+bool Runtime::IsUpperCaseChar(uint16_t ch) {
+  unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
+  int char_length = to_upper_mapping.get(ch, 0, chars);
+  return char_length == 0;
+}
+
+
  static Object* Runtime_NumberToString(Arguments args) {
    NoHandleAllocation ha;
    ASSERT(args.length() == 1);
@@ -6061,8 +6068,8 @@
  }


-static Object* FindSharedFunctionInfoInScript(Handle<Script> script,
-                                              int position) {
+Object* Runtime::FindSharedFunctionInfoInScript(Handle<Script> script,
+                                                int position) {
    // Iterate the heap looking for SharedFunctionInfo generated from the
    // script. The inner most SharedFunctionInfo containing the source  
position
    // for the requested break point is found.
@@ -6159,7 +6166,8 @@
    RUNTIME_ASSERT(wrapper->value()->IsScript());
    Handle<Script> script(Script::cast(wrapper->value()));

-  Object* result = FindSharedFunctionInfoInScript(script, source_position);
+  Object* result = Runtime::FindSharedFunctionInfoInScript(
+      script, source_position);
    if (!result->IsUndefined()) {
      Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
      // Find position within function. The script position might be before  
the

Modified: trunk/src/runtime.h
==============================================================================
--- trunk/src/runtime.h (original)
+++ trunk/src/runtime.h Tue Apr 14 06:38:25 2009
@@ -355,6 +355,8 @@

    static int StringMatch(Handle<String> sub, Handle<String> pat, int  
index);

+  static bool IsUpperCaseChar(uint16_t ch);
+
    // TODO(1240886): The following three methods are *not* handle safe,
    // but accept handle arguments. This seems fragile.

@@ -368,6 +370,10 @@
                                     PropertyAttributes attr);

    static Object* GetObjectProperty(Handle<Object> object, Handle<Object>  
key);
+
+  // This function is used in FunctionNameUsing* tests.
+  static Object* FindSharedFunctionInfoInScript(Handle<Script> script,
+                                                int position);

    // Helper functions used stubs.
    static void PerformGC(Object* result);

Modified: trunk/test/cctest/SConscript
==============================================================================
--- trunk/test/cctest/SConscript        (original)
+++ trunk/test/cctest/SConscript        Tue Apr 14 06:38:25 2009
@@ -42,6 +42,7 @@
      'test-debug.cc',
      'test-decls.cc',
      'test-flags.cc',
+    'test-func-name-inference.cc',
      'test-hashmap.cc',
      'test-heap.cc',
      'test-list.cc',

Modified: trunk/tools/v8.xcodeproj/project.pbxproj
==============================================================================
--- trunk/tools/v8.xcodeproj/project.pbxproj    (original)
+++ trunk/tools/v8.xcodeproj/project.pbxproj    Tue Apr 14 06:38:25 2009
@@ -203,6 +203,8 @@
                89F23C9F0E78D604006B2466 /* simulator-arm.cc in Sources */ = 
{isa =  
PBXBuildFile; fileRef = 897FF17D0E719B8F00D62E90 /* simulator-arm.cc */; };
                89F23CA00E78D609006B2466 /* stub-cache-arm.cc in Sources */ = 
{isa =  
PBXBuildFile; fileRef = 897FF18A0E719B8F00D62E90 /* stub-cache-arm.cc */; };
                89FB0E3A0F8E533F00B04B3C /* d8-posix.cc in Sources */ = {isa =  
PBXBuildFile; fileRef = 89FB0E360F8E531900B04B3C /* d8-posix.cc */; };
+               9F92FAA90F8F28AD0089F02C /* func-name-inferrer.cc in Sources */ 
= {isa =  
PBXBuildFile; fileRef = 9F92FAA70F8F28AD0089F02C /* func-name-inferrer.cc  
*/; };
+               9F92FAAA0F8F28AD0089F02C /* func-name-inferrer.cc in Sources */ 
= {isa =  
PBXBuildFile; fileRef = 9F92FAA70F8F28AD0089F02C /* func-name-inferrer.cc  
*/; };
                9FC86ABD0F5FEDAC00F22668 /* oprofile-agent.cc in Sources */ = 
{isa =  
PBXBuildFile; fileRef = 9FC86ABB0F5FEDAC00F22668 /* oprofile-agent.cc */; };
                9FC86ABE0F5FEDAC00F22668 /* oprofile-agent.cc in Sources */ = 
{isa =  
PBXBuildFile; fileRef = 9FC86ABB0F5FEDAC00F22668 /* oprofile-agent.cc */; };
  /* End PBXBuildFile section */
@@ -520,6 +522,8 @@
                89F23C950E78D5B6006B2466 /* v8_shell-arm */ = {isa = 
PBXFileReference;  
explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path  
= "v8_shell-arm"; sourceTree = BUILT_PRODUCTS_DIR; };
                89FB0E360F8E531900B04B3C /* d8-posix.cc */ = {isa = 
PBXFileReference;  
fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name  
= "d8-posix.cc"; path = "../src/d8-posix.cc"; sourceTree = "<group>"; };
                89FB0E370F8E531900B04B3C /* d8-windows.cc */ = {isa = 
PBXFileReference;  
fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name  
= "d8-windows.cc"; path = "../src/d8-windows.cc"; sourceTree = "<group>"; };
+               9F92FAA70F8F28AD0089F02C /* func-name-inferrer.cc */ = {isa =  
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp;  
path = "func-name-inferrer.cc"; sourceTree = "<group>"; };
+               9F92FAA80F8F28AD0089F02C /* func-name-inferrer.h */ = {isa =  
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h;  
path = "func-name-inferrer.h"; sourceTree = "<group>"; };
                9FC86ABB0F5FEDAC00F22668 /* oprofile-agent.cc */ = {isa =  
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp;  
path = "oprofile-agent.cc"; sourceTree = "<group>"; };
                9FC86ABC0F5FEDAC00F22668 /* oprofile-agent.h */ = {isa =  
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h;  
path = "oprofile-agent.h"; sourceTree = "<group>"; };
  /* End PBXFileReference section */
@@ -692,6 +696,8 @@
                                897FF13B0E719B8F00D62E90 /* frames-inl.h */,
                                897FF13C0E719B8F00D62E90 /* frames.cc */,
                                897FF13D0E719B8F00D62E90 /* frames.h */,
+                               9F92FAA70F8F28AD0089F02C /* 
func-name-inferrer.cc */,
+                               9F92FAA80F8F28AD0089F02C /* 
func-name-inferrer.h */,
                                897FF13E0E719B8F00D62E90 /* global-handles.cc 
*/,
                                897FF13F0E719B8F00D62E90 /* global-handles.h */,
                                897FF1400E719B8F00D62E90 /* globals.h */,
@@ -1117,6 +1123,7 @@
                                89A88E050E71A65D0043BA31 /* flags.cc in Sources 
*/,
                                89A88E060E71A6600043BA31 /* frames-ia32.cc in 
Sources */,
                                89A88E070E71A6610043BA31 /* frames.cc in 
Sources */,
+                               9F92FAA90F8F28AD0089F02C /* 
func-name-inferrer.cc in Sources */,
                                89A88E080E71A6620043BA31 /* global-handles.cc 
in Sources */,
                                89A88E090E71A6640043BA31 /* handles.cc in 
Sources */,
                                89A88E0A0E71A6650043BA31 /* hashmap.cc in 
Sources */,
@@ -1217,6 +1224,7 @@
                                89F23C580E78D5B2006B2466 /* flags.cc in Sources 
*/,
                                89F23C9C0E78D5F1006B2466 /* frames-arm.cc in 
Sources */,
                                89F23C5A0E78D5B2006B2466 /* frames.cc in 
Sources */,
+                               9F92FAAA0F8F28AD0089F02C /* 
func-name-inferrer.cc in Sources */,
                                89F23C5B0E78D5B2006B2466 /* global-handles.cc 
in Sources */,
                                89F23C5C0E78D5B2006B2466 /* handles.cc in 
Sources */,
                                89F23C5D0E78D5B2006B2466 /* hashmap.cc in 
Sources */,

Modified: trunk/tools/visual_studio/v8_base.vcproj
==============================================================================
--- trunk/tools/visual_studio/v8_base.vcproj    (original)
+++ trunk/tools/visual_studio/v8_base.vcproj    Tue Apr 14 06:38:25 2009
@@ -417,6 +417,14 @@
                                >
                        </File>
                        <File
+                               RelativePath="..\..\src\func-name-inferrer.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\func-name-inferrer.h"
+                               >
+                       </File>
+                       <File
                                RelativePath="..\..\src\global-handles.cc"
                                >
                        </File>

Modified: trunk/tools/visual_studio/v8_base_arm.vcproj
==============================================================================
--- trunk/tools/visual_studio/v8_base_arm.vcproj        (original)
+++ trunk/tools/visual_studio/v8_base_arm.vcproj        Tue Apr 14 06:38:25 2009
@@ -413,6 +413,14 @@
                                >
                        </File>
                        <File
+                               RelativePath="..\..\src\func-name-inferrer.cc"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\src\func-name-inferrer.h"
+                               >
+                       </File>
+                       <File
                                RelativePath="..\..\src\global-handles.cc"
                                >
                        </File>

Modified: trunk/tools/visual_studio/v8_cctest.vcproj
==============================================================================
--- trunk/tools/visual_studio/v8_cctest.vcproj  (original)
+++ trunk/tools/visual_studio/v8_cctest.vcproj  Tue Apr 14 06:38:25 2009
@@ -186,6 +186,10 @@
                        >
                </File>
                <File
+                       
RelativePath="..\..\test\cctest\test-func-name-inference.cc"
+                       >
+               </File>
+               <File
                        RelativePath="..\..\test\cctest\test-hashmap.cc"
                        >
                </File>

--~--~---------~--~----~------------~-------~--~----~
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
-~----------~----~----~----~------~----~------~--~---

Reply via email to