Version 3.15.7
Activated code aging by default.
Included more information in --prof log.
Removed eager sweeping for lazy swept spaces. Try to find in SlowAllocateRaw a bounded number of times a big enough memory slot. (issue 2194)
Performance and stability improvements on all platforms.
git-svn-id: http://v8.googlecode.com/svn/trunk@13101 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/ChangeLog b/ChangeLog
index 77b198e..c102910 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2012-11-30: Version 3.15.7
+
+ Activated code aging by default.
+
+ Included more information in --prof log.
+
+ Removed eager sweeping for lazy swept spaces. Try to find in
+ SlowAllocateRaw a bounded number of times a big enough memory slot.
+ (issue 2194)
+
+ Performance and stability improvements on all platforms.
+
+
2012-11-26: Version 3.15.6
Ensure double arrays are filled with holes when extended from
diff --git a/src/api.cc b/src/api.cc
index 5351b96..39741f5 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -1237,7 +1237,7 @@
void FunctionTemplate::ReadOnlyPrototype() {
i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
- if (IsDeadCheck(isolate, "v8::FunctionTemplate::SetPrototypeAttributes()")) {
+ if (IsDeadCheck(isolate, "v8::FunctionTemplate::ReadOnlyPrototype()")) {
return;
}
ENTER_V8(isolate);
diff --git a/src/arm/codegen-arm.cc b/src/arm/codegen-arm.cc
index 689de9f..0470035 100644
--- a/src/arm/codegen-arm.cc
+++ b/src/arm/codegen-arm.cc
@@ -615,29 +615,6 @@
}
-byte* Code::FindPlatformCodeAgeSequence() {
- byte* start = instruction_start();
- uint32_t young_length;
- byte* young_sequence = GetNoCodeAgeSequence(&young_length);
- if (!memcmp(start, young_sequence, young_length) ||
- Memory::uint32_at(start) == kCodeAgePatchFirstInstruction) {
- return start;
- } else {
- byte* start_after_strict = NULL;
- if (kind() == FUNCTION) {
- start_after_strict = start + kSizeOfFullCodegenStrictModePrologue;
- } else {
- ASSERT(kind() == OPTIMIZED_FUNCTION);
- start_after_strict = start + kSizeOfOptimizedStrictModePrologue;
- }
- ASSERT(!memcmp(start_after_strict, young_sequence, young_length) ||
- Memory::uint32_at(start_after_strict) ==
- kCodeAgePatchFirstInstruction);
- return start_after_strict;
- }
-}
-
-
bool Code::IsYoungSequence(byte* sequence) {
uint32_t young_length;
byte* young_sequence = GetNoCodeAgeSequence(&young_length);
diff --git a/src/arm/codegen-arm.h b/src/arm/codegen-arm.h
index 7ca2c8d..8f0033e 100644
--- a/src/arm/codegen-arm.h
+++ b/src/arm/codegen-arm.h
@@ -34,9 +34,6 @@
namespace v8 {
namespace internal {
-static const int kSizeOfFullCodegenStrictModePrologue = 16;
-static const int kSizeOfOptimizedStrictModePrologue = 16;
-
// Forward declarations
class CompilationInfo;
diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc
index 9c69e8e..7cb402e 100644
--- a/src/arm/full-codegen-arm.cc
+++ b/src/arm/full-codegen-arm.cc
@@ -149,15 +149,12 @@
// function calls.
if (!info->is_classic_mode() || info->is_native()) {
Label ok;
- Label begin;
- __ bind(&begin);
__ cmp(r5, Operand(0));
__ b(eq, &ok);
int receiver_offset = info->scope()->num_parameters() * kPointerSize;
__ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
__ str(r2, MemOperand(sp, receiver_offset));
__ bind(&ok);
- ASSERT_EQ(kSizeOfFullCodegenStrictModePrologue, ok.pos() - begin.pos());
}
// Open a frame scope to indicate that there is a frame on the stack. The
@@ -167,6 +164,7 @@
int locals_count = info->scope()->num_stack_slots();
+ info->set_prologue_offset(masm_->pc_offset());
// The following four instructions must remain together and unmodified for
// code aging to work properly.
__ stm(db_w, sp, r1.bit() | cp.bit() | fp.bit() | lr.bit());
diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc
index 6ff4cab..39e239a 100644
--- a/src/arm/lithium-codegen-arm.cc
+++ b/src/arm/lithium-codegen-arm.cc
@@ -138,17 +138,16 @@
// function calls.
if (!info_->is_classic_mode() || info_->is_native()) {
Label ok;
- Label begin;
- __ bind(&begin);
__ cmp(r5, Operand(0));
__ b(eq, &ok);
int receiver_offset = scope()->num_parameters() * kPointerSize;
__ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
__ str(r2, MemOperand(sp, receiver_offset));
__ bind(&ok);
- ASSERT_EQ(kSizeOfOptimizedStrictModePrologue, ok.pos() - begin.pos());
}
+
+ info()->set_prologue_offset(masm_->pc_offset());
// The following three instructions must remain together and unmodified for
// code aging to work properly.
__ stm(db_w, sp, r1.bit() | cp.bit() | fp.bit() | lr.bit());
diff --git a/src/arm/macro-assembler-arm.cc b/src/arm/macro-assembler-arm.cc
index 158476e..7f6c60d 100644
--- a/src/arm/macro-assembler-arm.cc
+++ b/src/arm/macro-assembler-arm.cc
@@ -2222,12 +2222,28 @@
add(r6, r6, Operand(1));
str(r6, MemOperand(r7, kLevelOffset));
+ if (FLAG_log_timer_events) {
+ FrameScope frame(this, StackFrame::MANUAL);
+ PushSafepointRegisters();
+ PrepareCallCFunction(0, r0);
+ CallCFunction(ExternalReference::log_enter_external_function(isolate()), 0);
+ PopSafepointRegisters();
+ }
+
// Native call returns to the DirectCEntry stub which redirects to the
// return address pushed on stack (could have moved after GC).
// DirectCEntry stub itself is generated early and never moves.
DirectCEntryStub stub;
stub.GenerateCall(this, function);
+ if (FLAG_log_timer_events) {
+ FrameScope frame(this, StackFrame::MANUAL);
+ PushSafepointRegisters();
+ PrepareCallCFunction(0, r0);
+ CallCFunction(ExternalReference::log_leave_external_function(isolate()), 0);
+ PopSafepointRegisters();
+ }
+
Label promote_scheduled_exception;
Label delete_allocated_handles;
Label leave_exit_frame;
diff --git a/src/arm/stub-cache-arm.cc b/src/arm/stub-cache-arm.cc
index 866ab55..4604c33 100644
--- a/src/arm/stub-cache-arm.cc
+++ b/src/arm/stub-cache-arm.cc
@@ -4690,9 +4690,12 @@
// -- r1 : key
// -- r2 : receiver
// -- lr : return address
- // -- r3 : scratch
+ // -- r3 : scratch (elements backing store)
// -- r4 : scratch
// -- r5 : scratch
+ // -- r6 : scratch
+ // -- r7 : scratch
+ // -- r9 : scratch
// -----------------------------------
Label miss_force_generic, transition_elements_kind, grow, slow;
Label finish_store, check_capacity;
@@ -4705,6 +4708,7 @@
Register scratch2 = r5;
Register scratch3 = r6;
Register scratch4 = r7;
+ Register scratch5 = r9;
Register length_reg = r7;
// This stub is meant to be tail-jumped to, the receiver must already
@@ -4791,6 +4795,17 @@
__ str(scratch1,
FieldMemOperand(elements_reg, FixedDoubleArray::kLengthOffset));
+ __ mov(scratch1, elements_reg);
+ __ StoreNumberToDoubleElements(value_reg,
+ key_reg,
+ // All registers after this are overwritten.
+ scratch1,
+ scratch2,
+ scratch3,
+ scratch4,
+ scratch5,
+ &transition_elements_kind);
+
__ mov(scratch1, Operand(kHoleNanLower32));
__ mov(scratch2, Operand(kHoleNanUpper32));
for (int i = 1; i < JSArray::kPreallocatedArrayElements; i++) {
@@ -4799,16 +4814,6 @@
__ str(scratch2, FieldMemOperand(elements_reg, offset + kPointerSize));
}
- __ StoreNumberToDoubleElements(value_reg,
- key_reg,
- // All registers after this are overwritten.
- elements_reg,
- scratch1,
- scratch2,
- scratch3,
- scratch4,
- &transition_elements_kind);
-
// Install the new backing store in the JSArray.
__ str(elements_reg,
FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
diff --git a/src/assembler.cc b/src/assembler.cc
index 344e203..25157be 100644
--- a/src/assembler.cc
+++ b/src/assembler.cc
@@ -1056,6 +1056,20 @@
}
+ExternalReference ExternalReference::log_enter_external_function(
+ Isolate* isolate) {
+ return ExternalReference(
+ Redirect(isolate, FUNCTION_ADDR(Logger::EnterExternal)));
+}
+
+
+ExternalReference ExternalReference::log_leave_external_function(
+ Isolate* isolate) {
+ return ExternalReference(
+ Redirect(isolate, FUNCTION_ADDR(Logger::LeaveExternal)));
+}
+
+
ExternalReference ExternalReference::keyed_lookup_cache_keys(Isolate* isolate) {
return ExternalReference(isolate->keyed_lookup_cache()->keys_address());
}
diff --git a/src/assembler.h b/src/assembler.h
index 76e0569..4639374 100644
--- a/src/assembler.h
+++ b/src/assembler.h
@@ -661,6 +661,10 @@
static ExternalReference new_deoptimizer_function(Isolate* isolate);
static ExternalReference compute_output_frames_function(Isolate* isolate);
+ // Log support.
+ static ExternalReference log_enter_external_function(Isolate* isolate);
+ static ExternalReference log_leave_external_function(Isolate* isolate);
+
// Static data in the keyed lookup cache.
static ExternalReference keyed_lookup_cache_keys(Isolate* isolate);
static ExternalReference keyed_lookup_cache_field_offsets(Isolate* isolate);
diff --git a/src/builtins.cc b/src/builtins.cc
index 5c8e32b..d9f8d15 100644
--- a/src/builtins.cc
+++ b/src/builtins.cc
@@ -574,14 +574,12 @@
MaybeObject* maybe_obj = heap->AllocateUninitializedFixedArray(capacity);
if (!maybe_obj->To(&new_elms)) return maybe_obj;
- if (len > 0) {
- ElementsAccessor* accessor = array->GetElementsAccessor();
- MaybeObject* maybe_failure =
- accessor->CopyElements(NULL, 0, new_elms, kind, 0, len, elms_obj);
- ASSERT(!maybe_failure->IsFailure());
- USE(maybe_failure);
- }
- FillWithHoles(heap, new_elms, new_length, capacity);
+ ElementsAccessor* accessor = array->GetElementsAccessor();
+ MaybeObject* maybe_failure = accessor->CopyElements(
+ NULL, 0, new_elms, kind, 0,
+ ElementsAccessor::kCopyToEndAndInitializeToHole, elms_obj);
+ ASSERT(!maybe_failure->IsFailure());
+ USE(maybe_failure);
elms = new_elms;
}
@@ -623,15 +621,12 @@
heap->AllocateUninitializedFixedDoubleArray(capacity);
if (!maybe_obj->To(&new_elms)) return maybe_obj;
- if (len > 0) {
- ElementsAccessor* accessor = array->GetElementsAccessor();
- MaybeObject* maybe_failure =
- accessor->CopyElements(NULL, 0, new_elms, kind, 0, len, elms_obj);
- ASSERT(!maybe_failure->IsFailure());
- USE(maybe_failure);
- }
-
- FillWithHoles(new_elms, len + to_add, new_elms->length());
+ ElementsAccessor* accessor = array->GetElementsAccessor();
+ MaybeObject* maybe_failure = accessor->CopyElements(
+ NULL, 0, new_elms, kind, 0,
+ ElementsAccessor::kCopyToEndAndInitializeToHole, elms_obj);
+ ASSERT(!maybe_failure->IsFailure());
+ USE(maybe_failure);
} else {
// to_add is > 0 and new_length <= elms_len, so elms_obj cannot be the
// empty_fixed_array.
@@ -787,16 +782,14 @@
MaybeObject* maybe_elms = heap->AllocateUninitializedFixedArray(capacity);
if (!maybe_elms->To(&new_elms)) return maybe_elms;
- if (len > 0) {
- ElementsKind kind = array->GetElementsKind();
- ElementsAccessor* accessor = array->GetElementsAccessor();
- MaybeObject* maybe_failure =
- accessor->CopyElements(NULL, 0, new_elms, kind, to_add, len, elms);
- ASSERT(!maybe_failure->IsFailure());
- USE(maybe_failure);
- }
+ ElementsKind kind = array->GetElementsKind();
+ ElementsAccessor* accessor = array->GetElementsAccessor();
+ MaybeObject* maybe_failure = accessor->CopyElements(
+ NULL, 0, new_elms, kind, to_add,
+ ElementsAccessor::kCopyToEndAndInitializeToHole, elms);
+ ASSERT(!maybe_failure->IsFailure());
+ USE(maybe_failure);
- FillWithHoles(heap, new_elms, new_length, capacity);
elms = new_elms;
array->set_elements(elms);
} else {
@@ -1116,16 +1109,12 @@
ASSERT(!maybe_failure->IsFailure());
USE(maybe_failure);
}
- const int to_copy = len - actual_delete_count - actual_start;
- if (to_copy > 0) {
- MaybeObject* maybe_failure = accessor->CopyElements(
- NULL, actual_start + actual_delete_count, new_elms, kind,
- actual_start + item_count, to_copy, elms);
- ASSERT(!maybe_failure->IsFailure());
- USE(maybe_failure);
- }
-
- FillWithHoles(heap, new_elms, new_length, capacity);
+ MaybeObject* maybe_failure = accessor->CopyElements(
+ NULL, actual_start + actual_delete_count, new_elms, kind,
+ actual_start + item_count,
+ ElementsAccessor::kCopyToEndAndInitializeToHole, elms);
+ ASSERT(!maybe_failure->IsFailure());
+ USE(maybe_failure);
elms_obj = new_elms;
elms_changed = true;
diff --git a/src/codegen.cc b/src/codegen.cc
index 0163580..83ac854 100644
--- a/src/codegen.cc
+++ b/src/codegen.cc
@@ -107,6 +107,7 @@
if (!code.is_null()) {
isolate->counters()->total_compiled_code_size()->Increment(
code->instruction_size());
+ code->set_prologue_offset(info->prologue_offset());
}
return code;
}
diff --git a/src/compiler.cc b/src/compiler.cc
index 3dfc4e3..ff6e05d 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -52,57 +52,53 @@
CompilationInfo::CompilationInfo(Handle<Script> script, Zone* zone)
- : isolate_(script->GetIsolate()),
- flags_(LanguageModeField::encode(CLASSIC_MODE)),
- function_(NULL),
- scope_(NULL),
- global_scope_(NULL),
+ : flags_(LanguageModeField::encode(CLASSIC_MODE)),
script_(script),
- extension_(NULL),
- pre_parse_data_(NULL),
- osr_ast_id_(BailoutId::None()),
- zone_(zone),
- deferred_handles_(NULL) {
- Initialize(BASE);
+ osr_ast_id_(BailoutId::None()) {
+ Initialize(zone);
}
CompilationInfo::CompilationInfo(Handle<SharedFunctionInfo> shared_info,
Zone* zone)
- : isolate_(shared_info->GetIsolate()),
- flags_(LanguageModeField::encode(CLASSIC_MODE) |
- IsLazy::encode(true)),
- function_(NULL),
- scope_(NULL),
- global_scope_(NULL),
+ : flags_(LanguageModeField::encode(CLASSIC_MODE) | IsLazy::encode(true)),
shared_info_(shared_info),
script_(Handle<Script>(Script::cast(shared_info->script()))),
- extension_(NULL),
- pre_parse_data_(NULL),
- osr_ast_id_(BailoutId::None()),
- zone_(zone),
- deferred_handles_(NULL) {
- Initialize(BASE);
+ osr_ast_id_(BailoutId::None()) {
+ Initialize(zone);
}
CompilationInfo::CompilationInfo(Handle<JSFunction> closure, Zone* zone)
- : isolate_(closure->GetIsolate()),
- flags_(LanguageModeField::encode(CLASSIC_MODE) |
- IsLazy::encode(true)),
- function_(NULL),
- scope_(NULL),
- global_scope_(NULL),
+ : flags_(LanguageModeField::encode(CLASSIC_MODE) | IsLazy::encode(true)),
closure_(closure),
shared_info_(Handle<SharedFunctionInfo>(closure->shared())),
script_(Handle<Script>(Script::cast(shared_info_->script()))),
- extension_(NULL),
- pre_parse_data_(NULL),
context_(closure->context()),
- osr_ast_id_(BailoutId::None()),
- zone_(zone),
- deferred_handles_(NULL) {
- Initialize(BASE);
+ osr_ast_id_(BailoutId::None()) {
+ Initialize(zone);
+}
+
+
+void CompilationInfo::Initialize(Zone* zone) {
+ isolate_ = script_->GetIsolate();
+ function_ = NULL;
+ scope_ = NULL;
+ global_scope_ = NULL;
+ extension_ = NULL;
+ pre_parse_data_ = NULL;
+ zone_ = zone;
+ deferred_handles_ = NULL;
+ prologue_offset_ = kPrologueOffsetNotSet;
+ mode_ = V8::UseCrankshaft() ? BASE : NONOPT;
+ if (script_->type()->value() == Script::TYPE_NATIVE) {
+ MarkAsNative();
+ }
+ if (!shared_info_.is_null()) {
+ ASSERT(language_mode() == CLASSIC_MODE);
+ SetLanguageMode(shared_info_->language_mode());
+ }
+ set_bailout_reason("unknown");
}
diff --git a/src/compiler.h b/src/compiler.h
index 62eedc2..653d5f1 100644
--- a/src/compiler.h
+++ b/src/compiler.h
@@ -35,6 +35,8 @@
namespace v8 {
namespace internal {
+static const int kPrologueOffsetNotSet = -1;
+
class ScriptDataImpl;
// CompilationInfo encapsulates some information known at compile time. It
@@ -186,6 +188,16 @@
const char* bailout_reason() const { return bailout_reason_; }
void set_bailout_reason(const char* reason) { bailout_reason_ = reason; }
+ int prologue_offset() const {
+ ASSERT_NE(kPrologueOffsetNotSet, prologue_offset_);
+ return prologue_offset_;
+ }
+
+ void set_prologue_offset(int prologue_offset) {
+ ASSERT_EQ(kPrologueOffsetNotSet, prologue_offset_);
+ prologue_offset_ = prologue_offset;
+ }
+
private:
Isolate* isolate_;
@@ -200,18 +212,7 @@
NONOPT
};
- void Initialize(Mode mode) {
- mode_ = V8::UseCrankshaft() ? mode : NONOPT;
- ASSERT(!script_.is_null());
- if (script_->type()->value() == Script::TYPE_NATIVE) {
- MarkAsNative();
- }
- if (!shared_info_.is_null()) {
- ASSERT(language_mode() == CLASSIC_MODE);
- SetLanguageMode(shared_info_->language_mode());
- }
- set_bailout_reason("unknown");
- }
+ void Initialize(Zone* zone);
void SetMode(Mode mode) {
ASSERT(V8::UseCrankshaft());
@@ -285,6 +286,8 @@
const char* bailout_reason_;
+ int prologue_offset_;
+
DISALLOW_COPY_AND_ASSIGN(CompilationInfo);
};
diff --git a/src/d8.cc b/src/d8.cc
index 814a8f4..8233f86 100644
--- a/src/d8.cc
+++ b/src/d8.cc
@@ -1511,9 +1511,9 @@
class ShellThread : public i::Thread {
public:
// Takes ownership of the underlying char array of |files|.
- ShellThread(Isolate* isolate, int no, char* files)
+ ShellThread(Isolate* isolate, char* files)
: Thread("d8:ShellThread"),
- isolate_(isolate), no_(no), files_(files) { }
+ isolate_(isolate), files_(files) { }
~ShellThread() {
delete[] files_;
@@ -1522,7 +1522,6 @@
virtual void Run();
private:
Isolate* isolate_;
- int no_;
char* files_;
};
@@ -1829,7 +1828,7 @@
printf("File list '%s' not found\n", options.parallel_files[i]);
Exit(1);
}
- ShellThread* thread = new ShellThread(isolate, threads.length(), files);
+ ShellThread* thread = new ShellThread(isolate, files);
thread->Start();
threads.Add(thread);
}
diff --git a/src/deoptimizer.h b/src/deoptimizer.h
index 4aa38ce..89955b3 100644
--- a/src/deoptimizer.h
+++ b/src/deoptimizer.h
@@ -537,9 +537,6 @@
intptr_t context_;
StackFrame::Type type_;
Smi* state_;
-#ifdef DEBUG
- Code::Kind kind_;
-#endif
// Continuation is the PC where the execution continues after
// deoptimizing.
diff --git a/src/elements.cc b/src/elements.cc
index 6103da4..8e1bf3e 100644
--- a/src/elements.cc
+++ b/src/elements.cc
@@ -146,33 +146,36 @@
}
-static void CopyObjectToObjectElements(FixedArray* from,
+static void CopyObjectToObjectElements(FixedArrayBase* from_base,
ElementsKind from_kind,
uint32_t from_start,
- FixedArray* to,
+ FixedArrayBase* to_base,
ElementsKind to_kind,
uint32_t to_start,
int raw_copy_size) {
- ASSERT(to->map() != HEAP->fixed_cow_array_map());
+ ASSERT(to_base->map() != HEAP->fixed_cow_array_map());
+ AssertNoAllocation no_allocation;
int copy_size = raw_copy_size;
if (raw_copy_size < 0) {
ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd ||
raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
- copy_size = Min(from->length() - from_start,
- to->length() - to_start);
-#ifdef DEBUG
- // FAST_*_ELEMENTS arrays cannot be uninitialized. Ensure they are already
- // marked with the hole.
+ copy_size = Min(from_base->length() - from_start,
+ to_base->length() - to_start);
if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
- for (int i = to_start + copy_size; i < to->length(); ++i) {
- ASSERT(to->get(i)->IsTheHole());
+ int start = to_start + copy_size;
+ int length = to_base->length() - start;
+ if (length > 0) {
+ Heap* heap = from_base->GetHeap();
+ MemsetPointer(FixedArray::cast(to_base)->data_start() + start,
+ heap->the_hole_value(), length);
}
}
-#endif
}
- ASSERT((copy_size + static_cast<int>(to_start)) <= to->length() &&
- (copy_size + static_cast<int>(from_start)) <= from->length());
+ ASSERT((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
+ (copy_size + static_cast<int>(from_start)) <= from_base->length());
if (copy_size == 0) return;
+ FixedArray* from = FixedArray::cast(from_base);
+ FixedArray* to = FixedArray::cast(to_base);
ASSERT(IsFastSmiOrObjectElementsKind(from_kind));
ASSERT(IsFastSmiOrObjectElementsKind(to_kind));
Address to_address = to->address() + FixedArray::kHeaderSize;
@@ -193,31 +196,34 @@
}
-static void CopyDictionaryToObjectElements(SeededNumberDictionary* from,
+static void CopyDictionaryToObjectElements(FixedArrayBase* from_base,
uint32_t from_start,
- FixedArray* to,
+ FixedArrayBase* to_base,
ElementsKind to_kind,
uint32_t to_start,
int raw_copy_size) {
+ SeededNumberDictionary* from = SeededNumberDictionary::cast(from_base);
+ AssertNoAllocation no_allocation;
int copy_size = raw_copy_size;
Heap* heap = from->GetHeap();
if (raw_copy_size < 0) {
ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd ||
raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
copy_size = from->max_number_key() + 1 - from_start;
-#ifdef DEBUG
- // Fast object arrays cannot be uninitialized. Ensure they are already
- // marked with the hole.
if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
- for (int i = to_start + copy_size; i < to->length(); ++i) {
- ASSERT(to->get(i)->IsTheHole());
+ int start = to_start + copy_size;
+ int length = to_base->length() - start;
+ if (length > 0) {
+ Heap* heap = from->GetHeap();
+ MemsetPointer(FixedArray::cast(to_base)->data_start() + start,
+ heap->the_hole_value(), length);
}
}
-#endif
}
- ASSERT(to != from);
+ ASSERT(to_base != from_base);
ASSERT(IsFastSmiOrObjectElementsKind(to_kind));
if (copy_size == 0) return;
+ FixedArray* to = FixedArray::cast(to_base);
uint32_t to_length = to->length();
if (to_start + copy_size > to_length) {
copy_size = to_length - to_start;
@@ -244,9 +250,9 @@
MUST_USE_RESULT static MaybeObject* CopyDoubleToObjectElements(
- FixedDoubleArray* from,
+ FixedArrayBase* from_base,
uint32_t from_start,
- FixedArray* to,
+ FixedArrayBase* to_base,
ElementsKind to_kind,
uint32_t to_start,
int raw_copy_size) {
@@ -255,21 +261,26 @@
if (raw_copy_size < 0) {
ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd ||
raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
- copy_size = Min(from->length() - from_start,
- to->length() - to_start);
-#ifdef DEBUG
- // FAST_*_ELEMENTS arrays cannot be uninitialized. Ensure they are already
- // marked with the hole.
+ copy_size = Min(from_base->length() - from_start,
+ to_base->length() - to_start);
if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
- for (int i = to_start + copy_size; i < to->length(); ++i) {
- ASSERT(to->get(i)->IsTheHole());
+ // Also initialize the area that will be copied over since HeapNumber
+ // allocation below can cause an incremental marking step, requiring all
+ // existing heap objects to be propertly initialized.
+ int start = to_start;
+ int length = to_base->length() - start;
+ if (length > 0) {
+ Heap* heap = from_base->GetHeap();
+ MemsetPointer(FixedArray::cast(to_base)->data_start() + start,
+ heap->the_hole_value(), length);
}
}
-#endif
}
- ASSERT((copy_size + static_cast<int>(to_start)) <= to->length() &&
- (copy_size + static_cast<int>(from_start)) <= from->length());
- if (copy_size == 0) return from;
+ ASSERT((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
+ (copy_size + static_cast<int>(from_start)) <= from_base->length());
+ if (copy_size == 0) return from_base;
+ FixedDoubleArray* from = FixedDoubleArray::cast(from_base);
+ FixedArray* to = FixedArray::cast(to_base);
for (int i = 0; i < copy_size; ++i) {
if (IsFastSmiElementsKind(to_kind)) {
UNIMPLEMENTED();
@@ -298,26 +309,28 @@
}
-static void CopyDoubleToDoubleElements(FixedDoubleArray* from,
+static void CopyDoubleToDoubleElements(FixedArrayBase* from_base,
uint32_t from_start,
- FixedDoubleArray* to,
+ FixedArrayBase* to_base,
uint32_t to_start,
int raw_copy_size) {
int copy_size = raw_copy_size;
if (raw_copy_size < 0) {
ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd ||
raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
- copy_size = Min(from->length() - from_start,
- to->length() - to_start);
+ copy_size = Min(from_base->length() - from_start,
+ to_base->length() - to_start);
if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
- for (int i = to_start + copy_size; i < to->length(); ++i) {
- to->set_the_hole(i);
+ for (int i = to_start + copy_size; i < to_base->length(); ++i) {
+ FixedDoubleArray::cast(to_base)->set_the_hole(i);
}
}
}
- ASSERT((copy_size + static_cast<int>(to_start)) <= to->length() &&
- (copy_size + static_cast<int>(from_start)) <= from->length());
+ ASSERT((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
+ (copy_size + static_cast<int>(from_start)) <= from_base->length());
if (copy_size == 0) return;
+ FixedDoubleArray* from = FixedDoubleArray::cast(from_base);
+ FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
Address to_address = to->address() + FixedDoubleArray::kHeaderSize;
Address from_address = from->address() + FixedDoubleArray::kHeaderSize;
to_address += kDoubleSize * to_start;
@@ -329,25 +342,27 @@
}
-static void CopySmiToDoubleElements(FixedArray* from,
+static void CopySmiToDoubleElements(FixedArrayBase* from_base,
uint32_t from_start,
- FixedDoubleArray* to,
+ FixedArrayBase* to_base,
uint32_t to_start,
int raw_copy_size) {
int copy_size = raw_copy_size;
if (raw_copy_size < 0) {
ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd ||
raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
- copy_size = from->length() - from_start;
+ copy_size = from_base->length() - from_start;
if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
- for (int i = to_start + copy_size; i < to->length(); ++i) {
- to->set_the_hole(i);
+ for (int i = to_start + copy_size; i < to_base->length(); ++i) {
+ FixedDoubleArray::cast(to_base)->set_the_hole(i);
}
}
}
- ASSERT((copy_size + static_cast<int>(to_start)) <= to->length() &&
- (copy_size + static_cast<int>(from_start)) <= from->length());
+ ASSERT((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
+ (copy_size + static_cast<int>(from_start)) <= from_base->length());
if (copy_size == 0) return;
+ FixedArray* from = FixedArray::cast(from_base);
+ FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
Object* the_hole = from->GetHeap()->the_hole_value();
for (uint32_t from_end = from_start + static_cast<uint32_t>(copy_size);
from_start < from_end; from_start++, to_start++) {
@@ -361,9 +376,9 @@
}
-static void CopyPackedSmiToDoubleElements(FixedArray* from,
+static void CopyPackedSmiToDoubleElements(FixedArrayBase* from_base,
uint32_t from_start,
- FixedDoubleArray* to,
+ FixedArrayBase* to_base,
uint32_t to_start,
int packed_size,
int raw_copy_size) {
@@ -372,11 +387,11 @@
if (raw_copy_size < 0) {
ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd ||
raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
- copy_size = from->length() - from_start;
+ copy_size = packed_size - from_start;
if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
- to_end = to->length();
+ to_end = to_base->length();
for (uint32_t i = to_start + copy_size; i < to_end; ++i) {
- to->set_the_hole(i);
+ FixedDoubleArray::cast(to_base)->set_the_hole(i);
}
} else {
to_end = to_start + static_cast<uint32_t>(copy_size);
@@ -384,11 +399,13 @@
} else {
to_end = to_start + static_cast<uint32_t>(copy_size);
}
- ASSERT(static_cast<int>(to_end) <= to->length());
+ ASSERT(static_cast<int>(to_end) <= to_base->length());
ASSERT(packed_size >= 0 && packed_size <= copy_size);
- ASSERT((copy_size + static_cast<int>(to_start)) <= to->length() &&
- (copy_size + static_cast<int>(from_start)) <= from->length());
+ ASSERT((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
+ (copy_size + static_cast<int>(from_start)) <= from_base->length());
if (copy_size == 0) return;
+ FixedArray* from = FixedArray::cast(from_base);
+ FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
for (uint32_t from_end = from_start + static_cast<uint32_t>(packed_size);
from_start < from_end; from_start++, to_start++) {
Object* smi = from->get(from_start);
@@ -398,25 +415,27 @@
}
-static void CopyObjectToDoubleElements(FixedArray* from,
+static void CopyObjectToDoubleElements(FixedArrayBase* from_base,
uint32_t from_start,
- FixedDoubleArray* to,
+ FixedArrayBase* to_base,
uint32_t to_start,
int raw_copy_size) {
int copy_size = raw_copy_size;
if (raw_copy_size < 0) {
ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd ||
raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
- copy_size = from->length() - from_start;
+ copy_size = from_base->length() - from_start;
if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
- for (int i = to_start + copy_size; i < to->length(); ++i) {
- to->set_the_hole(i);
+ for (int i = to_start + copy_size; i < to_base->length(); ++i) {
+ FixedDoubleArray::cast(to_base)->set_the_hole(i);
}
}
}
- ASSERT((copy_size + static_cast<int>(to_start)) <= to->length() &&
- (copy_size + static_cast<int>(from_start)) <= from->length());
+ ASSERT((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
+ (copy_size + static_cast<int>(from_start)) <= from_base->length());
if (copy_size == 0) return;
+ FixedArray* from = FixedArray::cast(from_base);
+ FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
Object* the_hole = from->GetHeap()->the_hole_value();
for (uint32_t from_end = from_start + copy_size;
from_start < from_end; from_start++, to_start++) {
@@ -430,23 +449,25 @@
}
-static void CopyDictionaryToDoubleElements(SeededNumberDictionary* from,
+static void CopyDictionaryToDoubleElements(FixedArrayBase* from_base,
uint32_t from_start,
- FixedDoubleArray* to,
+ FixedArrayBase* to_base,
uint32_t to_start,
int raw_copy_size) {
+ SeededNumberDictionary* from = SeededNumberDictionary::cast(from_base);
int copy_size = raw_copy_size;
if (copy_size < 0) {
ASSERT(copy_size == ElementsAccessor::kCopyToEnd ||
copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
copy_size = from->max_number_key() + 1 - from_start;
if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
- for (int i = to_start + copy_size; i < to->length(); ++i) {
- to->set_the_hole(i);
+ for (int i = to_start + copy_size; i < to_base->length(); ++i) {
+ FixedDoubleArray::cast(to_base)->set_the_hole(i);
}
}
}
if (copy_size == 0) return;
+ FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
uint32_t to_length = to->length();
if (to_start + copy_size > to_length) {
copy_size = to_length - to_start;
@@ -526,7 +547,7 @@
static bool HasElementImpl(Object* receiver,
JSObject* holder,
uint32_t key,
- BackingStore* backing_store) {
+ FixedArrayBase* backing_store) {
return ElementsAccessorSubclass::GetAttributesImpl(
receiver, holder, key, backing_store) != ABSENT;
}
@@ -539,7 +560,7 @@
backing_store = holder->elements();
}
return ElementsAccessorSubclass::HasElementImpl(
- receiver, holder, key, BackingStore::cast(backing_store));
+ receiver, holder, key, backing_store);
}
MUST_USE_RESULT virtual MaybeObject* Get(Object* receiver,
@@ -550,15 +571,15 @@
backing_store = holder->elements();
}
return ElementsAccessorSubclass::GetImpl(
- receiver, holder, key, BackingStore::cast(backing_store));
+ receiver, holder, key, backing_store);
}
MUST_USE_RESULT static MaybeObject* GetImpl(Object* receiver,
JSObject* obj,
uint32_t key,
- BackingStore* backing_store) {
+ FixedArrayBase* backing_store) {
return (key < ElementsAccessorSubclass::GetCapacityImpl(backing_store))
- ? backing_store->get(key)
+ ? BackingStore::cast(backing_store)->get(key)
: backing_store->GetHeap()->the_hole_value();
}
@@ -571,18 +592,18 @@
backing_store = holder->elements();
}
return ElementsAccessorSubclass::GetAttributesImpl(
- receiver, holder, key, BackingStore::cast(backing_store));
+ receiver, holder, key, backing_store);
}
MUST_USE_RESULT static PropertyAttributes GetAttributesImpl(
Object* receiver,
JSObject* obj,
uint32_t key,
- BackingStore* backing_store) {
+ FixedArrayBase* backing_store) {
if (key >= ElementsAccessorSubclass::GetCapacityImpl(backing_store)) {
return ABSENT;
}
- return backing_store->is_the_hole(key) ? ABSENT : NONE;
+ return BackingStore::cast(backing_store)->is_the_hole(key) ? ABSENT : NONE;
}
MUST_USE_RESULT virtual PropertyType GetType(
@@ -594,18 +615,19 @@
backing_store = holder->elements();
}
return ElementsAccessorSubclass::GetTypeImpl(
- receiver, holder, key, BackingStore::cast(backing_store));
+ receiver, holder, key, backing_store);
}
MUST_USE_RESULT static PropertyType GetTypeImpl(
Object* receiver,
JSObject* obj,
uint32_t key,
- BackingStore* backing_store) {
+ FixedArrayBase* backing_store) {
if (key >= ElementsAccessorSubclass::GetCapacityImpl(backing_store)) {
return NONEXISTENT;
}
- return backing_store->is_the_hole(key) ? NONEXISTENT : FIELD;
+ return BackingStore::cast(backing_store)->is_the_hole(key)
+ ? NONEXISTENT : FIELD;
}
MUST_USE_RESULT virtual AccessorPair* GetAccessorPair(
@@ -617,27 +639,27 @@
backing_store = holder->elements();
}
return ElementsAccessorSubclass::GetAccessorPairImpl(
- receiver, holder, key, BackingStore::cast(backing_store));
+ receiver, holder, key, backing_store);
}
MUST_USE_RESULT static AccessorPair* GetAccessorPairImpl(
Object* receiver,
JSObject* obj,
uint32_t key,
- BackingStore* backing_store) {
+ FixedArrayBase* backing_store) {
return NULL;
}
MUST_USE_RESULT virtual MaybeObject* SetLength(JSArray* array,
Object* length) {
return ElementsAccessorSubclass::SetLengthImpl(
- array, length, BackingStore::cast(array->elements()));
+ array, length, array->elements());
}
MUST_USE_RESULT static MaybeObject* SetLengthImpl(
JSObject* obj,
Object* length,
- BackingStore* backing_store);
+ FixedArrayBase* backing_store);
MUST_USE_RESULT virtual MaybeObject* SetCapacityAndLength(
JSArray* array,
@@ -715,25 +737,22 @@
if (from == NULL) {
from = holder->elements();
}
- BackingStore* backing_store = BackingStore::cast(from);
- uint32_t len1 = ElementsAccessorSubclass::GetCapacityImpl(backing_store);
// Optimize if 'other' is empty.
// We cannot optimize if 'this' is empty, as other may have holes.
+ uint32_t len1 = ElementsAccessorSubclass::GetCapacityImpl(from);
if (len1 == 0) return to;
// Compute how many elements are not in other.
uint32_t extra = 0;
for (uint32_t y = 0; y < len1; y++) {
- uint32_t key =
- ElementsAccessorSubclass::GetKeyForIndexImpl(backing_store, y);
+ uint32_t key = ElementsAccessorSubclass::GetKeyForIndexImpl(from, y);
if (ElementsAccessorSubclass::HasElementImpl(
- receiver, holder, key, backing_store)) {
+ receiver, holder, key, from)) {
MaybeObject* maybe_value =
- ElementsAccessorSubclass::GetImpl(receiver, holder,
- key, backing_store);
+ ElementsAccessorSubclass::GetImpl(receiver, holder, key, from);
Object* value;
- if (!maybe_value->ToObject(&value)) return maybe_value;
+ if (!maybe_value->To(&value)) return maybe_value;
ASSERT(!value->IsTheHole());
if (!HasKey(to, value)) {
extra++;
@@ -745,9 +764,8 @@
// Allocate the result
FixedArray* result;
- MaybeObject* maybe_obj =
- backing_store->GetHeap()->AllocateFixedArray(len0 + extra);
- if (!maybe_obj->To<FixedArray>(&result)) return maybe_obj;
+ MaybeObject* maybe_obj = from->GetHeap()->AllocateFixedArray(len0 + extra);
+ if (!maybe_obj->To(&result)) return maybe_obj;
// Fill in the content
{
@@ -763,14 +781,13 @@
uint32_t index = 0;
for (uint32_t y = 0; y < len1; y++) {
uint32_t key =
- ElementsAccessorSubclass::GetKeyForIndexImpl(backing_store, y);
+ ElementsAccessorSubclass::GetKeyForIndexImpl(from, y);
if (ElementsAccessorSubclass::HasElementImpl(
- receiver, holder, key, backing_store)) {
+ receiver, holder, key, from)) {
MaybeObject* maybe_value =
- ElementsAccessorSubclass::GetImpl(receiver, holder,
- key, backing_store);
+ ElementsAccessorSubclass::GetImpl(receiver, holder, key, from);
Object* value;
- if (!maybe_value->ToObject(&value)) return maybe_value;
+ if (!maybe_value->To(&value)) return maybe_value;
if (!value->IsTheHole() && !HasKey(to, value)) {
result->set(len0 + index, value);
index++;
@@ -782,24 +799,22 @@
}
protected:
- static uint32_t GetCapacityImpl(BackingStore* backing_store) {
+ static uint32_t GetCapacityImpl(FixedArrayBase* backing_store) {
return backing_store->length();
}
virtual uint32_t GetCapacity(FixedArrayBase* backing_store) {
- return ElementsAccessorSubclass::GetCapacityImpl(
- BackingStore::cast(backing_store));
+ return ElementsAccessorSubclass::GetCapacityImpl(backing_store);
}
- static uint32_t GetKeyForIndexImpl(BackingStore* backing_store,
+ static uint32_t GetKeyForIndexImpl(FixedArrayBase* backing_store,
uint32_t index) {
return index;
}
virtual uint32_t GetKeyForIndex(FixedArrayBase* backing_store,
uint32_t index) {
- return ElementsAccessorSubclass::GetKeyForIndexImpl(
- BackingStore::cast(backing_store), index);
+ return ElementsAccessorSubclass::GetKeyForIndexImpl(backing_store, index);
}
private:
@@ -825,7 +840,7 @@
// Adjusts the length of the fast backing store or returns the new length or
// undefined in case conversion to a slow backing store should be performed.
- static MaybeObject* SetLengthWithoutNormalize(BackingStore* backing_store,
+ static MaybeObject* SetLengthWithoutNormalize(FixedArrayBase* backing_store,
JSArray* array,
Object* length_object,
uint32_t length) {
@@ -863,7 +878,7 @@
// Otherwise, fill the unused tail with holes.
int old_length = FastD2IChecked(array->length()->Number());
for (int i = length; i < old_length; i++) {
- backing_store->set_the_hole(i);
+ BackingStore::cast(backing_store)->set_the_hole(i);
}
}
return length_object;
@@ -900,9 +915,8 @@
bool is_non_strict_arguments_elements_map =
backing_store->map() == heap->non_strict_arguments_elements_map();
if (is_non_strict_arguments_elements_map) {
- backing_store =
- KindTraits::BackingStore::cast(
- FixedArray::cast(backing_store)->get(1));
+ backing_store = KindTraits::BackingStore::cast(
+ FixedArray::cast(backing_store)->get(1));
}
uint32_t length = static_cast<uint32_t>(
obj->IsJSArray()
@@ -958,11 +972,11 @@
Object* receiver,
JSObject* holder,
uint32_t key,
- typename KindTraits::BackingStore* backing_store) {
+ FixedArrayBase* backing_store) {
if (key >= static_cast<uint32_t>(backing_store->length())) {
return false;
}
- return !backing_store->is_the_hole(key);
+ return !BackingStore::cast(backing_store)->is_the_hole(key);
}
static void ValidateContents(JSObject* holder, int length) {
@@ -1010,25 +1024,18 @@
int copy_size) {
if (IsFastSmiOrObjectElementsKind(to_kind)) {
CopyObjectToObjectElements(
- FixedArray::cast(from), KindTraits::Kind, from_start,
- FixedArray::cast(to), to_kind, to_start, copy_size);
+ from, KindTraits::Kind, from_start, to, to_kind, to_start, copy_size);
} else if (IsFastDoubleElementsKind(to_kind)) {
if (IsFastSmiElementsKind(KindTraits::Kind)) {
if (IsFastPackedElementsKind(KindTraits::Kind) &&
packed_size != kPackedSizeNotKnown) {
CopyPackedSmiToDoubleElements(
- FixedArray::cast(from), from_start,
- FixedDoubleArray::castOrEmptyFixedArray(to), to_start,
- packed_size, copy_size);
+ from, from_start, to, to_start, packed_size, copy_size);
} else {
- CopySmiToDoubleElements(
- FixedArray::cast(from), from_start,
- FixedDoubleArray::castOrEmptyFixedArray(to), to_start, copy_size);
+ CopySmiToDoubleElements(from, from_start, to, to_start, copy_size);
}
} else {
- CopyObjectToDoubleElements(
- FixedArray::cast(from), from_start,
- FixedDoubleArray::castOrEmptyFixedArray(to), to_start, copy_size);
+ CopyObjectToDoubleElements(from, from_start, to, to_start, copy_size);
}
} else {
UNREACHABLE();
@@ -1132,13 +1139,10 @@
case FAST_HOLEY_SMI_ELEMENTS:
case FAST_HOLEY_ELEMENTS:
return CopyDoubleToObjectElements(
- FixedDoubleArray::castOrEmptyFixedArray(from), from_start,
- FixedArray::cast(to), to_kind, to_start, copy_size);
+ from, from_start, to, to_kind, to_start, copy_size);
case FAST_DOUBLE_ELEMENTS:
case FAST_HOLEY_DOUBLE_ELEMENTS:
- CopyDoubleToDoubleElements(
- FixedDoubleArray::castOrEmptyFixedArray(from), from_start,
- FixedDoubleArray::castOrEmptyFixedArray(to), to_start, copy_size);
+ CopyDoubleToDoubleElements(from, from_start, to, to_start, copy_size);
return from;
default:
UNREACHABLE();
@@ -1197,10 +1201,10 @@
MUST_USE_RESULT static MaybeObject* GetImpl(Object* receiver,
JSObject* obj,
uint32_t key,
- BackingStore* backing_store) {
+ FixedArrayBase* backing_store) {
return
key < ExternalElementsAccessorSubclass::GetCapacityImpl(backing_store)
- ? backing_store->get(key)
+ ? BackingStore::cast(backing_store)->get(key)
: backing_store->GetHeap()->undefined_value();
}
@@ -1208,7 +1212,7 @@
Object* receiver,
JSObject* obj,
uint32_t key,
- BackingStore* backing_store) {
+ FixedArrayBase* backing_store) {
return
key < ExternalElementsAccessorSubclass::GetCapacityImpl(backing_store)
? NONE : ABSENT;
@@ -1218,7 +1222,7 @@
Object* receiver,
JSObject* obj,
uint32_t key,
- BackingStore* backing_store) {
+ FixedArrayBase* backing_store) {
return
key < ExternalElementsAccessorSubclass::GetCapacityImpl(backing_store)
? FIELD : NONEXISTENT;
@@ -1227,7 +1231,7 @@
MUST_USE_RESULT static MaybeObject* SetLengthImpl(
JSObject* obj,
Object* length,
- BackingStore* backing_store) {
+ FixedArrayBase* backing_store) {
// External arrays do not support changing their length.
UNREACHABLE();
return obj;
@@ -1243,7 +1247,7 @@
static bool HasElementImpl(Object* receiver,
JSObject* holder,
uint32_t key,
- BackingStore* backing_store) {
+ FixedArrayBase* backing_store) {
uint32_t capacity =
ExternalElementsAccessorSubclass::GetCapacityImpl(backing_store);
return key < capacity;
@@ -1352,10 +1356,11 @@
// Adjusts the length of the dictionary backing store and returns the new
// length according to ES5 section 15.4.5.2 behavior.
MUST_USE_RESULT static MaybeObject* SetLengthWithoutNormalize(
- SeededNumberDictionary* dict,
+ FixedArrayBase* store,
JSArray* array,
Object* length_object,
uint32_t length) {
+ SeededNumberDictionary* dict = SeededNumberDictionary::cast(store);
Heap* heap = array->GetHeap();
int capacity = dict->Capacity();
uint32_t new_length = length;
@@ -1465,15 +1470,12 @@
case FAST_HOLEY_SMI_ELEMENTS:
case FAST_HOLEY_ELEMENTS:
CopyDictionaryToObjectElements(
- SeededNumberDictionary::cast(from), from_start,
- FixedArray::cast(to), to_kind, to_start, copy_size);
+ from, from_start, to, to_kind, to_start, copy_size);
return from;
case FAST_DOUBLE_ELEMENTS:
case FAST_HOLEY_DOUBLE_ELEMENTS:
CopyDictionaryToDoubleElements(
- SeededNumberDictionary::cast(from), from_start,
- FixedDoubleArray::castOrEmptyFixedArray(to), to_start,
- copy_size);
+ from, from_start, to, to_start, copy_size);
return from;
default:
UNREACHABLE();
@@ -1496,7 +1498,8 @@
Object* receiver,
JSObject* obj,
uint32_t key,
- SeededNumberDictionary* backing_store) {
+ FixedArrayBase* store) {
+ SeededNumberDictionary* backing_store = SeededNumberDictionary::cast(store);
int entry = backing_store->FindEntry(key);
if (entry != SeededNumberDictionary::kNotFound) {
Object* element = backing_store->ValueAt(entry);
@@ -1517,10 +1520,12 @@
Object* receiver,
JSObject* obj,
uint32_t key,
- SeededNumberDictionary* backing_store) {
- int entry = backing_store->FindEntry(key);
+ FixedArrayBase* backing_store) {
+ SeededNumberDictionary* dictionary =
+ SeededNumberDictionary::cast(backing_store);
+ int entry = dictionary->FindEntry(key);
if (entry != SeededNumberDictionary::kNotFound) {
- return backing_store->DetailsAt(entry).attributes();
+ return dictionary->DetailsAt(entry).attributes();
}
return ABSENT;
}
@@ -1529,7 +1534,8 @@
Object* receiver,
JSObject* obj,
uint32_t key,
- SeededNumberDictionary* backing_store) {
+ FixedArrayBase* store) {
+ SeededNumberDictionary* backing_store = SeededNumberDictionary::cast(store);
int entry = backing_store->FindEntry(key);
if (entry != SeededNumberDictionary::kNotFound) {
return backing_store->DetailsAt(entry).type();
@@ -1541,7 +1547,8 @@
Object* receiver,
JSObject* obj,
uint32_t key,
- BackingStore* backing_store) {
+ FixedArrayBase* store) {
+ SeededNumberDictionary* backing_store = SeededNumberDictionary::cast(store);
int entry = backing_store->FindEntry(key);
if (entry != SeededNumberDictionary::kNotFound &&
backing_store->DetailsAt(entry).type() == CALLBACKS &&
@@ -1554,13 +1561,14 @@
static bool HasElementImpl(Object* receiver,
JSObject* holder,
uint32_t key,
- SeededNumberDictionary* backing_store) {
- return backing_store->FindEntry(key) !=
+ FixedArrayBase* backing_store) {
+ return SeededNumberDictionary::cast(backing_store)->FindEntry(key) !=
SeededNumberDictionary::kNotFound;
}
- static uint32_t GetKeyForIndexImpl(SeededNumberDictionary* dict,
+ static uint32_t GetKeyForIndexImpl(FixedArrayBase* store,
uint32_t index) {
+ SeededNumberDictionary* dict = SeededNumberDictionary::cast(store);
Object* key = dict->KeyAt(index);
return Smi::cast(key)->value();
}
@@ -1583,7 +1591,8 @@
MUST_USE_RESULT static MaybeObject* GetImpl(Object* receiver,
JSObject* obj,
uint32_t key,
- FixedArray* parameter_map) {
+ FixedArrayBase* parameters) {
+ FixedArray* parameter_map = FixedArray::cast(parameters);
Object* probe = GetParameterMapArg(obj, parameter_map, key);
if (!probe->IsTheHole()) {
Context* context = Context::cast(parameter_map->get(0));
@@ -1614,7 +1623,8 @@
Object* receiver,
JSObject* obj,
uint32_t key,
- FixedArray* parameter_map) {
+ FixedArrayBase* backing_store) {
+ FixedArray* parameter_map = FixedArray::cast(backing_store);
Object* probe = GetParameterMapArg(obj, parameter_map, key);
if (!probe->IsTheHole()) {
return NONE;
@@ -1630,7 +1640,8 @@
Object* receiver,
JSObject* obj,
uint32_t key,
- FixedArray* parameter_map) {
+ FixedArrayBase* parameters) {
+ FixedArray* parameter_map = FixedArray::cast(parameters);
Object* probe = GetParameterMapArg(obj, parameter_map, key);
if (!probe->IsTheHole()) {
return FIELD;
@@ -1646,7 +1657,8 @@
Object* receiver,
JSObject* obj,
uint32_t key,
- FixedArray* parameter_map) {
+ FixedArrayBase* parameters) {
+ FixedArray* parameter_map = FixedArray::cast(parameters);
Object* probe = GetParameterMapArg(obj, parameter_map, key);
if (!probe->IsTheHole()) {
return NULL;
@@ -1661,7 +1673,7 @@
MUST_USE_RESULT static MaybeObject* SetLengthImpl(
JSObject* obj,
Object* length,
- FixedArray* parameter_map) {
+ FixedArrayBase* parameter_map) {
// TODO(mstarzinger): This was never implemented but will be used once we
// correctly implement [[DefineOwnProperty]] on arrays.
UNIMPLEMENTED();
@@ -1700,19 +1712,20 @@
int packed_size,
int copy_size) {
FixedArray* parameter_map = FixedArray::cast(from);
- FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
+ FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
ElementsAccessor* accessor = ElementsAccessor::ForArray(arguments);
return accessor->CopyElements(NULL, from_start, to, to_kind,
to_start, copy_size, arguments);
}
- static uint32_t GetCapacityImpl(FixedArray* parameter_map) {
+ static uint32_t GetCapacityImpl(FixedArrayBase* backing_store) {
+ FixedArray* parameter_map = FixedArray::cast(backing_store);
FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
return Max(static_cast<uint32_t>(parameter_map->length() - 2),
ForArray(arguments)->GetCapacity(arguments));
}
- static uint32_t GetKeyForIndexImpl(FixedArray* dict,
+ static uint32_t GetKeyForIndexImpl(FixedArrayBase* dict,
uint32_t index) {
return index;
}
@@ -1720,12 +1733,14 @@
static bool HasElementImpl(Object* receiver,
JSObject* holder,
uint32_t key,
- FixedArray* parameter_map) {
+ FixedArrayBase* parameters) {
+ FixedArray* parameter_map = FixedArray::cast(parameters);
Object* probe = GetParameterMapArg(holder, parameter_map, key);
if (!probe->IsTheHole()) {
return true;
} else {
- FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
+ FixedArrayBase* arguments =
+ FixedArrayBase::cast(FixedArray::cast(parameter_map)->get(1));
ElementsAccessor* accessor = ElementsAccessor::ForArray(arguments);
return !accessor->Get(receiver, holder, key, arguments)->IsTheHole();
}
@@ -1738,7 +1753,7 @@
uint32_t length = holder->IsJSArray()
? Smi::cast(JSArray::cast(holder)->length())->value()
: parameter_map->length();
- return key < (length - 2 )
+ return key < (length - 2)
? parameter_map->get(key + 2)
: parameter_map->GetHeap()->the_hole_value();
}
@@ -1805,7 +1820,7 @@
ElementsKindTraits>::
SetLengthImpl(JSObject* obj,
Object* length,
- typename ElementsKindTraits::BackingStore* backing_store) {
+ FixedArrayBase* backing_store) {
JSArray* array = JSArray::cast(obj);
// Fast case: The new length fits into a Smi.
diff --git a/src/extensions/gc-extension.cc b/src/extensions/gc-extension.cc
index 2282075..813b921 100644
--- a/src/extensions/gc-extension.cc
+++ b/src/extensions/gc-extension.cc
@@ -43,7 +43,7 @@
if (args[0]->BooleanValue()) {
HEAP->CollectGarbage(NEW_SPACE, "gc extension");
} else {
- HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask, "gc extension");
+ HEAP->CollectAllGarbage(Heap::kNoGCFlags, "gc extension");
}
return v8::Undefined();
}
diff --git a/src/flag-definitions.h b/src/flag-definitions.h
index b25fe5f..61cd864 100644
--- a/src/flag-definitions.h
+++ b/src/flag-definitions.h
@@ -404,7 +404,7 @@
"flush code that we expect not to use again (during full gc)")
DEFINE_bool(flush_code_incrementally, false,
"flush code that we expect not to use again (incrementally)")
-DEFINE_bool(age_code, false,
+DEFINE_bool(age_code, true,
"track un-executed functions to age code and flush only "
"old code")
DEFINE_bool(incremental_marking, true, "use incremental marking")
diff --git a/src/heap.cc b/src/heap.cc
index d7331dd..ff791d8 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -615,7 +615,7 @@
}
if (collector == MARK_COMPACTOR &&
- !mark_compact_collector()->abort_incremental_marking_ &&
+ !mark_compact_collector()->abort_incremental_marking() &&
!incremental_marking()->IsStopped() &&
!incremental_marking()->should_hurry() &&
FLAG_incremental_marking_steps) {
@@ -651,16 +651,16 @@
PerformGarbageCollection(collector, &tracer);
}
- ASSERT(collector == SCAVENGER || incremental_marking()->IsStopped());
-
- // This can do debug callbacks and restart incremental marking.
GarbageCollectionEpilogue();
}
- if (incremental_marking()->IsStopped()) {
- if (incremental_marking()->WorthActivating() && NextGCIsLikelyToBeFull()) {
- incremental_marking()->Start();
- }
+ // Start incremental marking for the next cycle. The heap snapshot
+ // generator needs incremental marking to stay off after it aborted.
+ if (!mark_compact_collector()->abort_incremental_marking() &&
+ incremental_marking()->IsStopped() &&
+ incremental_marking()->WorthActivating() &&
+ NextGCIsLikelyToBeFull()) {
+ incremental_marking()->Start();
}
return next_gc_likely_to_collect_more;
@@ -957,6 +957,10 @@
isolate_->counters()->objs_since_last_young()->Set(0);
+ // Callbacks that fire after this point might trigger nested GCs and
+ // restart incremental marking, the assertion can't be moved down.
+ ASSERT(collector == SCAVENGER || incremental_marking()->IsStopped());
+
gc_post_processing_depth_++;
{ DisableAssertNoAllocation allow_allocation;
GCTracer::Scope scope(tracer, GCTracer::Scope::EXTERNAL);
@@ -3791,6 +3795,7 @@
code->set_handler_table(empty_fixed_array(), SKIP_WRITE_BARRIER);
code->set_gc_metadata(Smi::FromInt(0));
code->set_ic_age(global_ic_age_);
+ code->set_prologue_offset(kPrologueOffsetNotSet);
// Allow self references to created code object by patching the handle to
// point to the newly allocated Code object.
if (!self_reference.is_null()) {
@@ -5318,7 +5323,8 @@
AgeInlineCaches();
}
int mark_sweep_time = Min(TimeMarkSweepWouldTakeInMs(), 1000);
- if (hint >= mark_sweep_time && incremental_marking()->IsStopped()) {
+ if (hint >= mark_sweep_time && !FLAG_expose_gc &&
+ incremental_marking()->IsStopped()) {
HistogramTimerScope scope(isolate_->counters()->gc_context());
CollectAllGarbage(kReduceMemoryFootprintMask,
"idle notification: contexts disposed");
@@ -5333,7 +5339,7 @@
return false;
}
- if (!FLAG_incremental_marking || Serializer::enabled()) {
+ if (!FLAG_incremental_marking || FLAG_expose_gc || Serializer::enabled()) {
return IdleGlobalGC();
}
diff --git a/src/ia32/codegen-ia32.cc b/src/ia32/codegen-ia32.cc
index a024339..2f5553c 100644
--- a/src/ia32/codegen-ia32.cc
+++ b/src/ia32/codegen-ia32.cc
@@ -872,42 +872,6 @@
}
-byte* Code::FindPlatformCodeAgeSequence() {
- byte* start = instruction_start();
- uint32_t young_length;
- byte* young_sequence = GetNoCodeAgeSequence(&young_length);
- if (!memcmp(start, young_sequence, young_length) ||
- *start == kCallOpcode) {
- return start;
- } else {
- if (kind() == FUNCTION) {
- byte* start_after_strict =
- start + kSizeOfFullCodegenStrictModePrologue;
- ASSERT(!memcmp(start_after_strict, young_sequence, young_length) ||
- start[kSizeOfFullCodegenStrictModePrologue] == kCallOpcode);
- return start_after_strict;
- } else {
- ASSERT(kind() == OPTIMIZED_FUNCTION);
- start = instruction_start() + kSizeOfOptimizedStrictModePrologue;
- if (!memcmp(start, young_sequence, young_length) ||
- *start == kCallOpcode) {
- return start;
- }
- start = instruction_start() + kSizeOfOptimizedAlignStackPrologue;
- if (!memcmp(start, young_sequence, young_length) ||
- *start == kCallOpcode) {
- return start;
- }
- start = instruction_start() + kSizeOfOptimizedAlignStackPrologue +
- kSizeOfOptimizedStrictModePrologue;
- ASSERT(!memcmp(start, young_sequence, young_length) ||
- *start == kCallOpcode);
- return start;
- }
- }
-}
-
-
bool Code::IsYoungSequence(byte* sequence) {
uint32_t young_length;
byte* young_sequence = GetNoCodeAgeSequence(&young_length);
diff --git a/src/ia32/codegen-ia32.h b/src/ia32/codegen-ia32.h
index 6de4725..5137274 100644
--- a/src/ia32/codegen-ia32.h
+++ b/src/ia32/codegen-ia32.h
@@ -37,10 +37,6 @@
// Forward declarations
class CompilationInfo;
-static const int kSizeOfFullCodegenStrictModePrologue = 34;
-static const int kSizeOfOptimizedStrictModePrologue = 12;
-static const int kSizeOfOptimizedAlignStackPrologue = 44;
-
// -------------------------------------------------------------------------
// CodeGenerator
diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc
index 88f204b..6dfec92 100644
--- a/src/ia32/full-codegen-ia32.cc
+++ b/src/ia32/full-codegen-ia32.cc
@@ -138,8 +138,6 @@
// function calls.
if (!info->is_classic_mode() || info->is_native()) {
Label ok;
- Label start;
- __ bind(&start);
__ test(ecx, ecx);
__ j(zero, &ok, Label::kNear);
// +1 for return address.
@@ -151,8 +149,6 @@
__ mov(Operand(esp, receiver_offset),
Immediate(isolate()->factory()->undefined_value()));
__ bind(&ok);
- ASSERT(!FLAG_age_code ||
- (kSizeOfFullCodegenStrictModePrologue == ok.pos() - start.pos()));
}
// Open a frame scope to indicate that there is a frame on the stack. The
@@ -160,6 +156,7 @@
// the frame (that is done below).
FrameScope frame_scope(masm_, StackFrame::MANUAL);
+ info->set_prologue_offset(masm_->pc_offset());
__ push(ebp); // Caller's frame pointer.
__ mov(ebp, esp);
__ push(esi); // Callee's context.
diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc
index 388d496..de60451 100644
--- a/src/ia32/lithium-codegen-ia32.cc
+++ b/src/ia32/lithium-codegen-ia32.cc
@@ -140,8 +140,6 @@
// receiver object). ecx is zero for method calls and non-zero for
// function calls.
if (!info_->is_classic_mode() || info_->is_native()) {
- Label begin;
- __ bind(&begin);
Label ok;
__ test(ecx, Operand(ecx));
__ j(zero, &ok, Label::kNear);
@@ -150,14 +148,10 @@
__ mov(Operand(esp, receiver_offset),
Immediate(isolate()->factory()->undefined_value()));
__ bind(&ok);
- ASSERT(!FLAG_age_code ||
- (kSizeOfOptimizedStrictModePrologue == ok.pos() - begin.pos()));
}
if (dynamic_frame_alignment_) {
- Label begin;
- __ bind(&begin);
// Move state of dynamic frame alignment into edx.
__ mov(edx, Immediate(kNoAlignmentPadding));
@@ -180,11 +174,9 @@
__ j(not_zero, &align_loop, Label::kNear);
__ mov(Operand(ebx, 0), Immediate(kAlignmentZapValue));
__ bind(&do_not_pad);
- ASSERT(!FLAG_age_code ||
- (kSizeOfOptimizedAlignStackPrologue ==
- do_not_pad.pos() - begin.pos()));
}
+ info()->set_prologue_offset(masm_->pc_offset());
__ push(ebp); // Caller's frame pointer.
__ mov(ebp, esp);
__ push(esi); // Callee's context.
diff --git a/src/ia32/macro-assembler-ia32.cc b/src/ia32/macro-assembler-ia32.cc
index 41c8667..14fb8ca 100644
--- a/src/ia32/macro-assembler-ia32.cc
+++ b/src/ia32/macro-assembler-ia32.cc
@@ -1920,9 +1920,25 @@
mov(edi, Operand::StaticVariable(limit_address));
add(Operand::StaticVariable(level_address), Immediate(1));
+ if (FLAG_log_timer_events) {
+ FrameScope frame(this, StackFrame::MANUAL);
+ PushSafepointRegisters();
+ PrepareCallCFunction(0, eax);
+ CallCFunction(ExternalReference::log_enter_external_function(isolate()), 0);
+ PopSafepointRegisters();
+ }
+
// Call the api function.
call(function_address, RelocInfo::RUNTIME_ENTRY);
+ if (FLAG_log_timer_events) {
+ FrameScope frame(this, StackFrame::MANUAL);
+ PushSafepointRegisters();
+ PrepareCallCFunction(0, eax);
+ CallCFunction(ExternalReference::log_leave_external_function(isolate()), 0);
+ PopSafepointRegisters();
+ }
+
if (!kReturnHandlesDirectly) {
// PrepareCallApiFunction saved pointer to the output slot into
// callee-save register esi.
diff --git a/src/ia32/stub-cache-ia32.cc b/src/ia32/stub-cache-ia32.cc
index c3a2654..c8695c5 100644
--- a/src/ia32/stub-cache-ia32.cc
+++ b/src/ia32/stub-cache-ia32.cc
@@ -4359,6 +4359,9 @@
__ mov(FieldOperand(edi, FixedDoubleArray::kLengthOffset),
Immediate(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
+ __ StoreNumberToDoubleElements(eax, edi, ecx, ebx, xmm0,
+ &transition_elements_kind, true);
+
for (int i = 1; i < JSArray::kPreallocatedArrayElements; i++) {
int offset = FixedDoubleArray::OffsetOfElementAt(i);
__ mov(FieldOperand(edi, offset), Immediate(kHoleNanLower32));
@@ -4366,9 +4369,6 @@
Immediate(kHoleNanUpper32));
}
- __ StoreNumberToDoubleElements(eax, edi, ecx, ebx, xmm0,
- &transition_elements_kind, true);
-
// Install the new backing store in the JSArray.
__ mov(FieldOperand(edx, JSObject::kElementsOffset), edi);
__ RecordWriteField(edx, JSObject::kElementsOffset, edi, ebx,
diff --git a/src/incremental-marking-inl.h b/src/incremental-marking-inl.h
index 8c64978..1c30383 100644
--- a/src/incremental-marking-inl.h
+++ b/src/incremental-marking-inl.h
@@ -44,8 +44,12 @@
if (Marking::IsBlack(obj_bit)) {
MemoryChunk* chunk = MemoryChunk::FromAddress(obj->address());
if (chunk->IsFlagSet(MemoryChunk::HAS_PROGRESS_BAR)) {
- WhiteToGreyAndPush(value_heap_obj, value_bit);
- RestartIfNotMarking();
+ if (chunk->IsLeftOfProgressBar(slot)) {
+ WhiteToGreyAndPush(value_heap_obj, value_bit);
+ RestartIfNotMarking();
+ } else {
+ return false;
+ }
} else {
BlackToGreyAndUnshift(obj, obj_bit);
RestartIfNotMarking();
diff --git a/src/incremental-marking.cc b/src/incremental-marking.cc
index 8cdcdb5..1457ee3 100644
--- a/src/incremental-marking.cc
+++ b/src/incremental-marking.cc
@@ -338,10 +338,9 @@
class IncrementalMarkingRootMarkingVisitor : public ObjectVisitor {
public:
- IncrementalMarkingRootMarkingVisitor(Heap* heap,
- IncrementalMarking* incremental_marking)
- : heap_(heap),
- incremental_marking_(incremental_marking) {
+ explicit IncrementalMarkingRootMarkingVisitor(
+ IncrementalMarking* incremental_marking)
+ : incremental_marking_(incremental_marking) {
}
void VisitPointer(Object** p) {
@@ -368,7 +367,6 @@
}
}
- Heap* heap_;
IncrementalMarking* incremental_marking_;
};
@@ -493,7 +491,8 @@
static const intptr_t kActivationThreshold = 0;
#endif
- return FLAG_incremental_marking &&
+ return !FLAG_expose_gc &&
+ FLAG_incremental_marking &&
!Serializer::enabled() &&
heap_->PromotedSpaceSizeOfObjects() > kActivationThreshold;
}
@@ -628,7 +627,7 @@
}
// Mark strong roots grey.
- IncrementalMarkingRootMarkingVisitor visitor(heap_, this);
+ IncrementalMarkingRootMarkingVisitor visitor(this);
heap_->IterateStrongRoots(&visitor, VISIT_ONLY_STRONG);
// Ready to start incremental marking.
diff --git a/src/log.cc b/src/log.cc
index 463ecc1..76af400 100644
--- a/src/log.cc
+++ b/src/log.cc
@@ -716,6 +716,33 @@
}
+void Logger::ExternalSwitch(StateTag old_tag, StateTag new_tag) {
+ if (old_tag != EXTERNAL && new_tag == EXTERNAL) {
+ enter_external_ = OS::Ticks();
+ }
+ if (old_tag == EXTERNAL && new_tag != EXTERNAL && enter_external_ != 0) {
+ TimerEvent("V8.External", enter_external_, OS::Ticks());
+ enter_external_ = 0;
+ }
+}
+
+
+void Logger::EnterExternal() {
+ LOGGER->enter_external_ = OS::Ticks();
+}
+
+
+void Logger::LeaveExternal() {
+ if (enter_external_ == 0) return;
+ Logger* logger = LOGGER;
+ logger->TimerEvent("V8.External", enter_external_, OS::Ticks());
+ logger->enter_external_ = 0;
+}
+
+
+int64_t Logger::enter_external_ = 0;
+
+
void Logger::TimerEventScope::LogTimerEvent() {
LOG(isolate_, TimerEvent(name_, start_, OS::Ticks()));
}
@@ -900,7 +927,7 @@
Address entry_point) {
if (!log_->IsEnabled() || !FLAG_log_code) return;
LogMessageBuilder msg(this);
- msg.Append("%s,%s,",
+ msg.Append("%s,%s,-3,",
kLogEventsNames[CODE_CREATION_EVENT],
kLogEventsNames[CALLBACK_TAG]);
msg.AppendAddress(entry_point);
@@ -956,9 +983,10 @@
}
if (!FLAG_log_code) return;
LogMessageBuilder msg(this);
- msg.Append("%s,%s,",
+ msg.Append("%s,%s,%d,",
kLogEventsNames[CODE_CREATION_EVENT],
- kLogEventsNames[tag]);
+ kLogEventsNames[tag],
+ code->kind());
msg.AppendAddress(code->address());
msg.Append(",%d,\"", code->ExecutableSize());
for (const char* p = comment; *p != '\0'; p++) {
@@ -995,9 +1023,10 @@
}
if (!FLAG_log_code) return;
LogMessageBuilder msg(this);
- msg.Append("%s,%s,",
+ msg.Append("%s,%s,%d,",
kLogEventsNames[CODE_CREATION_EVENT],
- kLogEventsNames[tag]);
+ kLogEventsNames[tag],
+ code->kind());
msg.AppendAddress(code->address());
msg.Append(",%d,\"", code->ExecutableSize());
msg.AppendDetailed(name, false);
@@ -1047,9 +1076,10 @@
LogMessageBuilder msg(this);
SmartArrayPointer<char> str =
name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
- msg.Append("%s,%s,",
+ msg.Append("%s,%s,%d,",
kLogEventsNames[CODE_CREATION_EVENT],
- kLogEventsNames[tag]);
+ kLogEventsNames[tag],
+ code->kind());
msg.AppendAddress(code->address());
msg.Append(",%d,\"%s\",", code->ExecutableSize(), *str);
msg.AppendAddress(shared->address());
@@ -1094,9 +1124,10 @@
shared->DebugName()->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
SmartArrayPointer<char> sourcestr =
source->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
- msg.Append("%s,%s,",
+ msg.Append("%s,%s,%d,",
kLogEventsNames[CODE_CREATION_EVENT],
- kLogEventsNames[tag]);
+ kLogEventsNames[tag],
+ code->kind());
msg.AppendAddress(code->address());
msg.Append(",%d,\"%s %s:%d\",",
code->ExecutableSize(),
@@ -1130,9 +1161,10 @@
}
if (!FLAG_log_code) return;
LogMessageBuilder msg(this);
- msg.Append("%s,%s,",
+ msg.Append("%s,%s,%d,",
kLogEventsNames[CODE_CREATION_EVENT],
- kLogEventsNames[tag]);
+ kLogEventsNames[tag],
+ code->kind());
msg.AppendAddress(code->address());
msg.Append(",%d,\"args_count: %d\"", code->ExecutableSize(), args_count);
msg.Append('\n');
@@ -1167,7 +1199,7 @@
}
if (!FLAG_log_code) return;
LogMessageBuilder msg(this);
- msg.Append("%s,%s,",
+ msg.Append("%s,%s,-2,",
kLogEventsNames[CODE_CREATION_EVENT],
kLogEventsNames[REG_EXP_TAG]);
msg.AppendAddress(code->address());
@@ -1347,6 +1379,8 @@
msg.AppendAddress(sample->pc);
msg.Append(',');
msg.AppendAddress(sample->sp);
+ msg.Append(",%ld",
+ FLAG_log_timer_events ? static_cast<int>(OS::Ticks() - epoch_) : 0);
if (sample->has_external_callback) {
msg.Append(",1,");
msg.AppendAddress(sample->external_callback);
diff --git a/src/log.h b/src/log.h
index c8f81bc..12dc923 100644
--- a/src/log.h
+++ b/src/log.h
@@ -275,7 +275,13 @@
void SharedLibraryEvent(const wchar_t* library_path,
uintptr_t start,
uintptr_t end);
+
+ // ==== Events logged by --log-timer-events. ====
void TimerEvent(const char* name, int64_t start, int64_t end);
+ void ExternalSwitch(StateTag old_tag, StateTag new_tag);
+
+ static void EnterExternal();
+ static void LeaveExternal();
class TimerEventScope {
public:
@@ -476,6 +482,7 @@
Address prev_code_;
int64_t epoch_;
+ static int64_t enter_external_;
friend class CpuProfiler;
};
diff --git a/src/mark-compact.cc b/src/mark-compact.cc
index 30abe6d..aa1900b 100644
--- a/src/mark-compact.cc
+++ b/src/mark-compact.cc
@@ -3525,7 +3525,6 @@
intptr_t freed_bytes = 0;
int pages_swept = 0;
- intptr_t newspace_size = space->heap()->new_space()->Size();
bool lazy_sweeping_active = false;
bool unused_page_present = false;
@@ -3588,15 +3587,8 @@
}
freed_bytes += SweepConservatively(space, p);
pages_swept++;
- if (freed_bytes > 2 * newspace_size) {
- space->SetPagesToSweep(p->next_page());
- lazy_sweeping_active = true;
- } else {
- if (FLAG_gc_verbose) {
- PrintF("Only %" V8PRIdPTR " bytes freed. Still sweeping.\n",
- freed_bytes);
- }
- }
+ space->SetPagesToSweep(p->next_page());
+ lazy_sweeping_active = true;
break;
}
case PRECISE: {
diff --git a/src/mark-compact.h b/src/mark-compact.h
index 0a4c1ea..b652e22 100644
--- a/src/mark-compact.h
+++ b/src/mark-compact.h
@@ -658,6 +658,8 @@
void ClearMarkbits();
+ bool abort_incremental_marking() const { return abort_incremental_marking_; }
+
bool is_compacting() const { return compacting_; }
MarkingParity marking_parity() { return marking_parity_; }
diff --git a/src/mips/code-stubs-mips.cc b/src/mips/code-stubs-mips.cc
index 0e4d37b..a05cee8 100644
--- a/src/mips/code-stubs-mips.cc
+++ b/src/mips/code-stubs-mips.cc
@@ -734,13 +734,13 @@
Register int_scratch,
Destination destination,
FPURegister double_dst,
- Register dst1,
- Register dst2,
+ Register dst_mantissa,
+ Register dst_exponent,
Register scratch2,
FPURegister single_scratch) {
ASSERT(!int_scratch.is(scratch2));
- ASSERT(!int_scratch.is(dst1));
- ASSERT(!int_scratch.is(dst2));
+ ASSERT(!int_scratch.is(dst_mantissa));
+ ASSERT(!int_scratch.is(dst_exponent));
Label done;
@@ -749,64 +749,65 @@
__ mtc1(int_scratch, single_scratch);
__ cvt_d_w(double_dst, single_scratch);
if (destination == kCoreRegisters) {
- __ Move(dst1, dst2, double_dst);
+ __ Move(dst_mantissa, dst_exponent, double_dst);
}
} else {
Label fewer_than_20_useful_bits;
// Expected output:
- // | dst2 | dst1 |
+ // | dst_exponent | dst_mantissa |
// | s | exp | mantissa |
// Check for zero.
- __ mov(dst2, int_scratch);
- __ mov(dst1, int_scratch);
+ __ mov(dst_exponent, int_scratch);
+ __ mov(dst_mantissa, int_scratch);
__ Branch(&done, eq, int_scratch, Operand(zero_reg));
// Preload the sign of the value.
- __ And(dst2, int_scratch, Operand(HeapNumber::kSignMask));
+ __ And(dst_exponent, int_scratch, Operand(HeapNumber::kSignMask));
// Get the absolute value of the object (as an unsigned integer).
Label skip_sub;
- __ Branch(&skip_sub, ge, dst2, Operand(zero_reg));
+ __ Branch(&skip_sub, ge, dst_exponent, Operand(zero_reg));
__ Subu(int_scratch, zero_reg, int_scratch);
__ bind(&skip_sub);
// Get mantissa[51:20].
// Get the position of the first set bit.
- __ Clz(dst1, int_scratch);
+ __ Clz(dst_mantissa, int_scratch);
__ li(scratch2, 31);
- __ Subu(dst1, scratch2, dst1);
+ __ Subu(dst_mantissa, scratch2, dst_mantissa);
// Set the exponent.
- __ Addu(scratch2, dst1, Operand(HeapNumber::kExponentBias));
- __ Ins(dst2, scratch2,
+ __ Addu(scratch2, dst_mantissa, Operand(HeapNumber::kExponentBias));
+ __ Ins(dst_exponent, scratch2,
HeapNumber::kExponentShift, HeapNumber::kExponentBits);
// Clear the first non null bit.
__ li(scratch2, Operand(1));
- __ sllv(scratch2, scratch2, dst1);
+ __ sllv(scratch2, scratch2, dst_mantissa);
__ li(at, -1);
__ Xor(scratch2, scratch2, at);
__ And(int_scratch, int_scratch, scratch2);
// Get the number of bits to set in the lower part of the mantissa.
- __ Subu(scratch2, dst1, Operand(HeapNumber::kMantissaBitsInTopWord));
+ __ Subu(scratch2, dst_mantissa,
+ Operand(HeapNumber::kMantissaBitsInTopWord));
__ Branch(&fewer_than_20_useful_bits, lt, scratch2, Operand(zero_reg));
// Set the higher 20 bits of the mantissa.
__ srlv(at, int_scratch, scratch2);
- __ or_(dst2, dst2, at);
+ __ or_(dst_exponent, dst_exponent, at);
__ li(at, 32);
__ subu(scratch2, at, scratch2);
- __ sllv(dst1, int_scratch, scratch2);
+ __ sllv(dst_mantissa, int_scratch, scratch2);
__ Branch(&done);
__ bind(&fewer_than_20_useful_bits);
__ li(at, HeapNumber::kMantissaBitsInTopWord);
- __ subu(scratch2, at, dst1);
+ __ subu(scratch2, at, dst_mantissa);
__ sllv(scratch2, int_scratch, scratch2);
- __ Or(dst2, dst2, scratch2);
- // Set dst1 to 0.
- __ mov(dst1, zero_reg);
+ __ Or(dst_exponent, dst_exponent, scratch2);
+ // Set dst_mantissa to 0.
+ __ mov(dst_mantissa, zero_reg);
}
__ bind(&done);
}
@@ -816,8 +817,9 @@
Register object,
Destination destination,
DoubleRegister double_dst,
- Register dst1,
- Register dst2,
+ DoubleRegister double_scratch,
+ Register dst_mantissa,
+ Register dst_exponent,
Register heap_number_map,
Register scratch1,
Register scratch2,
@@ -833,8 +835,8 @@
__ JumpIfNotSmi(object, &obj_is_not_smi);
__ SmiUntag(scratch1, object);
- ConvertIntToDouble(masm, scratch1, destination, double_dst, dst1, dst2,
- scratch2, single_scratch);
+ ConvertIntToDouble(masm, scratch1, destination, double_dst, dst_mantissa,
+ dst_exponent, scratch2, single_scratch);
__ Branch(&done);
__ bind(&obj_is_not_smi);
@@ -851,9 +853,10 @@
Register except_flag = scratch2;
__ EmitFPUTruncate(kRoundToZero,
- single_scratch,
- double_dst,
scratch1,
+ double_dst,
+ at,
+ double_scratch,
except_flag,
kCheckForInexactConversion);
@@ -861,27 +864,51 @@
__ Branch(not_int32, ne, except_flag, Operand(zero_reg));
if (destination == kCoreRegisters) {
- __ Move(dst1, dst2, double_dst);
+ __ Move(dst_mantissa, dst_exponent, double_dst);
}
} else {
ASSERT(!scratch1.is(object) && !scratch2.is(object));
// Load the double value in the destination registers.
- __ lw(dst2, FieldMemOperand(object, HeapNumber::kExponentOffset));
- __ lw(dst1, FieldMemOperand(object, HeapNumber::kMantissaOffset));
+ bool save_registers = object.is(dst_mantissa) || object.is(dst_exponent);
+ if (save_registers) {
+ // Save both output registers, because the other one probably holds
+ // an important value too.
+ __ Push(dst_exponent, dst_mantissa);
+ }
+ __ lw(dst_exponent, FieldMemOperand(object, HeapNumber::kExponentOffset));
+ __ lw(dst_mantissa, FieldMemOperand(object, HeapNumber::kMantissaOffset));
// Check for 0 and -0.
- __ And(scratch1, dst1, Operand(~HeapNumber::kSignMask));
- __ Or(scratch1, scratch1, Operand(dst2));
- __ Branch(&done, eq, scratch1, Operand(zero_reg));
+ Label zero;
+ __ And(scratch1, dst_exponent, Operand(~HeapNumber::kSignMask));
+ __ Or(scratch1, scratch1, Operand(dst_mantissa));
+ __ Branch(&zero, eq, scratch1, Operand(zero_reg));
// Check that the value can be exactly represented by a 32-bit integer.
// Jump to not_int32 if that's not the case.
- DoubleIs32BitInteger(masm, dst1, dst2, scratch1, scratch2, not_int32);
+ Label restore_input_and_miss;
+ DoubleIs32BitInteger(masm, dst_exponent, dst_mantissa, scratch1, scratch2,
+ &restore_input_and_miss);
- // dst1 and dst2 were trashed. Reload the double value.
- __ lw(dst2, FieldMemOperand(object, HeapNumber::kExponentOffset));
- __ lw(dst1, FieldMemOperand(object, HeapNumber::kMantissaOffset));
+ // dst_* were trashed. Reload the double value.
+ if (save_registers) {
+ __ Pop(dst_exponent, dst_mantissa);
+ }
+ __ lw(dst_exponent, FieldMemOperand(object, HeapNumber::kExponentOffset));
+ __ lw(dst_mantissa, FieldMemOperand(object, HeapNumber::kMantissaOffset));
+ __ Branch(&done);
+
+ __ bind(&restore_input_and_miss);
+ if (save_registers) {
+ __ Pop(dst_exponent, dst_mantissa);
+ }
+ __ Branch(not_int32);
+
+ __ bind(&zero);
+ if (save_registers) {
+ __ Drop(2);
+ }
}
__ bind(&done);
@@ -895,7 +922,8 @@
Register scratch1,
Register scratch2,
Register scratch3,
- DoubleRegister double_scratch,
+ DoubleRegister double_scratch0,
+ DoubleRegister double_scratch1,
Label* not_int32) {
ASSERT(!dst.is(object));
ASSERT(!scratch1.is(object) && !scratch2.is(object) && !scratch3.is(object));
@@ -918,22 +946,19 @@
if (CpuFeatures::IsSupported(FPU)) {
CpuFeatures::Scope scope(FPU);
// Load the double value.
- __ ldc1(double_scratch, FieldMemOperand(object, HeapNumber::kValueOffset));
+ __ ldc1(double_scratch0, FieldMemOperand(object, HeapNumber::kValueOffset));
- FPURegister single_scratch = double_scratch.low();
Register except_flag = scratch2;
__ EmitFPUTruncate(kRoundToZero,
- single_scratch,
- double_scratch,
+ dst,
+ double_scratch0,
scratch1,
+ double_scratch1,
except_flag,
kCheckForInexactConversion);
// Jump to not_int32 if the operation did not succeed.
__ Branch(not_int32, ne, except_flag, Operand(zero_reg));
- // Get the result in the destination register.
- __ mfc1(dst, single_scratch);
-
} else {
// Load the double value in the destination registers.
__ lw(scratch2, FieldMemOperand(object, HeapNumber::kExponentOffset));
@@ -979,14 +1004,14 @@
void FloatingPointHelper::DoubleIs32BitInteger(MacroAssembler* masm,
- Register src1,
- Register src2,
+ Register src_exponent,
+ Register src_mantissa,
Register dst,
Register scratch,
Label* not_int32) {
// Get exponent alone in scratch.
__ Ext(scratch,
- src1,
+ src_exponent,
HeapNumber::kExponentShift,
HeapNumber::kExponentBits);
@@ -1006,11 +1031,11 @@
// Another way to put it is that if (exponent - signbit) > 30 then the
// number cannot be represented as an int32.
Register tmp = dst;
- __ srl(at, src1, 31);
+ __ srl(at, src_exponent, 31);
__ subu(tmp, scratch, at);
__ Branch(not_int32, gt, tmp, Operand(30));
// - Bits [21:0] in the mantissa are not null.
- __ And(tmp, src2, 0x3fffff);
+ __ And(tmp, src_mantissa, 0x3fffff);
__ Branch(not_int32, ne, tmp, Operand(zero_reg));
// Otherwise the exponent needs to be big enough to shift left all the
@@ -1021,20 +1046,20 @@
// Get the 32 higher bits of the mantissa in dst.
__ Ext(dst,
- src2,
+ src_mantissa,
HeapNumber::kMantissaBitsInTopWord,
32 - HeapNumber::kMantissaBitsInTopWord);
- __ sll(at, src1, HeapNumber::kNonMantissaBitsInTopWord);
+ __ sll(at, src_exponent, HeapNumber::kNonMantissaBitsInTopWord);
__ or_(dst, dst, at);
// Create the mask and test the lower bits (of the higher bits).
__ li(at, 32);
__ subu(scratch, at, scratch);
- __ li(src2, 1);
- __ sllv(src1, src2, scratch);
- __ Subu(src1, src1, Operand(1));
- __ And(src1, dst, src1);
- __ Branch(not_int32, ne, src1, Operand(zero_reg));
+ __ li(src_mantissa, 1);
+ __ sllv(src_exponent, src_mantissa, scratch);
+ __ Subu(src_exponent, src_exponent, Operand(1));
+ __ And(src_exponent, dst, src_exponent);
+ __ Branch(not_int32, ne, src_exponent, Operand(zero_reg));
}
@@ -2955,6 +2980,7 @@
right,
destination,
f14,
+ f16,
a2,
a3,
heap_number_map,
@@ -2966,6 +2992,7 @@
left,
destination,
f12,
+ f16,
t0,
t1,
heap_number_map,
@@ -3002,9 +3029,10 @@
Register except_flag = scratch2;
__ EmitFPUTruncate(kRoundToZero,
- single_scratch,
- f10,
scratch1,
+ f10,
+ at,
+ f16,
except_flag);
if (result_type_ <= BinaryOpIC::INT32) {
@@ -3013,7 +3041,6 @@
}
// Check if the result fits in a smi.
- __ mfc1(scratch1, single_scratch);
__ Addu(scratch2, scratch1, Operand(0x40000000));
// If not try to return a heap number.
__ Branch(&return_heap_number, lt, scratch2, Operand(zero_reg));
@@ -3108,6 +3135,7 @@
scratch2,
scratch3,
f0,
+ f2,
&transition);
FloatingPointHelper::LoadNumberAsInt32(masm,
right,
@@ -3117,6 +3145,7 @@
scratch2,
scratch3,
f0,
+ f2,
&transition);
// The ECMA-262 standard specifies that, for shift operations, only the
@@ -3683,9 +3712,10 @@
Label int_exponent_convert;
// Detect integer exponents stored as double.
__ EmitFPUTruncate(kRoundToMinusInf,
- single_scratch,
- double_exponent,
scratch,
+ double_exponent,
+ at,
+ double_scratch,
scratch2,
kCheckForInexactConversion);
// scratch2 == 0 means there was no conversion error.
@@ -3743,7 +3773,7 @@
__ push(ra);
{
AllowExternalCallThatCantCauseGC scope(masm);
- __ PrepareCallCFunction(0, 2, scratch);
+ __ PrepareCallCFunction(0, 2, scratch2);
__ SetCallCDoubleArguments(double_base, double_exponent);
__ CallCFunction(
ExternalReference::power_double_double_function(masm->isolate()),
@@ -3754,7 +3784,6 @@
__ jmp(&done);
__ bind(&int_exponent_convert);
- __ mfc1(scratch, single_scratch);
}
// Calculate power with integer exponent.
diff --git a/src/mips/code-stubs-mips.h b/src/mips/code-stubs-mips.h
index bb36d22..b560c63 100644
--- a/src/mips/code-stubs-mips.h
+++ b/src/mips/code-stubs-mips.h
@@ -657,6 +657,7 @@
Register object,
Destination destination,
FPURegister double_dst,
+ FPURegister double_scratch,
Register dst1,
Register dst2,
Register heap_number_map,
@@ -678,7 +679,8 @@
Register scratch1,
Register scratch2,
Register scratch3,
- FPURegister double_scratch,
+ FPURegister double_scratch0,
+ FPURegister double_scratch1,
Label* not_int32);
// Generate non FPU code to check if a double can be exactly represented by a
diff --git a/src/mips/codegen-mips.cc b/src/mips/codegen-mips.cc
index 51ad474..0119c11 100644
--- a/src/mips/codegen-mips.cc
+++ b/src/mips/codegen-mips.cc
@@ -31,11 +31,11 @@
#include "codegen.h"
#include "macro-assembler.h"
+#include "simulator-mips.h"
namespace v8 {
namespace internal {
-#define __ ACCESS_MASM(masm)
UnaryMathFunction CreateTranscendentalFunction(TranscendentalCache::Type type) {
switch (type) {
@@ -49,6 +49,74 @@
}
+#define __ masm.
+
+
+#if defined(USE_SIMULATOR)
+byte* fast_exp_mips_machine_code = NULL;
+double fast_exp_simulator(double x) {
+ return Simulator::current(Isolate::Current())->CallFP(
+ fast_exp_mips_machine_code, x, 0);
+}
+#endif
+
+
+UnaryMathFunction CreateExpFunction() {
+ if (!CpuFeatures::IsSupported(FPU)) return &exp;
+ if (!FLAG_fast_math) return &exp;
+ size_t actual_size;
+ byte* buffer = static_cast<byte*>(OS::Allocate(1 * KB, &actual_size, true));
+ if (buffer == NULL) return &exp;
+ ExternalReference::InitializeMathExpData();
+
+ MacroAssembler masm(NULL, buffer, static_cast<int>(actual_size));
+
+ {
+ CpuFeatures::Scope use_fpu(FPU);
+ DoubleRegister input = f12;
+ DoubleRegister result = f0;
+ DoubleRegister double_scratch1 = f4;
+ DoubleRegister double_scratch2 = f6;
+ Register temp1 = t0;
+ Register temp2 = t1;
+ Register temp3 = t2;
+
+ if (!IsMipsSoftFloatABI) {
+ // Input value is in f12 anyway, nothing to do.
+ } else {
+ __ Move(input, a0, a1);
+ }
+ __ Push(temp3, temp2, temp1);
+ MathExpGenerator::EmitMathExp(
+ &masm, input, result, double_scratch1, double_scratch2,
+ temp1, temp2, temp3);
+ __ Pop(temp3, temp2, temp1);
+ if (!IsMipsSoftFloatABI) {
+ // Result is already in f0, nothing to do.
+ } else {
+ __ Move(a0, a1, result);
+ }
+ __ Ret();
+ }
+
+ CodeDesc desc;
+ masm.GetCode(&desc);
+
+ CPU::FlushICache(buffer, actual_size);
+ OS::ProtectCode(buffer, actual_size);
+
+#if !defined(USE_SIMULATOR)
+ return FUNCTION_CAST<UnaryMathFunction>(buffer);
+#else
+ fast_exp_mips_machine_code = buffer;
+ return &fast_exp_simulator;
+#endif
+}
+
+
+#undef __
+
+
UnaryMathFunction CreateSqrtFunction() {
return &sqrt;
}
@@ -72,6 +140,8 @@
// -------------------------------------------------------------------------
// Code generators
+#define __ ACCESS_MASM(masm)
+
void ElementsTransitionGenerator::GenerateMapChangeElementsTransition(
MacroAssembler* masm) {
// ----------- S t a t e -------------
@@ -446,6 +516,81 @@
__ bind(&done);
}
+
+static MemOperand ExpConstant(int index, Register base) {
+ return MemOperand(base, index * kDoubleSize);
+}
+
+
+void MathExpGenerator::EmitMathExp(MacroAssembler* masm,
+ DoubleRegister input,
+ DoubleRegister result,
+ DoubleRegister double_scratch1,
+ DoubleRegister double_scratch2,
+ Register temp1,
+ Register temp2,
+ Register temp3) {
+ ASSERT(!input.is(result));
+ ASSERT(!input.is(double_scratch1));
+ ASSERT(!input.is(double_scratch2));
+ ASSERT(!result.is(double_scratch1));
+ ASSERT(!result.is(double_scratch2));
+ ASSERT(!double_scratch1.is(double_scratch2));
+ ASSERT(!temp1.is(temp2));
+ ASSERT(!temp1.is(temp3));
+ ASSERT(!temp2.is(temp3));
+ ASSERT(ExternalReference::math_exp_constants(0).address() != NULL);
+
+ Label done;
+
+ __ li(temp3, Operand(ExternalReference::math_exp_constants(0)));
+
+ __ ldc1(double_scratch1, ExpConstant(0, temp3));
+ __ Move(result, kDoubleRegZero);
+ __ BranchF(&done, NULL, ge, double_scratch1, input);
+ __ ldc1(double_scratch2, ExpConstant(1, temp3));
+ __ ldc1(result, ExpConstant(2, temp3));
+ __ BranchF(&done, NULL, ge, input, double_scratch2);
+ __ ldc1(double_scratch1, ExpConstant(3, temp3));
+ __ ldc1(result, ExpConstant(4, temp3));
+ __ mul_d(double_scratch1, double_scratch1, input);
+ __ add_d(double_scratch1, double_scratch1, result);
+ __ Move(temp2, temp1, double_scratch1);
+ __ sub_d(double_scratch1, double_scratch1, result);
+ __ ldc1(result, ExpConstant(6, temp3));
+ __ ldc1(double_scratch2, ExpConstant(5, temp3));
+ __ mul_d(double_scratch1, double_scratch1, double_scratch2);
+ __ sub_d(double_scratch1, double_scratch1, input);
+ __ sub_d(result, result, double_scratch1);
+ __ mul_d(input, double_scratch1, double_scratch1);
+ __ mul_d(result, result, input);
+ __ srl(temp1, temp2, 11);
+ __ ldc1(double_scratch2, ExpConstant(7, temp3));
+ __ mul_d(result, result, double_scratch2);
+ __ sub_d(result, result, double_scratch1);
+ __ ldc1(double_scratch2, ExpConstant(8, temp3));
+ __ add_d(result, result, double_scratch2);
+ __ li(at, 0x7ff);
+ __ And(temp2, temp2, at);
+ __ Addu(temp1, temp1, Operand(0x3ff));
+ __ sll(temp1, temp1, 20);
+
+ // Must not call ExpConstant() after overwriting temp3!
+ __ li(temp3, Operand(ExternalReference::math_exp_log_table()));
+ __ sll(at, temp2, 3);
+ __ addu(at, at, temp3);
+ __ lw(at, MemOperand(at));
+ __ Addu(temp3, temp3, Operand(kPointerSize));
+ __ sll(temp2, temp2, 3);
+ __ addu(temp2, temp2, temp3);
+ __ lw(temp2, MemOperand(temp2));
+ __ Or(temp1, temp1, temp2);
+ __ Move(input, at, temp1);
+ __ mul_d(result, result, input);
+ __ bind(&done);
+}
+
+
// nop(CODE_AGE_MARKER_NOP)
static const uint32_t kCodeAgePatchFirstInstruction = 0x00010180;
@@ -467,29 +612,6 @@
}
-byte* Code::FindPlatformCodeAgeSequence() {
- byte* start = instruction_start();
- uint32_t young_length;
- byte* young_sequence = GetNoCodeAgeSequence(&young_length);
- if (!memcmp(start, young_sequence, young_length) ||
- Memory::uint32_at(start) == kCodeAgePatchFirstInstruction) {
- return start;
- } else {
- byte* start_after_strict = NULL;
- if (kind() == FUNCTION) {
- start_after_strict = start + kSizeOfFullCodegenStrictModePrologue;
- } else {
- ASSERT(kind() == OPTIMIZED_FUNCTION);
- start_after_strict = start + kSizeOfOptimizedStrictModePrologue;
- }
- ASSERT(!memcmp(start_after_strict, young_sequence, young_length) ||
- Memory::uint32_at(start_after_strict) ==
- kCodeAgePatchFirstInstruction);
- return start_after_strict;
- }
-}
-
-
bool Code::IsYoungSequence(byte* sequence) {
uint32_t young_length;
byte* young_sequence = GetNoCodeAgeSequence(&young_length);
diff --git a/src/mips/codegen-mips.h b/src/mips/codegen-mips.h
index 27c8a8b..0ed2414 100644
--- a/src/mips/codegen-mips.h
+++ b/src/mips/codegen-mips.h
@@ -36,9 +36,6 @@
namespace v8 {
namespace internal {
-static const int kSizeOfFullCodegenStrictModePrologue = 16;
-static const int kSizeOfOptimizedStrictModePrologue = 16;
-
// Forward declarations
class CompilationInfo;
@@ -93,6 +90,22 @@
DISALLOW_COPY_AND_ASSIGN(StringCharLoadGenerator);
};
+
+class MathExpGenerator : public AllStatic {
+ public:
+ static void EmitMathExp(MacroAssembler* masm,
+ DoubleRegister input,
+ DoubleRegister result,
+ DoubleRegister double_scratch1,
+ DoubleRegister double_scratch2,
+ Register temp1,
+ Register temp2,
+ Register temp3);
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MathExpGenerator);
+};
+
} } // namespace v8::internal
#endif // V8_MIPS_CODEGEN_MIPS_H_
diff --git a/src/mips/full-codegen-mips.cc b/src/mips/full-codegen-mips.cc
index 5a0bb30..b8b3ea1 100644
--- a/src/mips/full-codegen-mips.cc
+++ b/src/mips/full-codegen-mips.cc
@@ -158,14 +158,11 @@
// function calls.
if (!info->is_classic_mode() || info->is_native()) {
Label ok;
- Label begin;
- __ bind(&begin);
__ Branch(&ok, eq, t1, Operand(zero_reg));
int receiver_offset = info->scope()->num_parameters() * kPointerSize;
__ LoadRoot(a2, Heap::kUndefinedValueRootIndex);
__ sw(a2, MemOperand(sp, receiver_offset));
__ bind(&ok);
- ASSERT_EQ(kSizeOfFullCodegenStrictModePrologue, ok.pos() - begin.pos());
}
// Open a frame scope to indicate that there is a frame on the stack. The
@@ -175,6 +172,7 @@
int locals_count = info->scope()->num_stack_slots();
+ info->set_prologue_offset(masm_->pc_offset());
// The following three instructions must remain together and unmodified for
// code aging to work properly.
__ Push(ra, fp, cp, a1);
diff --git a/src/mips/lithium-codegen-mips.cc b/src/mips/lithium-codegen-mips.cc
index e19caf3..22352e1 100644
--- a/src/mips/lithium-codegen-mips.cc
+++ b/src/mips/lithium-codegen-mips.cc
@@ -136,17 +136,15 @@
// function calls.
if (!info_->is_classic_mode() || info_->is_native()) {
Label ok;
- Label begin;
- __ bind(&begin);
__ Branch(&ok, eq, t1, Operand(zero_reg));
int receiver_offset = scope()->num_parameters() * kPointerSize;
__ LoadRoot(a2, Heap::kUndefinedValueRootIndex);
__ sw(a2, MemOperand(sp, receiver_offset));
__ bind(&ok);
- ASSERT_EQ(kSizeOfOptimizedStrictModePrologue, ok.pos() - begin.pos());
}
+ info()->set_prologue_offset(masm_->pc_offset());
// The following three instructions must remain together and unmodified for
// code aging to work properly.
__ Push(ra, fp, cp, a1);
@@ -3264,22 +3262,19 @@
void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) {
DoubleRegister input = ToDoubleRegister(instr->value());
Register result = ToRegister(instr->result());
- FPURegister single_scratch = double_scratch0().low();
Register scratch1 = scratch0();
Register except_flag = ToRegister(instr->temp());
__ EmitFPUTruncate(kRoundToMinusInf,
- single_scratch,
+ result,
input,
scratch1,
+ double_scratch0(),
except_flag);
// Deopt if the operation did not succeed.
DeoptimizeIf(ne, instr->environment(), except_flag, Operand(zero_reg));
- // Load the result.
- __ mfc1(result, single_scratch);
-
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
// Test for -0.
Label done;
@@ -3295,6 +3290,7 @@
void LCodeGen::DoMathRound(LUnaryMathOperation* instr) {
DoubleRegister input = ToDoubleRegister(instr->value());
Register result = ToRegister(instr->result());
+ DoubleRegister double_scratch1 = ToDoubleRegister(instr->temp());
Register scratch = scratch0();
Label done, check_sign_on_zero;
@@ -3346,17 +3342,15 @@
}
Register except_flag = scratch;
-
__ EmitFPUTruncate(kRoundToMinusInf,
- double_scratch0().low(),
- double_scratch0(),
result,
+ double_scratch0(),
+ at,
+ double_scratch1,
except_flag);
DeoptimizeIf(ne, instr->environment(), except_flag, Operand(zero_reg));
- __ mfc1(result, double_scratch0().low());
-
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
// Test for -0.
__ Branch(&done, ne, result, Operand(zero_reg));
@@ -3506,6 +3500,20 @@
}
+void LCodeGen::DoMathExp(LMathExp* instr) {
+ DoubleRegister input = ToDoubleRegister(instr->value());
+ DoubleRegister result = ToDoubleRegister(instr->result());
+ DoubleRegister double_scratch1 = ToDoubleRegister(instr->double_temp());
+ DoubleRegister double_scratch2 = double_scratch0();
+ Register temp1 = ToRegister(instr->temp1());
+ Register temp2 = ToRegister(instr->temp2());
+
+ MathExpGenerator::EmitMathExp(
+ masm(), input, result, double_scratch1, double_scratch2,
+ temp1, temp2, scratch0());
+}
+
+
void LCodeGen::DoMathLog(LUnaryMathOperation* instr) {
ASSERT(ToDoubleRegister(instr->result()).is(f4));
TranscendentalCacheStub stub(TranscendentalCache::LOG,
@@ -4251,7 +4259,7 @@
if (FLAG_inline_new) {
__ LoadRoot(t2, Heap::kHeapNumberMapRootIndex);
- __ AllocateHeapNumber(t1, a3, t0, t2, &slow);
+ __ AllocateHeapNumber(t1, a3, t0, t2, &slow, DONT_TAG_RESULT);
__ Move(dst, t1);
__ Branch(&done);
}
@@ -4265,11 +4273,13 @@
__ StoreToSafepointRegisterSlot(zero_reg, dst);
CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, instr);
__ Move(dst, v0);
+ __ Subu(dst, dst, kHeapObjectTag);
// Done. Put the value in dbl_scratch into the value of the allocated heap
// number.
__ bind(&done);
- __ sdc1(dbl_scratch, FieldMemOperand(dst, HeapNumber::kValueOffset));
+ __ sdc1(dbl_scratch, MemOperand(dst, HeapNumber::kValueOffset));
+ __ Addu(dst, dst, kHeapObjectTag);
__ StoreToSafepointRegisterSlot(dst, dst);
}
@@ -4294,12 +4304,16 @@
DeferredNumberTagD* deferred = new(zone()) DeferredNumberTagD(this, instr);
if (FLAG_inline_new) {
__ LoadRoot(scratch, Heap::kHeapNumberMapRootIndex);
- __ AllocateHeapNumber(reg, temp1, temp2, scratch, deferred->entry());
+ // We want the untagged address first for performance
+ __ AllocateHeapNumber(reg, temp1, temp2, scratch, deferred->entry(),
+ DONT_TAG_RESULT);
} else {
__ Branch(deferred->entry());
}
__ bind(deferred->exit());
- __ sdc1(input_reg, FieldMemOperand(reg, HeapNumber::kValueOffset));
+ __ sdc1(input_reg, MemOperand(reg, HeapNumber::kValueOffset));
+ // Now that we have finished with the object's real address tag it
+ __ Addu(reg, reg, kHeapObjectTag);
}
@@ -4312,6 +4326,7 @@
PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, instr);
+ __ Subu(v0, v0, kHeapObjectTag);
__ StoreToSafepointRegisterSlot(v0, reg);
}
@@ -4393,7 +4408,7 @@
Register scratch1 = scratch0();
Register scratch2 = ToRegister(instr->temp());
DoubleRegister double_scratch = double_scratch0();
- FPURegister single_scratch = double_scratch.low();
+ DoubleRegister double_scratch2 = ToDoubleRegister(instr->temp3());
ASSERT(!scratch1.is(input_reg) && !scratch1.is(scratch2));
ASSERT(!scratch2.is(input_reg) && !scratch2.is(scratch1));
@@ -4409,7 +4424,7 @@
if (instr->truncating()) {
Register scratch3 = ToRegister(instr->temp2());
- DoubleRegister double_scratch2 = ToDoubleRegister(instr->temp3());
+ FPURegister single_scratch = double_scratch.low();
ASSERT(!scratch3.is(input_reg) &&
!scratch3.is(scratch1) &&
!scratch3.is(scratch2));
@@ -4444,18 +4459,16 @@
Register except_flag = scratch2;
__ EmitFPUTruncate(kRoundToZero,
- single_scratch,
+ input_reg,
double_scratch,
scratch1,
+ double_scratch2,
except_flag,
kCheckForInexactConversion);
// Deopt if the operation did not succeed.
DeoptimizeIf(ne, instr->environment(), except_flag, Operand(zero_reg));
- // Load the result.
- __ mfc1(input_reg, single_scratch);
-
if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
__ Branch(&done, ne, input_reg, Operand(zero_reg));
@@ -4517,10 +4530,10 @@
Register scratch1 = scratch0();
Register scratch2 = ToRegister(instr->temp());
DoubleRegister double_input = ToDoubleRegister(instr->value());
- FPURegister single_scratch = double_scratch0().low();
if (instr->truncating()) {
Register scratch3 = ToRegister(instr->temp2());
+ FPURegister single_scratch = double_scratch0().low();
__ EmitECMATruncate(result_reg,
double_input,
single_scratch,
@@ -4531,17 +4544,15 @@
Register except_flag = scratch2;
__ EmitFPUTruncate(kRoundToMinusInf,
- single_scratch,
+ result_reg,
double_input,
scratch1,
+ double_scratch0(),
except_flag,
kCheckForInexactConversion);
// Deopt if the operation did not succeed (except_flag != 0).
DeoptimizeIf(ne, instr->environment(), except_flag, Operand(zero_reg));
-
- // Load the result.
- __ mfc1(result_reg, single_scratch);
}
}
diff --git a/src/mips/lithium-mips.cc b/src/mips/lithium-mips.cc
index 796d153..56dd33d 100644
--- a/src/mips/lithium-mips.cc
+++ b/src/mips/lithium-mips.cc
@@ -297,6 +297,11 @@
}
+void LMathExp::PrintDataTo(StringStream* stream) {
+ value()->PrintTo(stream);
+}
+
+
void LLoadContextSlot::PrintDataTo(StringStream* stream) {
context()->PrintTo(stream);
stream->Add("[%d]", slot_index());
@@ -398,6 +403,15 @@
}
+void LStoreKeyedGeneric::PrintDataTo(StringStream* stream) {
+ object()->PrintTo(stream);
+ stream->Add("[");
+ key()->PrintTo(stream);
+ stream->Add("] <- ");
+ value()->PrintTo(stream);
+}
+
+
void LTransitionElementsKind::PrintDataTo(StringStream* stream) {
object()->PrintTo(stream);
stream->Add(" %p -> %p", *original_map(), *transitioned_map());
@@ -1031,6 +1045,15 @@
LOperand* input = UseFixedDouble(instr->value(), f4);
LUnaryMathOperation* result = new(zone()) LUnaryMathOperation(input, NULL);
return MarkAsCall(DefineFixedDouble(result, f4), instr);
+ } else if (op == kMathExp) {
+ ASSERT(instr->representation().IsDouble());
+ ASSERT(instr->value()->representation().IsDouble());
+ LOperand* input = UseTempRegister(instr->value());
+ LOperand* temp1 = TempRegister();
+ LOperand* temp2 = TempRegister();
+ LOperand* double_temp = FixedTemp(f6); // Chosen by fair dice roll.
+ LMathExp* result = new(zone()) LMathExp(input, double_temp, temp1, temp2);
+ return DefineAsRegister(result);
} else if (op == kMathPowHalf) {
// Input cannot be the same as the result.
// See lithium-codegen-mips.cc::DoMathPowHalf.
@@ -1040,7 +1063,9 @@
return DefineFixedDouble(result, f4);
} else {
LOperand* input = UseRegisterAtStart(instr->value());
- LOperand* temp = (op == kMathFloor) ? TempRegister() : NULL;
+
+ LOperand* temp = (op == kMathRound) ? FixedTemp(f6) :
+ (op == kMathFloor) ? TempRegister() : NULL;
LUnaryMathOperation* result = new(zone()) LUnaryMathOperation(input, temp);
switch (op) {
case kMathAbs:
@@ -1557,8 +1582,7 @@
LOperand* temp1 = TempRegister();
LOperand* temp2 = instr->CanTruncateToInt32() ? TempRegister()
: NULL;
- LOperand* temp3 = instr->CanTruncateToInt32() ? FixedTemp(f22)
- : NULL;
+ LOperand* temp3 = FixedTemp(f22);
res = DefineSameAsFirst(new(zone()) LTaggedToI(value,
temp1,
temp2,
diff --git a/src/mips/lithium-mips.h b/src/mips/lithium-mips.h
index 1baf07d..17ef24c 100644
--- a/src/mips/lithium-mips.h
+++ b/src/mips/lithium-mips.h
@@ -131,6 +131,7 @@
V(LoadNamedFieldPolymorphic) \
V(LoadNamedGeneric) \
V(MapEnumLength) \
+ V(MathExp) \
V(MathMinMax) \
V(ModI) \
V(MulI) \
@@ -641,6 +642,30 @@
};
+class LMathExp: public LTemplateInstruction<1, 1, 3> {
+ public:
+ LMathExp(LOperand* value,
+ LOperand* double_temp,
+ LOperand* temp1,
+ LOperand* temp2) {
+ inputs_[0] = value;
+ temps_[0] = temp1;
+ temps_[1] = temp2;
+ temps_[2] = double_temp;
+ ExternalReference::InitializeMathExpData();
+ }
+
+ LOperand* value() { return inputs_[0]; }
+ LOperand* temp1() { return temps_[0]; }
+ LOperand* temp2() { return temps_[1]; }
+ LOperand* double_temp() { return temps_[2]; }
+
+ DECLARE_CONCRETE_INSTRUCTION(MathExp, "math-exp")
+
+ virtual void PrintDataTo(StringStream* stream);
+};
+
+
class LCmpObjectEqAndBranch: public LControlInstruction<2, 0> {
public:
LCmpObjectEqAndBranch(LOperand* left, LOperand* right) {
diff --git a/src/mips/macro-assembler-mips.cc b/src/mips/macro-assembler-mips.cc
index 926b3bf..9249917 100644
--- a/src/mips/macro-assembler-mips.cc
+++ b/src/mips/macro-assembler-mips.cc
@@ -1395,49 +1395,68 @@
void MacroAssembler::EmitFPUTruncate(FPURoundingMode rounding_mode,
- FPURegister result,
+ Register result,
DoubleRegister double_input,
- Register scratch1,
+ Register scratch,
+ DoubleRegister double_scratch,
Register except_flag,
CheckForInexactConversion check_inexact) {
+ ASSERT(!result.is(scratch));
+ ASSERT(!double_input.is(double_scratch));
+ ASSERT(!except_flag.is(scratch));
+
ASSERT(CpuFeatures::IsSupported(FPU));
CpuFeatures::Scope scope(FPU);
+ Label done;
+
+ // Clear the except flag (0 = no exception)
+ mov(except_flag, zero_reg);
+
+ // Test for values that can be exactly represented as a signed 32-bit integer.
+ cvt_w_d(double_scratch, double_input);
+ mfc1(result, double_scratch);
+ cvt_d_w(double_scratch, double_scratch);
+ BranchF(&done, NULL, eq, double_input, double_scratch);
int32_t except_mask = kFCSRFlagMask; // Assume interested in all exceptions.
if (check_inexact == kDontCheckForInexactConversion) {
- // Ingore inexact exceptions.
+ // Ignore inexact exceptions.
except_mask &= ~kFCSRInexactFlagMask;
}
// Save FCSR.
- cfc1(scratch1, FCSR);
+ cfc1(scratch, FCSR);
// Disable FPU exceptions.
ctc1(zero_reg, FCSR);
// Do operation based on rounding mode.
switch (rounding_mode) {
case kRoundToNearest:
- Round_w_d(result, double_input);
+ Round_w_d(double_scratch, double_input);
break;
case kRoundToZero:
- Trunc_w_d(result, double_input);
+ Trunc_w_d(double_scratch, double_input);
break;
case kRoundToPlusInf:
- Ceil_w_d(result, double_input);
+ Ceil_w_d(double_scratch, double_input);
break;
case kRoundToMinusInf:
- Floor_w_d(result, double_input);
+ Floor_w_d(double_scratch, double_input);
break;
} // End of switch-statement.
// Retrieve FCSR.
cfc1(except_flag, FCSR);
// Restore FCSR.
- ctc1(scratch1, FCSR);
+ ctc1(scratch, FCSR);
+ // Move the converted value into the result register.
+ mfc1(result, double_scratch);
// Check for fpu exceptions.
And(except_flag, except_flag, Operand(except_mask));
+
+ bind(&done);
}
@@ -3215,7 +3234,8 @@
Register scratch1,
Register scratch2,
Register heap_number_map,
- Label* need_gc) {
+ Label* need_gc,
+ TaggingMode tagging_mode) {
// Allocate an object in the heap for the heap number and tag it as a heap
// object.
AllocateInNewSpace(HeapNumber::kSize,
@@ -3223,11 +3243,16 @@
scratch1,
scratch2,
need_gc,
- TAG_OBJECT);
+ tagging_mode == TAG_RESULT ? TAG_OBJECT :
+ NO_ALLOCATION_FLAGS);
// Store heap number map in the allocated object.
AssertRegisterIsRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
- sw(heap_number_map, FieldMemOperand(result, HeapObject::kMapOffset));
+ if (tagging_mode == TAG_RESULT) {
+ sw(heap_number_map, FieldMemOperand(result, HeapObject::kMapOffset));
+ } else {
+ sw(heap_number_map, MemOperand(result, HeapObject::kMapOffset));
+ }
}
@@ -3951,6 +3976,14 @@
Addu(s2, s2, Operand(1));
sw(s2, MemOperand(s3, kLevelOffset));
+ if (FLAG_log_timer_events) {
+ FrameScope frame(this, StackFrame::MANUAL);
+ PushSafepointRegisters();
+ PrepareCallCFunction(0, a0);
+ CallCFunction(ExternalReference::log_enter_external_function(isolate()), 0);
+ PopSafepointRegisters();
+ }
+
// The O32 ABI requires us to pass a pointer in a0 where the returned struct
// (4 bytes) will be placed. This is also built into the Simulator.
// Set up the pointer to the returned value (a0). It was allocated in
@@ -3963,6 +3996,14 @@
DirectCEntryStub stub;
stub.GenerateCall(this, function);
+ if (FLAG_log_timer_events) {
+ FrameScope frame(this, StackFrame::MANUAL);
+ PushSafepointRegisters();
+ PrepareCallCFunction(0, a0);
+ CallCFunction(ExternalReference::log_leave_external_function(isolate()), 0);
+ PopSafepointRegisters();
+ }
+
// As mentioned above, on MIPS a pointer is returned - we need to dereference
// it to get the actual return value (which is also a pointer).
lw(v0, MemOperand(v0));
diff --git a/src/mips/macro-assembler-mips.h b/src/mips/macro-assembler-mips.h
index ada3184..474772e 100644
--- a/src/mips/macro-assembler-mips.h
+++ b/src/mips/macro-assembler-mips.h
@@ -65,6 +65,14 @@
SIZE_IN_WORDS = 1 << 2
};
+// Flags used for AllocateHeapNumber
+enum TaggingMode {
+ // Tag the result.
+ TAG_RESULT,
+ // Don't tag
+ DONT_TAG_RESULT
+};
+
// Flags used for the ObjectToDoubleFPURegister function.
enum ObjectToDoubleFlags {
// No special flags.
@@ -536,7 +544,8 @@
Register scratch1,
Register scratch2,
Register heap_number_map,
- Label* gc_required);
+ Label* gc_required,
+ TaggingMode tagging_mode = TAG_RESULT);
void AllocateHeapNumberWithValue(Register result,
FPURegister value,
Register scratch1,
@@ -753,14 +762,16 @@
FPURegister double_scratch,
Label *not_int32);
- // Truncates a double using a specific rounding mode.
+ // Truncates a double using a specific rounding mode, and writes the value
+ // to the result register.
// The except_flag will contain any exceptions caused by the instruction.
- // If check_inexact is kDontCheckForInexactConversion, then the inexacat
+ // If check_inexact is kDontCheckForInexactConversion, then the inexact
// exception is masked.
void EmitFPUTruncate(FPURoundingMode rounding_mode,
- FPURegister result,
+ Register result,
DoubleRegister double_input,
- Register scratch1,
+ Register scratch,
+ DoubleRegister double_scratch,
Register except_flag,
CheckForInexactConversion check_inexact
= kDontCheckForInexactConversion);
diff --git a/src/mips/simulator-mips.cc b/src/mips/simulator-mips.cc
index cb56473..ea359ea 100644
--- a/src/mips/simulator-mips.cc
+++ b/src/mips/simulator-mips.cc
@@ -1016,6 +1016,13 @@
}
+void Simulator::set_dw_register(int reg, const int* dbl) {
+ ASSERT((reg >= 0) && (reg < kNumSimuRegisters));
+ registers_[reg] = dbl[0];
+ registers_[reg + 1] = dbl[1];
+}
+
+
void Simulator::set_fpu_register(int fpureg, int32_t value) {
ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters));
FPUregisters_[fpureg] = value;
@@ -1045,6 +1052,19 @@
}
+double Simulator::get_double_from_register_pair(int reg) {
+ ASSERT((reg >= 0) && (reg < kNumSimuRegisters) && ((reg % 2) == 0));
+
+ double dm_val = 0.0;
+ // Read the bits from the unsigned integer register_[] array
+ // into the double precision floating point value and return it.
+ char buffer[2 * sizeof(registers_[0])];
+ memcpy(buffer, ®isters_[reg], 2 * sizeof(registers_[0]));
+ memcpy(&dm_val, buffer, 2 * sizeof(registers_[0]));
+ return(dm_val);
+}
+
+
int32_t Simulator::get_fpu_register(int fpureg) const {
ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters));
return FPUregisters_[fpureg];
@@ -2718,34 +2738,7 @@
}
-int32_t Simulator::Call(byte* entry, int argument_count, ...) {
- va_list parameters;
- va_start(parameters, argument_count);
- // Set up arguments.
-
- // First four arguments passed in registers.
- ASSERT(argument_count >= 4);
- set_register(a0, va_arg(parameters, int32_t));
- set_register(a1, va_arg(parameters, int32_t));
- set_register(a2, va_arg(parameters, int32_t));
- set_register(a3, va_arg(parameters, int32_t));
-
- // Remaining arguments passed on stack.
- int original_stack = get_register(sp);
- // Compute position of stack on entry to generated code.
- int entry_stack = (original_stack - (argument_count - 4) * sizeof(int32_t)
- - kCArgsSlotsSize);
- if (OS::ActivationFrameAlignment() != 0) {
- entry_stack &= -OS::ActivationFrameAlignment();
- }
- // Store remaining arguments on stack, from low to high memory.
- intptr_t* stack_argument = reinterpret_cast<intptr_t*>(entry_stack);
- for (int i = 4; i < argument_count; i++) {
- stack_argument[i - 4 + kCArgSlotCount] = va_arg(parameters, int32_t);
- }
- va_end(parameters);
- set_register(sp, entry_stack);
-
+void Simulator::CallInternal(byte* entry) {
// Prepare to execute the code at entry.
set_register(pc, reinterpret_cast<int32_t>(entry));
// Put down marker for end of simulation. The simulator will stop simulation
@@ -2809,6 +2802,38 @@
set_register(gp, gp_val);
set_register(sp, sp_val);
set_register(fp, fp_val);
+}
+
+
+int32_t Simulator::Call(byte* entry, int argument_count, ...) {
+ va_list parameters;
+ va_start(parameters, argument_count);
+ // Set up arguments.
+
+ // First four arguments passed in registers.
+ ASSERT(argument_count >= 4);
+ set_register(a0, va_arg(parameters, int32_t));
+ set_register(a1, va_arg(parameters, int32_t));
+ set_register(a2, va_arg(parameters, int32_t));
+ set_register(a3, va_arg(parameters, int32_t));
+
+ // Remaining arguments passed on stack.
+ int original_stack = get_register(sp);
+ // Compute position of stack on entry to generated code.
+ int entry_stack = (original_stack - (argument_count - 4) * sizeof(int32_t)
+ - kCArgsSlotsSize);
+ if (OS::ActivationFrameAlignment() != 0) {
+ entry_stack &= -OS::ActivationFrameAlignment();
+ }
+ // Store remaining arguments on stack, from low to high memory.
+ intptr_t* stack_argument = reinterpret_cast<intptr_t*>(entry_stack);
+ for (int i = 4; i < argument_count; i++) {
+ stack_argument[i - 4 + kCArgSlotCount] = va_arg(parameters, int32_t);
+ }
+ va_end(parameters);
+ set_register(sp, entry_stack);
+
+ CallInternal(entry);
// Pop stack passed arguments.
CHECK_EQ(entry_stack, get_register(sp));
@@ -2819,6 +2844,27 @@
}
+double Simulator::CallFP(byte* entry, double d0, double d1) {
+ if (!IsMipsSoftFloatABI) {
+ set_fpu_register_double(f12, d0);
+ set_fpu_register_double(f14, d1);
+ } else {
+ int buffer[2];
+ ASSERT(sizeof(buffer[0]) * 2 == sizeof(d0));
+ memcpy(buffer, &d0, sizeof(d0));
+ set_dw_register(a0, buffer);
+ memcpy(buffer, &d1, sizeof(d1));
+ set_dw_register(a2, buffer);
+ }
+ CallInternal(entry);
+ if (!IsMipsSoftFloatABI) {
+ return get_fpu_register_double(f0);
+ } else {
+ return get_double_from_register_pair(v0);
+ }
+}
+
+
uintptr_t Simulator::PushAddress(uintptr_t address) {
int new_sp = get_register(sp) - sizeof(uintptr_t);
uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(new_sp);
diff --git a/src/mips/simulator-mips.h b/src/mips/simulator-mips.h
index 776badc..67f5953 100644
--- a/src/mips/simulator-mips.h
+++ b/src/mips/simulator-mips.h
@@ -184,7 +184,9 @@
// architecture specification and is off by a 8 from the currently executing
// instruction.
void set_register(int reg, int32_t value);
+ void set_dw_register(int dreg, const int* dbl);
int32_t get_register(int reg) const;
+ double get_double_from_register_pair(int reg);
// Same for FPURegisters.
void set_fpu_register(int fpureg, int32_t value);
void set_fpu_register_float(int fpureg, float value);
@@ -214,6 +216,8 @@
// generated RegExp code with 7 parameters. This is a convenience function,
// which sets up the simulator state and grabs the result on return.
int32_t Call(byte* entry, int argument_count, ...);
+ // Alternative: call a 2-argument double function.
+ double CallFP(byte* entry, double d0, double d1);
// Push an address onto the JS stack.
uintptr_t PushAddress(uintptr_t address);
@@ -353,6 +357,7 @@
void GetFpArgs(double* x, int32_t* y);
void SetFpResult(const double& result);
+ void CallInternal(byte* entry);
// Architecture state.
// Registers.
diff --git a/src/mips/stub-cache-mips.cc b/src/mips/stub-cache-mips.cc
index 85497b5..323933b 100644
--- a/src/mips/stub-cache-mips.cc
+++ b/src/mips/stub-cache-mips.cc
@@ -3695,6 +3695,7 @@
Register scratch0,
Register scratch1,
FPURegister double_scratch0,
+ FPURegister double_scratch1,
Label* fail) {
if (CpuFeatures::IsSupported(FPU)) {
CpuFeatures::Scope scope(FPU);
@@ -3710,15 +3711,15 @@
DONT_DO_SMI_CHECK);
__ ldc1(double_scratch0, FieldMemOperand(key, HeapNumber::kValueOffset));
__ EmitFPUTruncate(kRoundToZero,
- double_scratch0,
- double_scratch0,
scratch0,
+ double_scratch0,
+ at,
+ double_scratch1,
scratch1,
kCheckForInexactConversion);
__ Branch(fail, ne, scratch1, Operand(zero_reg));
- __ mfc1(scratch0, double_scratch0);
__ SmiTagCheckOverflow(key, scratch0, scratch1);
__ BranchOnOverflow(fail, scratch1);
__ bind(&key_ok);
@@ -3746,7 +3747,7 @@
// have been verified by the caller to not be a smi.
// Check that the key is a smi or a heap number convertible to a smi.
- GenerateSmiKeyCheck(masm, key, t0, t1, f2, &miss_force_generic);
+ GenerateSmiKeyCheck(masm, key, t0, t1, f2, f4, &miss_force_generic);
__ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
// a3: elements array
@@ -3846,34 +3847,41 @@
__ Ret();
__ bind(&box_int);
- // Allocate a HeapNumber for the result and perform int-to-double
- // conversion.
- // The arm version uses a temporary here to save r0, but we don't need to
- // (a0 is not modified).
- __ LoadRoot(t1, Heap::kHeapNumberMapRootIndex);
- __ AllocateHeapNumber(v0, a3, t0, t1, &slow);
if (CpuFeatures::IsSupported(FPU)) {
CpuFeatures::Scope scope(FPU);
+ // Allocate a HeapNumber for the result and perform int-to-double
+ // conversion.
+ // The arm version uses a temporary here to save r0, but we don't need to
+ // (a0 is not modified).
+ __ LoadRoot(t1, Heap::kHeapNumberMapRootIndex);
+ __ AllocateHeapNumber(v0, a3, t0, t1, &slow, DONT_TAG_RESULT);
__ mtc1(value, f0);
__ cvt_d_w(f0, f0);
- __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
+ __ sdc1(f0, MemOperand(v0, HeapNumber::kValueOffset));
+ __ Addu(v0, v0, kHeapObjectTag);
__ Ret();
} else {
- Register dst1 = t2;
- Register dst2 = t3;
+ // Allocate a HeapNumber for the result and perform int-to-double
+ // conversion.
+ // The arm version uses a temporary here to save r0, but we don't need to
+ // (a0 is not modified).
+ __ LoadRoot(t1, Heap::kHeapNumberMapRootIndex);
+ __ AllocateHeapNumber(v0, a3, t0, t1, &slow, TAG_RESULT);
+ Register dst_mantissa = t2;
+ Register dst_exponent = t3;
FloatingPointHelper::Destination dest =
FloatingPointHelper::kCoreRegisters;
FloatingPointHelper::ConvertIntToDouble(masm,
value,
dest,
f0,
- dst1,
- dst2,
+ dst_mantissa,
+ dst_exponent,
t1,
f2);
- __ sw(dst1, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
- __ sw(dst2, FieldMemOperand(v0, HeapNumber::kExponentOffset));
+ __ sw(dst_mantissa, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
+ __ sw(dst_exponent, FieldMemOperand(v0, HeapNumber::kExponentOffset));
__ Ret();
}
} else if (elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) {
@@ -3896,7 +3904,7 @@
// conversion. Don't use a0 and a1 as AllocateHeapNumber clobbers all
// registers - also when jumping due to exhausted young space.
__ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
- __ AllocateHeapNumber(v0, t2, t3, t6, &slow);
+ __ AllocateHeapNumber(v0, t2, t3, t6, &slow, DONT_TAG_RESULT);
// This is replaced by a macro:
// __ mtc1(value, f0); // LS 32-bits.
@@ -3905,8 +3913,9 @@
__ Cvt_d_uw(f0, value, f22);
- __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
+ __ sdc1(f0, MemOperand(v0, HeapNumber::kValueOffset));
+ __ Addu(v0, v0, kHeapObjectTag);
__ Ret();
} else {
// Check whether unsigned integer fits into smi.
@@ -3939,7 +3948,7 @@
// clobbers all registers - also when jumping due to exhausted young
// space.
__ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
- __ AllocateHeapNumber(t2, t3, t5, t6, &slow);
+ __ AllocateHeapNumber(t2, t3, t5, t6, &slow, TAG_RESULT);
__ sw(hiword, FieldMemOperand(t2, HeapNumber::kExponentOffset));
__ sw(loword, FieldMemOperand(t2, HeapNumber::kMantissaOffset));
@@ -3956,17 +3965,19 @@
// AllocateHeapNumber clobbers all registers - also when jumping due to
// exhausted young space.
__ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
- __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
+ __ AllocateHeapNumber(v0, t3, t5, t6, &slow, DONT_TAG_RESULT);
// The float (single) value is already in fpu reg f0 (if we use float).
__ cvt_d_s(f0, f0);
- __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
+ __ sdc1(f0, MemOperand(v0, HeapNumber::kValueOffset));
+
+ __ Addu(v0, v0, kHeapObjectTag);
__ Ret();
} else {
// Allocate a HeapNumber for the result. Don't use a0 and a1 as
// AllocateHeapNumber clobbers all registers - also when jumping due to
// exhausted young space.
__ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
- __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
+ __ AllocateHeapNumber(v0, t3, t5, t6, &slow, TAG_RESULT);
// FPU is not available, do manual single to double conversion.
// a2: floating point value (binary32).
@@ -4021,16 +4032,18 @@
// AllocateHeapNumber clobbers all registers - also when jumping due to
// exhausted young space.
__ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
- __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
+ __ AllocateHeapNumber(v0, t3, t5, t6, &slow, DONT_TAG_RESULT);
// The double value is already in f0
- __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
+ __ sdc1(f0, MemOperand(v0, HeapNumber::kValueOffset));
+
+ __ Addu(v0, v0, kHeapObjectTag);
__ Ret();
} else {
// Allocate a HeapNumber for the result. Don't use a0 and a1 as
// AllocateHeapNumber clobbers all registers - also when jumping due to
// exhausted young space.
__ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
- __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
+ __ AllocateHeapNumber(v0, t3, t5, t6, &slow, TAG_RESULT);
__ sw(a2, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
__ sw(a3, FieldMemOperand(v0, HeapNumber::kExponentOffset));
@@ -4088,7 +4101,7 @@
// have been verified by the caller to not be a smi.
// Check that the key is a smi or a heap number convertible to a smi.
- GenerateSmiKeyCheck(masm, key, t0, t1, f2, &miss_force_generic);
+ GenerateSmiKeyCheck(masm, key, t0, t1, f2, f4, &miss_force_generic);
__ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
@@ -4167,7 +4180,7 @@
}
FloatingPointHelper::ConvertIntToDouble(
masm, t1, destination,
- f0, t2, t3, // These are: double_dst, dst1, dst2.
+ f0, t2, t3, // These are: double_dst, dst_mantissa, dst_exponent.
t0, f2); // These are: scratch2, single_scratch.
if (destination == FloatingPointHelper::kFPURegisters) {
CpuFeatures::Scope scope(FPU);
@@ -4477,7 +4490,7 @@
// have been verified by the caller to not be a smi.
// Check that the key is a smi or a heap number convertible to a smi.
- GenerateSmiKeyCheck(masm, a0, t0, t1, f2, &miss_force_generic);
+ GenerateSmiKeyCheck(masm, a0, t0, t1, f2, f4, &miss_force_generic);
// Get the elements array.
__ lw(a2, FieldMemOperand(a1, JSObject::kElementsOffset));
@@ -4528,7 +4541,7 @@
// have been verified by the caller to not be a smi.
// Check that the key is a smi or a heap number convertible to a smi.
- GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, &miss_force_generic);
+ GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, f4, &miss_force_generic);
// Get the elements array.
__ lw(elements_reg,
@@ -4548,7 +4561,7 @@
// Non-NaN. Allocate a new heap number and copy the double value into it.
__ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
__ AllocateHeapNumber(heap_number_reg, scratch2, scratch3,
- heap_number_map, &slow_allocate_heapnumber);
+ heap_number_map, &slow_allocate_heapnumber, TAG_RESULT);
// Don't need to reload the upper 32 bits of the double, it's already in
// scratch.
@@ -4602,7 +4615,7 @@
// have been verified by the caller to not be a smi.
// Check that the key is a smi or a heap number convertible to a smi.
- GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, &miss_force_generic);
+ GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, f4, &miss_force_generic);
if (IsFastSmiElementsKind(elements_kind)) {
__ JumpIfNotSmi(value_reg, &transition_elements_kind);
@@ -4746,11 +4759,12 @@
// -- a1 : key
// -- a2 : receiver
// -- ra : return address
- // -- a3 : scratch
+ // -- a3 : scratch (elements backing store)
// -- t0 : scratch (elements_reg)
// -- t1 : scratch (mantissa_reg)
// -- t2 : scratch (exponent_reg)
// -- t3 : scratch4
+ // -- t4 : scratch
// -----------------------------------
Label miss_force_generic, transition_elements_kind, grow, slow;
Label finish_store, check_capacity;
@@ -4763,13 +4777,14 @@
Register scratch2 = t1;
Register scratch3 = t2;
Register scratch4 = t3;
+ Register scratch5 = t4;
Register length_reg = t3;
// This stub is meant to be tail-jumped to, the receiver must already
// have been verified by the caller to not be a smi.
// Check that the key is a smi or a heap number convertible to a smi.
- GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, &miss_force_generic);
+ GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, f4, &miss_force_generic);
__ lw(elements_reg,
FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
@@ -4843,14 +4858,32 @@
__ AllocateInNewSpace(size, elements_reg, scratch1, scratch2, &slow,
TAG_OBJECT);
- // Initialize the new FixedDoubleArray. Leave elements unitialized for
- // efficiency, they are guaranteed to be initialized before use.
+ // Initialize the new FixedDoubleArray.
__ LoadRoot(scratch1, Heap::kFixedDoubleArrayMapRootIndex);
__ sw(scratch1, FieldMemOperand(elements_reg, JSObject::kMapOffset));
__ li(scratch1, Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
__ sw(scratch1,
FieldMemOperand(elements_reg, FixedDoubleArray::kLengthOffset));
+ __ mov(scratch1, elements_reg);
+ __ StoreNumberToDoubleElements(value_reg,
+ key_reg,
+ // All registers after this are overwritten.
+ scratch1,
+ scratch2,
+ scratch3,
+ scratch4,
+ scratch5,
+ &transition_elements_kind);
+
+ __ li(scratch1, Operand(kHoleNanLower32));
+ __ li(scratch2, Operand(kHoleNanUpper32));
+ for (int i = 1; i < JSArray::kPreallocatedArrayElements; i++) {
+ int offset = FixedDoubleArray::OffsetOfElementAt(i);
+ __ sw(scratch1, FieldMemOperand(elements_reg, offset));
+ __ sw(scratch2, FieldMemOperand(elements_reg, offset + kPointerSize));
+ }
+
// Install the new backing store in the JSArray.
__ sw(elements_reg,
FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
@@ -4863,7 +4896,7 @@
__ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
__ lw(elements_reg,
FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
- __ jmp(&finish_store);
+ __ Ret();
__ bind(&check_capacity);
// Make sure that the backing store can hold additional elements.
diff --git a/src/objects-inl.h b/src/objects-inl.h
index 6e8d148..b99ba44 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -2342,13 +2342,6 @@
// Cast operations
-FixedDoubleArray* FixedDoubleArray::castOrEmptyFixedArray(Object* object) {
- ASSERT(object == HeapObject::cast(object)->GetHeap()->empty_fixed_array() ||
- object->IsFixedDoubleArray());
- return reinterpret_cast<FixedDoubleArray*>(object);
-}
-
-
CAST_ACCESSOR(FixedArray)
CAST_ACCESSOR(FixedDoubleArray)
CAST_ACCESSOR(DescriptorArray)
@@ -4578,6 +4571,7 @@
INT_ACCESSORS(Code, instruction_size, kInstructionSizeOffset)
+INT_ACCESSORS(Code, prologue_offset, kPrologueOffset)
ACCESSORS(Code, relocation_info, ByteArray, kRelocationInfoOffset)
ACCESSORS(Code, handler_table, FixedArray, kHandlerTableOffset)
ACCESSORS(Code, deoptimization_data, FixedArray, kDeoptimizationDataOffset)
diff --git a/src/objects-printer.cc b/src/objects-printer.cc
index b1118de..9a1a58e 100644
--- a/src/objects-printer.cc
+++ b/src/objects-printer.cc
@@ -384,7 +384,7 @@
case EXTERNAL_DOUBLE_ELEMENTS: {
ExternalDoubleArray* p = ExternalDoubleArray::cast(elements());
for (int i = 0; i < p->length(); i++) {
- PrintF(out, " %d: %f\n", i, p->get_scalar(i));
+ PrintF(out, " %d: %f\n", i, p->get_scalar(i));
}
break;
}
@@ -393,11 +393,16 @@
break;
case NON_STRICT_ARGUMENTS_ELEMENTS: {
FixedArray* p = FixedArray::cast(elements());
+ PrintF(out, " parameter map:");
for (int i = 2; i < p->length(); i++) {
- PrintF(out, " %d: ", i);
+ PrintF(out, " %d:", i - 2);
p->get(i)->ShortPrint(out);
- PrintF(out, "\n");
}
+ PrintF(out, "\n context: ");
+ p->get(0)->ShortPrint(out);
+ PrintF(out, "\n arguments: ");
+ p->get(1)->ShortPrint(out);
+ PrintF(out, "\n");
break;
}
}
diff --git a/src/objects.cc b/src/objects.cc
index 944c5a1..324b10c 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -4157,14 +4157,12 @@
HandleScope scope(isolate);
Handle<JSObject> self(this);
- Handle<String> name;
Handle<Object> old_value;
- bool preexists = false;
- if (FLAG_harmony_observation && map()->is_observed()) {
- name = isolate->factory()->Uint32ToString(index);
- preexists = self->HasLocalElement(index);
- if (preexists) {
- old_value = GetLocalElementAccessorPair(index) != NULL
+ bool should_enqueue_change_record = false;
+ if (FLAG_harmony_observation && self->map()->is_observed()) {
+ should_enqueue_change_record = self->HasLocalElement(index);
+ if (should_enqueue_change_record) {
+ old_value = self->GetLocalElementAccessorPair(index) != NULL
? Handle<Object>::cast(isolate->factory()->the_hole_value())
: Object::GetElement(self, index);
}
@@ -4181,9 +4179,9 @@
Handle<Object> hresult;
if (!result->ToHandle(&hresult, isolate)) return result;
- if (FLAG_harmony_observation && map()->is_observed()) {
- if (preexists && !self->HasLocalElement(index))
- EnqueueChangeRecord(self, "deleted", name, old_value);
+ if (should_enqueue_change_record && !self->HasLocalElement(index)) {
+ Handle<String> name = isolate->factory()->Uint32ToString(index);
+ EnqueueChangeRecord(self, "deleted", name, old_value);
}
return *hresult;
@@ -4243,7 +4241,8 @@
Handle<String> hname(name);
Handle<Object> old_value(isolate->heap()->the_hole_value());
- if (FLAG_harmony_observation && map()->is_observed()) {
+ bool is_observed = FLAG_harmony_observation && self->map()->is_observed();
+ if (is_observed) {
old_value = handle(lookup.GetLazyValue(), isolate);
}
MaybeObject* result;
@@ -4268,9 +4267,8 @@
Handle<Object> hresult;
if (!result->ToHandle(&hresult, isolate)) return result;
- if (FLAG_harmony_observation && map()->is_observed()) {
- if (!self->HasLocalProperty(*hname))
- EnqueueChangeRecord(self, "deleted", hname, old_value);
+ if (is_observed && !self->HasLocalProperty(*hname)) {
+ EnqueueChangeRecord(self, "deleted", hname, old_value);
}
return *hresult;
@@ -4924,11 +4922,12 @@
bool is_element = name->AsArrayIndex(&index);
Handle<Object> old_value = isolate->factory()->the_hole_value();
+ bool is_observed = FLAG_harmony_observation && self->map()->is_observed();
bool preexists = false;
- if (FLAG_harmony_observation && map()->is_observed()) {
+ if (is_observed) {
if (is_element) {
preexists = HasLocalElement(index);
- if (preexists && GetLocalElementAccessorPair(index) == NULL) {
+ if (preexists && self->GetLocalElementAccessorPair(index) == NULL) {
old_value = Object::GetElement(self, index);
}
} else {
@@ -4946,7 +4945,7 @@
Handle<Object> hresult;
if (!result->ToHandle(&hresult, isolate)) return result;
- if (FLAG_harmony_observation && map()->is_observed()) {
+ if (is_observed) {
const char* type = preexists ? "reconfigured" : "new";
EnqueueChangeRecord(self, type, name, old_value);
}
@@ -8876,11 +8875,10 @@
byte* Code::FindCodeAgeSequence() {
return FLAG_age_code &&
- strlen(FLAG_stop_at) == 0 &&
- !ProfileEntryHookStub::HasEntryHook() &&
+ prologue_offset() != kPrologueOffsetNotSet &&
(kind() == OPTIMIZED_FUNCTION ||
(kind() == FUNCTION && !has_debug_break_slots()))
- ? FindPlatformCodeAgeSequence()
+ ? instruction_start() + prologue_offset()
: NULL;
}
@@ -9283,9 +9281,8 @@
// Allocate a new fast elements backing store.
FixedArray* new_elements;
- { MaybeObject* maybe = heap->AllocateFixedArrayWithHoles(capacity);
- if (!maybe->To(&new_elements)) return maybe;
- }
+ MaybeObject* maybe = heap->AllocateUninitializedFixedArray(capacity);
+ if (!maybe->To(&new_elements)) return maybe;
ElementsKind elements_kind = GetElementsKind();
ElementsKind new_elements_kind;
@@ -9309,10 +9306,10 @@
}
FixedArrayBase* old_elements = elements();
ElementsAccessor* accessor = ElementsAccessor::ForKind(elements_kind);
- { MaybeObject* maybe_obj =
- accessor->CopyElements(this, new_elements, new_elements_kind);
- if (maybe_obj->IsFailure()) return maybe_obj;
- }
+ MaybeObject* maybe_obj =
+ accessor->CopyElements(this, new_elements, new_elements_kind);
+ if (maybe_obj->IsFailure()) return maybe_obj;
+
if (elements_kind != NON_STRICT_ARGUMENTS_ELEMENTS) {
Map* new_map = map();
if (new_elements_kind != elements_kind) {
@@ -10345,7 +10342,7 @@
Handle<Object> old_length;
if (old_attributes != ABSENT) {
- if (GetLocalElementAccessorPair(index) == NULL)
+ if (self->GetLocalElementAccessorPair(index) == NULL)
old_value = Object::GetElement(self, index);
} else if (self->IsJSArray()) {
// Store old array length in case adding an element grows the array.
@@ -11598,9 +11595,8 @@
public:
explicit SubStringAsciiSymbolKey(Handle<SeqOneByteString> string,
int from,
- int length,
- uint32_t seed)
- : string_(string), from_(from), length_(length), seed_(seed) { }
+ int length)
+ : string_(string), from_(from), length_(length) { }
uint32_t Hash() {
ASSERT(length_ >= 0);
@@ -11657,7 +11653,6 @@
int from_;
int length_;
uint32_t hash_field_;
- uint32_t seed_;
};
@@ -12583,7 +12578,7 @@
int from,
int length,
Object** s) {
- SubStringAsciiSymbolKey key(str, from, length, GetHeap()->HashSeed());
+ SubStringAsciiSymbolKey key(str, from, length);
return LookupKey(&key, s);
}
@@ -13271,8 +13266,7 @@
PropertyType type = DetailsAt(i).type();
ASSERT(type != FIELD);
instance_descriptor_length++;
- if (type == NORMAL &&
- (!value->IsJSFunction() || heap->InNewSpace(value))) {
+ if (type == NORMAL && !value->IsJSFunction()) {
number_of_fields += 1;
}
}
@@ -13337,7 +13331,7 @@
int enumeration_index = details.descriptor_index();
PropertyType type = details.type();
- if (value->IsJSFunction() && !heap->InNewSpace(value)) {
+ if (value->IsJSFunction()) {
ConstantFunctionDescriptor d(key,
JSFunction::cast(value),
details.attributes(),
diff --git a/src/objects.h b/src/objects.h
index 7d46c06..c476692 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -2489,7 +2489,6 @@
// Casting.
static inline FixedDoubleArray* cast(Object* obj);
- static inline FixedDoubleArray* castOrEmptyFixedArray(Object* obj);
// Maximal allowed size, in bytes, of a single FixedDoubleArray.
// Prevents overflowing size computations, as well as extreme memory
@@ -4325,6 +4324,11 @@
inline void set_ic_age(int count);
inline int ic_age();
+ // [prologue_offset]: Offset of the function prologue, used for aging
+ // FUNCTIONs and OPTIMIZED_FUNCTIONs.
+ inline int prologue_offset();
+ inline void set_prologue_offset(int offset);
+
// Unchecked accessors to be used during GC.
inline ByteArray* unchecked_relocation_info();
inline FixedArray* unchecked_deoptimization_data();
@@ -4593,8 +4597,10 @@
static const int kKindSpecificFlags1Offset = kFlagsOffset + kIntSize;
static const int kKindSpecificFlags2Offset =
kKindSpecificFlags1Offset + kIntSize;
+ // Note: We might be able to squeeze this into the flags above.
+ static const int kPrologueOffset = kKindSpecificFlags2Offset + kIntSize;
- static const int kHeaderPaddingStart = kKindSpecificFlags2Offset + kIntSize;
+ static const int kHeaderPaddingStart = kPrologueOffset + kIntSize;
// Add padding to align the instruction start following right after
// the Code object header.
@@ -4688,7 +4694,6 @@
static Code* GetCodeAgeStub(Age age, MarkingParity parity);
// Code aging -- platform-specific
- byte* FindPlatformCodeAgeSequence();
static void PatchPlatformCodeAge(byte* sequence, Age age,
MarkingParity parity);
diff --git a/src/parser.cc b/src/parser.cc
index a7bb4e7..6e18381 100644
--- a/src/parser.cc
+++ b/src/parser.cc
@@ -3714,16 +3714,16 @@
int literal_index = current_function_state_->NextMaterializedLiteralIndex();
// Allocate a fixed array to hold all the object literals.
- Handle<FixedArray> object_literals =
- isolate()->factory()->NewFixedArray(values->length(), TENURED);
- Handle<FixedDoubleArray> double_literals;
- ElementsKind elements_kind = FAST_SMI_ELEMENTS;
- bool has_hole_values = false;
+ Handle<JSArray> array =
+ isolate()->factory()->NewJSArray(0, FAST_HOLEY_SMI_ELEMENTS);
+ isolate()->factory()->SetElementsCapacityAndLength(
+ array, values->length(), values->length());
// Fill in the literals.
Heap* heap = isolate()->heap();
bool is_simple = true;
int depth = 1;
+ bool is_holey = false;
for (int i = 0, n = values->length(); i < n; i++) {
MaterializedLiteral* m_literal = values->at(i)->AsMaterializedLiteral();
if (m_literal != NULL && m_literal->depth() + 1 > depth) {
@@ -3731,83 +3731,33 @@
}
Handle<Object> boilerplate_value = GetBoilerplateValue(values->at(i));
if (boilerplate_value->IsTheHole()) {
- has_hole_values = true;
- object_literals->set_the_hole(i);
- if (elements_kind == FAST_DOUBLE_ELEMENTS) {
- double_literals->set_the_hole(i);
- }
+ is_holey = true;
} else if (boilerplate_value->IsUndefined()) {
is_simple = false;
- object_literals->set(i, Smi::FromInt(0));
- if (elements_kind == FAST_DOUBLE_ELEMENTS) {
- double_literals->set(i, 0);
- }
+ JSObject::SetOwnElement(
+ array, i, handle(Smi::FromInt(0), isolate()), kNonStrictMode);
} else {
- // Examine each literal element, and adjust the ElementsKind if the
- // literal element is not of a type that can be stored in the current
- // ElementsKind. Start with FAST_SMI_ONLY_ELEMENTS, and transition to
- // FAST_DOUBLE_ELEMENTS and FAST_ELEMENTS as necessary. Always remember
- // the tagged value, no matter what the ElementsKind is in case we
- // ultimately end up in FAST_ELEMENTS.
- object_literals->set(i, *boilerplate_value);
- if (elements_kind == FAST_SMI_ELEMENTS) {
- // Smi only elements. Notice if a transition to FAST_DOUBLE_ELEMENTS or
- // FAST_ELEMENTS is required.
- if (!boilerplate_value->IsSmi()) {
- if (boilerplate_value->IsNumber() && FLAG_smi_only_arrays) {
- // Allocate a double array on the FAST_DOUBLE_ELEMENTS transition to
- // avoid over-allocating in TENURED space.
- double_literals = isolate()->factory()->NewFixedDoubleArray(
- values->length(), TENURED);
- // Copy the contents of the FAST_SMI_ONLY_ELEMENT array to the
- // FAST_DOUBLE_ELEMENTS array so that they are in sync.
- for (int j = 0; j < i; ++j) {
- Object* smi_value = object_literals->get(j);
- if (smi_value->IsTheHole()) {
- double_literals->set_the_hole(j);
- } else {
- double_literals->set(j, Smi::cast(smi_value)->value());
- }
- }
- double_literals->set(i, boilerplate_value->Number());
- elements_kind = FAST_DOUBLE_ELEMENTS;
- } else {
- elements_kind = FAST_ELEMENTS;
- }
- }
- } else if (elements_kind == FAST_DOUBLE_ELEMENTS) {
- // Continue to store double values in to FAST_DOUBLE_ELEMENTS arrays
- // until the first value is seen that can't be stored as a double.
- if (boilerplate_value->IsNumber()) {
- double_literals->set(i, boilerplate_value->Number());
- } else {
- elements_kind = FAST_ELEMENTS;
- }
- }
+ JSObject::SetOwnElement(array, i, boilerplate_value, kNonStrictMode);
}
}
+ Handle<FixedArrayBase> element_values(array->elements());
+
// Simple and shallow arrays can be lazily copied, we transform the
// elements array to a copy-on-write array.
if (is_simple && depth == 1 && values->length() > 0 &&
- elements_kind != FAST_DOUBLE_ELEMENTS) {
- object_literals->set_map(heap->fixed_cow_array_map());
+ array->HasFastSmiOrObjectElements()) {
+ element_values->set_map(heap->fixed_cow_array_map());
}
- Handle<FixedArrayBase> element_values = elements_kind == FAST_DOUBLE_ELEMENTS
- ? Handle<FixedArrayBase>(double_literals)
- : Handle<FixedArrayBase>(object_literals);
-
// Remember both the literal's constant values as well as the ElementsKind
// in a 2-element FixedArray.
- Handle<FixedArray> literals =
- isolate()->factory()->NewFixedArray(2, TENURED);
+ Handle<FixedArray> literals = isolate()->factory()->NewFixedArray(2, TENURED);
- if (has_hole_values || !FLAG_packed_arrays) {
- elements_kind = GetHoleyElementsKind(elements_kind);
- }
+ ElementsKind kind = array->GetElementsKind();
+ kind = is_holey ? GetHoleyElementsKind(kind) : GetPackedElementsKind(kind);
- literals->set(0, Smi::FromInt(elements_kind));
+ literals->set(0, Smi::FromInt(kind));
literals->set(1, *element_values);
return factory()->NewArrayLiteral(
diff --git a/src/parser.h b/src/parser.h
index 93fd1b8..0f85f91 100644
--- a/src/parser.h
+++ b/src/parser.h
@@ -96,7 +96,6 @@
private:
Vector<unsigned> backing_;
- bool owns_data_;
};
diff --git a/src/spaces.cc b/src/spaces.cc
index 0ac23d2..cacd969 100644
--- a/src/spaces.cc
+++ b/src/spaces.cc
@@ -2391,10 +2391,13 @@
HeapObject* PagedSpace::SlowAllocateRaw(int size_in_bytes) {
// Allocation in this space has failed.
- // If there are unswept pages advance lazy sweeper then sweep one page before
- // allocating a new page.
- if (first_unswept_page_->is_valid()) {
- AdvanceSweeper(size_in_bytes);
+ // If there are unswept pages advance lazy sweeper a bounded number of times
+ // until we find a size_in_bytes contiguous piece of memory
+ const int kMaxSweepingTries = 5;
+ bool sweeping_complete = false;
+
+ for (int i = 0; i < kMaxSweepingTries && !sweeping_complete; i++) {
+ sweeping_complete = AdvanceSweeper(size_in_bytes);
// Retry the free list allocation.
HeapObject* object = free_list_.Allocate(size_in_bytes);
diff --git a/src/spaces.h b/src/spaces.h
index 4fbabd6..56f629e 100644
--- a/src/spaces.h
+++ b/src/spaces.h
@@ -503,6 +503,12 @@
}
}
+ bool IsLeftOfProgressBar(Object** slot) {
+ Address slot_address = reinterpret_cast<Address>(slot);
+ ASSERT(slot_address > this->address());
+ return (slot_address - (this->address() + kObjectStartOffset)) <
+ progress_bar();
+ }
static void IncrementLiveBytesFromGC(Address address, int by) {
MemoryChunk::FromAddress(address)->IncrementLiveBytes(by);
@@ -2434,11 +2440,9 @@
FixedSpace(Heap* heap,
intptr_t max_capacity,
AllocationSpace id,
- int object_size_in_bytes,
- const char* name)
+ int object_size_in_bytes)
: PagedSpace(heap, max_capacity, id, NOT_EXECUTABLE),
- object_size_in_bytes_(object_size_in_bytes),
- name_(name) {
+ object_size_in_bytes_(object_size_in_bytes) {
page_extra_ = Page::kNonCodeObjectAreaSize % object_size_in_bytes;
}
@@ -2455,9 +2459,6 @@
private:
// The size of objects in this space.
int object_size_in_bytes_;
-
- // The name of this space.
- const char* name_;
};
@@ -2468,7 +2469,7 @@
public:
// Creates a map space object with a maximum capacity.
MapSpace(Heap* heap, intptr_t max_capacity, AllocationSpace id)
- : FixedSpace(heap, max_capacity, id, Map::kSize, "map"),
+ : FixedSpace(heap, max_capacity, id, Map::kSize),
max_map_space_pages_(kMaxMapPageIndex - 1) {
}
@@ -2509,7 +2510,7 @@
public:
// Creates a property cell space object with a maximum capacity.
CellSpace(Heap* heap, intptr_t max_capacity, AllocationSpace id)
- : FixedSpace(heap, max_capacity, id, JSGlobalPropertyCell::kSize, "cell")
+ : FixedSpace(heap, max_capacity, id, JSGlobalPropertyCell::kSize)
{}
virtual int RoundSizeDownToObjectAlignment(int size) {
diff --git a/src/store-buffer.h b/src/store-buffer.h
index 0ade8ce..79046d1 100644
--- a/src/store-buffer.h
+++ b/src/store-buffer.h
@@ -210,8 +210,7 @@
explicit StoreBufferRebuildScope(Heap* heap,
StoreBuffer* store_buffer,
StoreBufferCallback callback)
- : heap_(heap),
- store_buffer_(store_buffer),
+ : store_buffer_(store_buffer),
stored_state_(store_buffer->store_buffer_rebuilding_enabled_),
stored_callback_(store_buffer->callback_) {
store_buffer_->store_buffer_rebuilding_enabled_ = true;
@@ -226,7 +225,6 @@
}
private:
- Heap* heap_;
StoreBuffer* store_buffer_;
bool stored_state_;
StoreBufferCallback stored_callback_;
diff --git a/src/version.cc b/src/version.cc
index 1b7f5c8..bd75eeb 100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -34,8 +34,8 @@
// cannot be changed without changing the SCons build script.
#define MAJOR_VERSION 3
#define MINOR_VERSION 15
-#define BUILD_NUMBER 6
-#define PATCH_LEVEL 2
+#define BUILD_NUMBER 7
+#define PATCH_LEVEL 0
// Use 1 for candidates and 0 otherwise.
// (Boolean macro values are not supported by all preprocessors.)
#define IS_CANDIDATE_VERSION 0
diff --git a/src/vm-state-inl.h b/src/vm-state-inl.h
index 97febd0..bc48160 100644
--- a/src/vm-state-inl.h
+++ b/src/vm-state-inl.h
@@ -67,6 +67,10 @@
LOG(isolate, UncheckedStringEvent("From", StateToString(previous_tag_)));
}
+ if (FLAG_log_timer_events) {
+ LOG(isolate, ExternalSwitch(previous_tag_, tag));
+ }
+
isolate_->SetCurrentVMState(tag);
}
@@ -80,6 +84,10 @@
UncheckedStringEvent("To", StateToString(previous_tag_)));
}
+ if (FLAG_log_timer_events) {
+ LOG(isolate_, ExternalSwitch(isolate_->current_vm_state(), previous_tag_));
+ }
+
isolate_->SetCurrentVMState(previous_tag_);
}
diff --git a/src/x64/codegen-x64.cc b/src/x64/codegen-x64.cc
index e2471e6..67d1d90 100644
--- a/src/x64/codegen-x64.cc
+++ b/src/x64/codegen-x64.cc
@@ -681,28 +681,6 @@
}
-byte* Code::FindPlatformCodeAgeSequence() {
- byte* start = instruction_start();
- uint32_t young_length;
- byte* young_sequence = GetNoCodeAgeSequence(&young_length);
- if (!memcmp(start, young_sequence, young_length) ||
- *start == kCallOpcode) {
- return start;
- } else {
- byte* start_after_strict = NULL;
- if (kind() == FUNCTION) {
- start_after_strict = start + kSizeOfFullCodegenStrictModePrologue;
- } else {
- ASSERT(kind() == OPTIMIZED_FUNCTION);
- start_after_strict = start + kSizeOfOptimizedStrictModePrologue;
- }
- ASSERT(!memcmp(start_after_strict, young_sequence, young_length) ||
- *start_after_strict == kCallOpcode);
- return start_after_strict;
- }
-}
-
-
bool Code::IsYoungSequence(byte* sequence) {
uint32_t young_length;
byte* young_sequence = GetNoCodeAgeSequence(&young_length);
diff --git a/src/x64/codegen-x64.h b/src/x64/codegen-x64.h
index 73438d7..d444095 100644
--- a/src/x64/codegen-x64.h
+++ b/src/x64/codegen-x64.h
@@ -39,9 +39,6 @@
enum TypeofState { INSIDE_TYPEOF, NOT_INSIDE_TYPEOF };
-static const int kSizeOfFullCodegenStrictModePrologue = 14;
-static const int kSizeOfOptimizedStrictModePrologue = 14;
-
// -------------------------------------------------------------------------
// CodeGenerator
diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc
index 1e16c66..650337a 100644
--- a/src/x64/full-codegen-x64.cc
+++ b/src/x64/full-codegen-x64.cc
@@ -138,8 +138,6 @@
// function calls.
if (!info->is_classic_mode() || info->is_native()) {
Label ok;
- Label begin;
- __ bind(&begin);
__ testq(rcx, rcx);
__ j(zero, &ok, Label::kNear);
// +1 for return address.
@@ -147,8 +145,6 @@
__ LoadRoot(kScratchRegister, Heap::kUndefinedValueRootIndex);
__ movq(Operand(rsp, receiver_offset), kScratchRegister);
__ bind(&ok);
- ASSERT(!FLAG_age_code ||
- (kSizeOfFullCodegenStrictModePrologue == ok.pos() - begin.pos()));
}
// Open a frame scope to indicate that there is a frame on the stack. The
@@ -156,6 +152,7 @@
// the frame (that is done below).
FrameScope frame_scope(masm_, StackFrame::MANUAL);
+ info->set_prologue_offset(masm_->pc_offset());
__ push(rbp); // Caller's frame pointer.
__ movq(rbp, rsp);
__ push(rsi); // Callee's context.
diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc
index c430465..9217a94 100644
--- a/src/x64/lithium-codegen-x64.cc
+++ b/src/x64/lithium-codegen-x64.cc
@@ -133,8 +133,6 @@
// object). rcx is zero for method calls and non-zero for function
// calls.
if (!info_->is_classic_mode() || info_->is_native()) {
- Label begin;
- __ bind(&begin);
Label ok;
__ testq(rcx, rcx);
__ j(zero, &ok, Label::kNear);
@@ -143,10 +141,9 @@
__ LoadRoot(kScratchRegister, Heap::kUndefinedValueRootIndex);
__ movq(Operand(rsp, receiver_offset), kScratchRegister);
__ bind(&ok);
- ASSERT(!FLAG_age_code ||
- (kSizeOfOptimizedStrictModePrologue == ok.pos() - begin.pos()));
}
+ info()->set_prologue_offset(masm_->pc_offset());
__ push(rbp); // Caller's frame pointer.
__ movq(rbp, rsp);
__ push(rsi); // Callee's context.
diff --git a/src/x64/macro-assembler-x64.cc b/src/x64/macro-assembler-x64.cc
index 5b85a24..4e4f2c5 100644
--- a/src/x64/macro-assembler-x64.cc
+++ b/src/x64/macro-assembler-x64.cc
@@ -720,11 +720,28 @@
movq(prev_next_address_reg, Operand(base_reg, kNextOffset));
movq(prev_limit_reg, Operand(base_reg, kLimitOffset));
addl(Operand(base_reg, kLevelOffset), Immediate(1));
+
+ if (FLAG_log_timer_events) {
+ FrameScope frame(this, StackFrame::MANUAL);
+ PushSafepointRegisters();
+ PrepareCallCFunction(0);
+ CallCFunction(ExternalReference::log_enter_external_function(isolate()), 0);
+ PopSafepointRegisters();
+ }
+
// Call the api function!
movq(rax, reinterpret_cast<int64_t>(function_address),
RelocInfo::RUNTIME_ENTRY);
call(rax);
+ if (FLAG_log_timer_events) {
+ FrameScope frame(this, StackFrame::MANUAL);
+ PushSafepointRegisters();
+ PrepareCallCFunction(0);
+ CallCFunction(ExternalReference::log_leave_external_function(isolate()), 0);
+ PopSafepointRegisters();
+ }
+
#if defined(_WIN64) && !defined(__MINGW64__)
// rax keeps a pointer to v8::Handle, unpack it.
movq(rax, Operand(rax, 0));
diff --git a/src/x64/stub-cache-x64.cc b/src/x64/stub-cache-x64.cc
index cd0124b..683aa9d 100644
--- a/src/x64/stub-cache-x64.cc
+++ b/src/x64/stub-cache-x64.cc
@@ -4108,16 +4108,16 @@
__ Move(FieldOperand(rdi, FixedDoubleArray::kLengthOffset),
Smi::FromInt(JSArray::kPreallocatedArrayElements));
- __ movq(r8, BitCast<int64_t, uint64_t>(kHoleNanInt64), RelocInfo::NONE);
- for (int i = 1; i < JSArray::kPreallocatedArrayElements; i++) {
- __ movq(FieldOperand(rdi, FixedDoubleArray::OffsetOfElementAt(i)), r8);
- }
-
// Increment the length of the array.
__ SmiToInteger32(rcx, rcx);
__ StoreNumberToDoubleElements(rax, rdi, rcx, xmm0,
&restore_key_transition_elements_kind);
+ __ movq(r8, BitCast<int64_t, uint64_t>(kHoleNanInt64), RelocInfo::NONE);
+ for (int i = 1; i < JSArray::kPreallocatedArrayElements; i++) {
+ __ movq(FieldOperand(rdi, FixedDoubleArray::OffsetOfElementAt(i)), r8);
+ }
+
// Install the new backing store in the JSArray.
__ movq(FieldOperand(rdx, JSObject::kElementsOffset), rdi);
__ RecordWriteField(rdx, JSObject::kElementsOffset, rdi, rbx,
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
index a51d301..aa85e2a 100644
--- a/test/cctest/test-api.cc
+++ b/test/cctest/test-api.cc
@@ -626,6 +626,8 @@
THREADED_TEST(ScavengeExternalString) {
+ i::FLAG_stress_compaction = false;
+ i::FLAG_gc_global = false;
int dispose_count = 0;
bool in_new_space = false;
{
@@ -646,6 +648,8 @@
THREADED_TEST(ScavengeExternalAsciiString) {
+ i::FLAG_stress_compaction = false;
+ i::FLAG_gc_global = false;
int dispose_count = 0;
bool in_new_space = false;
{
@@ -2546,6 +2550,8 @@
// TODO(mstarzinger): This should be a THREADED_TEST but causes failures
// on the buildbots, so was made non-threaded for the time being.
TEST(ApiObjectGroupsCycleForScavenger) {
+ i::FLAG_stress_compaction = false;
+ i::FLAG_gc_global = false;
HandleScope scope;
LocalContext env;
@@ -17987,7 +17993,6 @@
private:
ThreadInterruptTest* test_;
- struct sigaction sa_;
};
i::Semaphore* sem_;
diff --git a/test/cctest/test-heap-profiler.cc b/test/cctest/test-heap-profiler.cc
index 5235971..eeb5a9d 100644
--- a/test/cctest/test-heap-profiler.cc
+++ b/test/cctest/test-heap-profiler.cc
@@ -1015,7 +1015,6 @@
private:
bool disposed_;
- int category_;
int hash_;
const char* group_label_;
const char* label_;
diff --git a/test/cctest/test-heap.cc b/test/cctest/test-heap.cc
index a51b37e..f5bac2c 100644
--- a/test/cctest/test-heap.cc
+++ b/test/cctest/test-heap.cc
@@ -1944,7 +1944,7 @@
if (!i::V8::UseCrankshaft() || i::FLAG_always_opt) return;
v8::HandleScope scope;
- FillUpNewSpace(HEAP->new_space());
+ SimulateFullSpace(HEAP->new_space());
AlwaysAllocateScope always_allocate;
v8::Local<v8::Value> res = CompileRun(
"function c(x) {"
@@ -2153,14 +2153,9 @@
// Generate a sliced string that is based on the above parent and
// lives in old-space.
- FillUpNewSpace(HEAP->new_space());
+ SimulateFullSpace(HEAP->new_space());
AlwaysAllocateScope always_allocate;
- Handle<String> t;
- // TODO(mstarzinger): Unfortunately FillUpNewSpace() still leaves
- // some slack, so we need to allocate a few sliced strings.
- for (int i = 0; i < 16; i++) {
- t = FACTORY->NewProperSubString(s, 5, 35);
- }
+ Handle<String> t = FACTORY->NewProperSubString(s, 5, 35);
CHECK(t->IsSlicedString());
CHECK(!HEAP->InNewSpace(*t));
*slice.location() = *t.location();
diff --git a/test/cctest/test-lockers.cc b/test/cctest/test-lockers.cc
index 5035f87..57f7178 100644
--- a/test/cctest/test-lockers.cc
+++ b/test/cctest/test-lockers.cc
@@ -59,9 +59,9 @@
class KangarooThread : public v8::internal::Thread {
public:
KangarooThread(v8::Isolate* isolate,
- v8::Handle<v8::Context> context, int value)
+ v8::Handle<v8::Context> context)
: Thread("KangarooThread"),
- isolate_(isolate), context_(context), value_(value) {
+ isolate_(isolate), context_(context) {
}
void Run() {
@@ -90,7 +90,6 @@
private:
v8::Isolate* isolate_;
Persistent<v8::Context> context_;
- int value_;
};
// Migrates an isolate from one thread to another
@@ -106,7 +105,7 @@
CHECK_EQ(isolate, v8::internal::Isolate::Current());
CompileRun("function getValue() { return 30; }");
}
- KangarooThread thread1(isolate, context, 1);
+ KangarooThread thread1(isolate, context);
thread1.Start();
thread1.Join();
}
diff --git a/test/cctest/test-log.cc b/test/cctest/test-log.cc
index 6f2324d..892a542 100644
--- a/test/cctest/test-log.cc
+++ b/test/cctest/test-log.cc
@@ -392,7 +392,7 @@
i::EmbeddedVector<char, 100> ref_data;
i::OS::SNPrintF(ref_data,
- "code-creation,Callback,0x%" V8PRIxPTR ",1,\"method1\"\0",
+ "code-creation,Callback,-3,0x%" V8PRIxPTR ",1,\"method1\"\0",
ObjMethod1);
CHECK_NE(NULL, StrNStr(log.start(), ref_data.start(), log.length()));
@@ -435,21 +435,21 @@
EmbeddedVector<char, 100> prop1_getter_record;
i::OS::SNPrintF(prop1_getter_record,
- "code-creation,Callback,0x%" V8PRIxPTR ",1,\"get prop1\"",
+ "code-creation,Callback,-3,0x%" V8PRIxPTR ",1,\"get prop1\"",
Prop1Getter);
CHECK_NE(NULL,
StrNStr(log.start(), prop1_getter_record.start(), log.length()));
EmbeddedVector<char, 100> prop1_setter_record;
i::OS::SNPrintF(prop1_setter_record,
- "code-creation,Callback,0x%" V8PRIxPTR ",1,\"set prop1\"",
+ "code-creation,Callback,-3,0x%" V8PRIxPTR ",1,\"set prop1\"",
Prop1Setter);
CHECK_NE(NULL,
StrNStr(log.start(), prop1_setter_record.start(), log.length()));
EmbeddedVector<char, 100> prop2_getter_record;
i::OS::SNPrintF(prop2_getter_record,
- "code-creation,Callback,0x%" V8PRIxPTR ",1,\"get prop2\"",
+ "code-creation,Callback,-3,0x%" V8PRIxPTR ",1,\"get prop2\"",
Prop2Getter);
CHECK_NE(NULL,
StrNStr(log.start(), prop2_getter_record.start(), log.length()));
diff --git a/test/cctest/test-mark-compact.cc b/test/cctest/test-mark-compact.cc
index c0ab763..69abd8d 100644
--- a/test/cctest/test-mark-compact.cc
+++ b/test/cctest/test-mark-compact.cc
@@ -311,6 +311,7 @@
}
TEST(ObjectGroups) {
+ FLAG_incremental_marking = false;
InitializeVM();
GlobalHandles* global_handles = Isolate::Current()->global_handles();
diff --git a/test/mjsunit/regress/regress-121407.js b/test/mjsunit/regress/regress-121407.js
index 25033fb..4403708 100644
--- a/test/mjsunit/regress/regress-121407.js
+++ b/test/mjsunit/regress/regress-121407.js
@@ -37,4 +37,4 @@
a.length=2000;
for (var i = 0; i <= 256; i++) {
a[i] = new Object();
-}
\ No newline at end of file
+}
diff --git a/test/mjsunit/regress/regress-2433.js b/test/mjsunit/regress/regress-2433.js
new file mode 100644
index 0000000..dfe7131
--- /dev/null
+++ b/test/mjsunit/regress/regress-2433.js
@@ -0,0 +1,36 @@
+// Copyright 2012 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:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Transitioning from a PackedSmi to PackedDouble should fill the destination
+// with holes.
+//
+// See http://code.google.com/p/v8/issues/detail?id=2433 for details.
+
+arr = [];
+arr[0] = 0;
+arr[0] = 1.1;
+assertEquals(undefined, arr[1]);
diff --git a/test/mjsunit/regress/regress-crbug-162085.js b/test/mjsunit/regress/regress-crbug-162085.js
index f26c711..a53b2c9 100644
--- a/test/mjsunit/regress/regress-crbug-162085.js
+++ b/test/mjsunit/regress/regress-crbug-162085.js
@@ -30,6 +30,7 @@
var a = [1,2,3];
a.length = 0;
a[0] = 1.4;
+assertEquals(1.4, a[0]);
assertEquals(undefined, a[1]);
assertEquals(undefined, a[2]);
assertEquals(undefined, a[3]);
@@ -43,6 +44,7 @@
grow_store(a2,1,1.4);
a2.length = 0;
grow_store(a2,0,1.5);
+assertEquals(1.5, a2[0]);
assertEquals(undefined, a2[1]);
assertEquals(undefined, a2[2]);
assertEquals(undefined, a2[3]);
@@ -53,3 +55,17 @@
grow_store(a3, 1, o);
assertEquals(1.3, a3[0]);
assertEquals(o, a3[1]);
+
+// Ensure the double array growstub initializes the array with holes.
+function grow_store2(a,i,v) {
+ a[i] = v;
+}
+
+var a4 = [1.3];
+grow_store2(a4,1,1.4);
+a4.length = 0;
+grow_store2(a4,0,1);
+assertEquals(1, a4[0]);
+assertEquals(undefined, a4[1]);
+assertEquals(undefined, a4[2]);
+assertEquals(undefined, a4[3]);
diff --git a/test/mjsunit/regress/regress-observe-empty-double-array.js b/test/mjsunit/regress/regress-observe-empty-double-array.js
new file mode 100644
index 0000000..aea9c73
--- /dev/null
+++ b/test/mjsunit/regress/regress-observe-empty-double-array.js
@@ -0,0 +1,37 @@
+// Copyright 2012 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:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived
+// from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// Flags: --harmony-observation --allow-natives-syntax
+//
+// Test passes if it does not crash.
+
+arr = [1.1];
+Object.observe(arr, function(){});
+arr.length = 0;
+assertTrue(%HasFastDoubleElements(arr));
+// Should not crash
+arr.push(1.1);
diff --git a/test/mjsunit/tools/tickprocessor-test-func-info.log b/test/mjsunit/tools/tickprocessor-test-func-info.log
index e4015d4..5e64dc0 100644
--- a/test/mjsunit/tools/tickprocessor-test-func-info.log
+++ b/test/mjsunit/tools/tickprocessor-test-func-info.log
@@ -2,10 +2,10 @@
shared-library,"/lib32/libm-2.7.so",0xf7db6000,0xf7dd9000
shared-library,"ffffe000-fffff000",0xffffe000,0xfffff000
profiler,"begin",1
-code-creation,Stub,0x424260,348,"CompareStub_GE"
-code-creation,LazyCompile,0x2a8100,18535,"DrawQube 3d-cube.js:188",0xf43abcac,
-code-creation,LazyCompile,0x480100,3908,"DrawLine 3d-cube.js:17",0xf43abc50,
-tick,0x424284,0xbfffeea0,0,0x480600,0,0x2aaaa5
-tick,0x42429f,0xbfffed88,0,0x480600,0,0x2aacb4
-tick,0x48063d,0xbfffec7c,0,0x2d0f7c,0,0x2aaec6
+code-creation,Stub,0,0x424260,348,"CompareStub_GE"
+code-creation,LazyCompile,0,0x2a8100,18535,"DrawQube 3d-cube.js:188",0xf43abcac,
+code-creation,LazyCompile,0,0x480100,3908,"DrawLine 3d-cube.js:17",0xf43abc50,
+tick,0x424284,0xbfffeea0,0,0,0x480600,0,0x2aaaa5
+tick,0x42429f,0xbfffed88,0,0,0x480600,0,0x2aacb4
+tick,0x48063d,0xbfffec7c,0,0,0x2d0f7c,0,0x2aaec6
profiler,"end"
diff --git a/test/mjsunit/tools/tickprocessor-test.log b/test/mjsunit/tools/tickprocessor-test.log
index db8be79..5ddad89 100644
--- a/test/mjsunit/tools/tickprocessor-test.log
+++ b/test/mjsunit/tools/tickprocessor-test.log
@@ -2,24 +2,24 @@
shared-library,"/lib32/libm-2.7.so",0xf7db6000,0xf7dd9000
shared-library,"ffffe000-fffff000",0xffffe000,0xfffff000
profiler,"begin",1
-code-creation,Stub,0xf540a100,474,"CEntryStub"
-code-creation,Script,0xf541cd80,736,"exp.js"
-code-creation,Stub,0xf541d0e0,47,"RuntimeStub_Math_exp"
-code-creation,LazyCompile,0xf541d120,145,"exp native math.js:41"
+code-creation,Stub,0,0xf540a100,474,"CEntryStub"
+code-creation,Script,0,0xf541cd80,736,"exp.js"
+code-creation,Stub,0,0xf541d0e0,47,"RuntimeStub_Math_exp"
+code-creation,LazyCompile,0,0xf541d120,145,"exp native math.js:41"
function-creation,0xf441d280,0xf541d120
-code-creation,LoadIC,0xf541d280,117,"j"
-code-creation,LoadIC,0xf541d360,63,"i"
-tick,0x80f82d1,0xffdfe880,0,0,0,0xf541ce5c
-tick,0x80f89a1,0xffdfecf0,0,0,0,0xf541ce5c
-tick,0x8123b5c,0xffdff1a0,0,0,0,0xf541d1a1,0xf541ceea
-tick,0x8123b65,0xffdff1a0,0,0,0,0xf541d1a1,0xf541ceea
-tick,0xf541d2be,0xffdff1e4,0,0,0
-tick,0xf541d320,0xffdff1dc,0,0,0
-tick,0xf541d384,0xffdff1d8,0,0,0
-tick,0xf7db94da,0xffdff0ec,0,0,0,0xf541d1a1,0xf541ceea
-tick,0xf7db951c,0xffdff0f0,0,0,0,0xf541d1a1,0xf541ceea
-tick,0xf7dbc508,0xffdff14c,0,0,0,0xf541d1a1,0xf541ceea
-tick,0xf7dbff21,0xffdff198,0,0,0,0xf541d1a1,0xf541ceea
-tick,0xf7edec90,0xffdff0ec,0,0,0,0xf541d1a1,0xf541ceea
-tick,0xffffe402,0xffdff488,0,0,0
+code-creation,LoadIC,0,0xf541d280,117,"j"
+code-creation,LoadIC,0,0xf541d360,63,"i"
+tick,0x80f82d1,0xffdfe880,0,0,0,0,0xf541ce5c
+tick,0x80f89a1,0xffdfecf0,0,0,0,0,0xf541ce5c
+tick,0x8123b5c,0xffdff1a0,0,0,0,0,0xf541d1a1,0xf541ceea
+tick,0x8123b65,0xffdff1a0,0,0,0,0,0xf541d1a1,0xf541ceea
+tick,0xf541d2be,0xffdff1e4,0,0,0,0
+tick,0xf541d320,0xffdff1dc,0,0,0,0
+tick,0xf541d384,0xffdff1d8,0,0,0,0
+tick,0xf7db94da,0xffdff0ec,0,0,0,0,0xf541d1a1,0xf541ceea
+tick,0xf7db951c,0xffdff0f0,0,0,0,0,0xf541d1a1,0xf541ceea
+tick,0xf7dbc508,0xffdff14c,0,0,0,0,0xf541d1a1,0xf541ceea
+tick,0xf7dbff21,0xffdff198,0,0,0,0,0xf541d1a1,0xf541ceea
+tick,0xf7edec90,0xffdff0ec,0,0,0,0,0xf541d1a1,0xf541ceea
+tick,0xffffe402,0xffdff488,0,0,0,0
profiler,"end"
diff --git a/tools/plot-timer-events b/tools/plot-timer-events
index 1db2c31..efa82bc 100755
--- a/tools/plot-timer-events
+++ b/tools/plot-timer-events
@@ -34,6 +34,7 @@
# nm spits out 'no symbols found' messages to stderr.
cat $log_file | $d8_exec $tools_path/csvparser.js \
+ $tools_path/splaytree.js $tools_path/codemap.js \
$tools_path/logreader.js $tools_path/plot-timer-events.js \
2>/dev/null | gnuplot > timer-events.png
diff --git a/tools/plot-timer-events.js b/tools/plot-timer-events.js
index 8ef0b8e..a41f080 100644
--- a/tools/plot-timer-events.js
+++ b/tools/plot-timer-events.js
@@ -25,50 +25,83 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-var kExecutionName = 'V8.Execute';
+var kV8BinarySuffixes = ["/d8", "/libv8.so"];
+var kStackFrames = 8;
-var TimerEvents = {
- 'V8.Execute':
- { ranges: [], color: "#444444", pause: false, index: 1 },
- 'V8.CompileFullCode':
- { ranges: [], color: "#CC0000", pause: true, index: 2 },
- 'V8.RecompileSynchronous':
- { ranges: [], color: "#CC0044", pause: true, index: 3 },
- 'V8.RecompileParallel':
- { ranges: [], color: "#CC4499", pause: false, index: 4 },
- 'V8.CompileEval':
- { ranges: [], color: "#CC4400", pause: true, index: 5 },
- 'V8.Parse':
- { ranges: [], color: "#00CC00", pause: true, index: 6 },
- 'V8.PreParse':
- { ranges: [], color: "#44CC00", pause: true, index: 7 },
- 'V8.ParseLazy':
- { ranges: [], color: "#00CC44", pause: true, index: 8 },
- 'V8.GCScavenger':
- { ranges: [], color: "#0044CC", pause: true, index: 9 },
- 'V8.GCCompactor':
- { ranges: [], color: "#4444CC", pause: true, index: 10 },
- 'V8.GCContext':
- { ranges: [], color: "#4400CC", pause: true, index: 11 },
-}
+var kTimerEventWidth = 0.33;
+var kExecutionFrameWidth = 0.2;
+var kStackFrameWidth = 0.1;
+var kGapWidth = 0.05;
-var kNumRows = 11;
-var kBarWidth = 0.33;
-var kPauseTolerance = 0.05; // Milliseconds.
-var kY1Offset = 3;
-var kY2Factor = 5;
+var kPauseTolerance = 0.1; // Milliseconds.
+var kY1Offset = 10;
+
var kResX = 1600;
-var kResY = 400;
-var kLabelPadding = 5;
+var kResY = 600;
+var kPauseLabelPadding = 5;
var kNumPauseLabels = 7;
+var kTickHalfDuration = 0.5; // Milliseconds
+var kCodeKindLabelPadding = 100;
var kOverrideRangeStart = undefined;
var kOverrideRangeEnd = undefined;
+var num_timer_event = kY1Offset + 0.5;
+
+
+function TimerEvent(color, pause, no_execution) {
+ this.color = color;
+ this.pause = pause;
+ this.ranges = [];
+ this.no_execution = no_execution;
+ this.index = ++num_timer_event;
+}
+
+
+var TimerEvents = {
+ 'V8.Execute': new TimerEvent("#000000", false, false),
+ 'V8.External': new TimerEvent("#3399FF", false, true),
+ 'V8.CompileFullCode': new TimerEvent("#CC0000", true, true),
+ 'V8.RecompileSynchronous': new TimerEvent("#CC0044", true, true),
+ 'V8.RecompileParallel': new TimerEvent("#CC4499", false, false),
+ 'V8.CompileEval': new TimerEvent("#CC4400", true, true),
+ 'V8.Parse': new TimerEvent("#00CC00", true, true),
+ 'V8.PreParse': new TimerEvent("#44CC00", true, true),
+ 'V8.ParseLazy': new TimerEvent("#00CC44", true, true),
+ 'V8.GCScavenger': new TimerEvent("#0044CC", true, true),
+ 'V8.GCCompactor': new TimerEvent("#4444CC", true, true),
+ 'V8.GCContext': new TimerEvent("#4400CC", true, true),
+}
+
+var kExecutionEvent = TimerEvents['V8.Execute'];
+
+
+function CodeKind(color, kinds) {
+ this.color = color;
+ this.in_execution = [];
+ this.stack_frames = [];
+ for (var i = 0; i < kStackFrames; i++) this.stack_frames.push([]);
+ this.kinds = kinds;
+}
+
+
+var CodeKinds = {
+ 'external ': new CodeKind("#3399FF", [-3]),
+ 'reg.exp. ': new CodeKind("#0000FF", [-2]),
+ 'runtime ': new CodeKind("#000000", [-1]),
+ 'full code': new CodeKind("#DD0000", [0]),
+ 'opt code ': new CodeKind("#00EE00", [1]),
+ 'code stub': new CodeKind("#FF00FF", [2]),
+ 'built-in ': new CodeKind("#AA00AA", [3]),
+ 'inl.cache': new CodeKind("#4444AA", [4, 5, 6, 7, 8, 9, 10, 11, 12, 13]),
+}
+
+
var xrange_start = Infinity;
var xrange_end = 0;
var obj_index = 0;
var execution_pauses = [];
+var code_map = new CodeMap();
function Range(start, end) {
@@ -88,19 +121,89 @@
length /= 1000;
var end = start + length;
event.ranges.push(new Range(start, end));
- if (name == kExecutionName) {
+ if (event == kExecutionEvent) {
if (start < xrange_start) xrange_start = start;
if (end > xrange_end) xrange_end = end;
}
}
+function ProcessCodeCreateEvent(type, kind, address, size, name) {
+ var code_entry = new CodeMap.CodeEntry(size, name);
+ code_entry.kind = kind;
+ code_map.addCode(address, code_entry);
+}
+
+
+function ProcessCodeMoveEvent(from, to) {
+ code_map.moveCode(from, to);
+}
+
+
+function ProcessCodeDeleteEvent(address) {
+ code_map.deleteCode(address);
+}
+
+
+function ProcessSharedLibrary(name, start, end) {
+ var code_entry = new CodeMap.CodeEntry(end - start, name);
+ code_entry.kind = -3; // External code kind.
+ for (var i = 0; i < kV8BinarySuffixes.length; i++) {
+ var suffix = kV8BinarySuffixes[i];
+ if (name.indexOf(suffix, name.length - suffix.length) >= 0) {
+ code_entry.kind = -1; // V8 runtime code kind.
+ break;
+ }
+ }
+ code_map.addLibrary(start, code_entry);
+}
+
+
+function FindCodeKind(kind) {
+ for (name in CodeKinds) {
+ if (CodeKinds[name].kinds.indexOf(kind) >= 0) {
+ return CodeKinds[name];
+ }
+ }
+}
+
+
+function ProcessTickEvent(pc, sp, timer, unused_x, unused_y, vmstate, stack) {
+ timer /= 1000;
+ var tick = new Range(timer - kTickHalfDuration, timer + kTickHalfDuration);
+
+ var entry = code_map.findEntry(pc);
+ if (entry) {
+ FindCodeKind(entry.kind).in_execution.push(tick);
+ }
+
+ for (var i = 0; i < kStackFrames; i++) {
+ if (!stack[i]) break;
+ var entry = code_map.findEntry(stack[i]);
+ if (entry) {
+ FindCodeKind(entry.kind).stack_frames[i].push(tick);
+ }
+ }
+}
+
+
function CollectData() {
// Collect data from log.
var logreader = new LogReader(
- { 'timer-event' : { parsers: [null, parseInt, parseInt],
- processor: ProcessTimerEvent
- } });
+ { 'timer-event' : { parsers: [null, parseInt, parseInt],
+ processor: ProcessTimerEvent },
+ 'shared-library': { parsers: [null, parseInt, parseInt],
+ processor: ProcessSharedLibrary },
+ 'code-creation': { parsers: [null, parseInt, parseInt, parseInt, null],
+ processor: ProcessCodeCreateEvent },
+ 'code-move': { parsers: [parseInt, parseInt],
+ processor: ProcessCodeMoveEvent },
+ 'code-delete': { parsers: [parseInt],
+ processor: ProcessCodeDeleteEvent },
+ 'tick': { parsers: [parseInt, parseInt, parseInt,
+ null, null, parseInt, 'var-args'],
+ processor: ProcessTickEvent },
+ });
var line;
while (line = readline()) {
@@ -112,25 +215,42 @@
var event = TimerEvents[name];
if (!event.pause) continue;
var ranges = event.ranges;
+ for (var j = 0; j < ranges.length; j++) execution_pauses.push(ranges[j]);
+ }
+ execution_pauses = MergeRanges(execution_pauses);
+
+ // Knock out time not spent in javascript execution. Note that this also
+ // includes time spent external code, which do not contribute to execution
+ // pauses.
+ var exclude_ranges = [];
+ for (name in TimerEvents) {
+ var event = TimerEvents[name];
+ if (!event.no_execution) continue;
+ var ranges = event.ranges;
// Add ranges of this event to the pause list.
for (var j = 0; j < ranges.length; j++) {
- execution_pauses.push(ranges[j]);
+ exclude_ranges.push(ranges[j]);
}
}
+
+ kExecutionEvent.ranges = MergeRanges(kExecutionEvent.ranges);
+ exclude_ranges = MergeRanges(exclude_ranges);
+ kExecutionEvent.ranges = ExcludeRanges(kExecutionEvent.ranges,
+ exclude_ranges);
}
-function drawBar(row, color, start, end) {
+function DrawBar(row, color, start, end, width) {
obj_index++;
command = "set object " + obj_index + " rect";
- command += " from " + start + ", " + (row - kBarWidth + kY1Offset);
- command += " to " + end + ", " + (row + kBarWidth + kY1Offset);
+ command += " from " + start + ", " + (row - width);
+ command += " to " + end + ", " + (row + width);
command += " fc rgb \"" + color + "\"";
print(command);
}
-function MergeRanges(ranges, merge_tolerance) {
+function MergeRanges(ranges) {
ranges.sort(function(a, b) { return a.start - b.start; });
var result = [];
var j = 0;
@@ -141,7 +261,7 @@
for (j = i + 1; j < ranges.length; j++) {
var next_range = ranges[j];
// Don't merge ranges if there is no overlap (including merge tolerance).
- if (next_range.start >= merge_end + kPauseTolerance) break;
+ if (next_range.start > merge_end + kPauseTolerance) break;
// Merge ranges.
if (next_range.end > merge_end) { // Extend range end.
merge_end = next_range.end;
@@ -239,10 +359,9 @@
function GnuplotOutput() {
xrange_start = kOverrideRangeStart ? kOverrideRangeStart : xrange_start;
xrange_end = kOverrideRangeEnd ? kOverrideRangeEnd : xrange_end;
-
print("set terminal pngcairo size " + kResX + "," + kResY +
" enhanced font 'Helvetica,10'");
- print("set yrange [0:" + (kNumRows + kY1Offset + 1) + "]");
+ print("set yrange [0:" + (num_timer_event + 1) + "]");
print("set xlabel \"execution time in ms\"");
print("set xrange [" + xrange_start + ":" + xrange_end + "]");
print("set style fill pattern 2 bo 1");
@@ -255,57 +374,71 @@
var ytics = [];
for (name in TimerEvents) {
var index = TimerEvents[name].index;
- ytics.push('"' + name + '"' + ' ' + (index + kY1Offset));
+ ytics.push('"' + name + '"' + ' ' + index);
}
+ ytics.push('"code kind being executed"' + ' ' + (kY1Offset - 1));
+ ytics.push('"top ' + kStackFrames + ' js stack frames"' + ' ' +
+ (kY1Offset - 2));
+ ytics.push('"pause times" 0');
print("set ytics out nomirror (" + ytics.join(', ') + ")");
- // Smallest visible gap given our resolution.
- // We remove superfluous objects to go easy on Gnuplot.
- var tolerance = (xrange_end - xrange_start) / kResX / 2;
-
- // Sort, merge and remove invisible gaps for each time row.
- for (var name in TimerEvents) {
- var event = TimerEvents[name];
- event.ranges = MergeRanges(event.ranges, tolerance);
- }
-
- // Knock out execution pauses.
- var execution_event = TimerEvents[kExecutionName];
- var exclude_ranges = MergeRanges(execution_pauses, tolerance);
- execution_event.ranges = ExcludeRanges(execution_event.ranges,
- exclude_ranges);
- execution_event.ranges = MergeRanges(execution_event.ranges, tolerance);
-
// Plot timeline.
for (var name in TimerEvents) {
var event = TimerEvents[name];
- var ranges = event.ranges;
+ var ranges = MergeRanges(event.ranges);
for (var i = 0; i < ranges.length; i++) {
- drawBar(event.index, event.color, ranges[i].start, ranges[i].end);
+ DrawBar(event.index, event.color,
+ ranges[i].start, ranges[i].end,
+ kTimerEventWidth);
}
}
+ // Plot code kind gathered from ticks.
+ for (var name in CodeKinds) {
+ var code_kind = CodeKinds[name];
+ var offset = kY1Offset - 1;
+ // Top most frame.
+ var row = MergeRanges(code_kind.in_execution);
+ for (var j = 0; j < row.length; j++) {
+ DrawBar(offset, code_kind.color,
+ row[j].start, row[j].end, kExecutionFrameWidth);
+ }
+ offset = offset - 2 * kExecutionFrameWidth - kGapWidth;
+ // Javascript frames.
+ for (var i = 0; i < kStackFrames; i++) {
+ offset = offset - 2 * kStackFrameWidth - kGapWidth;
+ row = MergeRanges(code_kind.stack_frames[i]);
+ for (var j = 0; j < row.length; j++) {
+ DrawBar(offset, code_kind.color,
+ row[j].start, row[j].end, kStackFrameWidth);
+ }
+ }
+ }
+
+ // Add labels as legend for code kind colors.
+ var padding = kCodeKindLabelPadding * (xrange_end - xrange_start) / kResX;
+ var label_x = xrange_start;
+ var label_y = kY1Offset;
+ for (var name in CodeKinds) {
+ label_x += padding;
+ print("set label \"" + name + "\" at " + label_x + "," + label_y +
+ " textcolor rgb \"" + CodeKinds[name].color + "\"" +
+ " font \"Helvetica,9'\"");
+ }
+
if (execution_pauses.length == 0) {
// Force plot and return without plotting execution pause impulses.
print("plot 1/0");
return;
}
- // Plot execution pauses as impulses. This may be better resolved
- // due to possibly smaller merge tolerance.
- if (tolerance > kPauseTolerance) {
- execution_pauses = MergeRanges(execution_pauses, kPauseTolerance);
- } else {
- execution_pauses = exclude_ranges;
- }
-
// Label the longest pauses.
execution_pauses.sort(
function(a, b) { return b.duration() - a.duration(); });
var max_pause_time = execution_pauses[0].duration();
- var padding = kLabelPadding * (xrange_end - xrange_start) / kResX;
- var y_scale = kY1Offset / max_pause_time;
+ padding = kPauseLabelPadding * (xrange_end - xrange_start) / kResX;
+ var y_scale = kY1Offset / max_pause_time / 2;
for (var i = 0; i < execution_pauses.length && i < kNumPauseLabels; i++) {
var pause = execution_pauses[i];
var label_content = (pause.duration() | 0) + " ms";
@@ -316,8 +449,8 @@
}
// Scale second Y-axis appropriately.
- print("set y2range [0:" + (max_pause_time * kY2Factor) + "]");
-
+ var y2range = max_pause_time * num_timer_event / kY1Offset * 2;
+ print("set y2range [0:" + y2range + "]");
// Plot graph with impulses as data set.
print("plot '-' using 1:2 axes x1y2 with impulses ls 1");
for (var i = 0; i < execution_pauses.length; i++) {
diff --git a/tools/tickprocessor.js b/tools/tickprocessor.js
index 78f4cee..7530c6b 100644
--- a/tools/tickprocessor.js
+++ b/tools/tickprocessor.js
@@ -73,7 +73,7 @@
function SnapshotLogProcessor() {
LogReader.call(this, {
'code-creation': {
- parsers: [null, parseInt, parseInt, null, 'var-args'],
+ parsers: [null, parseInt, parseInt, parseInt, null, 'var-args'],
processor: this.processCodeCreation },
'code-move': { parsers: [parseInt, parseInt],
processor: this.processCodeMove },
@@ -107,7 +107,7 @@
SnapshotLogProcessor.prototype.processCodeCreation = function(
- type, start, size, name, maybe_func) {
+ type, kind, start, size, name, maybe_func) {
if (maybe_func.length) {
var funcAddr = parseInt(maybe_func[0]);
var state = parseState(maybe_func[1]);
@@ -156,7 +156,7 @@
'shared-library': { parsers: [null, parseInt, parseInt],
processor: this.processSharedLibrary },
'code-creation': {
- parsers: [null, parseInt, parseInt, null, 'var-args'],
+ parsers: [null, parseInt, parseInt, parseInt, null, 'var-args'],
processor: this.processCodeCreation },
'code-move': { parsers: [parseInt, parseInt],
processor: this.processCodeMove },
@@ -167,7 +167,7 @@
'snapshot-pos': { parsers: [parseInt, parseInt],
processor: this.processSnapshotPosition },
'tick': {
- parsers: [parseInt, parseInt, parseInt,
+ parsers: [parseInt, parseInt, parseInt, parseInt,
parseInt, parseInt, 'var-args'],
processor: this.processTick },
'heap-sample-begin': { parsers: [null, null, parseInt],
@@ -309,7 +309,7 @@
TickProcessor.prototype.processCodeCreation = function(
- type, start, size, name, maybe_func) {
+ type, kind, start, size, name, maybe_func) {
name = this.deserializedEntriesNames_[start] || name;
if (maybe_func.length) {
var funcAddr = parseInt(maybe_func[0]);
@@ -350,6 +350,7 @@
TickProcessor.prototype.processTick = function(pc,
sp,
+ ns_since_start,
is_external_callback,
tos_or_external_callback,
vmState,