| OLD | NEW |
| 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 | |
| OLD | NEW |