Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(37)

Side by Side Diff: third_party/WebKit/Source/bindings/core/v8/ScriptState.h

Issue 2843603002: Move ScriptWrappable and dependencies to platform/bindings (Closed)
Patch Set: Rebase and try again Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #ifndef ScriptState_h 5 // This file has been moved to platform/bindings/ScriptState.h.
6 #define ScriptState_h 6 // TODO(adithyas): Remove this file.
7 7 #include "platform/bindings/ScriptState.h"
8 #include <memory>
9
10 #include "bindings/core/v8/ScopedPersistent.h"
11 #include "bindings/core/v8/V8PerContextData.h"
12 #include "core/CoreExport.h"
13 #include "platform/wtf/RefCounted.h"
14 #include "v8/include/v8-debug.h"
15 #include "v8/include/v8.h"
16
17 namespace blink {
18
19 class DOMWrapperWorld;
20 class ScriptValue;
21
22 // ScriptState is an abstraction class that holds all information about script
23 // exectuion (e.g., v8::Isolate, v8::Context, DOMWrapperWorld, ExecutionContext
24 // etc). If you need any info about the script execution, you're expected to
25 // pass around ScriptState in the code base. ScriptState is in a 1:1
26 // relationship with v8::Context.
27 //
28 // When you need ScriptState, you can add [CallWith=ScriptState] to IDL files
29 // and pass around ScriptState into a place where you need ScriptState.
30 //
31 // In some cases, you need ScriptState in code that doesn't have any JavaScript
32 // on the stack. Then you can store ScriptState on a C++ object using
33 // RefPtr<ScriptState>.
34 //
35 // class SomeObject {
36 // void someMethod(ScriptState* scriptState) {
37 // m_scriptState = scriptState; // Record the ScriptState.
38 // ...;
39 // }
40 //
41 // void asynchronousMethod() {
42 // if (!m_scriptState->contextIsValid()) {
43 // // It's possible that the context is already gone.
44 // return;
45 // }
46 // // Enter the ScriptState.
47 // ScriptState::Scope scope(m_scriptState.get());
48 // // Do V8 related things.
49 // ToV8(...);
50 // }
51 // RefPtr<ScriptState> m_scriptState;
52 // };
53 //
54 // You should not store ScriptState on a C++ object that can be accessed
55 // by multiple worlds. For example, you can store ScriptState on
56 // ScriptPromiseResolver, ScriptValue etc because they can be accessed from one
57 // world. However, you cannot store ScriptState on a DOM object that has
58 // an IDL interface because the DOM object can be accessed from multiple
59 // worlds. If ScriptState of one world "leak"s to another world, you will
60 // end up with leaking any JavaScript objects from one Chrome extension
61 // to another Chrome extension, which is a severe security bug.
62 //
63 // Lifetime:
64 // ScriptState is created when v8::Context is created.
65 // ScriptState is destroyed when v8::Context is garbage-collected and
66 // all V8 proxy objects that have references to the ScriptState are destructed.
67 class CORE_EXPORT ScriptState : public RefCounted<ScriptState> {
68 WTF_MAKE_NONCOPYABLE(ScriptState);
69
70 public:
71 class Scope {
72 STACK_ALLOCATED();
73
74 public:
75 // You need to make sure that scriptState->context() is not empty before
76 // creating a Scope.
77 explicit Scope(ScriptState* script_state)
78 : handle_scope_(script_state->GetIsolate()),
79 context_(script_state->GetContext()) {
80 DCHECK(script_state->ContextIsValid());
81 context_->Enter();
82 }
83
84 ~Scope() { context_->Exit(); }
85
86 private:
87 v8::HandleScope handle_scope_;
88 v8::Local<v8::Context> context_;
89 };
90
91 static PassRefPtr<ScriptState> Create(v8::Local<v8::Context>,
92 PassRefPtr<DOMWrapperWorld>);
93 virtual ~ScriptState();
94
95 static ScriptState* Current(v8::Isolate* isolate) // DEPRECATED
96 {
97 return From(isolate->GetCurrentContext());
98 }
99
100 static ScriptState* ForFunctionObject(
101 const v8::FunctionCallbackInfo<v8::Value>& info) {
102 // We're assuming that the current context is not yet changed since
103 // the callback function has got called back.
104 // TODO(yukishiino): Once info.GetFunctionContext() gets implemented,
105 // we should use it instead.
106 return From(info.GetIsolate()->GetCurrentContext());
107 }
108
109 static ScriptState* ForReceiverObject(
110 const v8::FunctionCallbackInfo<v8::Value>& info) {
111 return From(info.Holder()->CreationContext());
112 }
113
114 static ScriptState* ForReceiverObject(
115 const v8::PropertyCallbackInfo<v8::Value>& info) {
116 return From(info.Holder()->CreationContext());
117 }
118
119 static ScriptState* ForReceiverObject(
120 const v8::PropertyCallbackInfo<void>& info) {
121 return From(info.Holder()->CreationContext());
122 }
123
124 static ScriptState* From(v8::Local<v8::Context> context) {
125 DCHECK(!context.IsEmpty());
126 ScriptState* script_state =
127 static_cast<ScriptState*>(context->GetAlignedPointerFromEmbedderData(
128 kV8ContextPerContextDataIndex));
129 // ScriptState::from() must not be called for a context that does not have
130 // valid embedder data in the embedder field.
131 SECURITY_CHECK(script_state);
132 SECURITY_CHECK(script_state->GetContext() == context);
133 return script_state;
134 }
135
136 v8::Isolate* GetIsolate() const { return isolate_; }
137 DOMWrapperWorld& World() const { return *world_; }
138
139 // This can return an empty handle if the v8::Context is gone.
140 v8::Local<v8::Context> GetContext() const {
141 return context_.NewLocal(isolate_);
142 }
143 bool ContextIsValid() const {
144 return !context_.IsEmpty() && per_context_data_;
145 }
146 void DetachGlobalObject();
147 void ClearContext() { return context_.Clear(); }
148
149 V8PerContextData* PerContextData() const { return per_context_data_.get(); }
150 void DisposePerContextData();
151
152 protected:
153 ScriptState(v8::Local<v8::Context>, PassRefPtr<DOMWrapperWorld>);
154
155 private:
156 v8::Isolate* isolate_;
157 // This persistent handle is weak.
158 ScopedPersistent<v8::Context> context_;
159
160 // This RefPtr doesn't cause a cycle because all persistent handles that
161 // DOMWrapperWorld holds are weak.
162 RefPtr<DOMWrapperWorld> world_;
163
164 // This std::unique_ptr causes a cycle:
165 // V8PerContextData --(Persistent)--> v8::Context --(RefPtr)--> ScriptState
166 // --(std::unique_ptr)--> V8PerContextData
167 // So you must explicitly clear the std::unique_ptr by calling
168 // disposePerContextData() once you no longer need V8PerContextData.
169 // Otherwise, the v8::Context will leak.
170 std::unique_ptr<V8PerContextData> per_context_data_;
171 };
172
173 // ScriptStateProtectingContext keeps the context associated with the
174 // ScriptState alive. You need to call clear() once you no longer need the
175 // context. Otherwise, the context will leak.
176 class ScriptStateProtectingContext {
177 WTF_MAKE_NONCOPYABLE(ScriptStateProtectingContext);
178 USING_FAST_MALLOC(ScriptStateProtectingContext);
179
180 public:
181 ScriptStateProtectingContext(ScriptState* script_state)
182 : script_state_(script_state) {
183 if (script_state_)
184 context_.Set(script_state_->GetIsolate(), script_state_->GetContext());
185 }
186
187 ScriptState* operator->() const { return script_state_.Get(); }
188 ScriptState* Get() const { return script_state_.Get(); }
189 void Clear() {
190 script_state_ = nullptr;
191 context_.Clear();
192 }
193
194 private:
195 RefPtr<ScriptState> script_state_;
196 ScopedPersistent<v8::Context> context_;
197 };
198
199 } // namespace blink
200
201 #endif // ScriptState_h
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698