blob: ed830320ac22b91028ae9f600b5136832e4bc04c [file] [log] [blame]
// Copyright 2017 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.
#ifndef NB_SCRIPT_STACKTRACE_H_
#define NB_SCRIPT_STACKTRACE_H_
#include "cobalt/script/mozjs/util/stack_trace_helpers.h"
#include <algorithm>
#include <sstream>
#include <vector>
#include "base/logging.h"
#include "base/stringprintf.h"
#include "cobalt/script/mozjs/util/exception_helpers.h"
#include "cobalt/script/stack_frame.h"
#include "nb/thread_local_object.h"
#include "starboard/memory.h"
#include "starboard/once.h"
#include "starboard/string.h"
#include "starboard/types.h"
#include "third_party/mozjs/js/src/jsapi.h"
namespace cobalt {
namespace script {
namespace mozjs {
namespace util {
namespace {
typedef nb::ThreadLocalObject<StackTraceGenerator> ThreadLocalJsStackTracer;
SB_ONCE_INITIALIZE_FUNCTION(ThreadLocalJsStackTracer,
s_thread_local_js_stack_tracer_singelton);
void ToStringAppend(const StackFrame& sf, std::string* out) {
base::SStringPrintf(out, "%s(%d,%d):%s", sf.source_url.c_str(),
sf.line_number, sf.column_number,
sf.function_name.c_str());
}
} // namespace.
void SetThreadLocalJSContext(JSContext* context) {
GetThreadLocalStackTraceGenerator()->set_js_context(context);
}
JSContext* GetThreadLocalJSContext() {
return GetThreadLocalStackTraceGenerator()->js_context();
}
StackTraceGenerator* GetThreadLocalStackTraceGenerator() {
return s_thread_local_js_stack_tracer_singelton()->GetOrCreate();
}
//////////////////////////////////// IMPL /////////////////////////////////////
StackTraceGenerator::StackTraceGenerator() : js_context_(NULL) {}
StackTraceGenerator::~StackTraceGenerator() {}
bool StackTraceGenerator::Valid() { return js_context_ != NULL; }
bool StackTraceGenerator::GenerateStackTrace(
int depth, nb::RewindableVector<StackFrame>* out) {
DCHECK(thread_checker_.CalledOnValidThread());
out->rewindAll();
if (!Valid()) {
return false;
}
GetStackTrace(js_context_, depth, out);
return !out->empty();
}
bool StackTraceGenerator::GenerateStackTraceLines(
int depth, nb::RewindableVector<std::string>* out) {
DCHECK(thread_checker_.CalledOnValidThread());
out->rewindAll();
nb::RewindableVector<StackFrame>& stack_frames = scratch_data_.stack_frames_;
if (!GenerateStackTrace(depth, &stack_frames)) {
return false;
}
for (size_t i = 0; i < stack_frames.size(); ++i) {
std::string& current_string = out->grow(1);
current_string.assign(""); // Should not deallocate memory.
StackFrame& sf = stack_frames[i];
ToStringAppend(sf, &current_string);
}
return true;
}
bool StackTraceGenerator::GenerateStackTraceString(int depth,
std::string* out) {
DCHECK(thread_checker_.CalledOnValidThread());
out->assign(""); // Should not deallocate memory.
nb::RewindableVector<StackFrame>& stack_frames = scratch_data_.stack_frames_;
if (!GenerateStackTrace(depth, &stack_frames)) {
return false;
}
for (size_t i = 0; i < stack_frames.size(); ++i) {
cobalt::script::StackFrame& sf = stack_frames[i];
ToStringAppend(sf, out);
if (i < stack_frames.size() - 1) {
base::SStringPrintf(out, "\n");
}
}
return true;
}
bool StackTraceGenerator::GenerateStackTraceString(int depth, char* buff,
size_t buff_size) {
DCHECK(thread_checker_.CalledOnValidThread());
SbMemorySet(buff, 0, buff_size);
std::string& scratch_symbol = scratch_data_.symbol_;
if (!GenerateStackTraceString(depth, &scratch_symbol)) {
return false;
}
SbStringCopy(buff, scratch_symbol.c_str(), buff_size);
return true;
}
JSContext* StackTraceGenerator::js_context() { return js_context_; }
void StackTraceGenerator::set_js_context(JSContext* js_ctx) {
js_context_ = js_ctx;
}
} // namespace util
} // namespace mozjs
} // namespace script
} // namespace cobalt
#endif // NB_SCRIPT_STACKTRACE_H_