Version 3.2.4.
Added isolates which allows several V8 instances in the same process. This is controlled through the new Isolate class in the API.
Implemented more of EcmaScript 5 strict mode.
Reduced the time it takes to make detailed heap snapshot.
Added a number of commands to the ARM simulator and enhanced the ARM disassembler.
git-svn-id: http://v8.googlecode.com/svn/trunk@7322 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/runtime-profiler.cc b/src/runtime-profiler.cc
index df6471e..98dc00b 100644
--- a/src/runtime-profiler.cc
+++ b/src/runtime-profiler.cc
@@ -36,8 +36,8 @@
#include "execution.h"
#include "global-handles.h"
#include "mark-compact.h"
+#include "platform.h"
#include "scopeinfo.h"
-#include "top.h"
namespace v8 {
namespace internal {
@@ -69,16 +69,9 @@
};
-enum SamplerState {
- IN_NON_JS_STATE = 0,
- IN_JS_STATE = 1
-};
-
-
// Optimization sampler constants.
static const int kSamplerFrameCount = 2;
static const int kSamplerFrameWeight[kSamplerFrameCount] = { 2, 1 };
-static const int kSamplerWindowSize = 16;
static const int kSamplerTicksBetweenThresholdAdjustment = 32;
@@ -92,34 +85,19 @@
static const int kSizeLimit = 1500;
-static int sampler_threshold = kSamplerThresholdInit;
-static int sampler_threshold_size_factor = kSamplerThresholdSizeFactorInit;
-
-static int sampler_ticks_until_threshold_adjustment =
- kSamplerTicksBetweenThresholdAdjustment;
-
-// The ratio of ticks spent in JS code in percent.
-static Atomic32 js_ratio;
-
-static Object* sampler_window[kSamplerWindowSize] = { NULL, };
-static int sampler_window_position = 0;
-static int sampler_window_weight[kSamplerWindowSize] = { 0, };
-
-
-// Support for pending 'optimize soon' requests.
-static PendingListNode* optimize_soon_list = NULL;
-
PendingListNode::PendingListNode(JSFunction* function) : next_(NULL) {
- function_ = GlobalHandles::Create(function);
+ GlobalHandles* global_handles = Isolate::Current()->global_handles();
+ function_ = global_handles->Create(function);
start_ = OS::Ticks();
- GlobalHandles::MakeWeak(function_.location(), this, &WeakCallback);
+ global_handles->MakeWeak(function_.location(), this, &WeakCallback);
}
void PendingListNode::Destroy() {
if (!IsValid()) return;
- GlobalHandles::Destroy(function_.location());
+ GlobalHandles* global_handles = Isolate::Current()->global_handles();
+ global_handles->Destroy(function_.location());
function_= Handle<Object>::null();
}
@@ -135,7 +113,37 @@
}
-static void Optimize(JSFunction* function, bool eager, int delay) {
+Atomic32 RuntimeProfiler::state_ = 0;
+// TODO(isolates): Create the semaphore lazily and clean it up when no
+// longer required.
+#ifdef ENABLE_LOGGING_AND_PROFILING
+Semaphore* RuntimeProfiler::semaphore_ = OS::CreateSemaphore(0);
+#endif
+
+
+RuntimeProfiler::RuntimeProfiler(Isolate* isolate)
+ : isolate_(isolate),
+ sampler_threshold_(kSamplerThresholdInit),
+ sampler_threshold_size_factor_(kSamplerThresholdSizeFactorInit),
+ sampler_ticks_until_threshold_adjustment_(
+ kSamplerTicksBetweenThresholdAdjustment),
+ js_ratio_(0),
+ sampler_window_position_(0),
+ optimize_soon_list_(NULL),
+ state_window_position_(0) {
+ state_counts_[0] = kStateWindowSize;
+ state_counts_[1] = 0;
+ memset(state_window_, 0, sizeof(state_window_));
+ ClearSampleBuffer();
+}
+
+
+bool RuntimeProfiler::IsEnabled() {
+ return V8::UseCrankshaft() && FLAG_opt;
+}
+
+
+void RuntimeProfiler::Optimize(JSFunction* function, bool eager, int delay) {
ASSERT(IsOptimizable(function));
if (FLAG_trace_opt) {
PrintF("[marking (%s) ", eager ? "eagerly" : "lazily");
@@ -152,11 +160,13 @@
}
-static void AttemptOnStackReplacement(JSFunction* function) {
+void RuntimeProfiler::AttemptOnStackReplacement(JSFunction* function) {
// See AlwaysFullCompiler (in compiler.cc) comment on why we need
// Debug::has_break_points().
ASSERT(function->IsMarkedForLazyRecompilation());
- if (!FLAG_use_osr || Debug::has_break_points() || function->IsBuiltin()) {
+ if (!FLAG_use_osr ||
+ isolate_->debug()->has_break_points() ||
+ function->IsBuiltin()) {
return;
}
@@ -186,7 +196,8 @@
Object* check_code;
MaybeObject* maybe_check_code = check_stub.TryGetCode();
if (maybe_check_code->ToObject(&check_code)) {
- Code* replacement_code = Builtins::builtin(Builtins::OnStackReplacement);
+ Code* replacement_code =
+ isolate_->builtins()->builtin(Builtins::OnStackReplacement);
Code* unoptimized_code = shared->code();
Deoptimizer::PatchStackCheckCode(unoptimized_code,
Code::cast(check_code),
@@ -195,21 +206,19 @@
}
-static void ClearSampleBuffer() {
- for (int i = 0; i < kSamplerWindowSize; i++) {
- sampler_window[i] = NULL;
- sampler_window_weight[i] = 0;
- }
+void RuntimeProfiler::ClearSampleBuffer() {
+ memset(sampler_window_, 0, sizeof(sampler_window_));
+ memset(sampler_window_weight_, 0, sizeof(sampler_window_weight_));
}
-static int LookupSample(JSFunction* function) {
+int RuntimeProfiler::LookupSample(JSFunction* function) {
int weight = 0;
for (int i = 0; i < kSamplerWindowSize; i++) {
- Object* sample = sampler_window[i];
+ Object* sample = sampler_window_[i];
if (sample != NULL) {
if (function == sample) {
- weight += sampler_window_weight[i];
+ weight += sampler_window_weight_[i];
}
}
}
@@ -217,18 +226,18 @@
}
-static void AddSample(JSFunction* function, int weight) {
+void RuntimeProfiler::AddSample(JSFunction* function, int weight) {
ASSERT(IsPowerOf2(kSamplerWindowSize));
- sampler_window[sampler_window_position] = function;
- sampler_window_weight[sampler_window_position] = weight;
- sampler_window_position = (sampler_window_position + 1) &
+ sampler_window_[sampler_window_position_] = function;
+ sampler_window_weight_[sampler_window_position_] = weight;
+ sampler_window_position_ = (sampler_window_position_ + 1) &
(kSamplerWindowSize - 1);
}
void RuntimeProfiler::OptimizeNow() {
- HandleScope scope;
- PendingListNode* current = optimize_soon_list;
+ HandleScope scope(isolate_);
+ PendingListNode* current = optimize_soon_list_;
while (current != NULL) {
PendingListNode* next = current->next();
if (current->IsValid()) {
@@ -241,7 +250,7 @@
delete current;
current = next;
}
- optimize_soon_list = NULL;
+ optimize_soon_list_ = NULL;
// Run through the JavaScript frames and collect them. If we already
// have a sample of the function, we mark it for optimizations
@@ -257,14 +266,14 @@
// Adjust threshold each time we have processed
// a certain number of ticks.
- if (sampler_ticks_until_threshold_adjustment > 0) {
- sampler_ticks_until_threshold_adjustment--;
- if (sampler_ticks_until_threshold_adjustment <= 0) {
+ if (sampler_ticks_until_threshold_adjustment_ > 0) {
+ sampler_ticks_until_threshold_adjustment_--;
+ if (sampler_ticks_until_threshold_adjustment_ <= 0) {
// If the threshold is not already at the minimum
// modify and reset the ticks until next adjustment.
- if (sampler_threshold > kSamplerThresholdMin) {
- sampler_threshold -= kSamplerThresholdDelta;
- sampler_ticks_until_threshold_adjustment =
+ if (sampler_threshold_ > kSamplerThresholdMin) {
+ sampler_threshold_ -= kSamplerThresholdDelta;
+ sampler_ticks_until_threshold_adjustment_ =
kSamplerTicksBetweenThresholdAdjustment;
}
}
@@ -284,11 +293,11 @@
int function_size = function->shared()->SourceSize();
int threshold_size_factor = (function_size > kSizeLimit)
- ? sampler_threshold_size_factor
+ ? sampler_threshold_size_factor_
: 1;
- int threshold = sampler_threshold * threshold_size_factor;
- int current_js_ratio = NoBarrier_Load(&js_ratio);
+ int threshold = sampler_threshold_ * threshold_size_factor;
+ int current_js_ratio = NoBarrier_Load(&js_ratio_);
// Adjust threshold depending on the ratio of time spent
// in JS code.
@@ -304,7 +313,8 @@
if (LookupSample(function) >= threshold) {
Optimize(function, false, 0);
- CompilationCache::MarkForEagerOptimizing(Handle<JSFunction>(function));
+ isolate_->compilation_cache()->MarkForEagerOptimizing(
+ Handle<JSFunction>(function));
}
}
@@ -320,26 +330,21 @@
void RuntimeProfiler::OptimizeSoon(JSFunction* function) {
if (!IsOptimizable(function)) return;
PendingListNode* node = new PendingListNode(function);
- node->set_next(optimize_soon_list);
- optimize_soon_list = node;
+ node->set_next(optimize_soon_list_);
+ optimize_soon_list_ = node;
}
#ifdef ENABLE_LOGGING_AND_PROFILING
-static void UpdateStateRatio(SamplerState current_state) {
- static const int kStateWindowSize = 128;
- static SamplerState state_window[kStateWindowSize];
- static int state_window_position = 0;
- static int state_counts[2] = { kStateWindowSize, 0 };
-
- SamplerState old_state = state_window[state_window_position];
- state_counts[old_state]--;
- state_window[state_window_position] = current_state;
- state_counts[current_state]++;
+void RuntimeProfiler::UpdateStateRatio(SamplerState current_state) {
+ SamplerState old_state = state_window_[state_window_position_];
+ state_counts_[old_state]--;
+ state_window_[state_window_position_] = current_state;
+ state_counts_[current_state]++;
ASSERT(IsPowerOf2(kStateWindowSize));
- state_window_position = (state_window_position + 1) &
+ state_window_position_ = (state_window_position_ + 1) &
(kStateWindowSize - 1);
- NoBarrier_Store(&js_ratio, state_counts[IN_JS_STATE] * 100 /
+ NoBarrier_Store(&js_ratio_, state_counts_[IN_JS_STATE] * 100 /
kStateWindowSize);
}
#endif
@@ -348,11 +353,11 @@
void RuntimeProfiler::NotifyTick() {
#ifdef ENABLE_LOGGING_AND_PROFILING
// Record state sample.
- SamplerState state = Top::IsInJSState()
+ SamplerState state = IsSomeIsolateInJS()
? IN_JS_STATE
: IN_NON_JS_STATE;
UpdateStateRatio(state);
- StackGuard::RequestRuntimeProfilerTick();
+ isolate_->stack_guard()->RequestRuntimeProfilerTick();
#endif
}
@@ -361,15 +366,15 @@
ClearSampleBuffer();
// If the ticker hasn't already started, make sure to do so to get
// the ticks for the runtime profiler.
- if (IsEnabled()) Logger::EnsureTickerStarted();
+ if (IsEnabled()) isolate_->logger()->EnsureTickerStarted();
}
void RuntimeProfiler::Reset() {
- sampler_threshold = kSamplerThresholdInit;
- sampler_ticks_until_threshold_adjustment =
+ sampler_threshold_ = kSamplerThresholdInit;
+ sampler_threshold_size_factor_ = kSamplerThresholdSizeFactorInit;
+ sampler_ticks_until_threshold_adjustment_ =
kSamplerTicksBetweenThresholdAdjustment;
- sampler_threshold_size_factor = kSamplerThresholdSizeFactorInit;
}
@@ -386,24 +391,61 @@
// Update the pointers in the sampler window after a GC.
void RuntimeProfiler::UpdateSamplesAfterScavenge() {
for (int i = 0; i < kSamplerWindowSize; i++) {
- Object* function = sampler_window[i];
- if (function != NULL && Heap::InNewSpace(function)) {
+ Object* function = sampler_window_[i];
+ if (function != NULL && isolate_->heap()->InNewSpace(function)) {
MapWord map_word = HeapObject::cast(function)->map_word();
if (map_word.IsForwardingAddress()) {
- sampler_window[i] = map_word.ToForwardingAddress();
+ sampler_window_[i] = map_word.ToForwardingAddress();
} else {
- sampler_window[i] = NULL;
+ sampler_window_[i] = NULL;
}
}
}
}
+void RuntimeProfiler::HandleWakeUp(Isolate* isolate) {
+#ifdef ENABLE_LOGGING_AND_PROFILING
+ // The profiler thread must still be waiting.
+ ASSERT(NoBarrier_Load(&state_) >= 0);
+ // In IsolateEnteredJS we have already incremented the counter and
+ // undid the decrement done by the profiler thread. Increment again
+ // to get the right count of active isolates.
+ NoBarrier_AtomicIncrement(&state_, 1);
+ semaphore_->Signal();
+ isolate->ResetEagerOptimizingData();
+#endif
+}
+
+
+bool RuntimeProfiler::IsSomeIsolateInJS() {
+ return NoBarrier_Load(&state_) > 0;
+}
+
+
+bool RuntimeProfiler::WaitForSomeIsolateToEnterJS() {
+#ifdef ENABLE_LOGGING_AND_PROFILING
+ Atomic32 old_state = NoBarrier_CompareAndSwap(&state_, 0, -1);
+ ASSERT(old_state >= -1);
+ if (old_state != 0) return false;
+ semaphore_->Wait();
+#endif
+ return true;
+}
+
+
+void RuntimeProfiler::WakeUpRuntimeProfilerThreadBeforeShutdown() {
+#ifdef ENABLE_LOGGING_AND_PROFILING
+ semaphore_->Signal();
+#endif
+}
+
+
void RuntimeProfiler::RemoveDeadSamples() {
for (int i = 0; i < kSamplerWindowSize; i++) {
- Object* function = sampler_window[i];
+ Object* function = sampler_window_[i];
if (function != NULL && !HeapObject::cast(function)->IsMarked()) {
- sampler_window[i] = NULL;
+ sampler_window_[i] = NULL;
}
}
}
@@ -411,7 +453,7 @@
void RuntimeProfiler::UpdateSamplesAfterCompact(ObjectVisitor* visitor) {
for (int i = 0; i < kSamplerWindowSize; i++) {
- visitor->VisitPointer(&sampler_window[i]);
+ visitor->VisitPointer(&sampler_window_[i]);
}
}
@@ -419,20 +461,13 @@
bool RuntimeProfilerRateLimiter::SuspendIfNecessary() {
#ifdef ENABLE_LOGGING_AND_PROFILING
static const int kNonJSTicksThreshold = 100;
- // We suspend the runtime profiler thread when not running
- // JavaScript. If the CPU profiler is active we must not do this
- // because it samples both JavaScript and C++ code.
- if (RuntimeProfiler::IsEnabled() &&
- !CpuProfiler::is_profiling() &&
- !(FLAG_prof && FLAG_prof_auto)) {
- if (Top::IsInJSState()) {
- non_js_ticks_ = 0;
+ if (RuntimeProfiler::IsSomeIsolateInJS()) {
+ non_js_ticks_ = 0;
+ } else {
+ if (non_js_ticks_ < kNonJSTicksThreshold) {
+ ++non_js_ticks_;
} else {
- if (non_js_ticks_ < kNonJSTicksThreshold) {
- ++non_js_ticks_;
- } else {
- if (Top::WaitForJSState()) return true;
- }
+ return RuntimeProfiler::WaitForSomeIsolateToEnterJS();
}
}
#endif