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