Commit f7563019 authored by danno@chromium.org's avatar danno@chromium.org

Add flag to trace element kind transitions

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
parent f985b15a
......@@ -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 {
......
......@@ -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,
......
......@@ -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")
......
......@@ -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();
......
......@@ -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);
......
This diff is collapsed.
......@@ -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;
......
......@@ -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");
......
......@@ -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) {
......
......@@ -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 {
......
......@@ -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;
......
......@@ -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) \
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment