blob: 0aa069dde9fd46ef590304ac573f0fe9401375c9 [file] [log] [blame]
// Copyright 2016 The Cobalt Authors. 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
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.
#include <memory>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include "base/containers/hash_tables.h"
#include "base/logging.h"
#include "base/optional.h"
#include "base/stl_util.h"
#include "base/threading/thread_checker.h"
#include "cobalt/script/global_environment.h"
#include "cobalt/script/javascript_engine.h"
#include "cobalt/script/mozjs-45/interface_data.h"
#include "cobalt/script/mozjs-45/util/exception_helpers.h"
#include "cobalt/script/mozjs-45/weak_heap_object_manager.h"
#include "cobalt/script/mozjs-45/wrapper_factory.h"
#include "third_party/mozjs-45/js/public/Proxy.h"
#include "third_party/mozjs-45/js/src/jsapi.h"
#include "third_party/mozjs-45/js/src/proxy/Proxy.h"
namespace cobalt {
namespace script {
namespace mozjs {
class MozjsScriptValueFactory;
class ReferencedObjectMap;
class WeakHandle;
// Manages a handle to a JavaScript engine's global object. The lifetime of
// the global object is not necessarily tied to the lifetime of the proxy.
class MozjsGlobalEnvironment : public GlobalEnvironment,
public Wrappable::CachedWrapperAccessor {
static MozjsGlobalEnvironment* GetFromContext(JSContext* context);
// This will be called every time an attempt is made to use eval() and
// friends. If it returns false, then the ReportErrorHandler will be fired
// with an error that eval() is disabled.
static bool CheckEval(JSContext* context);
explicit MozjsGlobalEnvironment(JSRuntime* runtime);
~MozjsGlobalEnvironment() override;
void CreateGlobalObject() override;
// |script::GlobalEnvironment| will dispatch to this implementation in the
// create_global_object_impl block of the bindings interface template.
template <typename GlobalInterface>
void CreateGlobalObject(
const scoped_refptr<GlobalInterface>& global_interface,
EnvironmentSettings* environment_settings);
bool EvaluateScript(const scoped_refptr<SourceCode>& script,
std::string* out_result_utf8) override;
bool EvaluateScript(
const scoped_refptr<SourceCode>& script_utf8,
const scoped_refptr<Wrappable>& owning_object,
base::Optional<ValueHandleHolder::Reference>* out_value_handle) override;
std::vector<StackFrame> GetStackTrace(int max_frames) override;
using GlobalEnvironment::GetStackTrace;
void PreventGarbageCollection(
const scoped_refptr<Wrappable>& wrappable) override;
void AllowGarbageCollection(Wrappable* wrappable) override;
void AddRoot(Traceable* traceable) override;
void RemoveRoot(Traceable* traceable) override;
void DisableEval(const std::string& message) override;
void EnableEval() override;
void DisableJit() override;
void SetReportEvalCallback(const base::Closure& report_eval) override;
void SetReportErrorCallback(
const ReportErrorCallback& report_error_callback) override;
void Bind(const std::string& identifier,
const scoped_refptr<Wrappable>& impl) override;
ScriptValueFactory* script_value_factory() override;
JSContext* context() const { return context_; }
JSObject* global_object_proxy() const { return global_object_proxy_; }
JSObject* global_object() const {
return js::GetProxyTargetObject(global_object_proxy_);
WrapperFactory* wrapper_factory() { return wrapper_factory_.get(); }
ReferencedObjectMap* referenced_objects() {
return referenced_objects_.get();
WeakHeapObjectManager* weak_object_manager() { return &weak_object_manager_; }
base::hash_set<Traceable*>* visited_traceables() {
return &visited_traceables_;
EnvironmentSettings* GetEnvironmentSettings() const {
return environment_settings_;
void GetStoredPromiseConstructor(
JS::MutableHandleObject out_promise_constructor) {
void SetGlobalObjectProxyAndWrapper(
JS::HandleObject global_object_proxy,
const scoped_refptr<Wrappable>& wrappable);
// Any tracked InterfaceData will have it's GC handles visited and marked as
// roots. |key| is the interface's unique id, which is generated during
// bindings idl compilation.
InterfaceData* GetInterfaceData(int key);
// This will be called during garbage collection after GC objects have been
// marked, but before they have been finalized. This allows an opportunity to
// sweep away references to GC objects that will be deleted.
void DoSweep();
void BeginGarbageCollection();
void EndGarbageCollection();
void ReportError(const char* message, JSErrorReport* report);
// Helper struct to ensure the context is destroyed in the correct order
// relative to the MozjsGlobalEnvironment's other members.
struct ContextDestructor {
explicit ContextDestructor(JSContext** context) : context(context) {}
~ContextDestructor() { JS_DestroyContext(*context); }
JSContext** const context;
struct CountedHeapObject {
CountedHeapObject(const JS::Heap<JSObject*>& heap_object, int count)
: heap_object(heap_object), count(count) {}
JS::Heap<JSObject*> heap_object;
int count;
static void TraceFunction(JSTracer* trace, void* data);
// Evaluates any automatically included JavaScript for the environment.
void EvaluateAutomatics();
bool EvaluateScriptInternal(const scoped_refptr<SourceCode>& source_code,
JS::MutableHandleValue out_result);
void EvaluateEmbeddedScript(const unsigned char* data, size_t size,
const char* filename);
// Flag indicating when the destructor is called.
bool destructing_ = false;
JSContext* context_;
int garbage_collection_count_;
WeakHeapObjectManager weak_object_manager_;
std::unique_ptr<ReferencedObjectMap> referenced_objects_;
// Beware the order of destruction. Anything which references the JSContext
// should be destroyed before ~ContextDestructor.
ContextDestructor context_destructor_;
JS::Heap<JSObject*> global_object_proxy_;
std::unique_ptr<WrapperFactory> wrapper_factory_;
std::unique_ptr<MozjsScriptValueFactory> script_value_factory_;
std::vector<InterfaceData> cached_interface_data_;
std::unordered_map<Wrappable*, CountedHeapObject> kept_alive_objects_;
EnvironmentSettings* environment_settings_;
// TODO: Should be |std::unordered_set| once C++11 is enabled.
base::hash_set<Traceable*> visited_traceables_;
std::unordered_multiset<Traceable*> roots_;
// Store the result of "Promise" immediately after evaluating the
// promise polyfill in order to defend against application JavaScript
// changing it to something else later. Note that this should be removed if
// we ever rebase to a SpiderMonkey version >= 50, as that is when native
// promises were added to it.
base::Optional<JS::PersistentRootedObject> stored_promise_constructor_;
// If non-NULL, the error message from the ReportErrorHandler will get
// assigned to this instead of being printed.
std::string* last_error_message_;
bool eval_enabled_;
base::Optional<std::string> eval_disabled_message_;
base::Closure report_eval_;
ReportErrorCallback report_error_callback_;
bool are_errors_muted_ = false;
friend class GlobalObjectProxy;
} // namespace mozjs
} // namespace script
} // namespace cobalt