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