1 /*
2  * Copyright (C) 2012 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_BINDINGS_V8_PER_CONTEXT_DATA_H_
32 #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_BINDINGS_V8_PER_CONTEXT_DATA_H_
33 
34 #include <memory>
35 
36 #include "gin/public/context_holder.h"
37 #include "gin/public/gin_embedders.h"
38 #include "third_party/blink/renderer/platform/bindings/scoped_persistent.h"
39 #include "third_party/blink/renderer/platform/bindings/v8_global_value_map.h"
40 #include "third_party/blink/renderer/platform/heap/handle.h"
41 #include "third_party/blink/renderer/platform/heap/persistent.h"
42 #include "third_party/blink/renderer/platform/platform_export.h"
43 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
44 #include "third_party/blink/renderer/platform/wtf/hash_map.h"
45 #include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
46 #include "third_party/blink/renderer/platform/wtf/text/atomic_string_hash.h"
47 #include "third_party/blink/renderer/platform/wtf/vector.h"
48 #include "v8/include/v8.h"
49 
50 namespace blink {
51 
52 class V0CustomElementBinding;
53 class V8DOMActivityLogger;
54 class V8PerContextData;
55 struct WrapperTypeInfo;
56 
57 // Used to hold data that is associated with a single v8::Context object, and
58 // has a 1:1 relationship with v8::Context.
59 class PLATFORM_EXPORT V8PerContextData final {
60   USING_FAST_MALLOC(V8PerContextData);
61 
62  public:
63   explicit V8PerContextData(v8::Local<v8::Context>);
64 
65   static V8PerContextData* From(v8::Local<v8::Context>);
66 
67   ~V8PerContextData();
68 
GetContext()69   v8::Local<v8::Context> GetContext() { return context_.NewLocal(isolate_); }
70 
71   // To create JS Wrapper objects, we create a cache of a 'boiler plate'
72   // object, and then simply Clone that object each time we need a new one.
73   // This is faster than going through the full object creation process.
CreateWrapperFromCache(const WrapperTypeInfo * type)74   v8::Local<v8::Object> CreateWrapperFromCache(const WrapperTypeInfo* type) {
75     v8::Local<v8::Object> boilerplate = wrapper_boilerplates_.Get(type);
76     return !boilerplate.IsEmpty() ? boilerplate->Clone()
77                                   : CreateWrapperFromCacheSlowCase(type);
78   }
79 
80   // Returns the interface object that is appropriately initialized (e.g.
81   // context-dependent properties are installed).
ConstructorForType(const WrapperTypeInfo * type)82   v8::Local<v8::Function> ConstructorForType(const WrapperTypeInfo* type) {
83     v8::Local<v8::Function> interface_object = constructor_map_.Get(type);
84     return (!interface_object.IsEmpty()) ? interface_object
85                                          : ConstructorForTypeSlowCase(type);
86   }
87 
88   v8::Local<v8::Object> PrototypeForType(const WrapperTypeInfo*);
89 
90   // Gets the constructor and prototype for a type, if they have already been
91   // created. Returns true if they exist, and sets the existing values in
92   // |prototypeObject| and |interfaceObject|. Otherwise, returns false, and the
93   // values are set to empty objects (non-null).
94   bool GetExistingConstructorAndPrototypeForType(
95       const WrapperTypeInfo*,
96       v8::Local<v8::Object>* prototype_object,
97       v8::Local<v8::Function>* interface_object);
98 
99   void AddCustomElementBinding(std::unique_ptr<V0CustomElementBinding>);
100 
101   // Gets a Private to store custom element definition IDs on a
102   // constructor that has been registered as a custom element in this
103   // context. This private has to be per-context because the same
104   // constructor could be simultaneously registered as a custom
105   // element in many contexts and they each need to give it a unique
106   // identifier.
GetPrivateCustomElementDefinitionId()107   v8::Local<v8::Private> GetPrivateCustomElementDefinitionId() {
108     if (UNLIKELY(private_custom_element_definition_id_.IsEmpty())) {
109       private_custom_element_definition_id_.Set(isolate_,
110                                                 v8::Private::New(isolate_));
111     }
112     return private_custom_element_definition_id_.NewLocal(isolate_);
113   }
114 
ActivityLogger()115   V8DOMActivityLogger* ActivityLogger() const { return activity_logger_; }
SetActivityLogger(V8DOMActivityLogger * activity_logger)116   void SetActivityLogger(V8DOMActivityLogger* activity_logger) {
117     activity_logger_ = activity_logger;
118   }
119 
120   // Garbage collected classes that use V8PerContextData to hold an instance
121   // should subclass Data, and use addData / clearData / getData to manage the
122   // instance.
123   class PLATFORM_EXPORT Data : public GarbageCollectedMixin {};
124 
125   void AddData(const char* key, Data*);
126   void ClearData(const char* key);
127   Data* GetData(const char* key);
128 
129  private:
130   v8::Local<v8::Object> CreateWrapperFromCacheSlowCase(const WrapperTypeInfo*);
131   v8::Local<v8::Function> ConstructorForTypeSlowCase(const WrapperTypeInfo*);
132 
133   v8::Isolate* isolate_;
134 
135   // For each possible type of wrapper, we keep a boilerplate object.
136   // The boilerplate is used to create additional wrappers of the same type.
137   V8GlobalValueMap<const WrapperTypeInfo*, v8::Object> wrapper_boilerplates_;
138 
139   V8GlobalValueMap<const WrapperTypeInfo*, v8::Function> constructor_map_;
140 
141   std::unique_ptr<gin::ContextHolder> context_holder_;
142 
143   ScopedPersistent<v8::Context> context_;
144 
145   ScopedPersistent<v8::Private> private_custom_element_definition_id_;
146 
147   typedef Vector<std::unique_ptr<V0CustomElementBinding>>
148       V0CustomElementBindingList;
149   V0CustomElementBindingList custom_element_bindings_;
150 
151   // This is owned by a static hash map in V8DOMActivityLogger.
152   V8DOMActivityLogger* activity_logger_;
153 
154   using DataMap = HeapHashMap<const char*, Member<Data>>;
155   Persistent<DataMap> data_map_;
156 
157   DISALLOW_COPY_AND_ASSIGN(V8PerContextData);
158 };
159 
160 }  // namespace blink
161 
162 #endif  // THIRD_PARTY_BLINK_RENDERER_PLATFORM_BINDINGS_V8_PER_CONTEXT_DATA_H_
163