blob: 61689026416d80b11be193bb480d6bcb91cd674e [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 COBALT_SCRIPT_MOZJS_45_UTIL_STACK_TRACE_HELPERS_H_
#define COBALT_SCRIPT_MOZJS_45_UTIL_STACK_TRACE_HELPERS_H_
#include <string>
#include <vector>
#include "base/compiler_specific.h"
#include "base/threading/thread_checker.h"
#include "cobalt/script/stack_frame.h"
#include "cobalt/script/util/stack_trace_helpers.h"
#include "nb/rewindable_vector.h"
#include "third_party/mozjs-45/js/src/jsapi.h"
#if defined(STARBOARD_ALLOWS_MEMORY_TRACKING)
#define ENABLE_JS_STACK_TRACE_IN_SCOPE(context) \
::cobalt::script::mozjs::util::StackTraceScope stack_trace_scope_object( \
context)
#else
#define ENABLE_JS_STACK_TRACE_IN_SCOPE(context)
#endif
namespace cobalt {
namespace script {
namespace mozjs {
namespace util {
// Usage:
// void Function(JSContext* js_ctx, ...) {
// ENABLE_JS_STACK_TRACE_IN_SCOPE(js_ctx);
// ...
// InvokeOtherFunctions();
// }
//
// void InvokeOtherFunctions() {
// ...
// std::string stack_trace_str;
// if (GetThreadLocalStackTraceGenerator()->GenerateStackTraceString(
// 2, &stack_trace_str)) {
// // Prints the stack trace from javascript.
// SbLogRaw(stack_trace_str.c_str());
// }
// }
class MozjsStackTraceGenerator
: public ::cobalt::script::util::StackTraceGenerator {
public:
MozjsStackTraceGenerator() : context_(NULL) {}
// Returns |true| if the current StackTraceGenerator can generate information
// about the stack.
bool Valid() OVERRIDE { return context_ != NULL; }
// Generates stack traces in the raw form. Returns true if any stack
// frames were generated. False otherwise. Output vector will be
// unconditionally rewound to being empty.
bool GenerateStackTrace(int depth,
nb::RewindableVector<StackFrame>* out) OVERRIDE;
// Returns true if any stack traces were written. The output vector will be
// re-wound to being empty.
// The first position is the most immediate stack frame.
bool GenerateStackTraceLines(int depth,
nb::RewindableVector<std::string>* out) OVERRIDE;
// Prints stack trace. Returns true on success.
bool GenerateStackTraceString(int depth, std::string* out) OVERRIDE;
bool GenerateStackTraceString(int depth, char* buff,
size_t buff_size) OVERRIDE;
// Gets the internal data structure used to generate stack traces.
JSContext* context() { return context_; }
// Internal only, do not set.
void set_context(JSContext* context) { context_ = context; }
private:
JSContext* context_;
// Recycles memory so that stack tracing is efficient.
struct Scratch {
nb::RewindableVector<StackFrame> stack_frames_;
nb::RewindableVector<std::string> strings_stack_frames_;
std::string symbol_;
};
Scratch scratch_data_;
// Checks that each instance can only be used within the same thread.
base::ThreadChecker thread_checker_;
};
// This should only be accessed by a scoped object.
void SetThreadLocalJSContext(JSContext* context);
JSContext* GetThreadLocalJSContext();
// Useful for updating the most recent stack trace.
struct StackTraceScope {
explicit StackTraceScope(JSContext* js)
: prev_context_(GetThreadLocalJSContext()) {
SetThreadLocalJSContext(js);
}
~StackTraceScope() { SetThreadLocalJSContext(prev_context_); }
JSContext* prev_context_;
};
} // namespace util
} // namespace mozjs
} // namespace script
} // namespace cobalt
#endif // COBALT_SCRIPT_MOZJS_45_UTIL_STACK_TRACE_HELPERS_H_