Add flag to trace element kind transitions
authordanno@chromium.org <danno@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 20 Oct 2011 09:38:24 +0000 (09:38 +0000)
committerdanno@chromium.org <danno@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 20 Oct 2011 09:38:24 +0000 (09:38 +0000)
Currently only traces transitions from generated ia32 code.

BUG=none
TEST=none

Review URL: http://codereview.chromium.org/8357004

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

12 files changed:
src/code-stubs.cc
src/code-stubs.h
src/flag-definitions.h
src/frames.cc
src/frames.h
src/ia32/code-stubs-ia32.cc
src/objects-inl.h
src/objects-printer.cc
src/objects.cc
src/objects.h
src/runtime.cc
src/runtime.h

index 896ffad..f1b918b 100644 (file)
@@ -418,7 +418,7 @@ bool ToBooleanStub::Types::CanBeUndetectable() const {
 void FastElementsConversionStub::Generate(MacroAssembler* masm) {
   if (to_ == FAST_ELEMENTS) {
     if (from_ == FAST_SMI_ONLY_ELEMENTS) {
-      GenerateSmiOnlyToObject(masm);
+      GenerateSmiOnlyToObject(masm, strict_mode_);
     } else if (from_ == FAST_DOUBLE_ELEMENTS) {
       GenerateDoubleToObject(masm, strict_mode_);
     } else {
index ab582a2..3777bf3 100644 (file)
@@ -1054,7 +1054,8 @@ class FastElementsConversionStub : public CodeStub {
   }
 
   void Generate(MacroAssembler* masm);
-  static void GenerateSmiOnlyToObject(MacroAssembler* masm);
+  static void GenerateSmiOnlyToObject(MacroAssembler* masm,
+                                      StrictModeFlag strict_mode);
   static void GenerateSmiOnlyToDouble(MacroAssembler* masm,
                                       StrictModeFlag strict_mode);
   static void GenerateDoubleToObject(MacroAssembler* masm,
index 58fab14..c3c0686 100644 (file)
@@ -527,6 +527,9 @@ DEFINE_bool(ll_prof, false, "Enable low-level linux profiler.")
 #define FLAG FLAG_READONLY
 #endif
 
+// elements.cc
+DEFINE_bool(trace_elements_transitions, false, "trace elements transitions")
+
 // code-stubs.cc
 DEFINE_bool(print_code_stubs, false, "print code stubs")
 
index 412a59c..7c4c573 100644 (file)
@@ -711,6 +711,69 @@ void JavaScriptFrame::Summarize(List<FrameSummary>* functions) {
 }
 
 
+void JavaScriptFrame::PrintTop(FILE* file,
+                               bool print_args,
+                               bool print_line_number) {
+  // constructor calls
+  HandleScope scope;
+  AssertNoAllocation no_allocation;
+  JavaScriptFrameIterator it;
+  while (!it.done()) {
+    if (it.frame()->is_java_script()) {
+      JavaScriptFrame* frame = it.frame();
+      if (frame->IsConstructor()) PrintF(file, "new ");
+      // function name
+      Object* fun = frame->function();
+      if (fun->IsJSFunction()) {
+        SharedFunctionInfo* shared = JSFunction::cast(fun)->shared();
+        shared->DebugName()->ShortPrint(file);
+        if (print_line_number) {
+          Address pc = frame->pc();
+          Code* code = Code::cast(
+              v8::internal::Isolate::Current()->heap()->FindCodeObject(pc));
+          int source_pos = code->SourcePosition(pc);
+          Object* maybe_script = shared->script();
+          if (maybe_script->IsScript()) {
+            Handle<Script> script(Script::cast(maybe_script));
+            int line = GetScriptLineNumberSafe(script, source_pos) + 1;
+            Object* script_name_raw = script->name();
+            if (script_name_raw->IsString()) {
+              String* script_name = String::cast(script->name());
+              SmartArrayPointer<char> c_script_name =
+                  script_name->ToCString(DISALLOW_NULLS,
+                                         ROBUST_STRING_TRAVERSAL);
+              PrintF(file, " at %s:%d", *c_script_name, line);
+            } else {
+              PrintF(file, "at <unknown>:%d", line);
+            }
+          } else {
+            PrintF(file, " at <unknown>:<unknown>");
+          }
+        }
+      } else {
+        fun->ShortPrint(file);
+      }
+
+      if (print_args) {
+        // function arguments
+        // (we are intentionally only printing the actually
+        // supplied parameters, not all parameters required)
+        PrintF(file, "(this=");
+        frame->receiver()->ShortPrint(file);
+        const int length = frame->ComputeParametersCount();
+        for (int i = 0; i < length; i++) {
+          PrintF(file, ", ");
+          frame->GetParameter(i)->ShortPrint(file);
+        }
+        PrintF(file, ")");
+      }
+      break;
+    }
+    it.Advance();
+  }
+}
+
+
 void FrameSummary::Print() {
   PrintF("receiver: ");
   receiver_->ShortPrint();
index ca19b05..778b803 100644 (file)
@@ -512,6 +512,8 @@ class JavaScriptFrame: public StandardFrame {
     return static_cast<JavaScriptFrame*>(frame);
   }
 
+  static void PrintTop(FILE* file, bool print_args, bool print_line_number);
+
  protected:
   inline explicit JavaScriptFrame(StackFrameIterator* iterator);
 
index fe1641c..01b2ee4 100644 (file)
@@ -7023,7 +7023,9 @@ void RecordWriteStub::CheckNeedsToInformIncrementalMarker(
 }
 
 
-void FastElementsConversionStub::GenerateSmiOnlyToObject(MacroAssembler* masm) {
+void FastElementsConversionStub::GenerateSmiOnlyToObject(MacroAssembler* masm,
+                                                         StrictModeFlag
+                                                         strict_mode) {
   // ----------- S t a t e -------------
   //  -- eax    : value
   //  -- ebx    : target map
@@ -7032,14 +7034,18 @@ void FastElementsConversionStub::GenerateSmiOnlyToObject(MacroAssembler* masm) {
   //  -- esp[0] : return address
   // -----------------------------------
   // Set transitioned map.
-  __ mov(FieldOperand(edx, HeapObject::kMapOffset), ebx);
-  __ RecordWriteField(edx,
-                      HeapObject::kMapOffset,
-                      ebx,
-                      edi,
-                      kDontSaveFPRegs,
-                      EMIT_REMEMBERED_SET,
-                      OMIT_SMI_CHECK);
+  if (FLAG_trace_elements_transitions) {
+    KeyedStoreIC::GenerateRuntimeSetProperty(masm, strict_mode);
+  } else {
+    __ mov(FieldOperand(edx, HeapObject::kMapOffset), ebx);
+    __ RecordWriteField(edx,
+                        HeapObject::kMapOffset,
+                        ebx,
+                        edi,
+                        kDontSaveFPRegs,
+                        EMIT_REMEMBERED_SET,
+                        OMIT_SMI_CHECK);
+  }
 }
 
 
@@ -7052,30 +7058,33 @@ void FastElementsConversionStub::GenerateSmiOnlyToDouble(
   //  -- edx    : receiver
   //  -- esp[0] : return address
   // -----------------------------------
-  Label loop, entry, convert_hole, gc_required;
-  __ push(eax);
-  __ push(ebx);
-
-  __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
-  __ mov(edi, FieldOperand(edi, FixedArray::kLengthOffset));
-
-  // Allocate new FixedDoubleArray.
-  // edx: receiver
-  // edi: length of source FixedArray (smi-tagged)
-  __ lea(esi, Operand(edi, times_4, FixedDoubleArray::kHeaderSize));
-  __ AllocateInNewSpace(esi, eax, ebx, no_reg, &gc_required, TAG_OBJECT);
+  if (FLAG_trace_elements_transitions) {
+    KeyedStoreIC::GenerateRuntimeSetProperty(masm, strict_mode);
+  } else {
+    Label loop, entry, convert_hole, gc_required;
 
-  // eax: destination FixedDoubleArray
-  // edi: number of elements
-  // edx: receiver
-  __ mov(FieldOperand(eax, HeapObject::kMapOffset),
-         Immediate(masm->isolate()->factory()->fixed_double_array_map()));
-  __ mov(FieldOperand(eax, FixedDoubleArray::kLengthOffset), edi);
-  __ mov(esi, FieldOperand(edx, JSObject::kElementsOffset));
-  // Replace receiver's backing store with newly created FixedDoubleArray.
-  __ mov(FieldOperand(edx, JSObject::kElementsOffset), eax);
-  __ mov(ebx, eax);
-  __ RecordWriteField(edx,
+    __ push(eax);
+    __ push(ebx);
+    __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
+    __ mov(edi, FieldOperand(edi, FixedArray::kLengthOffset));
+
+    // Allocate new FixedDoubleArray.
+    // edx: receiver
+    // edi: length of source FixedArray (smi-tagged)
+    __ lea(esi, Operand(edi, times_4, FixedDoubleArray::kHeaderSize));
+    __ AllocateInNewSpace(esi, eax, ebx, no_reg, &gc_required, TAG_OBJECT);
+
+    // eax: destination FixedDoubleArray
+    // edi: number of elements
+    // edx: receiver
+    __ mov(FieldOperand(eax, HeapObject::kMapOffset),
+           Immediate(masm->isolate()->factory()->fixed_double_array_map()));
+    __ mov(FieldOperand(eax, FixedDoubleArray::kLengthOffset), edi);
+    __ mov(esi, FieldOperand(edx, JSObject::kElementsOffset));
+    // Replace receiver's backing store with newly created FixedDoubleArray.
+    __ mov(FieldOperand(edx, JSObject::kElementsOffset), eax);
+    __ mov(ebx, eax);
+    __ RecordWriteField(edx,
                       JSObject::kElementsOffset,
                       ebx,
                       edi,
@@ -7083,82 +7092,83 @@ void FastElementsConversionStub::GenerateSmiOnlyToDouble(
                       EMIT_REMEMBERED_SET,
                       OMIT_SMI_CHECK);
 
-  __ mov(edi, FieldOperand(esi, FixedArray::kLengthOffset));
-
-  // Prepare for conversion loop.
-  ExternalReference canonical_the_hole_nan_reference =
-      ExternalReference::address_of_the_hole_nan();
-  XMMRegister the_hole_nan = xmm1;
-  if (CpuFeatures::IsSupported(SSE2)) {
-    CpuFeatures::Scope use_sse2(SSE2);
-    __ movdbl(the_hole_nan,
-              Operand::StaticVariable(canonical_the_hole_nan_reference));
-  }
-  __ jmp(&entry);
-
-  // Call into runtime if GC is required.
-  __ bind(&gc_required);
-  // Restore registers before jumping into runtime.
-  __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
-  __ pop(ebx);
-  __ pop(eax);
-  KeyedStoreIC::GenerateRuntimeSetProperty(masm, strict_mode);
+    __ mov(edi, FieldOperand(esi, FixedArray::kLengthOffset));
 
-  // Convert and copy elements
-  // esi: source FixedArray
-  // edi: number of elements to convert/copy
-  __ bind(&loop);
-  __ sub(edi, Immediate(Smi::FromInt(1)));
-  __ mov(ebx, FieldOperand(esi, edi, times_2, FixedArray::kHeaderSize));
-  // ebx: current element from source
-  // edi: index of current element
-  __ JumpIfNotSmi(ebx, &convert_hole);
+    // Prepare for conversion loop.
+    ExternalReference canonical_the_hole_nan_reference =
+        ExternalReference::address_of_the_hole_nan();
+    XMMRegister the_hole_nan = xmm1;
+    if (CpuFeatures::IsSupported(SSE2)) {
+      CpuFeatures::Scope use_sse2(SSE2);
+      __ movdbl(the_hole_nan,
+                Operand::StaticVariable(canonical_the_hole_nan_reference));
+    }
+    __ jmp(&entry);
 
-  // Normal smi, convert it to double and store.
-  __ SmiUntag(ebx);
-  if (CpuFeatures::IsSupported(SSE2)) {
-    CpuFeatures::Scope fscope(SSE2);
-    __ cvtsi2sd(xmm0, ebx);
-    __ movdbl(FieldOperand(eax, edi, times_4, FixedDoubleArray::kHeaderSize),
-              xmm0);
-  } else {
-    __ push(ebx);
-    __ fild_s(Operand(esp, 0));
+    // Call into runtime if GC is required.
+    __ bind(&gc_required);
+    // Restore registers before jumping into runtime.
+    __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
     __ pop(ebx);
-    __ fstp_d(FieldOperand(eax, edi, times_4, FixedDoubleArray::kHeaderSize));
-  }
-  __ jmp(&entry);
+    __ pop(eax);
+    KeyedStoreIC::GenerateRuntimeSetProperty(masm, strict_mode);
+
+    // Convert and copy elements
+    // esi: source FixedArray
+    // edi: number of elements to convert/copy
+    __ bind(&loop);
+    __ sub(edi, Immediate(Smi::FromInt(1)));
+    __ mov(ebx, FieldOperand(esi, edi, times_2, FixedArray::kHeaderSize));
+    // ebx: current element from source
+    // edi: index of current element
+    __ JumpIfNotSmi(ebx, &convert_hole);
+
+    // Normal smi, convert it to double and store.
+    __ SmiUntag(ebx);
+    if (CpuFeatures::IsSupported(SSE2)) {
+      CpuFeatures::Scope fscope(SSE2);
+      __ cvtsi2sd(xmm0, ebx);
+      __ movdbl(FieldOperand(eax, edi, times_4, FixedDoubleArray::kHeaderSize),
+                xmm0);
+    } else {
+      __ push(ebx);
+      __ fild_s(Operand(esp, 0));
+      __ pop(ebx);
+      __ fstp_d(FieldOperand(eax, edi, times_4, FixedDoubleArray::kHeaderSize));
+    }
+    __ jmp(&entry);
 
-  // Found hole, store hole_nan_as_double instead.
-  __ bind(&convert_hole);
-  if (CpuFeatures::IsSupported(SSE2)) {
-    CpuFeatures::Scope use_sse2(SSE2);
-    __ movdbl(FieldOperand(eax, edi, times_4, FixedDoubleArray::kHeaderSize),
-              the_hole_nan);
-  } else {
-    __ fld_d(Operand::StaticVariable(canonical_the_hole_nan_reference));
-    __ fstp_d(FieldOperand(eax, edi, times_4, FixedDoubleArray::kHeaderSize));
-  }
+    // Found hole, store hole_nan_as_double instead.
+    __ bind(&convert_hole);
+    if (CpuFeatures::IsSupported(SSE2)) {
+      CpuFeatures::Scope use_sse2(SSE2);
+      __ movdbl(FieldOperand(eax, edi, times_4, FixedDoubleArray::kHeaderSize),
+                the_hole_nan);
+    } else {
+      __ fld_d(Operand::StaticVariable(canonical_the_hole_nan_reference));
+      __ fstp_d(FieldOperand(eax, edi, times_4, FixedDoubleArray::kHeaderSize));
+    }
 
-  __ bind(&entry);
-  __ test(edi, edi);
-  __ j(not_zero, &loop);
+    __ bind(&entry);
+    __ test(edi, edi);
+    __ j(not_zero, &loop);
 
-  __ pop(ebx);
-  __ pop(eax);
-  // eax: value
-  // ebx: target map
-  // Set transitioned map.
-  __ mov(FieldOperand(edx, HeapObject::kMapOffset), ebx);
-  __ RecordWriteField(edx,
-                      HeapObject::kMapOffset,
-                      ebx,
-                      edi,
-                      kDontSaveFPRegs,
-                      EMIT_REMEMBERED_SET,
-                      OMIT_SMI_CHECK);
-  // Restore esi.
-  __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
+    __ pop(ebx);
+    __ pop(eax);
+    // eax: value
+    // ebx: target map
+    // Set transitioned map.
+    __ mov(FieldOperand(edx, HeapObject::kMapOffset), ebx);
+    __ RecordWriteField(edx,
+                        HeapObject::kMapOffset,
+                        ebx,
+                        edi,
+                        kDontSaveFPRegs,
+                        EMIT_REMEMBERED_SET,
+                        OMIT_SMI_CHECK);
+    // Restore esi.
+    __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
+  }
 }
 
 
@@ -7171,105 +7181,111 @@ void FastElementsConversionStub::GenerateDoubleToObject(
   //  -- edx    : receiver
   //  -- esp[0] : return address
   // -----------------------------------
-  Label loop, entry, convert_hole, gc_required;
-  __ push(eax);
-  __ push(edx);
-  __ push(ebx);
-
-  __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
-  __ mov(ebx, FieldOperand(edi, FixedDoubleArray::kLengthOffset));
+  if (FLAG_trace_elements_transitions) {
+    KeyedStoreIC::GenerateRuntimeSetProperty(masm, strict_mode);
+  } else {
+    Label loop, entry, convert_hole, gc_required;
+    __ push(eax);
+    __ push(edx);
+    __ push(ebx);
 
-  // Allocate new FixedArray.
-  // ebx: length of source FixedDoubleArray (smi-tagged)
-  __ lea(edi, Operand(ebx, times_2, FixedArray::kHeaderSize));
-  __ AllocateInNewSpace(edi, eax, esi, no_reg, &gc_required, TAG_OBJECT);
+    __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
+    __ mov(ebx, FieldOperand(edi, FixedDoubleArray::kLengthOffset));
 
-  // eax: destination FixedArray
-  // ebx: number of elements
-  __ mov(FieldOperand(eax, HeapObject::kMapOffset),
-         Immediate(masm->isolate()->factory()->fixed_array_map()));
-  __ mov(FieldOperand(eax, FixedArray::kLengthOffset), ebx);
-  __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
+    // Allocate new FixedArray.
+    // ebx: length of source FixedDoubleArray (smi-tagged)
+    __ lea(edi, Operand(ebx, times_2, FixedArray::kHeaderSize));
+    __ AllocateInNewSpace(edi, eax, esi, no_reg, &gc_required, TAG_OBJECT);
 
-  __ jmp(&entry);
+    // eax: destination FixedArray
+    // ebx: number of elements
+    __ mov(FieldOperand(eax, HeapObject::kMapOffset),
+           Immediate(masm->isolate()->factory()->fixed_array_map()));
+    __ mov(FieldOperand(eax, FixedArray::kLengthOffset), ebx);
+    __ mov(edi, FieldOperand(edx, JSObject::kElementsOffset));
 
-  // Call into runtime if GC is required.
-  __ bind(&gc_required);
-  __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
-  __ pop(ebx);
-  __ pop(edx);
-  __ pop(eax);
-  KeyedStoreIC::GenerateRuntimeSetProperty(masm, strict_mode);
+    __ jmp(&entry);
 
-  // Box doubles into heap numbers.
-  // edi: source FixedDoubleArray
-  // eax: destination FixedArray
-  __ bind(&loop);
-  __ sub(ebx, Immediate(Smi::FromInt(1)));
-  // ebx: index of current element (smi-tagged)
-  uint32_t offset = FixedDoubleArray::kHeaderSize + sizeof(kHoleNanLower32);
-  __ cmp(FieldOperand(edi, ebx, times_4, offset), Immediate(kHoleNanUpper32));
-  __ j(equal, &convert_hole);
-
-  // Non-hole double, copy value into a heap number.
-  __ AllocateHeapNumber(edx, esi, no_reg, &gc_required);
-  // edx: new heap number
-  if (CpuFeatures::IsSupported(SSE2)) {
-    CpuFeatures::Scope fscope(SSE2);
-    __ movdbl(xmm0,
-              FieldOperand(edi, ebx, times_4, FixedDoubleArray::kHeaderSize));
-    __ movdbl(FieldOperand(edx, HeapNumber::kValueOffset), xmm0);
-  } else {
-    __ mov(esi, FieldOperand(edi, ebx, times_4, FixedDoubleArray::kHeaderSize));
-    __ mov(FieldOperand(edx, HeapNumber::kValueOffset), esi);
-    __ mov(esi, FieldOperand(edi, ebx, times_4, offset));
-    __ mov(FieldOperand(edx, HeapNumber::kValueOffset + kPointerSize), esi);
-  }
-  __ mov(FieldOperand(eax, ebx, times_2, FixedArray::kHeaderSize), edx);
-  __ mov(esi, ebx);
-  __ RecordWriteArray(eax,
-                      edx,
-                      esi,
-                      kDontSaveFPRegs,
-                      EMIT_REMEMBERED_SET,
-                      OMIT_SMI_CHECK);
-  __ jmp(&entry, Label::kNear);
+    // Call into runtime if GC is required.
+    __ bind(&gc_required);
+    __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
+    __ pop(ebx);
+    __ pop(edx);
+    __ pop(eax);
+    KeyedStoreIC::GenerateRuntimeSetProperty(masm, strict_mode);
+
+    // Box doubles into heap numbers.
+    // edi: source FixedDoubleArray
+    // eax: destination FixedArray
+    __ bind(&loop);
+    __ sub(ebx, Immediate(Smi::FromInt(1)));
+    // ebx: index of current element (smi-tagged)
+    uint32_t offset = FixedDoubleArray::kHeaderSize + sizeof(kHoleNanLower32);
+    __ cmp(FieldOperand(edi, ebx, times_4, offset), Immediate(kHoleNanUpper32));
+    __ j(equal, &convert_hole);
+
+    // Non-hole double, copy value into a heap number.
+    __ AllocateHeapNumber(edx, esi, no_reg, &gc_required);
+    // edx: new heap number
+    if (CpuFeatures::IsSupported(SSE2)) {
+      CpuFeatures::Scope fscope(SSE2);
+      __ movdbl(xmm0,
+                FieldOperand(edi, ebx, times_4, FixedDoubleArray::kHeaderSize));
+      __ movdbl(FieldOperand(edx, HeapNumber::kValueOffset), xmm0);
+    } else {
+      __ mov(esi, FieldOperand(edi, ebx, times_4,
+                               FixedDoubleArray::kHeaderSize));
+      __ mov(FieldOperand(edx, HeapNumber::kValueOffset), esi);
+      __ mov(esi, FieldOperand(edi, ebx, times_4, offset));
+      __ mov(FieldOperand(edx, HeapNumber::kValueOffset + kPointerSize), esi);
+    }
+    __ mov(FieldOperand(eax, ebx, times_2, FixedArray::kHeaderSize), edx);
+    __ mov(esi, ebx);
+    __ RecordWriteArray(eax,
+                        edx,
+                        esi,
+                        kDontSaveFPRegs,
+                        EMIT_REMEMBERED_SET,
+                        OMIT_SMI_CHECK);
+    __ jmp(&entry, Label::kNear);
 
-  // Replace the-hole NaN with the-hole pointer.
-  __ bind(&convert_hole);
-  __ mov(FieldOperand(eax, ebx, times_2, FixedArray::kHeaderSize),
-         masm->isolate()->factory()->the_hole_value());
+    // Replace the-hole NaN with the-hole pointer.
+    __ bind(&convert_hole);
+    __ mov(FieldOperand(eax, ebx, times_2, FixedArray::kHeaderSize),
+           masm->isolate()->factory()->the_hole_value());
 
-  __ bind(&entry);
-  __ test(ebx, ebx);
-  __ j(not_zero, &loop);
+    __ bind(&entry);
+    __ test(ebx, ebx);
+    __ j(not_zero, &loop);
 
-  __ pop(ebx);
-  __ pop(edx);
-  // ebx: target map
-  // edx: receiver
-  // Set transitioned map.
-  __ mov(FieldOperand(edx, HeapObject::kMapOffset), ebx);
-  __ RecordWriteField(edx,
-                      HeapObject::kMapOffset,
-                      ebx,
-                      edi,
-                      kDontSaveFPRegs,
-                      EMIT_REMEMBERED_SET,
-                      OMIT_SMI_CHECK);
-  // Replace receiver's backing store with newly created and filled FixedArray.
-  __ mov(FieldOperand(edx, JSObject::kElementsOffset), eax);
-  __ RecordWriteField(edx,
-                      JSObject::kElementsOffset,
-                      eax,
-                      edi,
-                      kDontSaveFPRegs,
-                      EMIT_REMEMBERED_SET,
-                      OMIT_SMI_CHECK);
+    __ pop(ebx);
+    __ pop(edx);
+    // ebx: target map
+    // edx: receiver
+    // Set transitioned map.
+    __ mov(FieldOperand(edx, HeapObject::kMapOffset), ebx);
+    __ RecordWriteField(edx,
+                        HeapObject::kMapOffset,
+                        ebx,
+                        edi,
+                        kDontSaveFPRegs,
+                        EMIT_REMEMBERED_SET,
+                        OMIT_SMI_CHECK);
+    // Replace receiver's backing store with newly created and filled
+    // FixedArray.
+    __ mov(FieldOperand(edx, JSObject::kElementsOffset), eax);
+    __ RecordWriteField(edx,
+                        JSObject::kElementsOffset,
+                        eax,
+                        edi,
+                        kDontSaveFPRegs,
+                        EMIT_REMEMBERED_SET,
+                        OMIT_SMI_CHECK);
 
-  // Restore registers.
-  __ pop(eax);
-  __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
+    // Restore registers.
+    __ pop(eax);
+    __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
+  }
 }
 
 #undef __
index 291c3c8..5e04e70 100644 (file)
@@ -112,6 +112,11 @@ PropertyDetails PropertyDetails::AsDeleted() {
   }
 
 
+bool Object::IsFixedArrayBase() {
+  return IsFixedArray() || IsFixedDoubleArray();
+}
+
+
 bool Object::IsInstanceOf(FunctionTemplateInfo* expected) {
   // There is a constraint on the object; check.
   if (!this->IsJSObject()) return false;
index fc75732..ecef891 100644 (file)
@@ -245,7 +245,7 @@ void ExternalDoubleArray::ExternalDoubleArrayPrint(FILE* out) {
 }
 
 
-static void PrintElementsKind(FILE* out, ElementsKind kind) {
+void PrintElementsKind(FILE* out, ElementsKind kind) {
   switch (kind) {
     case FAST_SMI_ONLY_ELEMENTS:
       PrintF(out, "FAST_SMI_ONLY_ELEMENTS");
index 8fc440e..028f243 100644 (file)
@@ -1097,6 +1097,27 @@ void JSObject::JSObjectShortPrint(StringStream* accumulator) {
 }
 
 
+void JSObject::PrintElementsTransition(
+    FILE* file, ElementsKind from_kind, FixedArrayBase* from_elements,
+    ElementsKind to_kind, FixedArrayBase* to_elements) {
+  if (from_kind != to_kind) {
+    PrintF(file, "elements transition [");
+    PrintElementsKind(file, from_kind);
+    PrintF(file, " -> ");
+    PrintElementsKind(file, to_kind);
+    PrintF(file, "] in ");
+    JavaScriptFrame::PrintTop(file, false, true);
+    PrintF(file, " for ");
+    ShortPrint(file);
+    PrintF(file, " from ");
+    from_elements->ShortPrint(file);
+    PrintF(file, " to ");
+    to_elements->ShortPrint(file);
+    PrintF(file, "\n");
+  }
+}
+
+
 void HeapObject::HeapObjectShortPrint(StringStream* accumulator) {
   Heap* heap = GetHeap();
   if (!heap->Contains(this)) {
@@ -1125,6 +1146,10 @@ void HeapObject::HeapObjectShortPrint(StringStream* accumulator) {
     case FIXED_ARRAY_TYPE:
       accumulator->Add("<FixedArray[%u]>", FixedArray::cast(this)->length());
       break;
+    case FIXED_DOUBLE_ARRAY_TYPE:
+      accumulator->Add("<FixedDoubleArray[%u]>",
+                       FixedDoubleArray::cast(this)->length());
+      break;
     case BYTE_ARRAY_TYPE:
       accumulator->Add("<ByteArray[%u]>", ByteArray::cast(this)->length());
       break;
@@ -8038,13 +8063,15 @@ MaybeObject* JSObject::SetFastElementsCapacityAndLength(
     new_map = Map::cast(object);
   }
 
+  FixedArrayBase* old_elements_raw = elements();
   ElementsKind elements_kind = GetElementsKind();
   switch (elements_kind) {
     case FAST_SMI_ONLY_ELEMENTS:
     case FAST_ELEMENTS: {
       AssertNoAllocation no_gc;
       WriteBarrierMode mode(new_elements->GetWriteBarrierMode(no_gc));
-      CopyFastElementsToFast(FixedArray::cast(elements()), new_elements, mode);
+      CopyFastElementsToFast(FixedArray::cast(old_elements_raw),
+                             new_elements, mode);
       set_map(new_map);
       set_elements(new_elements);
       break;
@@ -8052,7 +8079,7 @@ MaybeObject* JSObject::SetFastElementsCapacityAndLength(
     case DICTIONARY_ELEMENTS: {
       AssertNoAllocation no_gc;
       WriteBarrierMode mode = new_elements->GetWriteBarrierMode(no_gc);
-      CopySlowElementsToFast(NumberDictionary::cast(elements()),
+      CopySlowElementsToFast(NumberDictionary::cast(old_elements_raw),
                              new_elements,
                              mode);
       set_map(new_map);
@@ -8064,7 +8091,7 @@ MaybeObject* JSObject::SetFastElementsCapacityAndLength(
       WriteBarrierMode mode = new_elements->GetWriteBarrierMode(no_gc);
       // The object's map and the parameter map are unchanged, the unaliased
       // arguments are copied to the new backing store.
-      FixedArray* parameter_map = FixedArray::cast(elements());
+      FixedArray* parameter_map = FixedArray::cast(old_elements_raw);
       FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
       if (arguments->IsDictionary()) {
         CopySlowElementsToFast(NumberDictionary::cast(arguments),
@@ -8077,7 +8104,7 @@ MaybeObject* JSObject::SetFastElementsCapacityAndLength(
       break;
     }
     case FAST_DOUBLE_ELEMENTS: {
-      FixedDoubleArray* old_elements = FixedDoubleArray::cast(elements());
+      FixedDoubleArray* old_elements = FixedDoubleArray::cast(old_elements_raw);
       uint32_t old_length = static_cast<uint32_t>(old_elements->length());
       // Fill out the new array with this content and array holes.
       for (uint32_t i = 0; i < old_length; i++) {
@@ -8115,6 +8142,11 @@ MaybeObject* JSObject::SetFastElementsCapacityAndLength(
       break;
   }
 
+  if (FLAG_trace_elements_transitions) {
+    PrintElementsTransition(stdout, elements_kind, old_elements_raw,
+                            FAST_ELEMENTS, new_elements);
+  }
+
   // Update the length if necessary.
   if (IsJSArray()) {
     JSArray::cast(this)->set_length(Smi::FromInt(length));
@@ -8144,19 +8176,21 @@ MaybeObject* JSObject::SetFastDoubleElementsCapacityAndLength(
   }
   Map* new_map = Map::cast(obj);
 
+  FixedArrayBase* old_elements = elements();
+  ElementsKind elements_kind(GetElementsKind());
   AssertNoAllocation no_gc;
-  switch (GetElementsKind()) {
+  switch (elements_kind) {
     case FAST_SMI_ONLY_ELEMENTS:
     case FAST_ELEMENTS: {
-      elems->Initialize(FixedArray::cast(elements()));
+      elems->Initialize(FixedArray::cast(old_elements));
       break;
     }
     case FAST_DOUBLE_ELEMENTS: {
-      elems->Initialize(FixedDoubleArray::cast(elements()));
+      elems->Initialize(FixedDoubleArray::cast(old_elements));
       break;
     }
     case DICTIONARY_ELEMENTS: {
-      elems->Initialize(NumberDictionary::cast(elements()));
+      elems->Initialize(NumberDictionary::cast(old_elements));
       break;
     }
     default:
@@ -8164,6 +8198,11 @@ MaybeObject* JSObject::SetFastDoubleElementsCapacityAndLength(
       break;
   }
 
+  if (FLAG_trace_elements_transitions) {
+    PrintElementsTransition(stdout, elements_kind, old_elements,
+                            FAST_DOUBLE_ELEMENTS, elems);
+  }
+
   ASSERT(new_map->has_fast_double_elements());
   set_map(new_map);
   ASSERT(elems->IsFixedDoubleArray());
@@ -8183,13 +8222,14 @@ MaybeObject* JSObject::SetSlowElements(Object* len) {
 
   uint32_t new_length = static_cast<uint32_t>(len->Number());
 
-  switch (GetElementsKind()) {
+  FixedArrayBase* old_elements = elements();
+  ElementsKind elements_kind = GetElementsKind();
+  switch (elements_kind) {
     case FAST_SMI_ONLY_ELEMENTS:
     case FAST_ELEMENTS:
     case FAST_DOUBLE_ELEMENTS: {
       // Make sure we never try to shrink dense arrays into sparse arrays.
-      ASSERT(static_cast<uint32_t>(
-          FixedArrayBase::cast(elements())->length()) <= new_length);
+      ASSERT(static_cast<uint32_t>(old_elements->length()) <= new_length);
       MaybeObject* result = NormalizeElements();
       if (result->IsFailure()) return result;
 
@@ -8221,6 +8261,12 @@ MaybeObject* JSObject::SetSlowElements(Object* len) {
       UNREACHABLE();
       break;
   }
+
+  if (FLAG_trace_elements_transitions) {
+    PrintElementsTransition(stdout, elements_kind, old_elements,
+                            DICTIONARY_ELEMENTS, elements());
+  }
+
   return this;
 }
 
@@ -9148,6 +9194,10 @@ MaybeObject* JSObject::SetFastElement(uint32_t index,
     Map* new_map;
     if (!maybe_new_map->To<Map>(&new_map)) return maybe_new_map;
     set_map(new_map);
+    if (FLAG_trace_elements_transitions) {
+      PrintElementsTransition(stdout, FAST_SMI_ONLY_ELEMENTS, elements(),
+                              FAST_ELEMENTS, elements());
+    }
   }
   // Increase backing store capacity if that's been decided previously.
   if (new_capacity != capacity) {
index 27bd020..6c1d269 100644 (file)
@@ -173,6 +173,8 @@ enum ElementsKind {
 static const int kElementsKindCount =
     LAST_ELEMENTS_KIND - FIRST_ELEMENTS_KIND + 1;
 
+void PrintElementsKind(FILE* out, ElementsKind kind);
+
 // PropertyDetails captures type and attributes for a property.
 // They are used both in property dictionaries and instance descriptors.
 class PropertyDetails BASE_EMBEDDED {
@@ -857,6 +859,8 @@ class Object : public MaybeObject {
   HEAP_OBJECT_TYPE_LIST(IS_TYPE_FUNCTION_DECL)
 #undef IS_TYPE_FUNCTION_DECL
 
+  inline bool IsFixedArrayBase();
+
   // Returns true if this object is an instance of the specified
   // function template.
   inline bool IsInstanceOf(FunctionTemplateInfo* type);
@@ -1912,6 +1916,10 @@ class JSObject: public JSReceiver {
   void PrintElements(FILE* out);
 #endif
 
+  void PrintElementsTransition(
+      FILE* file, ElementsKind from_kind, FixedArrayBase* from_elements,
+      ElementsKind to_kind, FixedArrayBase* to_elements);
+
 #ifdef DEBUG
   // Structure for collecting spill information about JSObjects.
   class SpillInformation {
index efb7aee..c0d357a 100644 (file)
@@ -9045,42 +9045,6 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
 }
 
 
-// NOTE: These PrintXXX functions are defined for all builds (not just
-// DEBUG builds) because we may want to be able to trace function
-// calls in all modes.
-static void PrintString(String* str) {
-  // not uncommon to have empty strings
-  if (str->length() > 0) {
-    SmartArrayPointer<char> s =
-        str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
-    PrintF("%s", *s);
-  }
-}
-
-
-static void PrintObject(Object* obj) {
-  if (obj->IsSmi()) {
-    PrintF("%d", Smi::cast(obj)->value());
-  } else if (obj->IsString() || obj->IsSymbol()) {
-    PrintString(String::cast(obj));
-  } else if (obj->IsNumber()) {
-    PrintF("%g", obj->Number());
-  } else if (obj->IsFailure()) {
-    PrintF("<failure>");
-  } else if (obj->IsUndefined()) {
-    PrintF("<undefined>");
-  } else if (obj->IsNull()) {
-    PrintF("<null>");
-  } else if (obj->IsTrue()) {
-    PrintF("<true>");
-  } else if (obj->IsFalse()) {
-    PrintF("<false>");
-  } else {
-    PrintF("%p", reinterpret_cast<void*>(obj));
-  }
-}
-
-
 static int StackSize() {
   int n = 0;
   for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
@@ -9099,38 +9063,33 @@ static void PrintTransition(Object* result) {
   }
 
   if (result == NULL) {
-    // constructor calls
-    JavaScriptFrameIterator it;
-    JavaScriptFrame* frame = it.frame();
-    if (frame->IsConstructor()) PrintF("new ");
-    // function name
-    Object* fun = frame->function();
-    if (fun->IsJSFunction()) {
-      PrintObject(JSFunction::cast(fun)->shared()->name());
-    } else {
-      PrintObject(fun);
-    }
-    // function arguments
-    // (we are intentionally only printing the actually
-    // supplied parameters, not all parameters required)
-    PrintF("(this=");
-    PrintObject(frame->receiver());
-    const int length = frame->ComputeParametersCount();
-    for (int i = 0; i < length; i++) {
-      PrintF(", ");
-      PrintObject(frame->GetParameter(i));
-    }
-    PrintF(") {\n");
-
+    JavaScriptFrame::PrintTop(stdout, true, false);
+    PrintF(" {\n");
   } else {
     // function result
     PrintF("} -> ");
-    PrintObject(result);
+    result->ShortPrint();
     PrintF("\n");
   }
 }
 
 
+RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceElementsKindTransition) {
+  ASSERT(args.length() == 5);
+  CONVERT_ARG_CHECKED(JSObject, obj, 0);
+  CONVERT_SMI_ARG_CHECKED(from_kind, 1);
+  CONVERT_ARG_CHECKED(FixedArrayBase, from_elements, 2);
+  CONVERT_SMI_ARG_CHECKED(to_kind, 3);
+  CONVERT_ARG_CHECKED(FixedArrayBase, to_elements, 4);
+  NoHandleAllocation ha;
+  PrintF("*");
+  obj->PrintElementsTransition(stdout,
+      static_cast<ElementsKind>(from_kind), *from_elements,
+      static_cast<ElementsKind>(to_kind), *to_elements);
+  return isolate->heap()->undefined_value();
+}
+
+
 RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
   ASSERT(args.length() == 0);
   NoHandleAllocation ha;
index dc780e6..1d7c48a 100644 (file)
@@ -333,6 +333,7 @@ namespace internal {
   /* Debugging */ \
   F(DebugPrint, 1, 1) \
   F(DebugTrace, 0, 1) \
+  F(TraceElementsKindTransition, 5, 1) \
   F(TraceEnter, 0, 1) \
   F(TraceExit, 1, 1) \
   F(Abort, 2, 1) \