blob: 927603d9b3cfacc09fabcdc965f24dbd6c091a97 [file] [log] [blame]
// Copyright 2018 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "cobalt/script/v8c/v8c_heap_tracer.h"
#include <algorithm>
#include "base/debug/trace_event.h"
#include "cobalt/script/v8c/v8c_engine.h"
#include "cobalt/script/v8c/v8c_global_environment.h"
#include "cobalt/script/v8c/wrapper_private.h"
namespace cobalt {
namespace script {
namespace v8c {
void V8cHeapTracer::RegisterV8References(
const std::vector<std::pair<void*, void*>>& embedder_fields) {
for (const auto& embedder_field : embedder_fields) {
WrapperPrivate* wrapper_private =
static_cast<WrapperPrivate*>(embedder_field.first);
Wrappable* wrappable = wrapper_private->raw_wrappable();
MaybeAddToFrontier(wrappable);
// We expect this field to always be null, since we only have it as a
// workaround for V8. See "wrapper_private.h" for details.
DCHECK(embedder_field.second == nullptr);
}
}
void V8cHeapTracer::TracePrologue() {
TRACE_EVENT0("cobalt::script", "V8cHeapTracer::TracePrologue");
DCHECK_EQ(frontier_.size(), 0);
DCHECK_EQ(visited_.size(), 0);
// This feels a bit weird, but as far as I can tell, we're expected to
// manually decide to trace the from the global object.
MaybeAddToFrontier(
V8cGlobalEnvironment::GetFromIsolate(isolate_)->global_wrappable());
}
bool V8cHeapTracer::AdvanceTracing(double deadline_in_ms,
AdvanceTracingActions actions) {
TRACE_EVENT0("cobalt::script", "V8cHeapTracer::AdvanceTracing");
while (actions.force_completion ==
v8::EmbedderHeapTracer::ForceCompletionAction::FORCE_COMPLETION ||
platform_->MonotonicallyIncreasingTime() < deadline_in_ms) {
if (frontier_.empty()) {
return false;
}
Traceable* traceable = frontier_.back();
frontier_.pop_back();
if (traceable->IsWrappable()) {
Wrappable* wrappable = base::polymorphic_downcast<Wrappable*>(traceable);
auto pair_range = reference_map_.equal_range(wrappable);
for (auto it = pair_range.first; it != pair_range.second; ++it) {
it->second->Get().RegisterExternalReference(isolate_);
}
WrapperFactory* wrapper_factory =
V8cGlobalEnvironment::GetFromIsolate(isolate_)->wrapper_factory();
WrapperPrivate* maybe_wrapper_private =
wrapper_factory->MaybeGetWrapperPrivate(
static_cast<Wrappable*>(traceable));
if (maybe_wrapper_private) {
maybe_wrapper_private->Mark();
}
}
traceable->TraceMembers(this);
}
return true;
}
void V8cHeapTracer::TraceEpilogue() {
TRACE_EVENT0("cobalt::script", "V8cHeapTracer::TraceEpilogue");
DCHECK(frontier_.empty());
visited_.clear();
}
void V8cHeapTracer::EnterFinalPause() {
TRACE_EVENT0("cobalt::script", "V8cHeapTracer::EnterFinalPause");
}
void V8cHeapTracer::AbortTracing() {
TRACE_EVENT0("cobalt::script", "V8cHeapTracer::AbortTracing");
LOG(WARNING) << "Tracing aborted.";
frontier_.clear();
visited_.clear();
}
size_t V8cHeapTracer::NumberOfWrappersToTrace() { return frontier_.size(); }
void V8cHeapTracer::Trace(Traceable* traceable) {
if (!traceable) {
return;
}
MaybeAddToFrontier(traceable);
}
void V8cHeapTracer::AddReferencedObject(Wrappable* owner,
ScopedPersistent<v8::Value>* value) {
auto it = reference_map_.insert({owner, value});
}
void V8cHeapTracer::RemoveReferencedObject(Wrappable* owner,
ScopedPersistent<v8::Value>* value) {
auto pair_range = reference_map_.equal_range(owner);
auto it = std::find_if(
pair_range.first, pair_range.second,
[&](decltype(*pair_range.first) it) { return it.second == value; });
DCHECK(it != pair_range.second);
reference_map_.erase(it);
}
void V8cHeapTracer::MaybeAddToFrontier(Traceable* traceable) {
if (!visited_.insert(traceable).second) {
return;
}
frontier_.push_back(traceable);
}
} // namespace v8c
} // namespace script
} // namespace cobalt