Home | History | Annotate | Download | only in v8
      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.
     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 
     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 
     51     static ScriptState* current(v8::Isolate* isolate)
     52     {
     53         return from(isolate->GetCurrentContext());
     54     }
     55 
     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 
     69     v8::Isolate* isolate() const { return m_isolate; }
     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.
     76     v8::Handle<v8::Context> context() const { return m_context.newLocal(m_isolate); }
     77     bool contextIsValid() const { return m_context.isEmpty() || m_globalObjectDetached; }
     78     void detachGlobalObject();
     79     void clearContext() { return m_context.clear(); }
     80 
     81     V8PerContextData* perContextData() const { return m_perContextData.get(); }
     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:
    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(); }
    134     ScriptState* get() const { return m_scriptState.get(); }
    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