Version 3.0.4
Added Date::ResetCache() to the API so that the cached values in the Date object can be reset to allow live DST / timezone changes.
Extended existing support for printing (while debugging) the contents of objects. Added support for printing objects from release builds.
Fixed V8 issues 989, 1006, and 1007.
git-svn-id: http://v8.googlecode.com/svn/trunk@6096 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/SConscript b/src/SConscript
index 8ab781e..dfa099c 100755
--- a/src/SConscript
+++ b/src/SConscript
@@ -230,7 +230,8 @@
'mode:release': [],
'mode:debug': [
'objects-debug.cc', 'prettyprinter.cc', 'regexp-macro-assembler-tracer.cc'
- ]
+ ],
+ 'objectprint:on': ['objects-debug.cc']
}
diff --git a/src/api.cc b/src/api.cc
index b85d658..110468e 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -3802,6 +3802,35 @@
}
+void v8::Date::DateTimeConfigurationChangeNotification() {
+ ON_BAILOUT("v8::Date::DateTimeConfigurationChangeNotification()", return);
+ LOG_API("Date::DateTimeConfigurationChangeNotification");
+ ENTER_V8;
+
+ HandleScope scope;
+
+ // Get the function ResetDateCache (defined in date-delay.js).
+ i::Handle<i::String> func_name_str =
+ i::Factory::LookupAsciiSymbol("ResetDateCache");
+ i::MaybeObject* result = i::Top::builtins()->GetProperty(*func_name_str);
+ i::Object* object_func;
+ if (!result->ToObject(&object_func)) {
+ return;
+ }
+
+ if (object_func->IsJSFunction()) {
+ i::Handle<i::JSFunction> func =
+ i::Handle<i::JSFunction>(i::JSFunction::cast(object_func));
+
+ // Call ResetDateCache(0 but expect no exceptions:
+ bool caught_exception = false;
+ i::Handle<i::Object> result =
+ i::Execution::TryCall(func, i::Top::builtins(), 0, NULL,
+ &caught_exception);
+ }
+}
+
+
static i::Handle<i::String> RegExpFlagsToString(RegExp::Flags flags) {
char flags_buf[3];
int num_flags = 0;
diff --git a/src/arm/code-stubs-arm.cc b/src/arm/code-stubs-arm.cc
index 3670765..5ec8584 100644
--- a/src/arm/code-stubs-arm.cc
+++ b/src/arm/code-stubs-arm.cc
@@ -2893,80 +2893,97 @@
}
-// This stub performs an instanceof, calling the builtin function if
-// necessary. Uses r1 for the object, r0 for the function that it may
-// be an instance of (these are fetched from the stack).
+// Uses registers r0 to r4. Expected input is
+// function in r0 (or at sp+1*ptrsz) and object in
+// r1 (or at sp), depending on whether or not
+// args_in_registers() is true.
void InstanceofStub::Generate(MacroAssembler* masm) {
- // Get the object - slow case for smis (we may need to throw an exception
- // depending on the rhs).
- Label slow, loop, is_instance, is_not_instance;
- __ ldr(r0, MemOperand(sp, 1 * kPointerSize));
- __ BranchOnSmi(r0, &slow);
+ // Fixed register usage throughout the stub:
+ const Register object = r1; // Object (lhs).
+ const Register map = r3; // Map of the object.
+ const Register function = r0; // Function (rhs).
+ const Register prototype = r4; // Prototype of the function.
+ const Register scratch = r2;
+ Label slow, loop, is_instance, is_not_instance, not_js_object;
+ if (!args_in_registers()) {
+ __ ldr(function, MemOperand(sp, 1 * kPointerSize));
+ __ ldr(object, MemOperand(sp, 0));
+ }
- // Check that the left hand is a JS object and put map in r3.
- __ CompareObjectType(r0, r3, r2, FIRST_JS_OBJECT_TYPE);
- __ b(lt, &slow);
- __ cmp(r2, Operand(LAST_JS_OBJECT_TYPE));
- __ b(gt, &slow);
-
- // Get the prototype of the function (r4 is result, r2 is scratch).
- __ ldr(r1, MemOperand(sp, 0));
- // r1 is function, r3 is map.
+ // Check that the left hand is a JS object and load map.
+ __ BranchOnSmi(object, &slow);
+ __ IsObjectJSObjectType(object, map, scratch, &slow);
// Look up the function and the map in the instanceof cache.
Label miss;
__ LoadRoot(ip, Heap::kInstanceofCacheFunctionRootIndex);
- __ cmp(r1, ip);
+ __ cmp(object, ip);
__ b(ne, &miss);
__ LoadRoot(ip, Heap::kInstanceofCacheMapRootIndex);
- __ cmp(r3, ip);
+ __ cmp(map, ip);
__ b(ne, &miss);
- __ LoadRoot(r0, Heap::kInstanceofCacheAnswerRootIndex);
- __ pop();
- __ pop();
- __ mov(pc, Operand(lr));
+ __ LoadRoot(function, Heap::kInstanceofCacheAnswerRootIndex);
+ __ Ret(args_in_registers() ? 0 : 2);
__ bind(&miss);
- __ TryGetFunctionPrototype(r1, r4, r2, &slow);
+ __ TryGetFunctionPrototype(object, prototype, scratch, &slow);
// Check that the function prototype is a JS object.
- __ BranchOnSmi(r4, &slow);
- __ CompareObjectType(r4, r5, r5, FIRST_JS_OBJECT_TYPE);
- __ b(lt, &slow);
- __ cmp(r5, Operand(LAST_JS_OBJECT_TYPE));
- __ b(gt, &slow);
+ __ BranchOnSmi(prototype, &slow);
+ __ IsObjectJSObjectType(prototype, scratch, scratch, &slow);
- __ StoreRoot(r1, Heap::kInstanceofCacheFunctionRootIndex);
- __ StoreRoot(r3, Heap::kInstanceofCacheMapRootIndex);
+ __ StoreRoot(object, Heap::kInstanceofCacheFunctionRootIndex);
+ __ StoreRoot(map, Heap::kInstanceofCacheMapRootIndex);
// Register mapping: r3 is object map and r4 is function prototype.
// Get prototype of object into r2.
- __ ldr(r2, FieldMemOperand(r3, Map::kPrototypeOffset));
+ __ ldr(scratch, FieldMemOperand(map, Map::kPrototypeOffset));
// Loop through the prototype chain looking for the function prototype.
__ bind(&loop);
- __ cmp(r2, Operand(r4));
+ __ cmp(scratch, Operand(prototype));
__ b(eq, &is_instance);
__ LoadRoot(ip, Heap::kNullValueRootIndex);
- __ cmp(r2, ip);
+ __ cmp(scratch, ip);
__ b(eq, &is_not_instance);
- __ ldr(r2, FieldMemOperand(r2, HeapObject::kMapOffset));
- __ ldr(r2, FieldMemOperand(r2, Map::kPrototypeOffset));
+ __ ldr(scratch, FieldMemOperand(scratch, HeapObject::kMapOffset));
+ __ ldr(scratch, FieldMemOperand(scratch, Map::kPrototypeOffset));
__ jmp(&loop);
__ bind(&is_instance);
__ mov(r0, Operand(Smi::FromInt(0)));
__ StoreRoot(r0, Heap::kInstanceofCacheAnswerRootIndex);
- __ pop();
- __ pop();
- __ mov(pc, Operand(lr)); // Return.
+ __ Ret(args_in_registers() ? 0 : 2);
__ bind(&is_not_instance);
__ mov(r0, Operand(Smi::FromInt(1)));
- __ StoreRoot(r0, Heap::kInstanceofCacheAnswerRootIndex);
- __ pop();
- __ pop();
- __ mov(pc, Operand(lr)); // Return.
+ __ Ret(args_in_registers() ? 0 : 2);
+
+ Label object_not_null, object_not_null_or_smi;
+ __ bind(¬_js_object);
+ // Before null, smi and string value checks, check that the rhs is a function
+ // as for a non-function rhs an exception needs to be thrown.
+ __ BranchOnSmi(function, &slow);
+ __ CompareObjectType(function, map, scratch, JS_FUNCTION_TYPE);
+ __ b(ne, &slow);
+
+ // Null is not instance of anything.
+ __ cmp(scratch, Operand(Factory::null_value()));
+ __ b(ne, &object_not_null);
+ __ mov(r0, Operand(Smi::FromInt(1)));
+ __ Ret(args_in_registers() ? 0 : 2);
+
+ __ bind(&object_not_null);
+ // Smi values are not instances of anything.
+ __ BranchOnNotSmi(object, &object_not_null_or_smi);
+ __ mov(r0, Operand(Smi::FromInt(1)));
+ __ Ret(args_in_registers() ? 0 : 2);
+
+ __ bind(&object_not_null_or_smi);
+ // String values are not instances of anything.
+ __ IsObjectJSStringType(object, scratch, &slow);
+ __ mov(r0, Operand(Smi::FromInt(1)));
+ __ Ret(args_in_registers() ? 0 : 2);
// Slow-case. Tail call builtin.
__ bind(&slow);
diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc
index 9c79231..e31d2e1 100644
--- a/src/arm/lithium-arm.cc
+++ b/src/arm/lithium-arm.cc
@@ -1316,7 +1316,8 @@
LInstruction* LChunkBuilder::DoInstanceOf(HInstanceOf* instr) {
LInstruction* result =
- new LInstanceOf(Use(instr->left()), Use(instr->right()));
+ new LInstanceOf(UseFixed(instr->left(), r1),
+ UseFixed(instr->right(), r0));
return MarkAsCall(DefineFixed(result, r0), instr);
}
@@ -1375,6 +1376,12 @@
case kMathLog:
Abort("MathLog LUnaryMathOperation not implemented");
return NULL;
+ case kMathCos:
+ Abort("MathCos LUnaryMathOperation not implemented");
+ return NULL;
+ case kMathSin:
+ Abort("MathSin LUnaryMathOperation not implemented");
+ return NULL;
default:
UNREACHABLE();
return NULL;
diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc
index 533d32c..dfc4891 100644
--- a/src/arm/lithium-codegen-arm.cc
+++ b/src/arm/lithium-codegen-arm.cc
@@ -1337,7 +1337,14 @@
void LCodeGen::DoInstanceOf(LInstanceOf* instr) {
- Abort("DoInstanceOf unimplemented.");
+ // We expect object and function in registers r1 and r0.
+ InstanceofStub stub(InstanceofStub::kArgsInRegisters);
+ CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
+
+ Label true_value, done;
+ __ tst(r0, r0);
+ __ mov(r0, Operand(Factory::false_value()), LeaveCC, eq);
+ __ mov(r0, Operand(Factory::true_value()), LeaveCC, ne);
}
@@ -1547,7 +1554,7 @@
void LCodeGen::DoMathAbs(LUnaryMathOperation* instr) {
- Abort("LUnaryMathOperation unimplemented.");
+ Abort("DoMathAbs unimplemented.");
}
@@ -1562,9 +1569,6 @@
void LCodeGen::DoUnaryMathOperation(LUnaryMathOperation* instr) {
- ASSERT(instr->op() == kMathFloor ||
- instr->op() == kMathAbs);
-
switch (instr->op()) {
case kMathAbs:
DoMathAbs(instr);
@@ -1576,6 +1580,7 @@
DoMathSqrt(instr);
break;
default:
+ Abort("Unimplemented type of LUnaryMathOperation.");
UNREACHABLE();
}
}
diff --git a/src/arm/macro-assembler-arm.cc b/src/arm/macro-assembler-arm.cc
index 6effec1..4a13146 100644
--- a/src/arm/macro-assembler-arm.cc
+++ b/src/arm/macro-assembler-arm.cc
@@ -178,6 +178,12 @@
}
+void MacroAssembler::Ret(int drop, Condition cond) {
+ Drop(drop, cond);
+ Ret(cond);
+}
+
+
void MacroAssembler::Swap(Register reg1,
Register reg2,
Register scratch,
@@ -821,6 +827,38 @@
}
+void MacroAssembler::IsObjectJSObjectType(Register heap_object,
+ Register map,
+ Register scratch,
+ Label* fail) {
+ ldr(map, FieldMemOperand(heap_object, HeapObject::kMapOffset));
+ IsInstanceJSObjectType(map, scratch, fail);
+}
+
+
+void MacroAssembler::IsInstanceJSObjectType(Register map,
+ Register scratch,
+ Label* fail) {
+ ldrb(scratch, FieldMemOperand(map, Map::kInstanceTypeOffset));
+ cmp(scratch, Operand(FIRST_JS_OBJECT_TYPE));
+ b(lt, fail);
+ cmp(scratch, Operand(LAST_JS_OBJECT_TYPE));
+ b(gt, fail);
+}
+
+
+void MacroAssembler::IsObjectJSStringType(Register object,
+ Register scratch,
+ Label* fail) {
+ ASSERT(kNotStringTag != 0);
+
+ ldr(scratch, FieldMemOperand(object, HeapObject::kMapOffset));
+ ldrb(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
+ tst(scratch, Operand(kIsNotStringMask));
+ b(nz, fail);
+}
+
+
#ifdef ENABLE_DEBUGGER_SUPPORT
void MacroAssembler::DebugBreak() {
ASSERT(allow_stub_calls());
diff --git a/src/arm/macro-assembler-arm.h b/src/arm/macro-assembler-arm.h
index 3da8726..97bbb2f 100644
--- a/src/arm/macro-assembler-arm.h
+++ b/src/arm/macro-assembler-arm.h
@@ -96,6 +96,7 @@
// from the stack, clobbering only the sp register.
void Drop(int count, Condition cond = al);
+ void Ret(int drop, Condition cond = al);
// Swap two registers. If the scratch register is omitted then a slightly
// less efficient form using xor instead of mov is emitted.
@@ -298,6 +299,18 @@
const ParameterCount& actual,
InvokeFlag flag);
+ void IsObjectJSObjectType(Register heap_object,
+ Register map,
+ Register scratch,
+ Label* fail);
+
+ void IsInstanceJSObjectType(Register map,
+ Register scratch,
+ Label* fail);
+
+ void IsObjectJSStringType(Register object,
+ Register scratch,
+ Label* fail);
#ifdef ENABLE_DEBUGGER_SUPPORT
// ---------------------------------------------------------------------------
diff --git a/src/array.js b/src/array.js
index a805157..0f1e969 100644
--- a/src/array.js
+++ b/src/array.js
@@ -1,4 +1,4 @@
-// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Copyright 2010 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -677,39 +677,76 @@
function QuickSort(a, from, to) {
// Insertion sort is faster for short arrays.
- if (to - from <= 22) {
+ if (to - from <= 10) {
InsertionSort(a, from, to);
return;
}
- var pivot_index = $floor($random() * (to - from)) + from;
- var pivot = a[pivot_index];
- // Issue 95: Keep the pivot element out of the comparisons to avoid
- // infinite recursion if comparefn(pivot, pivot) != 0.
- %_SwapElements(a, from, pivot_index);
- var low_end = from; // Upper bound of the elements lower than pivot.
- var high_start = to; // Lower bound of the elements greater than pivot.
+ // Find a pivot as the median of first, last and middle element.
+ var v0 = a[from];
+ var v1 = a[to - 1];
+ var middle_index = from + ((to - from) >> 1);
+ var v2 = a[middle_index];
+ var c01 = %_CallFunction(global_receiver, v0, v1, comparefn);
+ if (c01 > 0) {
+ // v1 < v0, so swap them.
+ var tmp = v0;
+ v0 = v1;
+ v1 = tmp;
+ } // v0 <= v1.
+ var c02 = %_CallFunction(global_receiver, v0, v2, comparefn);
+ if (c02 >= 0) {
+ // v2 <= v0 <= v1.
+ var tmp = v0;
+ v0 = v2;
+ v2 = v1;
+ v1 = tmp;
+ } else {
+ // v0 <= v1 && v0 < v2
+ var c12 = %_CallFunction(global_receiver, v1, v2, comparefn);
+ if (c12 > 0) {
+ // v0 <= v2 < v1
+ var tmp = v1;
+ v1 = v2;
+ v2 = tmp;
+ }
+ }
+ // v0 <= v1 <= v2
+ a[from] = v0;
+ a[to - 1] = v2;
+ var pivot = v1;
+ var low_end = from + 1; // Upper bound of elements lower than pivot.
+ var high_start = to - 1; // Lower bound of elements greater than pivot.
+ a[middle_index] = a[low_end];
+ a[low_end] = pivot;
+
// From low_end to i are elements equal to pivot.
// From i to high_start are elements that haven't been compared yet.
- for (var i = from + 1; i < high_start; ) {
+ partition: for (var i = low_end + 1; i < high_start; i++) {
var element = a[i];
var order = %_CallFunction(global_receiver, element, pivot, comparefn);
if (order < 0) {
%_SwapElements(a, i, low_end);
- i++;
low_end++;
} else if (order > 0) {
- high_start--;
+ do {
+ high_start--;
+ if (high_start == i) break partition;
+ var top_elem = a[high_start];
+ order = %_CallFunction(global_receiver, top_elem, pivot, comparefn);
+ } while (order > 0);
%_SwapElements(a, i, high_start);
- } else { // order == 0
- i++;
+ if (order < 0) {
+ %_SwapElements(a, i, low_end);
+ low_end++;
+ }
}
}
QuickSort(a, from, low_end);
QuickSort(a, high_start, to);
}
- // Copies elements in the range 0..length from obj's prototype chain
- // to obj itself, if obj has holes. Returns one more than the maximal index
+ // Copy elements in the range 0..length from obj's prototype chain
+ // to obj itself, if obj has holes. Return one more than the maximal index
// of a prototype property.
function CopyFromPrototype(obj, length) {
var max = 0;
diff --git a/src/assembler.cc b/src/assembler.cc
index 3b44efa..eeb8412 100644
--- a/src/assembler.cc
+++ b/src/assembler.cc
@@ -467,34 +467,35 @@
}
-void RelocInfo::Print() {
- PrintF("%p %s", pc_, RelocModeName(rmode_));
+void RelocInfo::Print(FILE* out) {
+ PrintF(out, "%p %s", pc_, RelocModeName(rmode_));
if (IsComment(rmode_)) {
- PrintF(" (%s)", reinterpret_cast<char*>(data_));
+ PrintF(out, " (%s)", reinterpret_cast<char*>(data_));
} else if (rmode_ == EMBEDDED_OBJECT) {
- PrintF(" (");
- target_object()->ShortPrint();
- PrintF(")");
+ PrintF(out, " (");
+ target_object()->ShortPrint(out);
+ PrintF(out, ")");
} else if (rmode_ == EXTERNAL_REFERENCE) {
ExternalReferenceEncoder ref_encoder;
- PrintF(" (%s) (%p)",
+ PrintF(out, " (%s) (%p)",
ref_encoder.NameOfAddress(*target_reference_address()),
*target_reference_address());
} else if (IsCodeTarget(rmode_)) {
Code* code = Code::GetCodeFromTargetAddress(target_address());
- PrintF(" (%s) (%p)", Code::Kind2String(code->kind()), target_address());
+ PrintF(out, " (%s) (%p)", Code::Kind2String(code->kind()),
+ target_address());
} else if (IsPosition(rmode_)) {
- PrintF(" (%" V8_PTR_PREFIX "d)", data());
+ PrintF(out, " (%" V8_PTR_PREFIX "d)", data());
} else if (rmode_ == RelocInfo::RUNTIME_ENTRY) {
// Depotimization bailouts are stored as runtime entries.
int id = Deoptimizer::GetDeoptimizationId(
target_address(), Deoptimizer::EAGER);
if (id != Deoptimizer::kNotDeoptimizationEntry) {
- PrintF(" (deoptimization bailout %d)", id);
+ PrintF(out, " (deoptimization bailout %d)", id);
}
}
- PrintF("\n");
+ PrintF(out, "\n");
}
#endif // ENABLE_DISASSEMBLER
diff --git a/src/assembler.h b/src/assembler.h
index 72a9b15..b68ad38 100644
--- a/src/assembler.h
+++ b/src/assembler.h
@@ -322,7 +322,7 @@
#ifdef ENABLE_DISASSEMBLER
// Printing
static const char* RelocModeName(Mode rmode);
- void Print();
+ void Print(FILE* out);
#endif // ENABLE_DISASSEMBLER
#ifdef DEBUG
// Debugging
diff --git a/src/builtins.cc b/src/builtins.cc
index a833119..21381f1 100644
--- a/src/builtins.cc
+++ b/src/builtins.cc
@@ -515,10 +515,10 @@
Object* elms_obj;
{ MaybeObject* maybe_elms_obj =
EnsureJSArrayWithWritableFastElements(receiver);
+ if (maybe_elms_obj == NULL) return CallJsBuiltin("ArrayShift", args);
if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
}
- if (elms_obj == NULL ||
- !IsJSArrayFastElementMovingAllowed(JSArray::cast(receiver))) {
+ if (!IsJSArrayFastElementMovingAllowed(JSArray::cast(receiver))) {
return CallJsBuiltin("ArrayShift", args);
}
FixedArray* elms = FixedArray::cast(elms_obj);
@@ -557,10 +557,10 @@
Object* elms_obj;
{ MaybeObject* maybe_elms_obj =
EnsureJSArrayWithWritableFastElements(receiver);
+ if (maybe_elms_obj == NULL) return CallJsBuiltin("ArrayUnshift", args);
if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
}
- if (elms_obj == NULL ||
- !IsJSArrayFastElementMovingAllowed(JSArray::cast(receiver))) {
+ if (!IsJSArrayFastElementMovingAllowed(JSArray::cast(receiver))) {
return CallJsBuiltin("ArrayUnshift", args);
}
FixedArray* elms = FixedArray::cast(elms_obj);
@@ -611,21 +611,46 @@
BUILTIN(ArraySlice) {
Object* receiver = *args.receiver();
- Object* elms_obj;
+ FixedArray* elms;
+ int len = -1;
{ MaybeObject* maybe_elms_obj =
EnsureJSArrayWithWritableFastElements(receiver);
- if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
- }
- if (elms_obj == NULL ||
- !IsJSArrayFastElementMovingAllowed(JSArray::cast(receiver))) {
- return CallJsBuiltin("ArraySlice", args);
- }
- FixedArray* elms = FixedArray::cast(elms_obj);
- JSArray* array = JSArray::cast(receiver);
- ASSERT(array->HasFastElements());
+ Object* elms_obj;
+ if (maybe_elms_obj != NULL && maybe_elms_obj->ToObject(&elms_obj)) {
+ if (!IsJSArrayFastElementMovingAllowed(JSArray::cast(receiver))) {
+ return CallJsBuiltin("ArraySlice", args);
+ }
+ elms = FixedArray::cast(elms_obj);
+ JSArray* array = JSArray::cast(receiver);
+ ASSERT(array->HasFastElements());
- int len = Smi::cast(array->length())->value();
+ len = Smi::cast(array->length())->value();
+ } else {
+ // Array.slice(arguments, ...) is quite a common idiom (notably more
+ // than 50% of invocations in Web apps). Treat it in C++ as well.
+ Map* arguments_map =
+ Top::context()->global_context()->arguments_boilerplate()->map();
+ bool is_arguments_object_with_fast_elements =
+ receiver->IsJSObject()
+ && JSObject::cast(receiver)->map() == arguments_map
+ && JSObject::cast(receiver)->HasFastElements();
+ if (!is_arguments_object_with_fast_elements) {
+ return CallJsBuiltin("ArraySlice", args);
+ }
+ elms = FixedArray::cast(JSObject::cast(receiver)->elements());
+ len = elms->length();
+#ifdef DEBUG
+ // Arguments object by construction should have no holes, check it.
+ if (FLAG_enable_slow_asserts) {
+ for (int i = 0; i < len; i++) {
+ ASSERT(elms->get(i) != Heap::the_hole_value());
+ }
+ }
+#endif
+ }
+ }
+ ASSERT(len >= 0);
int n_arguments = args.length() - 1;
// Note carefully choosen defaults---if argument is missing,
@@ -693,10 +718,10 @@
Object* elms_obj;
{ MaybeObject* maybe_elms_obj =
EnsureJSArrayWithWritableFastElements(receiver);
+ if (maybe_elms_obj == NULL) return CallJsBuiltin("ArraySplice", args);
if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
}
- if (elms_obj == NULL ||
- !IsJSArrayFastElementMovingAllowed(JSArray::cast(receiver))) {
+ if (!IsJSArrayFastElementMovingAllowed(JSArray::cast(receiver))) {
return CallJsBuiltin("ArraySplice", args);
}
FixedArray* elms = FixedArray::cast(elms_obj);
diff --git a/src/codegen.cc b/src/codegen.cc
index 8a64d77..da479e8 100644
--- a/src/codegen.cc
+++ b/src/codegen.cc
@@ -215,8 +215,17 @@
}
PrintF("\n\n");
}
- PrintF("--- Code ---\n");
- code->Disassemble(*function->name()->ToCString());
+ if (info->IsOptimizing()) {
+ if (FLAG_print_unopt_code) {
+ PrintF("--- Unoptimized code ---\n");
+ info->closure()->shared()->code()->Disassemble(
+ *function->debug_name()->ToCString());
+ }
+ PrintF("--- Optimized code ---\n");
+ } else {
+ PrintF("--- Code ---\n");
+ }
+ code->Disassemble(*function->debug_name()->ToCString());
}
#endif // ENABLE_DISASSEMBLER
}
diff --git a/src/counters.h b/src/counters.h
index aed46cf..048fdaa 100644
--- a/src/counters.h
+++ b/src/counters.h
@@ -28,6 +28,9 @@
#ifndef V8_COUNTERS_H_
#define V8_COUNTERS_H_
+#include "../include/v8.h"
+#include "allocation.h"
+
namespace v8 {
namespace internal {
diff --git a/src/date.js b/src/date.js
index 38bb8eb..bc70327 100644
--- a/src/date.js
+++ b/src/date.js
@@ -1007,6 +1007,39 @@
}
+function ResetDateCache() {
+
+ // Reset the local_time_offset:
+ local_time_offset = %DateLocalTimeOffset();
+
+ // Reset the DST offset cache:
+ var cache = DST_offset_cache;
+ cache.offset = 0;
+ cache.start = 0;
+ cache.end = -1;
+ cache.increment = 0;
+ cache.initial_increment = 19 * msPerDay;
+
+ // Reset the timezone cache:
+ timezone_cache_time = $NaN;
+ timezone_cache_timezone = undefined;
+
+ // Reset the ltcache:
+ ltcache.key = null;
+ ltcache.val = null;
+
+ // Reset the ymd_from_time_cache:
+ ymd_from_time_cache = [$NaN, $NaN, $NaN];
+ ymd_from_time_cached_time = $NaN;
+
+ // Reset the date cache:
+ cache = Date_cache;
+ cache.time = $NaN;
+ cache.year = $NaN;
+ cache.string = null;
+}
+
+
// -------------------------------------------------------------------
function SetupDate() {
diff --git a/src/debug.cc b/src/debug.cc
index 7709eb0..ca3c1db 100644
--- a/src/debug.cc
+++ b/src/debug.cc
@@ -858,7 +858,7 @@
if (caught_exception) return false;
// Debugger loaded.
- debug_context_ = Handle<Context>::cast(GlobalHandles::Create(*context));
+ debug_context_ = context;
return true;
}
diff --git a/src/deoptimizer.cc b/src/deoptimizer.cc
index 93839a4..dd70baa 100644
--- a/src/deoptimizer.cc
+++ b/src/deoptimizer.cc
@@ -1096,7 +1096,7 @@
}
-#ifdef DEBUG
+#ifdef OBJECT_PRINT
const char* Translation::StringFor(Opcode opcode) {
switch (opcode) {
diff --git a/src/deoptimizer.h b/src/deoptimizer.h
index 32edd10..2d7dfc8 100644
--- a/src/deoptimizer.h
+++ b/src/deoptimizer.h
@@ -476,7 +476,7 @@
static int NumberOfOperandsFor(Opcode opcode);
-#ifdef DEBUG
+#ifdef OBJECT_PRINT
static const char* StringFor(Opcode opcode);
#endif
diff --git a/src/flag-definitions.h b/src/flag-definitions.h
index facbec2..f160a85 100644
--- a/src/flag-definitions.h
+++ b/src/flag-definitions.h
@@ -296,6 +296,9 @@
DEFINE_bool(h, false, "print this message")
DEFINE_bool(new_snapshot, true, "use new snapshot implementation")
+// objects.cc
+DEFINE_bool(use_verbose_printer, true, "allows verbose printing")
+
// parser.cc
DEFINE_bool(allow_natives_syntax, false, "allow natives syntax")
@@ -503,6 +506,8 @@
// codegen-ia32.cc / codegen-arm.cc
DEFINE_bool(print_code, false, "print generated code")
DEFINE_bool(print_opt_code, false, "print optimized code")
+DEFINE_bool(print_unopt_code, false, "print unoptimized code before "
+ "printing optimized code based on it")
DEFINE_bool(print_code_verbose, false, "print more information for code")
DEFINE_bool(print_builtin_code, false, "print generated code for builtins")
diff --git a/src/full-codegen.cc b/src/full-codegen.cc
index 96307a3..58540f0 100644
--- a/src/full-codegen.cc
+++ b/src/full-codegen.cc
@@ -671,8 +671,12 @@
FullCodeGenerator::InlineFunctionGenerator
FullCodeGenerator::FindInlineFunctionGenerator(Runtime::FunctionId id) {
- return kInlineFunctionGenerators[
- static_cast<int>(id) - static_cast<int>(Runtime::kFirstInlineFunction)];
+ int lookup_index =
+ static_cast<int>(id) - static_cast<int>(Runtime::kFirstInlineFunction);
+ ASSERT(lookup_index >= 0);
+ ASSERT(static_cast<size_t>(lookup_index) <
+ ARRAY_SIZE(kInlineFunctionGenerators));
+ return kInlineFunctionGenerators[lookup_index];
}
@@ -684,7 +688,6 @@
ASSERT(function->intrinsic_type == Runtime::INLINE);
InlineFunctionGenerator generator =
FindInlineFunctionGenerator(function->function_id);
- ASSERT(generator != NULL);
((*this).*(generator))(args);
}
diff --git a/src/heap-profiler.cc b/src/heap-profiler.cc
index 0029500..dfda7c6 100644
--- a/src/heap-profiler.cc
+++ b/src/heap-profiler.cc
@@ -367,7 +367,6 @@
HeapSnapshot* HeapProfiler::TakeSnapshotImpl(const char* name,
int type,
v8::ActivityControl* control) {
- Heap::CollectAllGarbage(true);
HeapSnapshot::Type s_type = static_cast<HeapSnapshot::Type>(type);
HeapSnapshot* result =
snapshots_->NewSnapshot(s_type, name, next_snapshot_uid_++);
@@ -379,6 +378,7 @@
break;
}
case HeapSnapshot::kAggregated: {
+ Heap::CollectAllGarbage(true);
AggregatedHeapSnapshot agg_snapshot;
AggregatedHeapSnapshotGenerator generator(&agg_snapshot);
generator.GenerateSnapshot();
@@ -808,7 +808,7 @@
void AggregatedHeapSnapshotGenerator::GenerateSnapshot() {
- HeapIterator iterator(HeapIterator::kPreciseFiltering);
+ HeapIterator iterator(HeapIterator::kFilterFreeListNodes);
for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
CollectStats(obj);
agg_snapshot_->js_cons_profile()->CollectStats(obj);
diff --git a/src/heap.cc b/src/heap.cc
index ccf9b47..1e99991 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -4483,7 +4483,7 @@
MemoryAllocator::Size() + MemoryAllocator::Available();
*stats->os_error = OS::GetLastError();
if (take_snapshot) {
- HeapIterator iterator(HeapIterator::kPreciseFiltering);
+ HeapIterator iterator(HeapIterator::kFilterFreeListNodes);
for (HeapObject* obj = iterator.next();
obj != NULL;
obj = iterator.next()) {
@@ -4917,13 +4917,20 @@
}
-class FreeListNodesFilter {
+class HeapObjectsFilter {
+ public:
+ virtual ~HeapObjectsFilter() {}
+ virtual bool SkipObject(HeapObject* object) = 0;
+};
+
+
+class FreeListNodesFilter : public HeapObjectsFilter {
public:
FreeListNodesFilter() {
MarkFreeListNodes();
}
- inline bool IsFreeListNode(HeapObject* object) {
+ bool SkipObject(HeapObject* object) {
if (object->IsMarked()) {
object->ClearMark();
return true;
@@ -4955,6 +4962,65 @@
};
+class UnreachableObjectsFilter : public HeapObjectsFilter {
+ public:
+ UnreachableObjectsFilter() {
+ MarkUnreachableObjects();
+ }
+
+ bool SkipObject(HeapObject* object) {
+ if (object->IsMarked()) {
+ object->ClearMark();
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ private:
+ class UnmarkingVisitor : public ObjectVisitor {
+ public:
+ UnmarkingVisitor() : list_(10) {}
+
+ void VisitPointers(Object** start, Object** end) {
+ for (Object** p = start; p < end; p++) {
+ if (!(*p)->IsHeapObject()) continue;
+ HeapObject* obj = HeapObject::cast(*p);
+ if (obj->IsMarked()) {
+ obj->ClearMark();
+ list_.Add(obj);
+ }
+ }
+ }
+
+ bool can_process() { return !list_.is_empty(); }
+
+ void ProcessNext() {
+ HeapObject* obj = list_.RemoveLast();
+ obj->Iterate(this);
+ }
+
+ private:
+ List<HeapObject*> list_;
+ };
+
+ void MarkUnreachableObjects() {
+ HeapIterator iterator;
+ for (HeapObject* obj = iterator.next();
+ obj != NULL;
+ obj = iterator.next()) {
+ obj->SetMark();
+ }
+ UnmarkingVisitor visitor;
+ Heap::IterateRoots(&visitor, VISIT_ONLY_STRONG);
+ while (visitor.can_process())
+ visitor.ProcessNext();
+ }
+
+ AssertNoAllocation no_alloc;
+};
+
+
HeapIterator::HeapIterator()
: filtering_(HeapIterator::kNoFiltering),
filter_(NULL) {
@@ -4962,7 +5028,7 @@
}
-HeapIterator::HeapIterator(HeapIterator::FreeListNodesFiltering filtering)
+HeapIterator::HeapIterator(HeapIterator::HeapObjectsFiltering filtering)
: filtering_(filtering),
filter_(NULL) {
Init();
@@ -4976,12 +5042,17 @@
void HeapIterator::Init() {
// Start the iteration.
- if (filtering_ == kPreciseFiltering) {
- filter_ = new FreeListNodesFilter;
- space_iterator_ =
- new SpaceIterator(MarkCompactCollector::SizeOfMarkedObject);
- } else {
- space_iterator_ = new SpaceIterator;
+ space_iterator_ = filtering_ == kNoFiltering ? new SpaceIterator :
+ new SpaceIterator(MarkCompactCollector::SizeOfMarkedObject);
+ switch (filtering_) {
+ case kFilterFreeListNodes:
+ filter_ = new FreeListNodesFilter;
+ break;
+ case kFilterUnreachable:
+ filter_ = new UnreachableObjectsFilter;
+ break;
+ default:
+ break;
}
object_iterator_ = space_iterator_->next();
}
@@ -4989,9 +5060,9 @@
void HeapIterator::Shutdown() {
#ifdef DEBUG
- // Assert that in precise mode we have iterated through all
+ // Assert that in filtering mode we have iterated through all
// objects. Otherwise, heap will be left in an inconsistent state.
- if (filtering_ == kPreciseFiltering) {
+ if (filtering_ != kNoFiltering) {
ASSERT(object_iterator_ == NULL);
}
#endif
@@ -5008,7 +5079,7 @@
if (filter_ == NULL) return NextObject();
HeapObject* obj = NextObject();
- while (obj != NULL && filter_->IsFreeListNode(obj)) obj = NextObject();
+ while (obj != NULL && filter_->SkipObject(obj)) obj = NextObject();
return obj;
}
diff --git a/src/heap.h b/src/heap.h
index fbcc70d..c2d36e2 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -1585,17 +1585,18 @@
// nodes filtering uses GC marks, it can't be used during MS/MC GC
// phases. Also, it is forbidden to interrupt iteration in this mode,
// as this will leave heap objects marked (and thus, unusable).
-class FreeListNodesFilter;
+class HeapObjectsFilter;
class HeapIterator BASE_EMBEDDED {
public:
- enum FreeListNodesFiltering {
+ enum HeapObjectsFiltering {
kNoFiltering,
- kPreciseFiltering
+ kFilterFreeListNodes,
+ kFilterUnreachable
};
HeapIterator();
- explicit HeapIterator(FreeListNodesFiltering filtering);
+ explicit HeapIterator(HeapObjectsFiltering filtering);
~HeapIterator();
HeapObject* next();
@@ -1608,8 +1609,8 @@
void Shutdown();
HeapObject* NextObject();
- FreeListNodesFiltering filtering_;
- FreeListNodesFilter* filter_;
+ HeapObjectsFiltering filtering_;
+ HeapObjectsFilter* filter_;
// Space iterator for iterating all the spaces.
SpaceIterator* space_iterator_;
// Object iterator for the space currently being iterated.
@@ -1968,6 +1969,8 @@
class TranscendentalCache {
public:
enum Type {ACOS, ASIN, ATAN, COS, EXP, LOG, SIN, TAN, kNumberOfCaches};
+ static const int kTranscendentalTypeBits = 3;
+ STATIC_ASSERT((1 << kTranscendentalTypeBits) >= kNumberOfCaches);
explicit TranscendentalCache(Type t);
diff --git a/src/hydrogen-instructions.cc b/src/hydrogen-instructions.cc
index a96ee40..3f39888 100644
--- a/src/hydrogen-instructions.cc
+++ b/src/hydrogen-instructions.cc
@@ -579,6 +579,13 @@
}
+void HCompareMapAndBranch::PrintDataTo(StringStream* stream) const {
+ stream->Add("on ");
+ value()->PrintNameTo(stream);
+ stream->Add(" (%p)", *map());
+}
+
+
void HGoto::PrintDataTo(StringStream* stream) const {
stream->Add("B%d", FirstSuccessor()->block_id());
}
diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h
index aafa7a8..cbbe8fc 100644
--- a/src/hydrogen-instructions.h
+++ b/src/hydrogen-instructions.h
@@ -905,6 +905,8 @@
virtual HBasicBlock* FirstSuccessor() const { return true_destination_; }
virtual HBasicBlock* SecondSuccessor() const { return false_destination_; }
+ virtual void PrintDataTo(StringStream* stream) const;
+
Handle<Map> map() const { return map_; }
DECLARE_CONCRETE_INSTRUCTION(CompareMapAndBranch, "compare_map_and_branch")
@@ -1387,6 +1389,8 @@
case kMathSqrt:
case kMathPowHalf:
case kMathLog:
+ case kMathSin:
+ case kMathCos:
set_representation(Representation::Double());
break;
default:
@@ -1409,6 +1413,8 @@
case kMathSqrt:
case kMathPowHalf:
case kMathLog:
+ case kMathSin:
+ case kMathCos:
return Representation::Double();
break;
case kMathAbs:
diff --git a/src/hydrogen.cc b/src/hydrogen.cc
index 32108dc..e34acd6 100644
--- a/src/hydrogen.cc
+++ b/src/hydrogen.cc
@@ -3165,6 +3165,9 @@
if (lookup->type() == MAP_TRANSITION) {
Handle<Map> transition(lookup->GetTransitionMapFromMap(*type));
instr->set_transition(transition);
+ // TODO(fschneider): Record the new map type of the object in the IR to
+ // enable elimination of redundant checks after the transition store.
+ instr->SetFlag(HValue::kChangesMaps);
}
return instr;
}
@@ -3529,9 +3532,10 @@
maps.Add(map);
HSubgraph* subgraph = CreateBranchSubgraph(environment());
SubgraphScope scope(this, subgraph);
- HInstruction* instr =
+ HLoadNamedField* instr =
BuildLoadNamedField(object, expr, map, &lookup, false);
instr->set_position(expr->position());
+ instr->ClearFlag(HValue::kUseGVN); // Don't do GVN on polymorphic loads.
PushAndAdd(instr);
subgraphs.Add(subgraph);
} else {
@@ -3570,11 +3574,11 @@
}
-HInstruction* HGraphBuilder::BuildLoadNamedField(HValue* object,
- Property* expr,
- Handle<Map> type,
- LookupResult* lookup,
- bool smi_and_map_check) {
+HLoadNamedField* HGraphBuilder::BuildLoadNamedField(HValue* object,
+ Property* expr,
+ Handle<Map> type,
+ LookupResult* lookup,
+ bool smi_and_map_check) {
if (smi_and_map_check) {
AddInstruction(new HCheckNonSmi(object));
AddInstruction(new HCheckMap(object, type));
@@ -4093,6 +4097,8 @@
case kMathAbs:
case kMathSqrt:
case kMathLog:
+ case kMathSin:
+ case kMathCos:
if (argument_count == 2) {
HValue* argument = Pop();
Drop(1); // Receiver.
@@ -4169,7 +4175,7 @@
if (args->length() != 2) return false;
VariableProxy* arg_two = args->at(1)->AsVariableProxy();
- if (arg_two == NULL) return false;
+ if (arg_two == NULL || !arg_two->var()->IsStackAllocated()) return false;
HValue* arg_two_value = environment()->Lookup(arg_two->var());
if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false;
diff --git a/src/hydrogen.h b/src/hydrogen.h
index 2c9aeac..ebabf3d 100644
--- a/src/hydrogen.h
+++ b/src/hydrogen.h
@@ -786,11 +786,11 @@
HValue* left,
HValue* right);
HInstruction* BuildIncrement(HValue* value, bool increment);
- HInstruction* BuildLoadNamedField(HValue* object,
- Property* expr,
- Handle<Map> type,
- LookupResult* result,
- bool smi_and_map_check);
+ HLoadNamedField* BuildLoadNamedField(HValue* object,
+ Property* expr,
+ Handle<Map> type,
+ LookupResult* result,
+ bool smi_and_map_check);
HInstruction* BuildLoadNamedGeneric(HValue* object, Property* expr);
HInstruction* BuildLoadKeyedFastElement(HValue* object,
HValue* key,
diff --git a/src/ia32/code-stubs-ia32.cc b/src/ia32/code-stubs-ia32.cc
index d75acab..a371c96 100644
--- a/src/ia32/code-stubs-ia32.cc
+++ b/src/ia32/code-stubs-ia32.cc
@@ -2472,41 +2472,65 @@
void TranscendentalCacheStub::Generate(MacroAssembler* masm) {
- // Input on stack:
- // esp[4]: argument (should be number).
- // esp[0]: return address.
- // Test that eax is a number.
+ // TAGGED case:
+ // Input:
+ // esp[4]: tagged number input argument (should be number).
+ // esp[0]: return address.
+ // Output:
+ // eax: tagged double result.
+ // UNTAGGED case:
+ // Input::
+ // esp[0]: return address.
+ // xmm1: untagged double input argument
+ // Output:
+ // xmm1: untagged double result.
+
Label runtime_call;
Label runtime_call_clear_stack;
- NearLabel input_not_smi;
- NearLabel loaded;
- __ mov(eax, Operand(esp, kPointerSize));
- __ test(eax, Immediate(kSmiTagMask));
- __ j(not_zero, &input_not_smi);
- // Input is a smi. Untag and load it onto the FPU stack.
- // Then load the low and high words of the double into ebx, edx.
- STATIC_ASSERT(kSmiTagSize == 1);
- __ sar(eax, 1);
- __ sub(Operand(esp), Immediate(2 * kPointerSize));
- __ mov(Operand(esp, 0), eax);
- __ fild_s(Operand(esp, 0));
- __ fst_d(Operand(esp, 0));
- __ pop(edx);
- __ pop(ebx);
- __ jmp(&loaded);
- __ bind(&input_not_smi);
- // Check if input is a HeapNumber.
- __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
- __ cmp(Operand(ebx), Immediate(Factory::heap_number_map()));
- __ j(not_equal, &runtime_call);
- // Input is a HeapNumber. Push it on the FPU stack and load its
- // low and high words into ebx, edx.
- __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
- __ mov(edx, FieldOperand(eax, HeapNumber::kExponentOffset));
- __ mov(ebx, FieldOperand(eax, HeapNumber::kMantissaOffset));
+ Label skip_cache;
+ const bool tagged = (argument_type_ == TAGGED);
+ if (tagged) {
+ // Test that eax is a number.
+ NearLabel input_not_smi;
+ NearLabel loaded;
+ __ mov(eax, Operand(esp, kPointerSize));
+ __ test(eax, Immediate(kSmiTagMask));
+ __ j(not_zero, &input_not_smi);
+ // Input is a smi. Untag and load it onto the FPU stack.
+ // Then load the low and high words of the double into ebx, edx.
+ STATIC_ASSERT(kSmiTagSize == 1);
+ __ sar(eax, 1);
+ __ sub(Operand(esp), Immediate(2 * kPointerSize));
+ __ mov(Operand(esp, 0), eax);
+ __ fild_s(Operand(esp, 0));
+ __ fst_d(Operand(esp, 0));
+ __ pop(edx);
+ __ pop(ebx);
+ __ jmp(&loaded);
+ __ bind(&input_not_smi);
+ // Check if input is a HeapNumber.
+ __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
+ __ cmp(Operand(ebx), Immediate(Factory::heap_number_map()));
+ __ j(not_equal, &runtime_call);
+ // Input is a HeapNumber. Push it on the FPU stack and load its
+ // low and high words into ebx, edx.
+ __ fld_d(FieldOperand(eax, HeapNumber::kValueOffset));
+ __ mov(edx, FieldOperand(eax, HeapNumber::kExponentOffset));
+ __ mov(ebx, FieldOperand(eax, HeapNumber::kMantissaOffset));
- __ bind(&loaded);
- // ST[0] == double value
+ __ bind(&loaded);
+ } else { // UNTAGGED.
+ if (CpuFeatures::IsSupported(SSE4_1)) {
+ CpuFeatures::Scope sse4_scope(SSE4_1);
+ __ pextrd(Operand(edx), xmm1, 0x1); // copy xmm1[63..32] to edx.
+ } else {
+ __ pshufd(xmm0, xmm1, 0x1);
+ __ movd(Operand(edx), xmm0);
+ }
+ __ movd(Operand(ebx), xmm1);
+ }
+
+ // ST[0] or xmm1 == double value
// ebx = low 32 bits of double value
// edx = high 32 bits of double value
// Compute hash (the shifts are arithmetic):
@@ -2522,7 +2546,7 @@
ASSERT(IsPowerOf2(TranscendentalCache::kCacheSize));
__ and_(Operand(ecx), Immediate(TranscendentalCache::kCacheSize - 1));
- // ST[0] == double value.
+ // ST[0] or xmm1 == double value.
// ebx = low 32 bits of double value.
// edx = high 32 bits of double value.
// ecx = TranscendentalCache::hash(double value).
@@ -2559,31 +2583,80 @@
__ j(not_equal, &cache_miss);
// Cache hit!
__ mov(eax, Operand(ecx, 2 * kIntSize));
- __ fstp(0);
- __ ret(kPointerSize);
+ if (tagged) {
+ __ fstp(0);
+ __ ret(kPointerSize);
+ } else { // UNTAGGED.
+ __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset));
+ __ Ret();
+ }
__ bind(&cache_miss);
// Update cache with new value.
// We are short on registers, so use no_reg as scratch.
// This gives slightly larger code.
- __ AllocateHeapNumber(eax, edi, no_reg, &runtime_call_clear_stack);
+ if (tagged) {
+ __ AllocateHeapNumber(eax, edi, no_reg, &runtime_call_clear_stack);
+ } else { // UNTAGGED.
+ __ AllocateHeapNumber(eax, edi, no_reg, &skip_cache);
+ __ sub(Operand(esp), Immediate(kDoubleSize));
+ __ movdbl(Operand(esp, 0), xmm1);
+ __ fld_d(Operand(esp, 0));
+ __ add(Operand(esp), Immediate(kDoubleSize));
+ }
GenerateOperation(masm);
__ mov(Operand(ecx, 0), ebx);
__ mov(Operand(ecx, kIntSize), edx);
__ mov(Operand(ecx, 2 * kIntSize), eax);
__ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
- __ ret(kPointerSize);
+ if (tagged) {
+ __ ret(kPointerSize);
+ } else { // UNTAGGED.
+ __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset));
+ __ Ret();
- __ bind(&runtime_call_clear_stack);
- __ fstp(0);
- __ bind(&runtime_call);
- __ TailCallExternalReference(ExternalReference(RuntimeFunction()), 1, 1);
+ // Skip cache and return answer directly, only in untagged case.
+ __ bind(&skip_cache);
+ __ sub(Operand(esp), Immediate(kDoubleSize));
+ __ movdbl(Operand(esp, 0), xmm1);
+ __ fld_d(Operand(esp, 0));
+ GenerateOperation(masm);
+ __ fstp_d(Operand(esp, 0));
+ __ movdbl(xmm1, Operand(esp, 0));
+ __ add(Operand(esp), Immediate(kDoubleSize));
+ // We return the value in xmm1 without adding it to the cache, but
+ // we cause a scavenging GC so that future allocations will succeed.
+ __ EnterInternalFrame();
+ // Allocate an unused object bigger than a HeapNumber.
+ __ push(Immediate(Smi::FromInt(2 * kDoubleSize)));
+ __ CallRuntimeSaveDoubles(Runtime::kAllocateInNewSpace);
+ __ LeaveInternalFrame();
+ __ Ret();
+ }
+
+ // Call runtime, doing whatever allocation and cleanup is necessary.
+ if (tagged) {
+ __ bind(&runtime_call_clear_stack);
+ __ fstp(0);
+ __ bind(&runtime_call);
+ __ TailCallExternalReference(ExternalReference(RuntimeFunction()), 1, 1);
+ } else { // UNTAGGED.
+ __ bind(&runtime_call_clear_stack);
+ __ bind(&runtime_call);
+ __ AllocateHeapNumber(eax, edi, no_reg, &skip_cache);
+ __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm1);
+ __ EnterInternalFrame();
+ __ push(eax);
+ __ CallRuntime(RuntimeFunction(), 1);
+ __ LeaveInternalFrame();
+ __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset));
+ __ Ret();
+ }
}
Runtime::FunctionId TranscendentalCacheStub::RuntimeFunction() {
switch (type_) {
- // Add more cases when necessary.
case TranscendentalCache::SIN: return Runtime::kMath_sin;
case TranscendentalCache::COS: return Runtime::kMath_cos;
case TranscendentalCache::LOG: return Runtime::kMath_log;
@@ -2596,14 +2669,14 @@
void TranscendentalCacheStub::GenerateOperation(MacroAssembler* masm) {
// Only free register is edi.
- // Input value is on FP stack, and also in ebx/edx. Address of result
- // (a newly allocated HeapNumber) is in eax.
- NearLabel done;
+ // Input value is on FP stack, and also in ebx/edx.
+ // Input value is possibly in xmm1.
+ // Address of result (a newly allocated HeapNumber) may be in eax.
if (type_ == TranscendentalCache::SIN || type_ == TranscendentalCache::COS) {
// Both fsin and fcos require arguments in the range +/-2^63 and
// return NaN for infinities and NaN. They can share all code except
// the actual fsin/fcos operation.
- NearLabel in_range;
+ NearLabel in_range, done;
// If argument is outside the range -2^63..2^63, fsin/cos doesn't
// work. We must reduce it to the appropriate range.
__ mov(edi, edx);
@@ -2683,145 +2756,6 @@
}
-void TranscendentalCacheSSE2Stub::Generate(MacroAssembler* masm) {
- // Input on stack:
- // esp[0]: return address.
- // Input in registers:
- // xmm1: untagged double input argument.
- // Output:
- // xmm1: untagged double result.
- Label skip_cache;
- Label call_runtime;
-
- // Input is an untagged double in xmm1.
- // Compute hash (the shifts are arithmetic):
- // h = (low ^ high); h ^= h >> 16; h ^= h >> 8; h = h & (cacheSize - 1);
- if (CpuFeatures::IsSupported(SSE4_1)) {
- CpuFeatures::Scope sse4_scope(SSE4_1);
- __ pextrd(Operand(edx), xmm1, 0x1); // copy xmm1[63..32] to edx.
- } else {
- __ pshufd(xmm0, xmm1, 0x1);
- __ movd(Operand(edx), xmm0);
- }
- __ movd(Operand(ebx), xmm1);
-
- // xmm1 = double value
- // ebx = low 32 bits of double value
- // edx = high 32 bits of double value
- // Compute hash (the shifts are arithmetic):
- // h = (low ^ high); h ^= h >> 16; h ^= h >> 8; h = h & (cacheSize - 1);
- __ mov(ecx, ebx);
- __ xor_(ecx, Operand(edx));
- __ mov(eax, ecx);
- __ sar(eax, 16);
- __ xor_(ecx, Operand(eax));
- __ mov(eax, ecx);
- __ sar(eax, 8);
- __ xor_(ecx, Operand(eax));
- ASSERT(IsPowerOf2(TranscendentalCache::kCacheSize));
- __ and_(Operand(ecx), Immediate(TranscendentalCache::kCacheSize - 1));
-
- // xmm1 = double value.
- // ebx = low 32 bits of double value.
- // edx = high 32 bits of double value.
- // ecx = TranscendentalCache::hash(double value).
- __ mov(eax,
- Immediate(ExternalReference::transcendental_cache_array_address()));
- // Eax points to cache array.
- __ mov(eax, Operand(eax, type_ * sizeof(TranscendentalCache::caches_[0])));
- // Eax points to the cache for the type type_.
- // If NULL, the cache hasn't been initialized yet, so go through runtime.
- __ test(eax, Operand(eax));
- __ j(zero, &call_runtime);
-#ifdef DEBUG
- // Check that the layout of cache elements match expectations.
- { TranscendentalCache::Element test_elem[2];
- char* elem_start = reinterpret_cast<char*>(&test_elem[0]);
- char* elem2_start = reinterpret_cast<char*>(&test_elem[1]);
- char* elem_in0 = reinterpret_cast<char*>(&(test_elem[0].in[0]));
- char* elem_in1 = reinterpret_cast<char*>(&(test_elem[0].in[1]));
- char* elem_out = reinterpret_cast<char*>(&(test_elem[0].output));
- CHECK_EQ(12, elem2_start - elem_start); // Two uint_32's and a pointer.
- CHECK_EQ(0, elem_in0 - elem_start);
- CHECK_EQ(kIntSize, elem_in1 - elem_start);
- CHECK_EQ(2 * kIntSize, elem_out - elem_start);
- }
-#endif
- // Find the address of the ecx'th entry in the cache, i.e., &eax[ecx*12].
- __ lea(ecx, Operand(ecx, ecx, times_2, 0));
- __ lea(ecx, Operand(eax, ecx, times_4, 0));
- // Check if cache matches: Double value is stored in uint32_t[2] array.
- NearLabel cache_miss;
- __ cmp(ebx, Operand(ecx, 0));
- __ j(not_equal, &cache_miss);
- __ cmp(edx, Operand(ecx, kIntSize));
- __ j(not_equal, &cache_miss);
- // Cache hit!
- __ mov(eax, Operand(ecx, 2 * kIntSize));
- __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset));
- __ Ret();
-
- __ bind(&cache_miss);
- // Update cache with new value.
- // We are short on registers, so use no_reg as scratch.
- // This gives slightly larger code.
- __ AllocateHeapNumber(eax, edi, no_reg, &skip_cache);
- __ sub(Operand(esp), Immediate(kDoubleSize));
- __ movdbl(Operand(esp, 0), xmm1);
- __ fld_d(Operand(esp, 0));
- __ add(Operand(esp), Immediate(kDoubleSize));
- GenerateOperation(masm);
- __ mov(Operand(ecx, 0), ebx);
- __ mov(Operand(ecx, kIntSize), edx);
- __ mov(Operand(ecx, 2 * kIntSize), eax);
- __ fstp_d(FieldOperand(eax, HeapNumber::kValueOffset));
- __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset));
- __ Ret();
-
- __ bind(&skip_cache);
- __ sub(Operand(esp), Immediate(kDoubleSize));
- __ movdbl(Operand(esp, 0), xmm1);
- __ fld_d(Operand(esp, 0));
- GenerateOperation(masm);
- __ fstp_d(Operand(esp, 0));
- __ movdbl(xmm1, Operand(esp, 0));
- __ add(Operand(esp), Immediate(kDoubleSize));
- __ Ret();
-
- __ bind(&call_runtime);
- __ AllocateHeapNumber(eax, edi, no_reg, &skip_cache);
- __ movdbl(FieldOperand(eax, HeapNumber::kValueOffset), xmm1);
- __ EnterInternalFrame();
- __ push(eax);
- __ CallRuntime(RuntimeFunction(), 1);
- __ LeaveInternalFrame();
- __ movdbl(xmm1, FieldOperand(eax, HeapNumber::kValueOffset));
- __ Ret();
-}
-
-
-Runtime::FunctionId TranscendentalCacheSSE2Stub::RuntimeFunction() {
- switch (type_) {
- // Add more cases when necessary.
- case TranscendentalCache::LOG: return Runtime::kMath_log;
- default:
- UNIMPLEMENTED();
- return Runtime::kAbort;
- }
-}
-
-
-void TranscendentalCacheSSE2Stub::GenerateOperation(MacroAssembler* masm) {
- // Only free register is edi.
- // Input value is on FP stack and in xmm1.
-
- ASSERT(type_ == TranscendentalCache::LOG);
- __ fldln2();
- __ fxch();
- __ fyl2x();
-}
-
-
// Get the integer part of a heap number. Surprisingly, all this bit twiddling
// is faster than using the built-in instructions on floating point registers.
// Trashes edi and ebx. Dest is ecx. Source cannot be ecx or one of the
diff --git a/src/ia32/code-stubs-ia32.h b/src/ia32/code-stubs-ia32.h
index 04f23ac..f66a8c7 100644
--- a/src/ia32/code-stubs-ia32.h
+++ b/src/ia32/code-stubs-ia32.h
@@ -40,32 +40,21 @@
// TranscendentalCache runtime function.
class TranscendentalCacheStub: public CodeStub {
public:
- explicit TranscendentalCacheStub(TranscendentalCache::Type type)
- : type_(type) {}
+ enum ArgumentType {
+ TAGGED = 0,
+ UNTAGGED = 1 << TranscendentalCache::kTranscendentalTypeBits
+ };
+
+ explicit TranscendentalCacheStub(TranscendentalCache::Type type,
+ ArgumentType argument_type)
+ : type_(type), argument_type_(argument_type) {}
void Generate(MacroAssembler* masm);
private:
TranscendentalCache::Type type_;
+ ArgumentType argument_type_;
Major MajorKey() { return TranscendentalCache; }
- int MinorKey() { return type_; }
- Runtime::FunctionId RuntimeFunction();
- void GenerateOperation(MacroAssembler* masm);
-};
-
-
-// Check the transcendental cache, or generate the result, using SSE2.
-// The argument and result will be in xmm1.
-// Only supports TranscendentalCache::LOG at this point.
-class TranscendentalCacheSSE2Stub: public CodeStub {
- public:
- explicit TranscendentalCacheSSE2Stub(TranscendentalCache::Type type)
- : type_(type) {}
- void Generate(MacroAssembler* masm);
- private:
- TranscendentalCache::Type type_;
-
- Major MajorKey() { return TranscendentalCacheSSE2; }
- int MinorKey() { return type_; }
+ int MinorKey() { return type_ | argument_type_; }
Runtime::FunctionId RuntimeFunction();
void GenerateOperation(MacroAssembler* masm);
};
diff --git a/src/ia32/codegen-ia32.cc b/src/ia32/codegen-ia32.cc
index 4c9d055..2f14e82 100644
--- a/src/ia32/codegen-ia32.cc
+++ b/src/ia32/codegen-ia32.cc
@@ -7912,7 +7912,8 @@
void CodeGenerator::GenerateMathSin(ZoneList<Expression*>* args) {
ASSERT_EQ(args->length(), 1);
Load(args->at(0));
- TranscendentalCacheStub stub(TranscendentalCache::SIN);
+ TranscendentalCacheStub stub(TranscendentalCache::SIN,
+ TranscendentalCacheStub::TAGGED);
Result result = frame_->CallStub(&stub, 1);
frame_->Push(&result);
}
@@ -7921,7 +7922,8 @@
void CodeGenerator::GenerateMathCos(ZoneList<Expression*>* args) {
ASSERT_EQ(args->length(), 1);
Load(args->at(0));
- TranscendentalCacheStub stub(TranscendentalCache::COS);
+ TranscendentalCacheStub stub(TranscendentalCache::COS,
+ TranscendentalCacheStub::TAGGED);
Result result = frame_->CallStub(&stub, 1);
frame_->Push(&result);
}
@@ -7930,7 +7932,8 @@
void CodeGenerator::GenerateMathLog(ZoneList<Expression*>* args) {
ASSERT_EQ(args->length(), 1);
Load(args->at(0));
- TranscendentalCacheStub stub(TranscendentalCache::LOG);
+ TranscendentalCacheStub stub(TranscendentalCache::LOG,
+ TranscendentalCacheStub::TAGGED);
Result result = frame_->CallStub(&stub, 1);
frame_->Push(&result);
}
diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc
index be059cd..13a1177 100644
--- a/src/ia32/full-codegen-ia32.cc
+++ b/src/ia32/full-codegen-ia32.cc
@@ -3067,7 +3067,8 @@
void FullCodeGenerator::EmitMathSin(ZoneList<Expression*>* args) {
// Load the argument on the stack and call the stub.
- TranscendentalCacheStub stub(TranscendentalCache::SIN);
+ TranscendentalCacheStub stub(TranscendentalCache::SIN,
+ TranscendentalCacheStub::TAGGED);
ASSERT(args->length() == 1);
VisitForStackValue(args->at(0));
__ CallStub(&stub);
@@ -3077,7 +3078,8 @@
void FullCodeGenerator::EmitMathCos(ZoneList<Expression*>* args) {
// Load the argument on the stack and call the stub.
- TranscendentalCacheStub stub(TranscendentalCache::COS);
+ TranscendentalCacheStub stub(TranscendentalCache::COS,
+ TranscendentalCacheStub::TAGGED);
ASSERT(args->length() == 1);
VisitForStackValue(args->at(0));
__ CallStub(&stub);
@@ -3087,7 +3089,8 @@
void FullCodeGenerator::EmitMathLog(ZoneList<Expression*>* args) {
// Load the argument on the stack and call the stub.
- TranscendentalCacheStub stub(TranscendentalCache::LOG);
+ TranscendentalCacheStub stub(TranscendentalCache::LOG,
+ TranscendentalCacheStub::TAGGED);
ASSERT(args->length() == 1);
VisitForStackValue(args->at(0));
__ CallStub(&stub);
diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc
index 0e97737..d64f528 100644
--- a/src/ia32/lithium-codegen-ia32.cc
+++ b/src/ia32/lithium-codegen-ia32.cc
@@ -686,7 +686,8 @@
break;
}
case CodeStub::TranscendentalCache: {
- TranscendentalCacheStub stub(instr->transcendental_type());
+ TranscendentalCacheStub stub(instr->transcendental_type(),
+ TranscendentalCacheStub::TAGGED);
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
break;
}
@@ -2314,7 +2315,24 @@
void LCodeGen::DoMathLog(LUnaryMathOperation* instr) {
ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
- TranscendentalCacheSSE2Stub stub(TranscendentalCache::LOG);
+ TranscendentalCacheStub stub(TranscendentalCache::LOG,
+ TranscendentalCacheStub::UNTAGGED);
+ CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
+}
+
+
+void LCodeGen::DoMathCos(LUnaryMathOperation* instr) {
+ ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
+ TranscendentalCacheStub stub(TranscendentalCache::COS,
+ TranscendentalCacheStub::UNTAGGED);
+ CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
+}
+
+
+void LCodeGen::DoMathSin(LUnaryMathOperation* instr) {
+ ASSERT(ToDoubleRegister(instr->result()).is(xmm1));
+ TranscendentalCacheStub stub(TranscendentalCache::SIN,
+ TranscendentalCacheStub::UNTAGGED);
CallCode(stub.GetCode(), RelocInfo::CODE_TARGET, instr);
}
@@ -2336,6 +2354,12 @@
case kMathPowHalf:
DoMathPowHalf(instr);
break;
+ case kMathCos:
+ DoMathCos(instr);
+ break;
+ case kMathSin:
+ DoMathSin(instr);
+ break;
case kMathLog:
DoMathLog(instr);
break;
diff --git a/src/ia32/lithium-codegen-ia32.h b/src/ia32/lithium-codegen-ia32.h
index 5ac7b1e..6d8173a 100644
--- a/src/ia32/lithium-codegen-ia32.h
+++ b/src/ia32/lithium-codegen-ia32.h
@@ -177,6 +177,8 @@
void DoMathSqrt(LUnaryMathOperation* instr);
void DoMathPowHalf(LUnaryMathOperation* instr);
void DoMathLog(LUnaryMathOperation* instr);
+ void DoMathCos(LUnaryMathOperation* instr);
+ void DoMathSin(LUnaryMathOperation* instr);
// Support for recording safepoint and position information.
void RecordSafepoint(LPointerMap* pointers, int deoptimization_index);
diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc
index e1148fc..3b272d0 100644
--- a/src/ia32/lithium-ia32.cc
+++ b/src/ia32/lithium-ia32.cc
@@ -1361,7 +1361,7 @@
LInstruction* LChunkBuilder::DoUnaryMathOperation(HUnaryMathOperation* instr) {
BuiltinFunctionId op = instr->op();
- if (op == kMathLog) {
+ if (op == kMathLog || op == kMathSin || op == kMathCos) {
LOperand* input = UseFixedDouble(instr->value(), xmm1);
LInstruction* result = new LUnaryMathOperation(input);
return MarkAsCall(DefineFixedDouble(result, xmm1), instr);
diff --git a/src/objects-debug.cc b/src/objects-debug.cc
index cb7b35e..53296d9 100644
--- a/src/objects-debug.cc
+++ b/src/objects-debug.cc
@@ -35,32 +35,34 @@
namespace v8 {
namespace internal {
-#ifdef DEBUG
+#ifdef OBJECT_PRINT
static const char* TypeToString(InstanceType type);
-void MaybeObject::Print() {
+void MaybeObject::Print(FILE* out) {
Object* this_as_object;
if (ToObject(&this_as_object)) {
if (this_as_object->IsSmi()) {
- Smi::cast(this_as_object)->SmiPrint();
+ Smi::cast(this_as_object)->SmiPrint(out);
} else {
- HeapObject::cast(this_as_object)->HeapObjectPrint();
+ HeapObject::cast(this_as_object)->HeapObjectPrint(out);
}
} else {
- Failure::cast(this)->FailurePrint();
+ Failure::cast(this)->FailurePrint(out);
}
- Flush();
+ Flush(out);
}
-void MaybeObject::PrintLn() {
- Print();
- PrintF("\n");
+void MaybeObject::PrintLn(FILE* out) {
+ Print(out);
+ PrintF(out, "\n");
}
+#endif // OBJECT_PRINT
+#ifdef DEBUG
void MaybeObject::Verify() {
Object* this_as_object;
if (ToObject(&this_as_object)) {
@@ -92,114 +94,120 @@
void Failure::FailureVerify() {
ASSERT(IsFailure());
}
+#endif // DEBUG
-void HeapObject::PrintHeader(const char* id) {
- PrintF("%p: [%s]\n", reinterpret_cast<void*>(this), id);
+#ifdef OBJECT_PRINT
+void HeapObject::PrintHeader(FILE* out, const char* id) {
+ PrintF(out, "%p: [%s]\n", reinterpret_cast<void*>(this), id);
}
-void HeapObject::HeapObjectPrint() {
+void HeapObject::HeapObjectPrint(FILE* out) {
InstanceType instance_type = map()->instance_type();
HandleScope scope;
if (instance_type < FIRST_NONSTRING_TYPE) {
- String::cast(this)->StringPrint();
+ String::cast(this)->StringPrint(out);
return;
}
switch (instance_type) {
case MAP_TYPE:
- Map::cast(this)->MapPrint();
+ Map::cast(this)->MapPrint(out);
break;
case HEAP_NUMBER_TYPE:
- HeapNumber::cast(this)->HeapNumberPrint();
+ HeapNumber::cast(this)->HeapNumberPrint(out);
break;
case FIXED_ARRAY_TYPE:
- FixedArray::cast(this)->FixedArrayPrint();
+ FixedArray::cast(this)->FixedArrayPrint(out);
break;
case BYTE_ARRAY_TYPE:
- ByteArray::cast(this)->ByteArrayPrint();
+ ByteArray::cast(this)->ByteArrayPrint(out);
break;
case PIXEL_ARRAY_TYPE:
- PixelArray::cast(this)->PixelArrayPrint();
+ PixelArray::cast(this)->PixelArrayPrint(out);
break;
case EXTERNAL_BYTE_ARRAY_TYPE:
- ExternalByteArray::cast(this)->ExternalByteArrayPrint();
+ ExternalByteArray::cast(this)->ExternalByteArrayPrint(out);
break;
case EXTERNAL_UNSIGNED_BYTE_ARRAY_TYPE:
- ExternalUnsignedByteArray::cast(this)->ExternalUnsignedByteArrayPrint();
+ ExternalUnsignedByteArray::cast(this)
+ ->ExternalUnsignedByteArrayPrint(out);
break;
case EXTERNAL_SHORT_ARRAY_TYPE:
- ExternalShortArray::cast(this)->ExternalShortArrayPrint();
+ ExternalShortArray::cast(this)->ExternalShortArrayPrint(out);
break;
case EXTERNAL_UNSIGNED_SHORT_ARRAY_TYPE:
- ExternalUnsignedShortArray::cast(this)->ExternalUnsignedShortArrayPrint();
+ ExternalUnsignedShortArray::cast(this)
+ ->ExternalUnsignedShortArrayPrint(out);
break;
case EXTERNAL_INT_ARRAY_TYPE:
- ExternalIntArray::cast(this)->ExternalIntArrayPrint();
+ ExternalIntArray::cast(this)->ExternalIntArrayPrint(out);
break;
case EXTERNAL_UNSIGNED_INT_ARRAY_TYPE:
- ExternalUnsignedIntArray::cast(this)->ExternalUnsignedIntArrayPrint();
+ ExternalUnsignedIntArray::cast(this)->ExternalUnsignedIntArrayPrint(out);
break;
case EXTERNAL_FLOAT_ARRAY_TYPE:
- ExternalFloatArray::cast(this)->ExternalFloatArrayPrint();
+ ExternalFloatArray::cast(this)->ExternalFloatArrayPrint(out);
break;
case FILLER_TYPE:
- PrintF("filler");
+ PrintF(out, "filler");
break;
case JS_OBJECT_TYPE: // fall through
case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
case JS_ARRAY_TYPE:
case JS_REGEXP_TYPE:
- JSObject::cast(this)->JSObjectPrint();
+ JSObject::cast(this)->JSObjectPrint(out);
break;
case ODDBALL_TYPE:
- Oddball::cast(this)->to_string()->Print();
+ Oddball::cast(this)->to_string()->Print(out);
break;
case JS_FUNCTION_TYPE:
- JSFunction::cast(this)->JSFunctionPrint();
+ JSFunction::cast(this)->JSFunctionPrint(out);
break;
case JS_GLOBAL_PROXY_TYPE:
- JSGlobalProxy::cast(this)->JSGlobalProxyPrint();
+ JSGlobalProxy::cast(this)->JSGlobalProxyPrint(out);
break;
case JS_GLOBAL_OBJECT_TYPE:
- JSGlobalObject::cast(this)->JSGlobalObjectPrint();
+ JSGlobalObject::cast(this)->JSGlobalObjectPrint(out);
break;
case JS_BUILTINS_OBJECT_TYPE:
- JSBuiltinsObject::cast(this)->JSBuiltinsObjectPrint();
+ JSBuiltinsObject::cast(this)->JSBuiltinsObjectPrint(out);
break;
case JS_VALUE_TYPE:
- PrintF("Value wrapper around:");
- JSValue::cast(this)->value()->Print();
+ PrintF(out, "Value wrapper around:");
+ JSValue::cast(this)->value()->Print(out);
break;
case CODE_TYPE:
- Code::cast(this)->CodePrint();
+ Code::cast(this)->CodePrint(out);
break;
case PROXY_TYPE:
- Proxy::cast(this)->ProxyPrint();
+ Proxy::cast(this)->ProxyPrint(out);
break;
case SHARED_FUNCTION_INFO_TYPE:
- SharedFunctionInfo::cast(this)->SharedFunctionInfoPrint();
+ SharedFunctionInfo::cast(this)->SharedFunctionInfoPrint(out);
break;
case JS_GLOBAL_PROPERTY_CELL_TYPE:
- JSGlobalPropertyCell::cast(this)->JSGlobalPropertyCellPrint();
+ JSGlobalPropertyCell::cast(this)->JSGlobalPropertyCellPrint(out);
break;
#define MAKE_STRUCT_CASE(NAME, Name, name) \
case NAME##_TYPE: \
- Name::cast(this)->Name##Print(); \
+ Name::cast(this)->Name##Print(out); \
break;
STRUCT_LIST(MAKE_STRUCT_CASE)
#undef MAKE_STRUCT_CASE
default:
- PrintF("UNKNOWN TYPE %d", map()->instance_type());
+ PrintF(out, "UNKNOWN TYPE %d", map()->instance_type());
UNREACHABLE();
break;
}
}
+#endif // OBJECT_PRINT
+#ifdef DEBUG
void HeapObject::HeapObjectVerify() {
InstanceType instance_type = map()->instance_type();
@@ -312,53 +320,57 @@
void HeapNumber::HeapNumberVerify() {
ASSERT(IsHeapNumber());
}
+#endif // DEBUG
-void ByteArray::ByteArrayPrint() {
- PrintF("byte array, data starts at %p", GetDataStartAddress());
+#ifdef OBJECT_PRINT
+void ByteArray::ByteArrayPrint(FILE* out) {
+ PrintF(out, "byte array, data starts at %p", GetDataStartAddress());
}
-void PixelArray::PixelArrayPrint() {
- PrintF("pixel array");
+void PixelArray::PixelArrayPrint(FILE* out) {
+ PrintF(out, "pixel array");
}
-void ExternalByteArray::ExternalByteArrayPrint() {
- PrintF("external byte array");
+void ExternalByteArray::ExternalByteArrayPrint(FILE* out) {
+ PrintF(out, "external byte array");
}
-void ExternalUnsignedByteArray::ExternalUnsignedByteArrayPrint() {
- PrintF("external unsigned byte array");
+void ExternalUnsignedByteArray::ExternalUnsignedByteArrayPrint(FILE* out) {
+ PrintF(out, "external unsigned byte array");
}
-void ExternalShortArray::ExternalShortArrayPrint() {
- PrintF("external short array");
+void ExternalShortArray::ExternalShortArrayPrint(FILE* out) {
+ PrintF(out, "external short array");
}
-void ExternalUnsignedShortArray::ExternalUnsignedShortArrayPrint() {
- PrintF("external unsigned short array");
+void ExternalUnsignedShortArray::ExternalUnsignedShortArrayPrint(FILE* out) {
+ PrintF(out, "external unsigned short array");
}
-void ExternalIntArray::ExternalIntArrayPrint() {
- PrintF("external int array");
+void ExternalIntArray::ExternalIntArrayPrint(FILE* out) {
+ PrintF(out, "external int array");
}
-void ExternalUnsignedIntArray::ExternalUnsignedIntArrayPrint() {
- PrintF("external unsigned int array");
+void ExternalUnsignedIntArray::ExternalUnsignedIntArrayPrint(FILE* out) {
+ PrintF(out, "external unsigned int array");
}
-void ExternalFloatArray::ExternalFloatArrayPrint() {
- PrintF("external float array");
+void ExternalFloatArray::ExternalFloatArrayPrint(FILE* out) {
+ PrintF(out, "external float array");
}
+#endif // OBJECT_PRINT
+#ifdef DEBUG
void ByteArray::ByteArrayVerify() {
ASSERT(IsByteArray());
}
@@ -402,38 +414,40 @@
void ExternalFloatArray::ExternalFloatArrayVerify() {
ASSERT(IsExternalFloatArray());
}
+#endif // DEBUG
-void JSObject::PrintProperties() {
+#ifdef OBJECT_PRINT
+void JSObject::PrintProperties(FILE* out) {
if (HasFastProperties()) {
DescriptorArray* descs = map()->instance_descriptors();
for (int i = 0; i < descs->number_of_descriptors(); i++) {
- PrintF(" ");
- descs->GetKey(i)->StringPrint();
- PrintF(": ");
+ PrintF(out, " ");
+ descs->GetKey(i)->StringPrint(out);
+ PrintF(out, ": ");
switch (descs->GetType(i)) {
case FIELD: {
int index = descs->GetFieldIndex(i);
- FastPropertyAt(index)->ShortPrint();
- PrintF(" (field at offset %d)\n", index);
+ FastPropertyAt(index)->ShortPrint(out);
+ PrintF(out, " (field at offset %d)\n", index);
break;
}
case CONSTANT_FUNCTION:
- descs->GetConstantFunction(i)->ShortPrint();
- PrintF(" (constant function)\n");
+ descs->GetConstantFunction(i)->ShortPrint(out);
+ PrintF(out, " (constant function)\n");
break;
case CALLBACKS:
- descs->GetCallbacksObject(i)->ShortPrint();
- PrintF(" (callback)\n");
+ descs->GetCallbacksObject(i)->ShortPrint(out);
+ PrintF(out, " (callback)\n");
break;
case MAP_TRANSITION:
- PrintF(" (map transition)\n");
+ PrintF(out, " (map transition)\n");
break;
case CONSTANT_TRANSITION:
- PrintF(" (constant transition)\n");
+ PrintF(out, " (constant transition)\n");
break;
case NULL_DESCRIPTOR:
- PrintF(" (null descriptor)\n");
+ PrintF(out, " (null descriptor)\n");
break;
default:
UNREACHABLE();
@@ -441,34 +455,34 @@
}
}
} else {
- property_dictionary()->Print();
+ property_dictionary()->Print(out);
}
}
-void JSObject::PrintElements() {
+void JSObject::PrintElements(FILE* out) {
switch (GetElementsKind()) {
case FAST_ELEMENTS: {
// Print in array notation for non-sparse arrays.
FixedArray* p = FixedArray::cast(elements());
for (int i = 0; i < p->length(); i++) {
- PrintF(" %d: ", i);
- p->get(i)->ShortPrint();
- PrintF("\n");
+ PrintF(out, " %d: ", i);
+ p->get(i)->ShortPrint(out);
+ PrintF(out, "\n");
}
break;
}
case PIXEL_ELEMENTS: {
PixelArray* p = PixelArray::cast(elements());
for (int i = 0; i < p->length(); i++) {
- PrintF(" %d: %d\n", i, p->get(i));
+ PrintF(out, " %d: %d\n", i, p->get(i));
}
break;
}
case EXTERNAL_BYTE_ELEMENTS: {
ExternalByteArray* p = ExternalByteArray::cast(elements());
for (int i = 0; i < p->length(); i++) {
- PrintF(" %d: %d\n", i, static_cast<int>(p->get(i)));
+ PrintF(out, " %d: %d\n", i, static_cast<int>(p->get(i)));
}
break;
}
@@ -476,14 +490,14 @@
ExternalUnsignedByteArray* p =
ExternalUnsignedByteArray::cast(elements());
for (int i = 0; i < p->length(); i++) {
- PrintF(" %d: %d\n", i, static_cast<int>(p->get(i)));
+ PrintF(out, " %d: %d\n", i, static_cast<int>(p->get(i)));
}
break;
}
case EXTERNAL_SHORT_ELEMENTS: {
ExternalShortArray* p = ExternalShortArray::cast(elements());
for (int i = 0; i < p->length(); i++) {
- PrintF(" %d: %d\n", i, static_cast<int>(p->get(i)));
+ PrintF(out, " %d: %d\n", i, static_cast<int>(p->get(i)));
}
break;
}
@@ -491,14 +505,14 @@
ExternalUnsignedShortArray* p =
ExternalUnsignedShortArray::cast(elements());
for (int i = 0; i < p->length(); i++) {
- PrintF(" %d: %d\n", i, static_cast<int>(p->get(i)));
+ PrintF(out, " %d: %d\n", i, static_cast<int>(p->get(i)));
}
break;
}
case EXTERNAL_INT_ELEMENTS: {
ExternalIntArray* p = ExternalIntArray::cast(elements());
for (int i = 0; i < p->length(); i++) {
- PrintF(" %d: %d\n", i, static_cast<int>(p->get(i)));
+ PrintF(out, " %d: %d\n", i, static_cast<int>(p->get(i)));
}
break;
}
@@ -506,19 +520,19 @@
ExternalUnsignedIntArray* p =
ExternalUnsignedIntArray::cast(elements());
for (int i = 0; i < p->length(); i++) {
- PrintF(" %d: %d\n", i, static_cast<int>(p->get(i)));
+ PrintF(out, " %d: %d\n", i, static_cast<int>(p->get(i)));
}
break;
}
case EXTERNAL_FLOAT_ELEMENTS: {
ExternalFloatArray* p = ExternalFloatArray::cast(elements());
for (int i = 0; i < p->length(); i++) {
- PrintF(" %d: %f\n", i, p->get(i));
+ PrintF(out, " %d: %f\n", i, p->get(i));
}
break;
}
case DICTIONARY_ELEMENTS:
- elements()->Print();
+ elements()->Print(out);
break;
default:
UNREACHABLE();
@@ -527,17 +541,19 @@
}
-void JSObject::JSObjectPrint() {
- PrintF("%p: [JSObject]\n", reinterpret_cast<void*>(this));
- PrintF(" - map = %p\n", reinterpret_cast<void*>(map()));
- PrintF(" - prototype = %p\n", reinterpret_cast<void*>(GetPrototype()));
- PrintF(" {\n");
- PrintProperties();
- PrintElements();
- PrintF(" }\n");
+void JSObject::JSObjectPrint(FILE* out) {
+ PrintF(out, "%p: [JSObject]\n", reinterpret_cast<void*>(this));
+ PrintF(out, " - map = %p\n", reinterpret_cast<void*>(map()));
+ PrintF(out, " - prototype = %p\n", reinterpret_cast<void*>(GetPrototype()));
+ PrintF(out, " {\n");
+ PrintProperties(out);
+ PrintElements(out);
+ PrintF(out, " }\n");
}
+#endif // OBJECT_PRINT
+#ifdef DEBUG
void JSObject::JSObjectVerify() {
VerifyHeapPointer(properties());
VerifyHeapPointer(elements());
@@ -551,8 +567,10 @@
elements()->map() == Heap::fixed_cow_array_map()));
ASSERT(map()->has_fast_elements() == HasFastElements());
}
+#endif // DEBUG
+#ifdef OBJECT_PRINT
static const char* TypeToString(InstanceType type) {
switch (type) {
case INVALID_TYPE: return "INVALID";
@@ -608,42 +626,44 @@
}
-void Map::MapPrint() {
- HeapObject::PrintHeader("Map");
- PrintF(" - type: %s\n", TypeToString(instance_type()));
- PrintF(" - instance size: %d\n", instance_size());
- PrintF(" - inobject properties: %d\n", inobject_properties());
- PrintF(" - pre-allocated property fields: %d\n",
+void Map::MapPrint(FILE* out) {
+ HeapObject::PrintHeader(out, "Map");
+ PrintF(out, " - type: %s\n", TypeToString(instance_type()));
+ PrintF(out, " - instance size: %d\n", instance_size());
+ PrintF(out, " - inobject properties: %d\n", inobject_properties());
+ PrintF(out, " - pre-allocated property fields: %d\n",
pre_allocated_property_fields());
- PrintF(" - unused property fields: %d\n", unused_property_fields());
+ PrintF(out, " - unused property fields: %d\n", unused_property_fields());
if (is_hidden_prototype()) {
- PrintF(" - hidden_prototype\n");
+ PrintF(out, " - hidden_prototype\n");
}
if (has_named_interceptor()) {
- PrintF(" - named_interceptor\n");
+ PrintF(out, " - named_interceptor\n");
}
if (has_indexed_interceptor()) {
- PrintF(" - indexed_interceptor\n");
+ PrintF(out, " - indexed_interceptor\n");
}
if (is_undetectable()) {
- PrintF(" - undetectable\n");
+ PrintF(out, " - undetectable\n");
}
if (has_instance_call_handler()) {
- PrintF(" - instance_call_handler\n");
+ PrintF(out, " - instance_call_handler\n");
}
if (is_access_check_needed()) {
- PrintF(" - access_check_needed\n");
+ PrintF(out, " - access_check_needed\n");
}
- PrintF(" - instance descriptors: ");
- instance_descriptors()->ShortPrint();
- PrintF("\n - prototype: ");
- prototype()->ShortPrint();
- PrintF("\n - constructor: ");
- constructor()->ShortPrint();
- PrintF("\n");
+ PrintF(out, " - instance descriptors: ");
+ instance_descriptors()->ShortPrint(out);
+ PrintF(out, "\n - prototype: ");
+ prototype()->ShortPrint(out);
+ PrintF(out, "\n - constructor: ");
+ constructor()->ShortPrint(out);
+ PrintF(out, "\n");
}
+#endif // OBJECT_PRINT
+#ifdef DEBUG
void Map::MapVerify() {
ASSERT(!Heap::InNewSpace(this));
ASSERT(FIRST_TYPE <= instance_type() && instance_type() <= LAST_TYPE);
@@ -665,17 +685,21 @@
ASSERT_EQ(StaticVisitorBase::GetVisitorId(instance_type(), instance_size()),
visitor_id());
}
+#endif // DEBUG
-void CodeCache::CodeCachePrint() {
- HeapObject::PrintHeader("CodeCache");
- PrintF("\n - default_cache: ");
- default_cache()->ShortPrint();
- PrintF("\n - normal_type_cache: ");
- normal_type_cache()->ShortPrint();
+#ifdef OBJECT_PRINT
+void CodeCache::CodeCachePrint(FILE* out) {
+ HeapObject::PrintHeader(out, "CodeCache");
+ PrintF(out, "\n - default_cache: ");
+ default_cache()->ShortPrint(out);
+ PrintF(out, "\n - normal_type_cache: ");
+ normal_type_cache()->ShortPrint(out);
}
+#endif // OBJECT_PRINT
+#ifdef DEBUG
void CodeCache::CodeCacheVerify() {
VerifyHeapPointer(default_cache());
VerifyHeapPointer(normal_type_cache());
@@ -683,19 +707,23 @@
ASSERT(normal_type_cache()->IsUndefined()
|| normal_type_cache()->IsCodeCacheHashTable());
}
+#endif // DEBUG
-void FixedArray::FixedArrayPrint() {
- HeapObject::PrintHeader("FixedArray");
- PrintF(" - length: %d", length());
+#ifdef OBJECT_PRINT
+void FixedArray::FixedArrayPrint(FILE* out) {
+ HeapObject::PrintHeader(out, "FixedArray");
+ PrintF(out, " - length: %d", length());
for (int i = 0; i < length(); i++) {
- PrintF("\n [%d]: ", i);
- get(i)->ShortPrint();
+ PrintF(out, "\n [%d]: ", i);
+ get(i)->ShortPrint(out);
}
- PrintF("\n");
+ PrintF(out, "\n");
}
+#endif // OBJECT_PRINT
+#ifdef DEBUG
void FixedArray::FixedArrayVerify() {
for (int i = 0; i < length(); i++) {
Object* e = get(i);
@@ -706,39 +734,57 @@
}
}
}
+#endif // DEBUG
-void JSValue::JSValuePrint() {
- HeapObject::PrintHeader("ValueObject");
- value()->Print();
+#ifdef OBJECT_PRINT
+void JSValue::JSValuePrint(FILE* out) {
+ HeapObject::PrintHeader(out, "ValueObject");
+ value()->Print(out);
}
+#endif // OBJECT_PRINT
+#ifdef DEBUG
void JSValue::JSValueVerify() {
Object* v = value();
if (v->IsHeapObject()) {
VerifyHeapPointer(v);
}
}
+#endif // DEBUG
-void String::StringPrint() {
+#ifdef OBJECT_PRINT
+void String::StringPrint(FILE* out) {
if (StringShape(this).IsSymbol()) {
- PrintF("#");
+ PrintF(out, "#");
} else if (StringShape(this).IsCons()) {
- PrintF("c\"");
+ PrintF(out, "c\"");
} else {
- PrintF("\"");
+ PrintF(out, "\"");
}
- for (int i = 0; i < length(); i++) {
- PrintF("%c", Get(i));
+ const char truncated_epilogue[] = "...<truncated>";
+ int len = length();
+ if (!FLAG_use_verbose_printer) {
+ if (len > 100) {
+ len = 100 - sizeof(truncated_epilogue);
+ }
+ }
+ for (int i = 0; i < len; i++) {
+ PrintF(out, "%c", Get(i));
+ }
+ if (len != length()) {
+ PrintF(out, "%s", truncated_epilogue);
}
- if (!StringShape(this).IsSymbol()) PrintF("\"");
+ if (!StringShape(this).IsSymbol()) PrintF(out, "\"");
}
+#endif // OBJECT_PRINT
+#ifdef DEBUG
void String::StringVerify() {
CHECK(IsString());
CHECK(length() >= 0 && length() <= Smi::kMaxValue);
@@ -746,32 +792,36 @@
CHECK(!Heap::InNewSpace(this));
}
}
+#endif // DEBUG
-void JSFunction::JSFunctionPrint() {
- HeapObject::PrintHeader("Function");
- PrintF(" - map = 0x%p\n", reinterpret_cast<void*>(map()));
- PrintF(" - initial_map = ");
+#ifdef OBJECT_PRINT
+void JSFunction::JSFunctionPrint(FILE* out) {
+ HeapObject::PrintHeader(out, "Function");
+ PrintF(out, " - map = 0x%p\n", reinterpret_cast<void*>(map()));
+ PrintF(out, " - initial_map = ");
if (has_initial_map()) {
- initial_map()->ShortPrint();
+ initial_map()->ShortPrint(out);
}
- PrintF("\n - shared_info = ");
- shared()->ShortPrint();
- PrintF("\n - name = ");
- shared()->name()->Print();
- PrintF("\n - context = ");
- unchecked_context()->ShortPrint();
- PrintF("\n - code = ");
- code()->ShortPrint();
- PrintF("\n");
+ PrintF(out, "\n - shared_info = ");
+ shared()->ShortPrint(out);
+ PrintF(out, "\n - name = ");
+ shared()->name()->Print(out);
+ PrintF(out, "\n - context = ");
+ unchecked_context()->ShortPrint(out);
+ PrintF(out, "\n - code = ");
+ code()->ShortPrint(out);
+ PrintF(out, "\n");
- PrintProperties();
- PrintElements();
+ PrintProperties(out);
+ PrintElements(out);
- PrintF("\n");
+ PrintF(out, "\n");
}
+#endif // OBJECT_PRINT
+#ifdef DEBUG
void JSFunction::JSFunctionVerify() {
CHECK(IsJSFunction());
VerifyObjectField(kPrototypeOrInitialMapOffset);
@@ -779,36 +829,41 @@
CHECK(next_function_link()->IsUndefined() ||
next_function_link()->IsJSFunction());
}
+#endif // DEBUG
-void SharedFunctionInfo::SharedFunctionInfoPrint() {
- HeapObject::PrintHeader("SharedFunctionInfo");
- PrintF(" - name: ");
- name()->ShortPrint();
- PrintF("\n - expected_nof_properties: %d", expected_nof_properties());
- PrintF("\n - instance class name = ");
- instance_class_name()->Print();
- PrintF("\n - code = ");
- code()->ShortPrint();
- PrintF("\n - source code = ");
- GetSourceCode()->ShortPrint();
+#ifdef OBJECT_PRINT
+void SharedFunctionInfo::SharedFunctionInfoPrint(FILE* out) {
+ HeapObject::PrintHeader(out, "SharedFunctionInfo");
+ PrintF(out, " - name: ");
+ name()->ShortPrint(out);
+ PrintF(out, "\n - expected_nof_properties: %d", expected_nof_properties());
+ PrintF(out, "\n - instance class name = ");
+ instance_class_name()->Print(out);
+ PrintF(out, "\n - code = ");
+ code()->ShortPrint(out);
+ PrintF(out, "\n - source code = ");
+ GetSourceCode()->ShortPrint(out);
// Script files are often large, hard to read.
- // PrintF("\n - script =");
- // script()->Print();
- PrintF("\n - function token position = %d", function_token_position());
- PrintF("\n - start position = %d", start_position());
- PrintF("\n - end position = %d", end_position());
- PrintF("\n - is expression = %d", is_expression());
- PrintF("\n - debug info = ");
- debug_info()->ShortPrint();
- PrintF("\n - length = %d", length());
- PrintF("\n - has_only_simple_this_property_assignments = %d",
+ // PrintF(out, "\n - script =");
+ // script()->Print(out);
+ PrintF(out, "\n - function token position = %d", function_token_position());
+ PrintF(out, "\n - start position = %d", start_position());
+ PrintF(out, "\n - end position = %d", end_position());
+ PrintF(out, "\n - is expression = %d", is_expression());
+ PrintF(out, "\n - debug info = ");
+ debug_info()->ShortPrint(out);
+ PrintF(out, "\n - length = %d", length());
+ PrintF(out, "\n - has_only_simple_this_property_assignments = %d",
has_only_simple_this_property_assignments());
- PrintF("\n - this_property_assignments = ");
- this_property_assignments()->ShortPrint();
- PrintF("\n");
+ PrintF(out, "\n - this_property_assignments = ");
+ this_property_assignments()->ShortPrint(out);
+ PrintF(out, "\n");
}
+#endif // OBJECT_PRINT
+
+#ifdef DEBUG
void SharedFunctionInfo::SharedFunctionInfoVerify() {
CHECK(IsSharedFunctionInfo());
VerifyObjectField(kNameOffset);
@@ -819,17 +874,21 @@
VerifyObjectField(kScriptOffset);
VerifyObjectField(kDebugInfoOffset);
}
+#endif // DEBUG
-void JSGlobalProxy::JSGlobalProxyPrint() {
- PrintF("global_proxy");
- JSObjectPrint();
- PrintF("context : ");
- context()->ShortPrint();
- PrintF("\n");
+#ifdef OBJECT_PRINT
+void JSGlobalProxy::JSGlobalProxyPrint(FILE* out) {
+ PrintF(out, "global_proxy");
+ JSObjectPrint(out);
+ PrintF(out, "context : ");
+ context()->ShortPrint(out);
+ PrintF(out, "\n");
}
+#endif // OBJECT_PRINT
+#ifdef DEBUG
void JSGlobalProxy::JSGlobalProxyVerify() {
CHECK(IsJSGlobalProxy());
JSObjectVerify();
@@ -839,17 +898,21 @@
CHECK(HasFastElements());
CHECK_EQ(0, FixedArray::cast(elements())->length());
}
+#endif // DEBUG
-void JSGlobalObject::JSGlobalObjectPrint() {
- PrintF("global ");
- JSObjectPrint();
- PrintF("global context : ");
- global_context()->ShortPrint();
- PrintF("\n");
+#ifdef OBJECT_PRINT
+void JSGlobalObject::JSGlobalObjectPrint(FILE* out) {
+ PrintF(out, "global ");
+ JSObjectPrint(out);
+ PrintF(out, "global context : ");
+ global_context()->ShortPrint(out);
+ PrintF(out, "\n");
}
+#endif // OBJECT_PRINT
+#ifdef DEBUG
void JSGlobalObject::JSGlobalObjectVerify() {
CHECK(IsJSGlobalObject());
JSObjectVerify();
@@ -859,14 +922,18 @@
VerifyObjectField(i);
}
}
+#endif // DEBUG
-void JSBuiltinsObject::JSBuiltinsObjectPrint() {
- PrintF("builtins ");
- JSObjectPrint();
+#ifdef OBJECT_PRINT
+void JSBuiltinsObject::JSBuiltinsObjectPrint(FILE* out) {
+ PrintF(out, "builtins ");
+ JSObjectPrint(out);
}
+#endif // OBJECT_PRINT
+#ifdef DEBUG
void JSBuiltinsObject::JSBuiltinsObjectVerify() {
CHECK(IsJSBuiltinsObject());
JSObjectVerify();
@@ -897,21 +964,27 @@
CHECK(IsJSGlobalPropertyCell());
VerifyObjectField(kValueOffset);
}
+#endif // DEBUG
-void JSGlobalPropertyCell::JSGlobalPropertyCellPrint() {
- HeapObject::PrintHeader("JSGlobalPropertyCell");
+#ifdef OBJECT_PRINT
+void JSGlobalPropertyCell::JSGlobalPropertyCellPrint(FILE* out) {
+ HeapObject::PrintHeader(out, "JSGlobalPropertyCell");
}
-void Code::CodePrint() {
- HeapObject::PrintHeader("Code");
+void Code::CodePrint(FILE* out) {
+ HeapObject::PrintHeader(out, "Code");
#ifdef ENABLE_DISASSEMBLER
- Disassemble(NULL);
+ if (FLAG_use_verbose_printer) {
+ Disassemble(NULL, out);
+ }
#endif
}
+#endif // OBJECT_PRINT
+#ifdef DEBUG
void Code::CodeVerify() {
CHECK(IsAligned(reinterpret_cast<intptr_t>(instruction_start()),
kCodeAlignment));
@@ -966,13 +1039,17 @@
break;
}
}
+#endif // DEBUG
-void Proxy::ProxyPrint() {
- PrintF("proxy to %p", proxy());
+#ifdef OBJECT_PRINT
+void Proxy::ProxyPrint(FILE* out) {
+ PrintF(out, "proxy to %p", proxy());
}
+#endif // OBJECT_PRINT
+#ifdef DEBUG
void Proxy::ProxyVerify() {
ASSERT(IsProxy());
}
@@ -986,38 +1063,50 @@
VerifyPointer(data());
VerifyPointer(flag());
}
+#endif // DEBUG
-void AccessorInfo::AccessorInfoPrint() {
- HeapObject::PrintHeader("AccessorInfo");
- PrintF("\n - getter: ");
- getter()->ShortPrint();
- PrintF("\n - setter: ");
- setter()->ShortPrint();
- PrintF("\n - name: ");
- name()->ShortPrint();
- PrintF("\n - data: ");
- data()->ShortPrint();
- PrintF("\n - flag: ");
- flag()->ShortPrint();
+
+#ifdef OBJECT_PRINT
+void AccessorInfo::AccessorInfoPrint(FILE* out) {
+ HeapObject::PrintHeader(out, "AccessorInfo");
+ PrintF(out, "\n - getter: ");
+ getter()->ShortPrint(out);
+ PrintF(out, "\n - setter: ");
+ setter()->ShortPrint(out);
+ PrintF(out, "\n - name: ");
+ name()->ShortPrint(out);
+ PrintF(out, "\n - data: ");
+ data()->ShortPrint(out);
+ PrintF(out, "\n - flag: ");
+ flag()->ShortPrint(out);
}
+#endif // OBJECT_PRINT
+
+#ifdef DEBUG
void AccessCheckInfo::AccessCheckInfoVerify() {
CHECK(IsAccessCheckInfo());
VerifyPointer(named_callback());
VerifyPointer(indexed_callback());
VerifyPointer(data());
}
+#endif // DEBUG
-void AccessCheckInfo::AccessCheckInfoPrint() {
- HeapObject::PrintHeader("AccessCheckInfo");
- PrintF("\n - named_callback: ");
- named_callback()->ShortPrint();
- PrintF("\n - indexed_callback: ");
- indexed_callback()->ShortPrint();
- PrintF("\n - data: ");
- data()->ShortPrint();
+
+#ifdef OBJECT_PRINT
+void AccessCheckInfo::AccessCheckInfoPrint(FILE* out) {
+ HeapObject::PrintHeader(out, "AccessCheckInfo");
+ PrintF(out, "\n - named_callback: ");
+ named_callback()->ShortPrint(out);
+ PrintF(out, "\n - indexed_callback: ");
+ indexed_callback()->ShortPrint(out);
+ PrintF(out, "\n - data: ");
+ data()->ShortPrint(out);
}
+#endif // OBJECT_PRINT
+
+#ifdef DEBUG
void InterceptorInfo::InterceptorInfoVerify() {
CHECK(IsInterceptorInfo());
VerifyPointer(getter());
@@ -1027,38 +1116,50 @@
VerifyPointer(enumerator());
VerifyPointer(data());
}
+#endif // DEBUG
-void InterceptorInfo::InterceptorInfoPrint() {
- HeapObject::PrintHeader("InterceptorInfo");
- PrintF("\n - getter: ");
- getter()->ShortPrint();
- PrintF("\n - setter: ");
- setter()->ShortPrint();
- PrintF("\n - query: ");
- query()->ShortPrint();
- PrintF("\n - deleter: ");
- deleter()->ShortPrint();
- PrintF("\n - enumerator: ");
- enumerator()->ShortPrint();
- PrintF("\n - data: ");
- data()->ShortPrint();
+
+#ifdef OBJECT_PRINT
+void InterceptorInfo::InterceptorInfoPrint(FILE* out) {
+ HeapObject::PrintHeader(out, "InterceptorInfo");
+ PrintF(out, "\n - getter: ");
+ getter()->ShortPrint(out);
+ PrintF(out, "\n - setter: ");
+ setter()->ShortPrint(out);
+ PrintF(out, "\n - query: ");
+ query()->ShortPrint(out);
+ PrintF(out, "\n - deleter: ");
+ deleter()->ShortPrint(out);
+ PrintF(out, "\n - enumerator: ");
+ enumerator()->ShortPrint(out);
+ PrintF(out, "\n - data: ");
+ data()->ShortPrint(out);
}
+#endif // OBJECT_PRINT
+
+#ifdef DEBUG
void CallHandlerInfo::CallHandlerInfoVerify() {
CHECK(IsCallHandlerInfo());
VerifyPointer(callback());
VerifyPointer(data());
}
+#endif // DEBUG
-void CallHandlerInfo::CallHandlerInfoPrint() {
- HeapObject::PrintHeader("CallHandlerInfo");
- PrintF("\n - callback: ");
- callback()->ShortPrint();
- PrintF("\n - data: ");
- data()->ShortPrint();
- PrintF("\n - call_stub_cache: ");
+
+#ifdef OBJECT_PRINT
+void CallHandlerInfo::CallHandlerInfoPrint(FILE* out) {
+ HeapObject::PrintHeader(out, "CallHandlerInfo");
+ PrintF(out, "\n - callback: ");
+ callback()->ShortPrint(out);
+ PrintF(out, "\n - data: ");
+ data()->ShortPrint(out);
+ PrintF(out, "\n - call_stub_cache: ");
}
+#endif // OBJECT_PRINT
+
+#ifdef DEBUG
void TemplateInfo::TemplateInfoVerify() {
VerifyPointer(tag());
VerifyPointer(property_list());
@@ -1078,81 +1179,106 @@
VerifyPointer(signature());
VerifyPointer(access_check_info());
}
+#endif // DEBUG
-void FunctionTemplateInfo::FunctionTemplateInfoPrint() {
- HeapObject::PrintHeader("FunctionTemplateInfo");
- PrintF("\n - class name: ");
- class_name()->ShortPrint();
- PrintF("\n - tag: ");
- tag()->ShortPrint();
- PrintF("\n - property_list: ");
- property_list()->ShortPrint();
- PrintF("\n - serial_number: ");
- serial_number()->ShortPrint();
- PrintF("\n - call_code: ");
- call_code()->ShortPrint();
- PrintF("\n - property_accessors: ");
- property_accessors()->ShortPrint();
- PrintF("\n - prototype_template: ");
- prototype_template()->ShortPrint();
- PrintF("\n - parent_template: ");
- parent_template()->ShortPrint();
- PrintF("\n - named_property_handler: ");
- named_property_handler()->ShortPrint();
- PrintF("\n - indexed_property_handler: ");
- indexed_property_handler()->ShortPrint();
- PrintF("\n - instance_template: ");
- instance_template()->ShortPrint();
- PrintF("\n - signature: ");
- signature()->ShortPrint();
- PrintF("\n - access_check_info: ");
- access_check_info()->ShortPrint();
- PrintF("\n - hidden_prototype: %s", hidden_prototype() ? "true" : "false");
- PrintF("\n - undetectable: %s", undetectable() ? "true" : "false");
- PrintF("\n - need_access_check: %s", needs_access_check() ? "true" : "false");
+
+#ifdef OBJECT_PRINT
+void FunctionTemplateInfo::FunctionTemplateInfoPrint(FILE* out) {
+ HeapObject::PrintHeader(out, "FunctionTemplateInfo");
+ PrintF(out, "\n - class name: ");
+ class_name()->ShortPrint(out);
+ PrintF(out, "\n - tag: ");
+ tag()->ShortPrint(out);
+ PrintF(out, "\n - property_list: ");
+ property_list()->ShortPrint(out);
+ PrintF(out, "\n - serial_number: ");
+ serial_number()->ShortPrint(out);
+ PrintF(out, "\n - call_code: ");
+ call_code()->ShortPrint(out);
+ PrintF(out, "\n - property_accessors: ");
+ property_accessors()->ShortPrint(out);
+ PrintF(out, "\n - prototype_template: ");
+ prototype_template()->ShortPrint(out);
+ PrintF(out, "\n - parent_template: ");
+ parent_template()->ShortPrint(out);
+ PrintF(out, "\n - named_property_handler: ");
+ named_property_handler()->ShortPrint(out);
+ PrintF(out, "\n - indexed_property_handler: ");
+ indexed_property_handler()->ShortPrint(out);
+ PrintF(out, "\n - instance_template: ");
+ instance_template()->ShortPrint(out);
+ PrintF(out, "\n - signature: ");
+ signature()->ShortPrint(out);
+ PrintF(out, "\n - access_check_info: ");
+ access_check_info()->ShortPrint(out);
+ PrintF(out, "\n - hidden_prototype: %s",
+ hidden_prototype() ? "true" : "false");
+ PrintF(out, "\n - undetectable: %s", undetectable() ? "true" : "false");
+ PrintF(out, "\n - need_access_check: %s",
+ needs_access_check() ? "true" : "false");
}
+#endif // OBJECT_PRINT
+
+#ifdef DEBUG
void ObjectTemplateInfo::ObjectTemplateInfoVerify() {
CHECK(IsObjectTemplateInfo());
TemplateInfoVerify();
VerifyPointer(constructor());
VerifyPointer(internal_field_count());
}
+#endif // DEBUG
-void ObjectTemplateInfo::ObjectTemplateInfoPrint() {
- HeapObject::PrintHeader("ObjectTemplateInfo");
- PrintF("\n - constructor: ");
- constructor()->ShortPrint();
- PrintF("\n - internal_field_count: ");
- internal_field_count()->ShortPrint();
+
+#ifdef OBJECT_PRINT
+void ObjectTemplateInfo::ObjectTemplateInfoPrint(FILE* out) {
+ HeapObject::PrintHeader(out, "ObjectTemplateInfo");
+ PrintF(out, "\n - constructor: ");
+ constructor()->ShortPrint(out);
+ PrintF(out, "\n - internal_field_count: ");
+ internal_field_count()->ShortPrint(out);
}
+#endif // OBJECT_PRINT
+
+#ifdef DEBUG
void SignatureInfo::SignatureInfoVerify() {
CHECK(IsSignatureInfo());
VerifyPointer(receiver());
VerifyPointer(args());
}
+#endif // DEBUG
-void SignatureInfo::SignatureInfoPrint() {
- HeapObject::PrintHeader("SignatureInfo");
- PrintF("\n - receiver: ");
- receiver()->ShortPrint();
- PrintF("\n - args: ");
- args()->ShortPrint();
+
+#ifdef OBJECT_PRINT
+void SignatureInfo::SignatureInfoPrint(FILE* out) {
+ HeapObject::PrintHeader(out, "SignatureInfo");
+ PrintF(out, "\n - receiver: ");
+ receiver()->ShortPrint(out);
+ PrintF(out, "\n - args: ");
+ args()->ShortPrint(out);
}
+#endif // OBJECT_PRINT
+
+#ifdef DEBUG
void TypeSwitchInfo::TypeSwitchInfoVerify() {
CHECK(IsTypeSwitchInfo());
VerifyPointer(types());
}
+#endif // DEBUG
-void TypeSwitchInfo::TypeSwitchInfoPrint() {
- HeapObject::PrintHeader("TypeSwitchInfo");
- PrintF("\n - types: ");
- types()->ShortPrint();
+
+#ifdef OBJECT_PRINT
+void TypeSwitchInfo::TypeSwitchInfoPrint(FILE* out) {
+ HeapObject::PrintHeader(out, "TypeSwitchInfo");
+ PrintF(out, "\n - types: ");
+ types()->ShortPrint(out);
}
+#endif // OBJECT_PRINT
+#ifdef DEBUG
void Script::ScriptVerify() {
CHECK(IsScript());
VerifyPointer(source());
@@ -1165,41 +1291,45 @@
VerifyPointer(line_ends());
VerifyPointer(id());
}
+#endif // DEBUG
-void Script::ScriptPrint() {
- HeapObject::PrintHeader("Script");
- PrintF("\n - source: ");
- source()->ShortPrint();
- PrintF("\n - name: ");
- name()->ShortPrint();
- PrintF("\n - line_offset: ");
- line_offset()->ShortPrint();
- PrintF("\n - column_offset: ");
- column_offset()->ShortPrint();
- PrintF("\n - type: ");
- type()->ShortPrint();
- PrintF("\n - id: ");
- id()->ShortPrint();
- PrintF("\n - data: ");
- data()->ShortPrint();
- PrintF("\n - context data: ");
- context_data()->ShortPrint();
- PrintF("\n - wrapper: ");
- wrapper()->ShortPrint();
- PrintF("\n - compilation type: ");
- compilation_type()->ShortPrint();
- PrintF("\n - line ends: ");
- line_ends()->ShortPrint();
- PrintF("\n - eval from shared: ");
- eval_from_shared()->ShortPrint();
- PrintF("\n - eval from instructions offset: ");
- eval_from_instructions_offset()->ShortPrint();
- PrintF("\n");
+#ifdef OBJECT_PRINT
+void Script::ScriptPrint(FILE* out) {
+ HeapObject::PrintHeader(out, "Script");
+ PrintF(out, "\n - source: ");
+ source()->ShortPrint(out);
+ PrintF(out, "\n - name: ");
+ name()->ShortPrint(out);
+ PrintF(out, "\n - line_offset: ");
+ line_offset()->ShortPrint(out);
+ PrintF(out, "\n - column_offset: ");
+ column_offset()->ShortPrint(out);
+ PrintF(out, "\n - type: ");
+ type()->ShortPrint(out);
+ PrintF(out, "\n - id: ");
+ id()->ShortPrint(out);
+ PrintF(out, "\n - data: ");
+ data()->ShortPrint(out);
+ PrintF(out, "\n - context data: ");
+ context_data()->ShortPrint(out);
+ PrintF(out, "\n - wrapper: ");
+ wrapper()->ShortPrint(out);
+ PrintF(out, "\n - compilation type: ");
+ compilation_type()->ShortPrint(out);
+ PrintF(out, "\n - line ends: ");
+ line_ends()->ShortPrint(out);
+ PrintF(out, "\n - eval from shared: ");
+ eval_from_shared()->ShortPrint(out);
+ PrintF(out, "\n - eval from instructions offset: ");
+ eval_from_instructions_offset()->ShortPrint(out);
+ PrintF(out, "\n");
}
+#endif // OBJECT_PRINT
#ifdef ENABLE_DEBUGGER_SUPPORT
+#ifdef DEBUG
void DebugInfo::DebugInfoVerify() {
CHECK(IsDebugInfo());
VerifyPointer(shared());
@@ -1207,21 +1337,25 @@
VerifyPointer(code());
VerifyPointer(break_points());
}
+#endif // DEBUG
-void DebugInfo::DebugInfoPrint() {
- HeapObject::PrintHeader("DebugInfo");
- PrintF("\n - shared: ");
- shared()->ShortPrint();
- PrintF("\n - original_code: ");
- original_code()->ShortPrint();
- PrintF("\n - code: ");
- code()->ShortPrint();
- PrintF("\n - break_points: ");
- break_points()->Print();
+#ifdef OBJECT_PRINT
+void DebugInfo::DebugInfoPrint(FILE* out) {
+ HeapObject::PrintHeader(out, "DebugInfo");
+ PrintF(out, "\n - shared: ");
+ shared()->ShortPrint(out);
+ PrintF(out, "\n - original_code: ");
+ original_code()->ShortPrint(out);
+ PrintF(out, "\n - code: ");
+ code()->ShortPrint(out);
+ PrintF(out, "\n - break_points: ");
+ break_points()->Print(out);
}
+#endif // OBJECT_PRINT
+#ifdef DEBUG
void BreakPointInfo::BreakPointInfoVerify() {
CHECK(IsBreakPointInfo());
code_position()->SmiVerify();
@@ -1229,19 +1363,23 @@
statement_position()->SmiVerify();
VerifyPointer(break_point_objects());
}
+#endif // DEBUG
-void BreakPointInfo::BreakPointInfoPrint() {
- HeapObject::PrintHeader("BreakPointInfo");
- PrintF("\n - code_position: %d", code_position()->value());
- PrintF("\n - source_position: %d", source_position()->value());
- PrintF("\n - statement_position: %d", statement_position()->value());
- PrintF("\n - break_point_objects: ");
- break_point_objects()->ShortPrint();
+#ifdef OBJECT_PRINT
+void BreakPointInfo::BreakPointInfoPrint(FILE* out) {
+ HeapObject::PrintHeader(out, "BreakPointInfo");
+ PrintF(out, "\n - code_position: %d", code_position()->value());
+ PrintF(out, "\n - source_position: %d", source_position()->value());
+ PrintF(out, "\n - statement_position: %d", statement_position()->value());
+ PrintF(out, "\n - break_point_objects: ");
+ break_point_objects()->ShortPrint(out);
}
-#endif
+#endif // OBJECT_PRINT
+#endif // ENABLE_DEBUGGER_SUPPORT
+#ifdef DEBUG
void JSObject::IncrementSpillStatistics(SpillInformation* info) {
info->number_of_objects_++;
// Named properties
@@ -1324,20 +1462,24 @@
PrintF("\n");
}
+#endif // DEBUG
-void DescriptorArray::PrintDescriptors() {
- PrintF("Descriptor array %d\n", number_of_descriptors());
+#ifdef OBJECT_PRINT
+void DescriptorArray::PrintDescriptors(FILE* out) {
+ PrintF(out, "Descriptor array %d\n", number_of_descriptors());
for (int i = 0; i < number_of_descriptors(); i++) {
- PrintF(" %d: ", i);
+ PrintF(out, " %d: ", i);
Descriptor desc;
Get(i, &desc);
- desc.Print();
+ desc.Print(out);
}
- PrintF("\n");
+ PrintF(out, "\n");
}
+#endif // OBJECT_PRINT
+#ifdef DEBUG
bool DescriptorArray::IsSortedNoDuplicates() {
String* current_key = NULL;
uint32_t current = 0;
diff --git a/src/objects.cc b/src/objects.cc
index 96f5c4b..ab2f964 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -553,11 +553,11 @@
}
-void Object::ShortPrint() {
+void Object::ShortPrint(FILE* out) {
HeapStringAllocator allocator;
StringStream accumulator(&allocator);
ShortPrint(&accumulator);
- accumulator.OutputToStdOut();
+ accumulator.OutputToFile(out);
}
@@ -572,8 +572,8 @@
}
-void Smi::SmiPrint() {
- PrintF("%d", value());
+void Smi::SmiPrint(FILE* out) {
+ PrintF(out, "%d", value());
}
@@ -587,8 +587,8 @@
}
-void Failure::FailurePrint() {
- PrintF("Failure(%p)", reinterpret_cast<void*>(value()));
+void Failure::FailurePrint(FILE* out) {
+ PrintF(out, "Failure(%p)", reinterpret_cast<void*>(value()));
}
@@ -1141,8 +1141,8 @@
}
-void HeapNumber::HeapNumberPrint() {
- PrintF("%.16g", Number());
+void HeapNumber::HeapNumberPrint(FILE* out) {
+ PrintF(out, "%.16g", Number());
}
@@ -5467,9 +5467,9 @@
}
-void JSFunction::PrintName() {
+void JSFunction::PrintName(FILE* out) {
SmartPointer<char> name = shared()->DebugName()->ToCString();
- PrintF("%s", *name);
+ PrintF(out, "%s", *name);
}
@@ -5999,18 +5999,18 @@
#ifdef ENABLE_DISASSEMBLER
-#ifdef DEBUG
+#ifdef OBJECT_PRINT
-void DeoptimizationInputData::DeoptimizationInputDataPrint() {
+void DeoptimizationInputData::DeoptimizationInputDataPrint(FILE* out) {
disasm::NameConverter converter;
int deopt_count = DeoptCount();
- PrintF("Deoptimization Input Data (deopt points = %d)\n", deopt_count);
+ PrintF(out, "Deoptimization Input Data (deopt points = %d)\n", deopt_count);
if (0 == deopt_count) return;
- PrintF("%6s %6s %6s %12s\n", "index", "ast id", "argc", "commands");
+ PrintF(out, "%6s %6s %6s %12s\n", "index", "ast id", "argc", "commands");
for (int i = 0; i < deopt_count; i++) {
int command_count = 0;
- PrintF("%6d %6d %6d",
+ PrintF(out, "%6d %6d %6d",
i, AstId(i)->value(), ArgumentsStackHeight(i)->value());
int translation_index = TranslationIndex(i)->value();
TranslationIterator iterator(TranslationByteArray(), translation_index);
@@ -6019,7 +6019,8 @@
ASSERT(Translation::BEGIN == opcode);
int frame_count = iterator.Next();
if (FLAG_print_code_verbose) {
- PrintF(" %s {count=%d}\n", Translation::StringFor(opcode), frame_count);
+ PrintF(out, " %s {count=%d}\n", Translation::StringFor(opcode),
+ frame_count);
}
for (int i = 0; i < frame_count; ++i) {
@@ -6031,10 +6032,10 @@
JSFunction::cast(LiteralArray()->get(function_id));
unsigned height = iterator.Next();
if (FLAG_print_code_verbose) {
- PrintF("%24s %s {ast_id=%d, function=",
+ PrintF(out, "%24s %s {ast_id=%d, function=",
"", Translation::StringFor(opcode), ast_id);
- function->PrintName();
- PrintF(", height=%u}\n", height);
+ function->PrintName(out);
+ PrintF(out, ", height=%u}\n", height);
}
// Size of translation is height plus all incoming arguments including
@@ -6044,13 +6045,13 @@
for (int j = 0; j < size; ++j) {
opcode = static_cast<Translation::Opcode>(iterator.Next());
if (FLAG_print_code_verbose) {
- PrintF("%24s %s ", "", Translation::StringFor(opcode));
+ PrintF(out, "%24s %s ", "", Translation::StringFor(opcode));
}
if (opcode == Translation::DUPLICATE) {
opcode = static_cast<Translation::Opcode>(iterator.Next());
if (FLAG_print_code_verbose) {
- PrintF("%s ", Translation::StringFor(opcode));
+ PrintF(out, "%s ", Translation::StringFor(opcode));
}
--j; // Two commands share the same frame index.
}
@@ -6065,7 +6066,7 @@
case Translation::REGISTER: {
int reg_code = iterator.Next();
if (FLAG_print_code_verbose) {
- PrintF("{input=%s}", converter.NameOfCPURegister(reg_code));
+ PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code));
}
break;
}
@@ -6073,7 +6074,7 @@
case Translation::INT32_REGISTER: {
int reg_code = iterator.Next();
if (FLAG_print_code_verbose) {
- PrintF("{input=%s}", converter.NameOfCPURegister(reg_code));
+ PrintF(out, "{input=%s}", converter.NameOfCPURegister(reg_code));
}
break;
}
@@ -6081,7 +6082,7 @@
case Translation::DOUBLE_REGISTER: {
int reg_code = iterator.Next();
if (FLAG_print_code_verbose) {
- PrintF("{input=%s}",
+ PrintF(out, "{input=%s}",
DoubleRegister::AllocationIndexToString(reg_code));
}
break;
@@ -6090,7 +6091,7 @@
case Translation::STACK_SLOT: {
int input_slot_index = iterator.Next();
if (FLAG_print_code_verbose) {
- PrintF("{input=%d}", input_slot_index);
+ PrintF(out, "{input=%d}", input_slot_index);
}
break;
}
@@ -6098,7 +6099,7 @@
case Translation::INT32_STACK_SLOT: {
int input_slot_index = iterator.Next();
if (FLAG_print_code_verbose) {
- PrintF("{input=%d}", input_slot_index);
+ PrintF(out, "{input=%d}", input_slot_index);
}
break;
}
@@ -6106,7 +6107,7 @@
case Translation::DOUBLE_STACK_SLOT: {
int input_slot_index = iterator.Next();
if (FLAG_print_code_verbose) {
- PrintF("{input=%d}", input_slot_index);
+ PrintF(out, "{input=%d}", input_slot_index);
}
break;
}
@@ -6114,7 +6115,7 @@
case Translation::LITERAL: {
unsigned literal_index = iterator.Next();
if (FLAG_print_code_verbose) {
- PrintF("{literal_id=%u}", literal_index);
+ PrintF(out, "{literal_id=%u}", literal_index);
}
break;
}
@@ -6122,16 +6123,16 @@
case Translation::ARGUMENTS_OBJECT:
break;
}
- if (FLAG_print_code_verbose) PrintF("\n");
+ if (FLAG_print_code_verbose) PrintF(out, "\n");
}
}
- if (!FLAG_print_code_verbose) PrintF(" %12d\n", command_count);
+ if (!FLAG_print_code_verbose) PrintF(out, " %12d\n", command_count);
}
}
-void DeoptimizationOutputData::DeoptimizationOutputDataPrint() {
- PrintF("Deoptimization Output Data (deopt points = %d)\n",
+void DeoptimizationOutputData::DeoptimizationOutputDataPrint(FILE* out) {
+ PrintF(out, "Deoptimization Output Data (deopt points = %d)\n",
this->DeoptPoints());
if (this->DeoptPoints() == 0) return;
@@ -6202,56 +6203,56 @@
}
-void Code::Disassemble(const char* name) {
- PrintF("kind = %s\n", Kind2String(kind()));
+void Code::Disassemble(const char* name, FILE* out) {
+ PrintF(out, "kind = %s\n", Kind2String(kind()));
if (is_inline_cache_stub()) {
- PrintF("ic_state = %s\n", ICState2String(ic_state()));
- PrintF("ic_in_loop = %d\n", ic_in_loop() == IN_LOOP);
+ PrintF(out, "ic_state = %s\n", ICState2String(ic_state()));
+ PrintF(out, "ic_in_loop = %d\n", ic_in_loop() == IN_LOOP);
if (ic_state() == MONOMORPHIC) {
- PrintF("type = %s\n", PropertyType2String(type()));
+ PrintF(out, "type = %s\n", PropertyType2String(type()));
}
}
if ((name != NULL) && (name[0] != '\0')) {
- PrintF("name = %s\n", name);
+ PrintF(out, "name = %s\n", name);
}
if (kind() == OPTIMIZED_FUNCTION) {
- PrintF("stack_slots = %d\n", stack_slots());
+ PrintF(out, "stack_slots = %d\n", stack_slots());
}
- PrintF("Instructions (size = %d)\n", instruction_size());
- Disassembler::Decode(NULL, this);
- PrintF("\n");
+ PrintF(out, "Instructions (size = %d)\n", instruction_size());
+ Disassembler::Decode(out, this);
+ PrintF(out, "\n");
#ifdef DEBUG
if (kind() == FUNCTION) {
DeoptimizationOutputData* data =
DeoptimizationOutputData::cast(this->deoptimization_data());
- data->DeoptimizationOutputDataPrint();
+ data->DeoptimizationOutputDataPrint(out);
} else if (kind() == OPTIMIZED_FUNCTION) {
DeoptimizationInputData* data =
DeoptimizationInputData::cast(this->deoptimization_data());
- data->DeoptimizationInputDataPrint();
+ data->DeoptimizationInputDataPrint(out);
}
PrintF("\n");
#endif
if (kind() == OPTIMIZED_FUNCTION) {
SafepointTable table(this);
- PrintF("Safepoints (size = %u)\n", table.size());
+ PrintF(out, "Safepoints (size = %u)\n", table.size());
for (unsigned i = 0; i < table.length(); i++) {
unsigned pc_offset = table.GetPcOffset(i);
- PrintF("%p %4d ", (instruction_start() + pc_offset), pc_offset);
+ PrintF(out, "%p %4d ", (instruction_start() + pc_offset), pc_offset);
table.PrintEntry(i);
- PrintF(" (sp -> fp)");
+ PrintF(out, " (sp -> fp)");
int deoptimization_index = table.GetDeoptimizationIndex(i);
if (deoptimization_index != Safepoint::kNoDeoptimizationIndex) {
- PrintF(" %6d", deoptimization_index);
+ PrintF(out, " %6d", deoptimization_index);
} else {
- PrintF(" <none>");
+ PrintF(out, " <none>");
}
- PrintF("\n");
+ PrintF(out, "\n");
}
- PrintF("\n");
+ PrintF(out, "\n");
} else if (kind() == FUNCTION) {
unsigned offset = stack_check_table_start();
// If there is no stack check table, the "table start" will at or after
@@ -6260,19 +6261,19 @@
unsigned* address =
reinterpret_cast<unsigned*>(instruction_start() + offset);
unsigned length = address[0];
- PrintF("Stack checks (size = %u)\n", length);
- PrintF("ast_id pc_offset\n");
+ PrintF(out, "Stack checks (size = %u)\n", length);
+ PrintF(out, "ast_id pc_offset\n");
for (unsigned i = 0; i < length; ++i) {
unsigned index = (2 * i) + 1;
- PrintF("%6u %9u\n", address[index], address[index + 1]);
+ PrintF(out, "%6u %9u\n", address[index], address[index + 1]);
}
- PrintF("\n");
+ PrintF(out, "\n");
}
}
PrintF("RelocInfo (size = %d)\n", relocation_size());
- for (RelocIterator it(this); !it.done(); it.next()) it.rinfo()->Print();
- PrintF("\n");
+ for (RelocIterator it(this); !it.done(); it.next()) it.rinfo()->Print(out);
+ PrintF(out, "\n");
}
#endif // ENABLE_DISASSEMBLER
@@ -7421,22 +7422,22 @@
// class. This requires us to have the template functions put
// together, so even though this function belongs in objects-debug.cc,
// we keep it here instead to satisfy certain compilers.
-#ifdef DEBUG
+#ifdef OBJECT_PRINT
template<typename Shape, typename Key>
-void Dictionary<Shape, Key>::Print() {
+void Dictionary<Shape, Key>::Print(FILE* out) {
int capacity = HashTable<Shape, Key>::Capacity();
for (int i = 0; i < capacity; i++) {
Object* k = HashTable<Shape, Key>::KeyAt(i);
if (HashTable<Shape, Key>::IsKey(k)) {
- PrintF(" ");
+ PrintF(out, " ");
if (k->IsString()) {
- String::cast(k)->StringPrint();
+ String::cast(k)->StringPrint(out);
} else {
- k->ShortPrint();
+ k->ShortPrint(out);
}
- PrintF(": ");
- ValueAt(i)->ShortPrint();
- PrintF("\n");
+ PrintF(out, ": ");
+ ValueAt(i)->ShortPrint(out);
+ PrintF(out, "\n");
}
}
}
diff --git a/src/objects.h b/src/objects.h
index 498ee45..c5fda7d 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -607,10 +607,18 @@
return reinterpret_cast<Object*>(this);
}
-#ifdef DEBUG
+#ifdef OBJECT_PRINT
// Prints this object with details.
- void Print();
- void PrintLn();
+ inline void Print() {
+ Print(stdout);
+ };
+ inline void PrintLn() {
+ PrintLn(stdout);
+ }
+ void Print(FILE* out);
+ void PrintLn(FILE* out);
+#endif
+#ifdef DEBUG
// Verifies the object.
void Verify();
#endif
@@ -762,7 +770,10 @@
#endif
// Prints this object without details.
- void ShortPrint();
+ inline void ShortPrint() {
+ ShortPrint(stdout);
+ }
+ void ShortPrint(FILE* out);
// Prints this object without details to a message accumulator.
void ShortPrint(StringStream* accumulator);
@@ -801,7 +812,10 @@
static inline Smi* cast(Object* object);
// Dispatched behavior.
- void SmiPrint();
+ inline void SmiPrint() {
+ SmiPrint(stdout);
+ }
+ void SmiPrint(FILE* out);
void SmiPrint(StringStream* accumulator);
#ifdef DEBUG
void SmiVerify();
@@ -870,7 +884,10 @@
static inline Failure* cast(MaybeObject* object);
// Dispatched behavior.
- void FailurePrint();
+ inline void FailurePrint() {
+ FailurePrint(stdout);
+ }
+ void FailurePrint(FILE* out);
void FailurePrint(StringStream* accumulator);
#ifdef DEBUG
void FailureVerify();
@@ -1099,14 +1116,23 @@
// Dispatched behavior.
void HeapObjectShortPrint(StringStream* accumulator);
+#ifdef OBJECT_PRINT
+ inline void HeapObjectPrint() {
+ HeapObjectPrint(stdout);
+ }
+ void HeapObjectPrint(FILE* out);
+#endif
#ifdef DEBUG
- void HeapObjectPrint();
void HeapObjectVerify();
inline void VerifyObjectField(int offset);
inline void VerifySmiField(int offset);
+#endif
- void PrintHeader(const char* id);
+#ifdef OBJECT_PRINT
+ void PrintHeader(FILE* out, const char* id);
+#endif
+#ifdef DEBUG
// Verify a pointer is a valid HeapObject pointer that points to object
// areas in the heap.
static void VerifyHeapPointer(Object* p);
@@ -1189,7 +1215,10 @@
// Dispatched behavior.
Object* HeapNumberToBoolean();
- void HeapNumberPrint();
+ inline void HeapNumberPrint() {
+ HeapNumberPrint(stdout);
+ }
+ void HeapNumberPrint(FILE* out);
void HeapNumberPrint(StringStream* accumulator);
#ifdef DEBUG
void HeapNumberVerify();
@@ -1649,12 +1678,28 @@
// Dispatched behavior.
void JSObjectShortPrint(StringStream* accumulator);
+#ifdef OBJECT_PRINT
+ inline void JSObjectPrint() {
+ JSObjectPrint(stdout);
+ }
+ void JSObjectPrint(FILE* out);
+#endif
#ifdef DEBUG
- void JSObjectPrint();
void JSObjectVerify();
- void PrintProperties();
- void PrintElements();
+#endif
+#ifdef OBJECT_PRINT
+ inline void PrintProperties() {
+ PrintProperties(stdout);
+ }
+ void PrintProperties(FILE* out);
+ inline void PrintElements() {
+ PrintElements(stdout);
+ }
+ void PrintElements(FILE* out);
+#endif
+
+#ifdef DEBUG
// Structure for collecting spill information about JSObjects.
class SpillInformation {
public:
@@ -1689,7 +1734,7 @@
static const uint32_t kMaxGap = 1024;
static const int kMaxFastElementsLength = 5000;
static const int kInitialMaxFastElementArray = 100000;
- static const int kMaxFastProperties = 8;
+ static const int kMaxFastProperties = 12;
static const int kMaxInstanceSize = 255 * kPointerSize;
// When extending the backing storage for property values, we increase
// its size by more than the 1 entry necessary, so sequentially adding fields
@@ -1835,8 +1880,13 @@
static const int kMaxLength = (kMaxSize - kHeaderSize) / kPointerSize;
// Dispatched behavior.
+#ifdef OBJECT_PRINT
+ inline void FixedArrayPrint() {
+ FixedArrayPrint(stdout);
+ }
+ void FixedArrayPrint(FILE* out);
+#endif
#ifdef DEBUG
- void FixedArrayPrint();
void FixedArrayVerify();
// Checks if two FixedArrays have identical contents.
bool IsEqualTo(FixedArray* other);
@@ -2012,10 +2062,15 @@
static const int kEnumCacheBridgeCacheOffset =
kEnumCacheBridgeEnumOffset + kPointerSize;
-#ifdef DEBUG
+#ifdef OBJECT_PRINT
// Print all the descriptors.
- void PrintDescriptors();
+ inline void PrintDescriptors() {
+ PrintDescriptors(stdout);
+ }
+ void PrintDescriptors(FILE* out);
+#endif
+#ifdef DEBUG
// Is the descriptor array sorted and without duplicates?
bool IsSortedNoDuplicates();
@@ -2396,8 +2451,11 @@
// Ensure enough space for n additional elements.
MUST_USE_RESULT MaybeObject* EnsureCapacity(int n, Key key);
-#ifdef DEBUG
- void Print();
+#ifdef OBJECT_PRINT
+ inline void Print() {
+ Print(stdout);
+ }
+ void Print(FILE* out);
#endif
// Returns the key (slow).
Object* SlowReverseLookup(Object* value);
@@ -2619,8 +2677,13 @@
inline int ByteArraySize() {
return SizeFor(this->length());
}
+#ifdef OBJECT_PRINT
+ inline void ByteArrayPrint() {
+ ByteArrayPrint(stdout);
+ }
+ void ByteArrayPrint(FILE* out);
+#endif
#ifdef DEBUG
- void ByteArrayPrint();
void ByteArrayVerify();
#endif
@@ -2669,8 +2732,13 @@
// Casting.
static inline PixelArray* cast(Object* obj);
+#ifdef OBJECT_PRINT
+ inline void PixelArrayPrint() {
+ PixelArrayPrint(stdout);
+ }
+ void PixelArrayPrint(FILE* out);
+#endif
#ifdef DEBUG
- void PixelArrayPrint();
void PixelArrayVerify();
#endif // DEBUG
@@ -2741,8 +2809,13 @@
// Casting.
static inline ExternalByteArray* cast(Object* obj);
+#ifdef OBJECT_PRINT
+ inline void ExternalByteArrayPrint() {
+ ExternalByteArrayPrint(stdout);
+ }
+ void ExternalByteArrayPrint(FILE* out);
+#endif
#ifdef DEBUG
- void ExternalByteArrayPrint();
void ExternalByteArrayVerify();
#endif // DEBUG
@@ -2764,8 +2837,13 @@
// Casting.
static inline ExternalUnsignedByteArray* cast(Object* obj);
+#ifdef OBJECT_PRINT
+ inline void ExternalUnsignedByteArrayPrint() {
+ ExternalUnsignedByteArrayPrint(stdout);
+ }
+ void ExternalUnsignedByteArrayPrint(FILE* out);
+#endif
#ifdef DEBUG
- void ExternalUnsignedByteArrayPrint();
void ExternalUnsignedByteArrayVerify();
#endif // DEBUG
@@ -2787,8 +2865,13 @@
// Casting.
static inline ExternalShortArray* cast(Object* obj);
+#ifdef OBJECT_PRINT
+ inline void ExternalShortArrayPrint() {
+ ExternalShortArrayPrint(stdout);
+ }
+ void ExternalShortArrayPrint(FILE* out);
+#endif
#ifdef DEBUG
- void ExternalShortArrayPrint();
void ExternalShortArrayVerify();
#endif // DEBUG
@@ -2810,8 +2893,13 @@
// Casting.
static inline ExternalUnsignedShortArray* cast(Object* obj);
+#ifdef OBJECT_PRINT
+ inline void ExternalUnsignedShortArrayPrint() {
+ ExternalUnsignedShortArrayPrint(stdout);
+ }
+ void ExternalUnsignedShortArrayPrint(FILE* out);
+#endif
#ifdef DEBUG
- void ExternalUnsignedShortArrayPrint();
void ExternalUnsignedShortArrayVerify();
#endif // DEBUG
@@ -2833,8 +2921,13 @@
// Casting.
static inline ExternalIntArray* cast(Object* obj);
+#ifdef OBJECT_PRINT
+ inline void ExternalIntArrayPrint() {
+ ExternalIntArrayPrint(stdout);
+ }
+ void ExternalIntArrayPrint(FILE* out);
+#endif
#ifdef DEBUG
- void ExternalIntArrayPrint();
void ExternalIntArrayVerify();
#endif // DEBUG
@@ -2856,8 +2949,13 @@
// Casting.
static inline ExternalUnsignedIntArray* cast(Object* obj);
+#ifdef OBJECT_PRINT
+ inline void ExternalUnsignedIntArrayPrint() {
+ ExternalUnsignedIntArrayPrint(stdout);
+ }
+ void ExternalUnsignedIntArrayPrint(FILE* out);
+#endif
#ifdef DEBUG
- void ExternalUnsignedIntArrayPrint();
void ExternalUnsignedIntArrayVerify();
#endif // DEBUG
@@ -2879,8 +2977,13 @@
// Casting.
static inline ExternalFloatArray* cast(Object* obj);
+#ifdef OBJECT_PRINT
+ inline void ExternalFloatArrayPrint() {
+ ExternalFloatArrayPrint(stdout);
+ }
+ void ExternalFloatArrayPrint(FILE* out);
+#endif
#ifdef DEBUG
- void ExternalFloatArrayPrint();
void ExternalFloatArrayVerify();
#endif // DEBUG
@@ -2960,8 +3063,8 @@
// Casting.
static inline DeoptimizationInputData* cast(Object* obj);
-#ifdef DEBUG
- void DeoptimizationInputDataPrint();
+#ifdef OBJECT_PRINT
+ void DeoptimizationInputDataPrint(FILE* out);
#endif
private:
@@ -2999,8 +3102,8 @@
// Casting.
static inline DeoptimizationOutputData* cast(Object* obj);
-#ifdef DEBUG
- void DeoptimizationOutputDataPrint();
+#ifdef OBJECT_PRINT
+ void DeoptimizationOutputDataPrint(FILE* out);
#endif
};
@@ -3049,7 +3152,10 @@
static const char* Kind2String(Kind kind);
static const char* ICState2String(InlineCacheState state);
static const char* PropertyType2String(PropertyType type);
- void Disassemble(const char* name);
+ inline void Disassemble(const char* name) {
+ Disassemble(name, stdout);
+ }
+ void Disassemble(const char* name, FILE* out);
#endif // ENABLE_DISASSEMBLER
// [instruction_size]: Size of the native instructions
@@ -3242,8 +3348,13 @@
template<typename StaticVisitor>
inline void CodeIterateBody();
+#ifdef OBJECT_PRINT
+ inline void CodePrint() {
+ CodePrint(stdout);
+ }
+ void CodePrint(FILE* out);
+#endif
#ifdef DEBUG
- void CodePrint();
void CodeVerify();
#endif
@@ -3531,8 +3642,13 @@
void ClearNonLiveTransitions(Object* real_prototype);
// Dispatched behavior.
+#ifdef OBJECT_PRINT
+ inline void MapPrint() {
+ MapPrint(stdout);
+ }
+ void MapPrint(FILE* out);
+#endif
#ifdef DEBUG
- void MapPrint();
void MapVerify();
void SharedMapVerify();
#endif
@@ -3688,8 +3804,13 @@
// resource is accessible. Otherwise, always return true.
inline bool HasValidSource();
+#ifdef OBJECT_PRINT
+ inline void ScriptPrint() {
+ ScriptPrint(stdout);
+ }
+ void ScriptPrint(FILE* out);
+#endif
#ifdef DEBUG
- void ScriptPrint();
void ScriptVerify();
#endif
@@ -4052,8 +4173,13 @@
// Dispatched behavior.
// Set max_length to -1 for unlimited length.
void SourceCodePrint(StringStream* accumulator, int max_length);
+#ifdef OBJECT_PRINT
+ inline void SharedFunctionInfoPrint() {
+ SharedFunctionInfoPrint(stdout);
+ }
+ void SharedFunctionInfoPrint(FILE* out);
+#endif
#ifdef DEBUG
- void SharedFunctionInfoPrint();
void SharedFunctionInfoVerify();
#endif
@@ -4285,7 +4411,10 @@
DECL_ACCESSORS(next_function_link, Object)
// Prints the name of the function using PrintF.
- void PrintName();
+ inline void PrintName() {
+ PrintName(stdout);
+ }
+ void PrintName(FILE* out);
// Casting.
static inline JSFunction* cast(Object* obj);
@@ -4295,8 +4424,13 @@
void JSFunctionIterateBody(int object_size, ObjectVisitor* v);
// Dispatched behavior.
+#ifdef OBJECT_PRINT
+ inline void JSFunctionPrint() {
+ JSFunctionPrint(stdout);
+ }
+ void JSFunctionPrint(FILE* out);
+#endif
#ifdef DEBUG
- void JSFunctionPrint();
void JSFunctionVerify();
#endif
@@ -4345,8 +4479,13 @@
static inline JSGlobalProxy* cast(Object* obj);
// Dispatched behavior.
+#ifdef OBJECT_PRINT
+ inline void JSGlobalProxyPrint() {
+ JSGlobalProxyPrint(stdout);
+ }
+ void JSGlobalProxyPrint(FILE* out);
+#endif
#ifdef DEBUG
- void JSGlobalProxyPrint();
void JSGlobalProxyVerify();
#endif
@@ -4416,8 +4555,13 @@
static inline JSGlobalObject* cast(Object* obj);
// Dispatched behavior.
+#ifdef OBJECT_PRINT
+ inline void JSGlobalObjectPrint() {
+ JSGlobalObjectPrint(stdout);
+ }
+ void JSGlobalObjectPrint(FILE* out);
+#endif
#ifdef DEBUG
- void JSGlobalObjectPrint();
void JSGlobalObjectVerify();
#endif
@@ -4445,8 +4589,13 @@
static inline JSBuiltinsObject* cast(Object* obj);
// Dispatched behavior.
+#ifdef OBJECT_PRINT
+ inline void JSBuiltinsObjectPrint() {
+ JSBuiltinsObjectPrint(stdout);
+ }
+ void JSBuiltinsObjectPrint(FILE* out);
+#endif
#ifdef DEBUG
- void JSBuiltinsObjectPrint();
void JSBuiltinsObjectVerify();
#endif
@@ -4483,8 +4632,13 @@
static inline JSValue* cast(Object* obj);
// Dispatched behavior.
+#ifdef OBJECT_PRINT
+ inline void JSValuePrint() {
+ JSValuePrint(stdout);
+ }
+ void JSValuePrint(FILE* out);
+#endif
#ifdef DEBUG
- void JSValuePrint();
void JSValueVerify();
#endif
@@ -4673,8 +4827,13 @@
static inline CodeCache* cast(Object* obj);
+#ifdef OBJECT_PRINT
+ inline void CodeCachePrint() {
+ CodeCachePrint(stdout);
+ }
+ void CodeCachePrint(FILE* out);
+#endif
#ifdef DEBUG
- void CodeCachePrint();
void CodeCacheVerify();
#endif
@@ -4975,8 +5134,13 @@
// Dispatched behavior.
void StringShortPrint(StringStream* accumulator);
+#ifdef OBJECT_PRINT
+ inline void StringPrint() {
+ StringPrint(stdout);
+ }
+ void StringPrint(FILE* out);
+#endif
#ifdef DEBUG
- void StringPrint();
void StringVerify();
#endif
inline bool IsFlat();
@@ -5531,7 +5695,12 @@
#ifdef DEBUG
void JSGlobalPropertyCellVerify();
- void JSGlobalPropertyCellPrint();
+#endif
+#ifdef OBJECT_PRINT
+ inline void JSGlobalPropertyCellPrint() {
+ JSGlobalPropertyCellPrint(stdout);
+ }
+ void JSGlobalPropertyCellPrint(FILE* out);
#endif
// Layout description.
@@ -5566,8 +5735,13 @@
template<typename StaticVisitor>
inline void ProxyIterateBody();
+#ifdef OBJECT_PRINT
+ inline void ProxyPrint() {
+ ProxyPrint(stdout);
+ }
+ void ProxyPrint(FILE* out);
+#endif
#ifdef DEBUG
- void ProxyPrint();
void ProxyVerify();
#endif
@@ -5616,8 +5790,13 @@
inline void EnsureSize(int minimum_size_of_backing_fixed_array);
// Dispatched behavior.
+#ifdef OBJECT_PRINT
+ inline void JSArrayPrint() {
+ JSArrayPrint(stdout);
+ }
+ void JSArrayPrint(FILE* out);
+#endif
#ifdef DEBUG
- void JSArrayPrint();
void JSArrayVerify();
#endif
@@ -5688,8 +5867,13 @@
static inline AccessorInfo* cast(Object* obj);
+#ifdef OBJECT_PRINT
+ inline void AccessorInfoPrint() {
+ AccessorInfoPrint(stdout);
+ }
+ void AccessorInfoPrint(FILE* out);
+#endif
#ifdef DEBUG
- void AccessorInfoPrint();
void AccessorInfoVerify();
#endif
@@ -5719,8 +5903,13 @@
static inline AccessCheckInfo* cast(Object* obj);
+#ifdef OBJECT_PRINT
+ inline void AccessCheckInfoPrint() {
+ AccessCheckInfoPrint(stdout);
+ }
+ void AccessCheckInfoPrint(FILE* out);
+#endif
#ifdef DEBUG
- void AccessCheckInfoPrint();
void AccessCheckInfoVerify();
#endif
@@ -5745,8 +5934,13 @@
static inline InterceptorInfo* cast(Object* obj);
+#ifdef OBJECT_PRINT
+ inline void InterceptorInfoPrint() {
+ InterceptorInfoPrint(stdout);
+ }
+ void InterceptorInfoPrint(FILE* out);
+#endif
#ifdef DEBUG
- void InterceptorInfoPrint();
void InterceptorInfoVerify();
#endif
@@ -5770,8 +5964,13 @@
static inline CallHandlerInfo* cast(Object* obj);
+#ifdef OBJECT_PRINT
+ inline void CallHandlerInfoPrint() {
+ CallHandlerInfoPrint(stdout);
+ }
+ void CallHandlerInfoPrint(FILE* out);
+#endif
#ifdef DEBUG
- void CallHandlerInfoPrint();
void CallHandlerInfoVerify();
#endif
@@ -5827,8 +6026,13 @@
static inline FunctionTemplateInfo* cast(Object* obj);
+#ifdef OBJECT_PRINT
+ inline void FunctionTemplateInfoPrint() {
+ FunctionTemplateInfoPrint(stdout);
+ }
+ void FunctionTemplateInfoPrint(FILE* out);
+#endif
#ifdef DEBUG
- void FunctionTemplateInfoPrint();
void FunctionTemplateInfoVerify();
#endif
@@ -5870,8 +6074,13 @@
static inline ObjectTemplateInfo* cast(Object* obj);
+#ifdef OBJECT_PRINT
+ inline void ObjectTemplateInfoPrint() {
+ ObjectTemplateInfoPrint(stdout);
+ }
+ void ObjectTemplateInfoPrint(FILE* out);
+#endif
#ifdef DEBUG
- void ObjectTemplateInfoPrint();
void ObjectTemplateInfoVerify();
#endif
@@ -5889,8 +6098,13 @@
static inline SignatureInfo* cast(Object* obj);
+#ifdef OBJECT_PRINT
+ inline void SignatureInfoPrint() {
+ SignatureInfoPrint(stdout);
+ }
+ void SignatureInfoPrint(FILE* out);
+#endif
#ifdef DEBUG
- void SignatureInfoPrint();
void SignatureInfoVerify();
#endif
@@ -5909,8 +6123,13 @@
static inline TypeSwitchInfo* cast(Object* obj);
+#ifdef OBJECT_PRINT
+ inline void TypeSwitchInfoPrint() {
+ TypeSwitchInfoPrint(stdout);
+ }
+ void TypeSwitchInfoPrint(FILE* out);
+#endif
#ifdef DEBUG
- void TypeSwitchInfoPrint();
void TypeSwitchInfoVerify();
#endif
@@ -5956,8 +6175,13 @@
static inline DebugInfo* cast(Object* obj);
+#ifdef OBJECT_PRINT
+ inline void DebugInfoPrint() {
+ DebugInfoPrint(stdout);
+ }
+ void DebugInfoPrint(FILE* out);
+#endif
#ifdef DEBUG
- void DebugInfoPrint();
void DebugInfoVerify();
#endif
@@ -6009,8 +6233,13 @@
static inline BreakPointInfo* cast(Object* obj);
+#ifdef OBJECT_PRINT
+ inline void BreakPointInfoPrint() {
+ BreakPointInfoPrint(stdout);
+ }
+ void BreakPointInfoPrint(FILE* out);
+#endif
#ifdef DEBUG
- void BreakPointInfoPrint();
void BreakPointInfoVerify();
#endif
diff --git a/src/parser.cc b/src/parser.cc
index 94ad57c..08f77b8 100644
--- a/src/parser.cc
+++ b/src/parser.cc
@@ -3730,7 +3730,7 @@
contains_anchor_(false),
is_scanned_for_captures_(false),
failed_(false) {
- Advance(1);
+ Advance();
}
@@ -3768,8 +3768,8 @@
void RegExpParser::Advance(int dist) {
- for (int i = 0; i < dist; i++)
- Advance();
+ next_pos_ += dist - 1;
+ Advance();
}
diff --git a/src/platform-nullos.cc b/src/platform-nullos.cc
index f34483d..72ea0e5 100644
--- a/src/platform-nullos.cc
+++ b/src/platform-nullos.cc
@@ -128,6 +128,19 @@
}
+void OS::FPrint(FILE* out, const char* format, ...) {
+ va_list args;
+ va_start(args, format);
+ VFPrint(out, format, args);
+ va_end(args);
+}
+
+
+void OS::VFPrint(FILE* out, const char* format, va_list args) {
+ vfprintf(out, format, args);
+}
+
+
// Print error message to console.
void OS::PrintError(const char* format, ...) {
// Minimalistic implementation for bootstrapping.
diff --git a/src/platform-posix.cc b/src/platform-posix.cc
index c50d396..ab5c0a3 100644
--- a/src/platform-posix.cc
+++ b/src/platform-posix.cc
@@ -142,6 +142,23 @@
}
+void OS::FPrint(FILE* out, const char* format, ...) {
+ va_list args;
+ va_start(args, format);
+ VFPrint(out, format, args);
+ va_end(args);
+}
+
+
+void OS::VFPrint(FILE* out, const char* format, va_list args) {
+#if defined(ANDROID)
+ LOG_PRI_VA(ANDROID_LOG_INFO, LOG_TAG, format, args);
+#else
+ vfprintf(out, format, args);
+#endif
+}
+
+
void OS::PrintError(const char* format, ...) {
va_list args;
va_start(args, format);
@@ -173,7 +190,9 @@
va_list args) {
int n = vsnprintf(str.start(), str.length(), format, args);
if (n < 0 || n >= str.length()) {
- str[str.length() - 1] = '\0';
+ // If the length is zero, the assignment fails.
+ if (str.length() > 0)
+ str[str.length() - 1] = '\0';
return -1;
} else {
return n;
@@ -204,6 +223,14 @@
explicit POSIXSocket() {
// Create the socket.
socket_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if (IsValid()) {
+ // Allow rapid reuse.
+ static const int kOn = 1;
+ int ret = setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR,
+ &kOn, sizeof(kOn));
+ ASSERT(ret == 0);
+ USE(ret);
+ }
}
explicit POSIXSocket(int socket): socket_(socket) { }
virtual ~POSIXSocket() { Shutdown(); }
diff --git a/src/platform-win32.cc b/src/platform-win32.cc
index badc31b..4438045 100644
--- a/src/platform-win32.cc
+++ b/src/platform-win32.cc
@@ -688,6 +688,19 @@
}
+void OS::FPrint(FILE* out, const char* format, ...) {
+ va_list args;
+ va_start(args, format);
+ VFPrint(out, format, args);
+ va_end(args);
+}
+
+
+void OS::VFPrint(FILE* out, const char* format, va_list args) {
+ VPrintHelper(out, format, args);
+}
+
+
// Print error message to console.
void OS::PrintError(const char* format, ...) {
va_list args;
@@ -716,7 +729,8 @@
// Make sure to zero-terminate the string if the output was
// truncated or if there was an error.
if (n < 0 || n >= str.length()) {
- str[str.length() - 1] = '\0';
+ if (str.length() > 0)
+ str[str.length() - 1] = '\0';
return -1;
} else {
return n;
diff --git a/src/platform.h b/src/platform.h
index 13ea983..5a3e4a3 100644
--- a/src/platform.h
+++ b/src/platform.h
@@ -184,6 +184,10 @@
static void Print(const char* format, ...);
static void VPrint(const char* format, va_list args);
+ // Print output to a file. This is mostly used for debugging output.
+ static void FPrint(FILE* out, const char* format, ...);
+ static void VFPrint(FILE* out, const char* format, va_list args);
+
// Print error output to console. This is mostly used for error message
// output. On platforms that has standard terminal output, the output
// should go to stderr.
diff --git a/src/profile-generator.cc b/src/profile-generator.cc
index 364f51d..34d1877 100644
--- a/src/profile-generator.cc
+++ b/src/profile-generator.cc
@@ -2218,7 +2218,7 @@
void HeapSnapshotGenerator::SetProgressTotal(int iterations_count) {
if (control_ == NULL) return;
- HeapIterator iterator(HeapIterator::kPreciseFiltering);
+ HeapIterator iterator(HeapIterator::kFilterUnreachable);
int objects_count = 0;
for (HeapObject* obj = iterator.next();
obj != NULL;
@@ -2342,8 +2342,6 @@
ASSERT(dominators[i] != NULL);
ordered_entries[i]->set_dominator(dominators[i]);
}
- // For nodes unreachable from root, set dominator to itself.
- snapshot_->SetDominatorsToSelf();
return true;
}
@@ -2373,9 +2371,9 @@
bool HeapSnapshotGenerator::IterateAndExtractReferences() {
- HeapIterator iterator(HeapIterator::kPreciseFiltering);
+ HeapIterator iterator(HeapIterator::kFilterUnreachable);
bool interrupted = false;
- // Heap iteration with precise filtering must be finished in any case.
+ // Heap iteration with filtering must be finished in any case.
for (HeapObject* obj = iterator.next();
obj != NULL;
obj = iterator.next(), IncProgressCounter()) {
diff --git a/src/property.cc b/src/property.cc
index b579b68..9677433 100644
--- a/src/property.cc
+++ b/src/property.cc
@@ -31,62 +31,62 @@
namespace internal {
-#ifdef DEBUG
-void LookupResult::Print() {
+#ifdef OBJECT_PRINT
+void LookupResult::Print(FILE* out) {
if (!IsFound()) {
- PrintF("Not Found\n");
+ PrintF(out, "Not Found\n");
return;
}
- PrintF("LookupResult:\n");
- PrintF(" -cacheable = %s\n", IsCacheable() ? "true" : "false");
- PrintF(" -attributes = %x\n", GetAttributes());
+ PrintF(out, "LookupResult:\n");
+ PrintF(out, " -cacheable = %s\n", IsCacheable() ? "true" : "false");
+ PrintF(out, " -attributes = %x\n", GetAttributes());
switch (type()) {
case NORMAL:
- PrintF(" -type = normal\n");
- PrintF(" -entry = %d", GetDictionaryEntry());
+ PrintF(out, " -type = normal\n");
+ PrintF(out, " -entry = %d", GetDictionaryEntry());
break;
case MAP_TRANSITION:
- PrintF(" -type = map transition\n");
- PrintF(" -map:\n");
- GetTransitionMap()->Print();
- PrintF("\n");
+ PrintF(out, " -type = map transition\n");
+ PrintF(out, " -map:\n");
+ GetTransitionMap()->Print(out);
+ PrintF(out, "\n");
break;
case CONSTANT_FUNCTION:
- PrintF(" -type = constant function\n");
- PrintF(" -function:\n");
- GetConstantFunction()->Print();
- PrintF("\n");
+ PrintF(out, " -type = constant function\n");
+ PrintF(out, " -function:\n");
+ GetConstantFunction()->Print(out);
+ PrintF(out, "\n");
break;
case FIELD:
- PrintF(" -type = field\n");
- PrintF(" -index = %d", GetFieldIndex());
- PrintF("\n");
+ PrintF(out, " -type = field\n");
+ PrintF(out, " -index = %d", GetFieldIndex());
+ PrintF(out, "\n");
break;
case CALLBACKS:
- PrintF(" -type = call backs\n");
- PrintF(" -callback object:\n");
- GetCallbackObject()->Print();
+ PrintF(out, " -type = call backs\n");
+ PrintF(out, " -callback object:\n");
+ GetCallbackObject()->Print(out);
break;
case INTERCEPTOR:
- PrintF(" -type = lookup interceptor\n");
+ PrintF(out, " -type = lookup interceptor\n");
break;
case CONSTANT_TRANSITION:
- PrintF(" -type = constant property transition\n");
+ PrintF(out, " -type = constant property transition\n");
break;
case NULL_DESCRIPTOR:
- PrintF(" =type = null descriptor\n");
+ PrintF(out, " =type = null descriptor\n");
break;
}
}
-void Descriptor::Print() {
- PrintF("Descriptor ");
- GetKey()->ShortPrint();
- PrintF(" @ ");
- GetValue()->ShortPrint();
- PrintF(" %d\n", GetDetails().index());
+void Descriptor::Print(FILE* out) {
+ PrintF(out, "Descriptor ");
+ GetKey()->ShortPrint(out);
+ PrintF(out, " @ ");
+ GetValue()->ShortPrint(out);
+ PrintF(out, " %d\n", GetDetails().index());
}
diff --git a/src/property.h b/src/property.h
index 537b4e6..c39fe41 100644
--- a/src/property.h
+++ b/src/property.h
@@ -60,8 +60,8 @@
Object* GetValue() { return value_; }
PropertyDetails GetDetails() { return details_; }
-#ifdef DEBUG
- void Print();
+#ifdef OBJECT_PRINT
+ void Print(FILE* out);
#endif
void SetEnumerationIndex(int index) {
@@ -310,8 +310,8 @@
return GetValue();
}
-#ifdef DEBUG
- void Print();
+#ifdef OBJECT_PRINT
+ void Print(FILE* out);
#endif
Object* GetValue() {
diff --git a/src/regexp.js b/src/regexp.js
index dd27266..0de66c6 100644
--- a/src/regexp.js
+++ b/src/regexp.js
@@ -32,7 +32,7 @@
// A recursive descent parser for Patterns according to the grammar of
// ECMA-262 15.10.1, with deviations noted below.
-function DoConstructRegExp(object, pattern, flags, isConstructorCall) {
+function DoConstructRegExp(object, pattern, flags) {
// RegExp : Called as constructor; see ECMA-262, section 15.10.4.
if (IS_REGEXP(pattern)) {
if (!IS_UNDEFINED(flags)) {
@@ -80,7 +80,7 @@
function RegExpConstructor(pattern, flags) {
if (%_IsConstructCall()) {
- DoConstructRegExp(this, pattern, flags, true);
+ DoConstructRegExp(this, pattern, flags);
} else {
// RegExp : Called as function; see ECMA-262, section 15.10.3.1.
if (IS_REGEXP(pattern) && IS_UNDEFINED(flags)) {
@@ -104,9 +104,9 @@
// the empty string. For compatibility with JSC, we match their
// behavior.
if (IS_UNDEFINED(pattern) && %_ArgumentsLength() != 0) {
- DoConstructRegExp(this, 'undefined', flags, false);
+ DoConstructRegExp(this, 'undefined', flags);
} else {
- DoConstructRegExp(this, pattern, flags, false);
+ DoConstructRegExp(this, pattern, flags);
}
}
@@ -150,12 +150,12 @@
function RegExpExecNoTests(regexp, string, start) {
// Must be called with RegExp, string and positive integer as arguments.
- var matchInfo = DoRegExpExec(regexp, string, start);
- var result = null;
+ var matchInfo = %_RegExpExec(regexp, string, start, lastMatchInfo);
if (matchInfo !== null) {
- result = BuildResultFromMatchInfo(matchInfo, string);
+ lastMatchInfoOverride = null;
+ return BuildResultFromMatchInfo(matchInfo, string);
}
- return result;
+ return null;
}
@@ -261,11 +261,14 @@
%_StringCharCodeAt(this.source, 2) != 63) { // '?'
if (!%_ObjectEquals(regexp_key, this)) {
regexp_key = this;
- regexp_val = new $RegExp(this.source.substring(2, this.source.length),
- (this.ignoreCase ? 'i' : '')
- + (this.multiline ? 'm' : ''));
+ regexp_val = new $RegExp(SubString(this.source, 2, this.source.length),
+ (!this.ignoreCase
+ ? !this.multiline ? "" : "m"
+ : !this.multiline ? "i" : "im"));
}
- if (!regexp_val.test(string)) return false;
+ if (%_RegExpExec(regexp_val, string, 0, lastMatchInfo) === null) {
+ return false;
+ }
}
%_Log('regexp', 'regexp-exec,%0r,%1S,%2i', [this, string, lastIndex]);
// matchIndices is either null or the lastMatchInfo array.
diff --git a/src/runtime.cc b/src/runtime.cc
index 0fd2f8b..724a436 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -7204,7 +7204,7 @@
// extension object itself.
if ((attributes & READ_ONLY) == 0 ||
(context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
- Handle<Object> set = SetProperty(context_ext, name, value, attributes);
+ Handle<Object> set = SetProperty(context_ext, name, value, NONE);
if (set.is_null()) {
// Failure::Exception is converted to a null handle in the
// handle-based methods such as SetProperty. We therefore need
diff --git a/src/spaces.cc b/src/spaces.cc
index 8e9d889..fca1032 100644
--- a/src/spaces.cc
+++ b/src/spaces.cc
@@ -364,15 +364,15 @@
}
-void MemoryAllocator::FreeChunkTables(AtomicWord* array, int len, int level) {
+void MemoryAllocator::FreeChunkTables(uintptr_t* array, int len, int level) {
for (int i = 0; i < len; i++) {
if (array[i] != kUnusedChunkTableEntry) {
- AtomicWord* subarray = reinterpret_cast<AtomicWord*>(array[i]);
+ uintptr_t* subarray = reinterpret_cast<uintptr_t*>(array[i]);
if (level > 1) {
- Release_Store(&array[i], kUnusedChunkTableEntry);
+ array[i] = kUnusedChunkTableEntry;
FreeChunkTables(subarray, 1 << kChunkTableBitsPerLevel, level - 1);
} else {
- Release_Store(&array[i], kUnusedChunkTableEntry);
+ array[i] = kUnusedChunkTableEntry;
}
delete[] subarray;
}
@@ -822,7 +822,7 @@
void MemoryAllocator::AddChunkUsingAddress(uintptr_t chunk_start,
uintptr_t chunk_index_base) {
- AtomicWord* fine_grained = AllocatedChunksFinder(
+ uintptr_t* fine_grained = AllocatedChunksFinder(
chunk_table_,
chunk_index_base,
kChunkSizeLog2 + (kChunkTableLevels - 1) * kChunkTableBitsPerLevel,
@@ -830,7 +830,7 @@
int index = FineGrainedIndexForAddress(chunk_index_base);
if (fine_grained[index] != kUnusedChunkTableEntry) index++;
ASSERT(fine_grained[index] == kUnusedChunkTableEntry);
- Release_Store(&fine_grained[index], chunk_start);
+ fine_grained[index] = chunk_start;
}
@@ -845,7 +845,7 @@
void MemoryAllocator::RemoveChunkFoundUsingAddress(
uintptr_t chunk_start,
uintptr_t chunk_index_base) {
- AtomicWord* fine_grained = AllocatedChunksFinder(
+ uintptr_t* fine_grained = AllocatedChunksFinder(
chunk_table_,
chunk_index_base,
kChunkSizeLog2 + (kChunkTableLevels - 1) * kChunkTableBitsPerLevel,
@@ -854,22 +854,23 @@
ASSERT(fine_grained != kUnusedChunkTableEntry);
int index = FineGrainedIndexForAddress(chunk_index_base);
ASSERT(fine_grained[index] != kUnusedChunkTableEntry);
- if (fine_grained[index] != static_cast<AtomicWord>(chunk_start)) {
+ if (fine_grained[index] != chunk_start) {
index++;
- ASSERT(fine_grained[index] == static_cast<AtomicWord>(chunk_start));
- Release_Store(&fine_grained[index], kUnusedChunkTableEntry);
+ ASSERT(fine_grained[index] == chunk_start);
+ fine_grained[index] = kUnusedChunkTableEntry;
} else {
- Release_Store(&fine_grained[index], fine_grained[index + 1]);
- // Here for a moment the two entries are duplicates, but the reader can
- // handle that.
- NoBarrier_Store(&fine_grained[index + 1], kUnusedChunkTableEntry);
+ // If only one of the entries is used it must be the first, since
+ // InAllocatedChunks relies on that. Move things around so that this is
+ // the case.
+ fine_grained[index] = fine_grained[index + 1];
+ fine_grained[index + 1] = kUnusedChunkTableEntry;
}
}
bool MemoryAllocator::InAllocatedChunks(Address addr) {
uintptr_t int_address = reinterpret_cast<uintptr_t>(addr);
- AtomicWord* fine_grained = AllocatedChunksFinder(
+ uintptr_t* fine_grained = AllocatedChunksFinder(
chunk_table_,
int_address,
kChunkSizeLog2 + (kChunkTableLevels - 1) * kChunkTableBitsPerLevel,
@@ -877,21 +878,18 @@
if (fine_grained == NULL) return false;
int index = FineGrainedIndexForAddress(int_address);
if (fine_grained[index] == kUnusedChunkTableEntry) return false;
- uintptr_t entry = static_cast<uintptr_t>(fine_grained[index]);
+ uintptr_t entry = fine_grained[index];
if (entry <= int_address && entry + kChunkSize > int_address) return true;
index++;
if (fine_grained[index] == kUnusedChunkTableEntry) return false;
- entry = static_cast<uintptr_t>(fine_grained[index]);
- // At this point it would seem that we must have a hit, but there is a small
- // window during RemoveChunkFoundUsingAddress where the two entries are
- // duplicates and we have to handle that.
+ entry = fine_grained[index];
if (entry <= int_address && entry + kChunkSize > int_address) return true;
return false;
}
-AtomicWord* MemoryAllocator::AllocatedChunksFinder(
- AtomicWord* table,
+uintptr_t* MemoryAllocator::AllocatedChunksFinder(
+ uintptr_t* table,
uintptr_t address,
int bit_position,
CreateTables create_as_needed) {
@@ -906,8 +904,8 @@
address & ((V8_INTPTR_C(1) << bit_position) - 1);
ASSERT((table == chunk_table_ && index < kChunkTableTopLevelEntries) ||
(table != chunk_table_ && index < 1 << kChunkTableBitsPerLevel));
- AtomicWord* more_fine_grained_table =
- reinterpret_cast<AtomicWord*>(table[index]);
+ uintptr_t* more_fine_grained_table =
+ reinterpret_cast<uintptr_t*>(table[index]);
if (more_fine_grained_table == kUnusedChunkTableEntry) {
if (create_as_needed == kDontCreateTables) return NULL;
int words_needed = 1 << kChunkTableBitsPerLevel;
@@ -915,12 +913,11 @@
words_needed =
(1 << kChunkTableBitsPerLevel) * kChunkTableFineGrainedWordsPerEntry;
}
- more_fine_grained_table = new AtomicWord[words_needed];
+ more_fine_grained_table = new uintptr_t[words_needed];
for (int i = 0; i < words_needed; i++) {
more_fine_grained_table[i] = kUnusedChunkTableEntry;
}
- Release_Store(&table[index],
- reinterpret_cast<AtomicWord>(more_fine_grained_table));
+ table[index] = reinterpret_cast<uintptr_t>(more_fine_grained_table);
}
return AllocatedChunksFinder(
more_fine_grained_table,
@@ -930,7 +927,7 @@
}
-AtomicWord MemoryAllocator::chunk_table_[kChunkTableTopLevelEntries];
+uintptr_t MemoryAllocator::chunk_table_[kChunkTableTopLevelEntries];
// -----------------------------------------------------------------------------
diff --git a/src/spaces.h b/src/spaces.h
index 2c17ef0..4f2d07b 100644
--- a/src/spaces.h
+++ b/src/spaces.h
@@ -28,7 +28,6 @@
#ifndef V8_SPACES_H_
#define V8_SPACES_H_
-#include "atomicops.h"
#include "list-inl.h"
#include "log.h"
@@ -688,7 +687,7 @@
// The chunks are not chunk-size aligned so for a given chunk-sized area of
// memory there can be two chunks that cover it.
static const int kChunkTableFineGrainedWordsPerEntry = 2;
- static const AtomicWord kUnusedChunkTableEntry = 0;
+ static const uintptr_t kUnusedChunkTableEntry = 0;
// Maximum space size in bytes.
static intptr_t capacity_;
@@ -696,7 +695,7 @@
static intptr_t capacity_executable_;
// Top level table to track whether memory is part of a chunk or not.
- static AtomicWord chunk_table_[kChunkTableTopLevelEntries];
+ static uintptr_t chunk_table_[kChunkTableTopLevelEntries];
// Allocated space size in bytes.
static intptr_t size_;
@@ -766,11 +765,11 @@
// Controls whether the lookup creates intermediate levels of tables as
// needed.
enum CreateTables { kDontCreateTables, kCreateTablesAsNeeded };
- static AtomicWord* AllocatedChunksFinder(AtomicWord* table,
- uintptr_t address,
- int bit_position,
- CreateTables create_as_needed);
- static void FreeChunkTables(AtomicWord* array, int length, int level);
+ static uintptr_t* AllocatedChunksFinder(uintptr_t* table,
+ uintptr_t address,
+ int bit_position,
+ CreateTables create_as_needed);
+ static void FreeChunkTables(uintptr_t* array, int length, int level);
static int FineGrainedIndexForAddress(uintptr_t address) {
int index = ((address >> kChunkSizeLog2) &
((1 << kChunkTableBitsPerLevel) - 1));
diff --git a/src/string-stream.cc b/src/string-stream.cc
index d1859a2..7abd1bb 100644
--- a/src/string-stream.cc
+++ b/src/string-stream.cc
@@ -264,7 +264,7 @@
}
-void StringStream::OutputToStdOut() {
+void StringStream::OutputToFile(FILE* out) {
// Dump the output to stdout, but make sure to break it up into
// manageable chunks to avoid losing parts of the output in the OS
// printing code. This is a problem on Windows in particular; see
@@ -273,10 +273,10 @@
for (unsigned next; (next = position + 2048) < length_; position = next) {
char save = buffer_[next];
buffer_[next] = '\0';
- internal::PrintF("%s", &buffer_[position]);
+ internal::PrintF(out, "%s", &buffer_[position]);
buffer_[next] = save;
}
- internal::PrintF("%s", &buffer_[position]);
+ internal::PrintF(out, "%s", &buffer_[position]);
}
diff --git a/src/string-stream.h b/src/string-stream.h
index b74c793..b3f2e0d 100644
--- a/src/string-stream.h
+++ b/src/string-stream.h
@@ -138,7 +138,8 @@
FmtElm arg3);
// Getting the message out.
- void OutputToStdOut();
+ void OutputToFile(FILE* out);
+ void OutputToStdOut() { OutputToFile(stdout); }
void Log();
Handle<String> ToString();
SmartPointer<const char> ToCString() const;
diff --git a/src/string.js b/src/string.js
index 6d4e0c1..9527599 100644
--- a/src/string.js
+++ b/src/string.js
@@ -159,7 +159,7 @@
function StringMatch(regexp) {
var subject = TO_STRING_INLINE(this);
if (IS_REGEXP(regexp)) {
- if (!regexp.global) return regexp.exec(subject);
+ if (!regexp.global) return RegExpExecNoTests(regexp, subject, 0);
%_Log('regexp', 'regexp-match,%0S,%1r', [subject, regexp]);
// lastMatchInfo is defined in regexp.js.
return %StringMatch(subject, regexp, lastMatchInfo);
@@ -245,17 +245,18 @@
// Expand the $-expressions in the string and return a new string with
// the result.
function ExpandReplacement(string, subject, matchInfo, builder) {
+ var length = string.length;
+ var builder_elements = builder.elements;
var next = %StringIndexOf(string, '$', 0);
if (next < 0) {
- builder.add(string);
+ if (length > 0) builder_elements.push(string);
return;
}
// Compute the number of captures; see ECMA-262, 15.5.4.11, p. 102.
var m = NUMBER_OF_CAPTURES(matchInfo) >> 1; // Includes the match.
- if (next > 0) builder.add(SubString(string, 0, next));
- var length = string.length;
+ if (next > 0) builder_elements.push(SubString(string, 0, next));
while (true) {
var expansion = '$';
@@ -264,7 +265,7 @@
var peek = %_StringCharCodeAt(string, position);
if (peek == 36) { // $$
++position;
- builder.add('$');
+ builder_elements.push('$');
} else if (peek == 38) { // $& - match
++position;
builder.addSpecialSlice(matchInfo[CAPTURE0],
@@ -301,14 +302,14 @@
// digit capture references, we can only enter here when a
// single digit capture reference is outside the range of
// captures.
- builder.add('$');
+ builder_elements.push('$');
--position;
}
} else {
- builder.add('$');
+ builder_elements.push('$');
}
} else {
- builder.add('$');
+ builder_elements.push('$');
}
// Go the the next $ in the string.
@@ -318,13 +319,15 @@
// haven't reached the end, we need to append the suffix.
if (next < 0) {
if (position < length) {
- builder.add(SubString(string, position, length));
+ builder_elements.push(SubString(string, position, length));
}
return;
}
// Append substring between the previous and the next $ character.
- builder.add(SubString(string, position, next));
+ if (next > position) {
+ builder_elements.push(SubString(string, position, next));
+ }
}
};
@@ -559,23 +562,22 @@
var currentIndex = 0;
var startIndex = 0;
+ var startMatch = 0;
var result = [];
outer_loop:
while (true) {
if (startIndex === length) {
- result.push(subject.slice(currentIndex, length));
+ result.push(SubString(subject, currentIndex, length));
break;
}
- var matchInfo = splitMatch(separator, subject, currentIndex, startIndex);
-
- if (IS_NULL(matchInfo)) {
- result.push(subject.slice(currentIndex, length));
+ var matchInfo = DoRegExpExec(separator, subject, startIndex);
+ if (matchInfo == null || length === (startMatch = matchInfo[CAPTURE0])) {
+ result.push(SubString(subject, currentIndex, length));
break;
}
-
var endIndex = matchInfo[CAPTURE1];
// We ignore a zero-length match at the currentIndex.
@@ -584,7 +586,12 @@
continue;
}
- result.push(SubString(subject, currentIndex, matchInfo[CAPTURE0]));
+ if (currentIndex + 1 == startMatch) {
+ result.push(%_StringCharAt(subject, currentIndex));
+ } else {
+ result.push(%_SubString(subject, currentIndex, startMatch));
+ }
+
if (result.length === limit) break;
var matchinfo_len = NUMBER_OF_CAPTURES(matchInfo) + REGEXP_FIRST_CAPTURE;
@@ -609,19 +616,6 @@
}
-// ECMA-262 section 15.5.4.14
-// Helper function used by split. This version returns the matchInfo
-// instead of allocating a new array with basically the same information.
-function splitMatch(separator, subject, current_index, start_index) {
- var matchInfo = DoRegExpExec(separator, subject, start_index);
- if (matchInfo == null) return null;
- // Section 15.5.4.14 paragraph two says that we do not allow zero length
- // matches at the end of the string.
- if (matchInfo[CAPTURE0] === subject.length) return null;
- return matchInfo;
-}
-
-
// ECMA-262 section 15.5.4.15
function StringSubstring(start, end) {
var s = TO_STRING_INLINE(this);
@@ -844,24 +838,21 @@
ReplaceResultBuilder.prototype.add = function(str) {
str = TO_STRING_INLINE(str);
- if (str.length > 0) {
- var elements = this.elements;
- elements[elements.length] = str;
- }
+ if (str.length > 0) this.elements.push(str);
}
ReplaceResultBuilder.prototype.addSpecialSlice = function(start, end) {
var len = end - start;
if (start < 0 || len <= 0) return;
- var elements = this.elements;
if (start < 0x80000 && len < 0x800) {
- elements[elements.length] = (start << 11) | len;
+ this.elements.push((start << 11) | len);
} else {
// 0 < len <= String::kMaxLength and Smi::kMaxValue >= String::kMaxLength,
// so -len is a smi.
- elements[elements.length] = -len;
- elements[elements.length] = start;
+ var elements = this.elements;
+ elements.push(-len);
+ elements.push(start);
}
}
diff --git a/src/utils.cc b/src/utils.cc
index 2c234bb..d0ec4ef 100644
--- a/src/utils.cc
+++ b/src/utils.cc
@@ -45,8 +45,16 @@
}
-void Flush() {
- fflush(stdout);
+void PrintF(FILE* out, const char* format, ...) {
+ va_list arguments;
+ va_start(arguments, format);
+ OS::VFPrint(out, format, arguments);
+ va_end(arguments);
+}
+
+
+void Flush(FILE* out) {
+ fflush(out);
}
diff --git a/src/v8-counters.h b/src/v8-counters.h
index a5cf42e..fa5d581 100644
--- a/src/v8-counters.h
+++ b/src/v8-counters.h
@@ -28,7 +28,9 @@
#ifndef V8_V8_COUNTERS_H_
#define V8_V8_COUNTERS_H_
+#include "allocation.h"
#include "counters.h"
+#include "v8globals.h"
namespace v8 {
namespace internal {
diff --git a/src/v8utils.h b/src/v8utils.h
index f6ed520..cfeb570 100644
--- a/src/v8utils.h
+++ b/src/v8utils.h
@@ -42,18 +42,26 @@
// so it works on MacOSX.
#if defined(__MACH__) && defined(__APPLE__)
#define PRINTF_CHECKING
+#define FPRINTF_CHECKING
#else // MacOsX.
#define PRINTF_CHECKING __attribute__ ((format (printf, 1, 2)))
+#define FPRINTF_CHECKING __attribute__ ((format (printf, 2, 3)))
#endif
#else
#define PRINTF_CHECKING
+#define FPRINTF_CHECKING
#endif
// Our version of printf().
void PRINTF_CHECKING PrintF(const char* format, ...);
+void FPRINTF_CHECKING PrintF(FILE* out, const char* format, ...);
// Our version of fflush.
-void Flush();
+void Flush(FILE* out);
+
+inline void Flush() {
+ Flush(stdout);
+}
// Read a line of characters after printing the prompt to stdout. The resulting
diff --git a/src/version.cc b/src/version.cc
index 60e61b1..a42a24f 100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -34,7 +34,7 @@
// cannot be changed without changing the SCons build script.
#define MAJOR_VERSION 3
#define MINOR_VERSION 0
-#define BUILD_NUMBER 3
+#define BUILD_NUMBER 4
#define PATCH_LEVEL 0
#define CANDIDATE_VERSION false
diff --git a/src/x64/codegen-x64.cc b/src/x64/codegen-x64.cc
index 6c8b333..9a25572 100644
--- a/src/x64/codegen-x64.cc
+++ b/src/x64/codegen-x64.cc
@@ -6784,9 +6784,9 @@
// Check that both indices are valid.
__ movq(tmp2.reg(), FieldOperand(object.reg(), JSArray::kLengthOffset));
- __ cmpl(tmp2.reg(), index1.reg());
+ __ SmiCompare(tmp2.reg(), index1.reg());
deferred->Branch(below_equal);
- __ cmpl(tmp2.reg(), index2.reg());
+ __ SmiCompare(tmp2.reg(), index2.reg());
deferred->Branch(below_equal);
// Bring addresses into index1 and index2.