1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
|
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef ScriptState_h
#define ScriptState_h
#include "bindings/core/v8/ScopedPersistent.h"
#include "bindings/core/v8/V8PerContextData.h"
#include "wtf/RefCounted.h"
#include "wtf/Vector.h"
#include <v8.h>
namespace blink {
class LocalDOMWindow;
class DOMWrapperWorld;
class ExecutionContext;
class LocalFrame;
class ScriptValue;
// ScriptState is created when v8::Context is created.
// ScriptState is destroyed when v8::Context is garbage-collected and
// all V8 proxy objects that have references to the ScriptState are destructed.
class ScriptState : public RefCounted<ScriptState> {
WTF_MAKE_NONCOPYABLE(ScriptState);
public:
class Scope {
public:
// You need to make sure that scriptState->context() is not empty before creating a Scope.
explicit Scope(ScriptState* scriptState)
: m_handleScope(scriptState->isolate())
, m_context(scriptState->context())
{
ASSERT(scriptState->contextIsValid());
m_context->Enter();
}
~Scope()
{
m_context->Exit();
}
private:
v8::HandleScope m_handleScope;
v8::Handle<v8::Context> m_context;
};
static PassRefPtr<ScriptState> create(v8::Handle<v8::Context>, PassRefPtr<DOMWrapperWorld>);
virtual ~ScriptState();
static ScriptState* current(v8::Isolate* isolate)
{
return from(isolate->GetCurrentContext());
}
static ScriptState* from(v8::Handle<v8::Context> context)
{
ASSERT(!context.IsEmpty());
ScriptState* scriptState = static_cast<ScriptState*>(context->GetAlignedPointerFromEmbedderData(v8ContextPerContextDataIndex));
// ScriptState::from() must not be called for a context that does not have
// valid embedder data in the embedder field.
RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(scriptState);
RELEASE_ASSERT_WITH_SECURITY_IMPLICATION(scriptState->context() == context);
return scriptState;
}
static ScriptState* forMainWorld(LocalFrame*);
v8::Isolate* isolate() const { return m_isolate; }
DOMWrapperWorld& world() const { return *m_world; }
LocalDOMWindow* domWindow() const;
virtual ExecutionContext* executionContext() const;
virtual void setExecutionContext(ExecutionContext*);
// This can return an empty handle if the v8::Context is gone.
v8::Handle<v8::Context> context() const { return m_context.newLocal(m_isolate); }
bool contextIsValid() const { return !m_context.isEmpty() && !m_globalObjectDetached; }
void detachGlobalObject();
void clearContext() { return m_context.clear(); }
V8PerContextData* perContextData() const { return m_perContextData.get(); }
void disposePerContextData();
class Observer {
public:
virtual ~Observer() { }
virtual void willDisposeScriptState(ScriptState*) = 0;
};
void addObserver(Observer*);
void removeObserver(Observer*);
bool evalEnabled() const;
void setEvalEnabled(bool);
ScriptValue getFromGlobalObject(const char* name);
protected:
ScriptState(v8::Handle<v8::Context>, PassRefPtr<DOMWrapperWorld>);
private:
v8::Isolate* m_isolate;
// This persistent handle is weak.
ScopedPersistent<v8::Context> m_context;
// This RefPtr doesn't cause a cycle because all persistent handles that DOMWrapperWorld holds are weak.
RefPtr<DOMWrapperWorld> m_world;
// This OwnPtr causes a cycle:
// V8PerContextData --(Persistent)--> v8::Context --(RefPtr)--> ScriptState --(OwnPtr)--> V8PerContextData
// So you must explicitly clear the OwnPtr by calling disposePerContextData()
// once you no longer need V8PerContextData. Otherwise, the v8::Context will leak.
OwnPtr<V8PerContextData> m_perContextData;
bool m_globalObjectDetached;
Vector<Observer*> m_observers;
};
class ScriptStateForTesting : public ScriptState {
public:
static PassRefPtr<ScriptStateForTesting> create(v8::Handle<v8::Context>, PassRefPtr<DOMWrapperWorld>);
virtual ExecutionContext* executionContext() const override;
virtual void setExecutionContext(ExecutionContext*) override;
private:
ScriptStateForTesting(v8::Handle<v8::Context>, PassRefPtr<DOMWrapperWorld>);
ExecutionContext* m_executionContext;
};
// ScriptStateProtectingContext keeps the context associated with the ScriptState alive.
// You need to call clear() once you no longer need the context. Otherwise, the context will leak.
class ScriptStateProtectingContext {
WTF_MAKE_NONCOPYABLE(ScriptStateProtectingContext);
public:
ScriptStateProtectingContext(ScriptState* scriptState)
: m_scriptState(scriptState)
{
if (m_scriptState)
m_context.set(m_scriptState->isolate(), m_scriptState->context());
}
ScriptState* operator->() const { return m_scriptState.get(); }
ScriptState* get() const { return m_scriptState.get(); }
void clear()
{
m_scriptState = nullptr;
m_context.clear();
}
private:
RefPtr<ScriptState> m_scriptState;
ScopedPersistent<v8::Context> m_context;
};
}
#endif // ScriptState_h
|