• 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/v8/ScopedPersistent.h"
9 #include "bindings/v8/V8PerContextData.h"
10 #include "wtf/RefCounted.h"
11 #include <v8.h>
12 
13 namespace WebCore {
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); }
contextIsEmpty()77     bool contextIsEmpty() const { return m_context.isEmpty(); }
clearContext()78     void clearContext() { return m_context.clear(); }
79 
perContextData()80     V8PerContextData* perContextData() const { return m_perContextData.get(); }
disposePerContextData()81     void disposePerContextData() { m_perContextData = nullptr; }
82 
83     bool evalEnabled() const;
84     void setEvalEnabled(bool);
85     ScriptValue getFromGlobalObject(const char* name);
86 
87 protected:
88     ScriptState(v8::Handle<v8::Context>, PassRefPtr<DOMWrapperWorld>);
89 
90 private:
91     v8::Isolate* m_isolate;
92     // This persistent handle is weak.
93     ScopedPersistent<v8::Context> m_context;
94 
95     // This RefPtr doesn't cause a cycle because all persistent handles that DOMWrapperWorld holds are weak.
96     RefPtr<DOMWrapperWorld> m_world;
97 
98     // This OwnPtr causes a cycle:
99     // V8PerContextData --(Persistent)--> v8::Context --(RefPtr)--> ScriptState --(OwnPtr)--> V8PerContextData
100     // So you must explicitly clear the OwnPtr by calling disposePerContextData()
101     // once you no longer need V8PerContextData. Otherwise, the v8::Context will leak.
102     OwnPtr<V8PerContextData> m_perContextData;
103 };
104 
105 class ScriptStateForTesting : public ScriptState {
106 public:
107     static PassRefPtr<ScriptStateForTesting> create(v8::Handle<v8::Context>, PassRefPtr<DOMWrapperWorld>);
108 
109     virtual ExecutionContext* executionContext() const OVERRIDE;
110     virtual void setExecutionContext(ExecutionContext*) OVERRIDE;
111 
112 private:
113     ScriptStateForTesting(v8::Handle<v8::Context>, PassRefPtr<DOMWrapperWorld>);
114 
115     ExecutionContext* m_executionContext;
116 };
117 
118 // ScriptStateProtectingContext keeps the context associated with the ScriptState alive.
119 // You need to call clear() once you no longer need the context. Otherwise, the context will leak.
120 class ScriptStateProtectingContext {
121     WTF_MAKE_NONCOPYABLE(ScriptStateProtectingContext);
122 public:
ScriptStateProtectingContext(ScriptState * scriptState)123     ScriptStateProtectingContext(ScriptState* scriptState)
124         : m_scriptState(scriptState)
125     {
126         if (m_scriptState)
127             m_context.set(m_scriptState->isolate(), m_scriptState->context());
128     }
129 
130     ScriptState* operator->() const { return m_scriptState.get(); }
get()131     ScriptState* get() const { return m_scriptState.get(); }
clear()132     void clear()
133     {
134         m_scriptState = nullptr;
135         m_context.clear();
136     }
137 
138 private:
139     RefPtr<ScriptState> m_scriptState;
140     ScopedPersistent<v8::Context> m_context;
141 };
142 
143 }
144 
145 #endif // ScriptState_h
146