1// Copyright (c) 2012 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#include "content/renderer/pepper/host_var_tracker.h"
6
7#include "base/logging.h"
8#include "content/renderer/pepper/host_array_buffer_var.h"
9#include "content/renderer/pepper/host_globals.h"
10#include "content/renderer/pepper/host_resource_var.h"
11#include "content/renderer/pepper/pepper_plugin_instance_impl.h"
12#include "content/renderer/pepper/v8object_var.h"
13#include "ppapi/c/pp_var.h"
14
15using ppapi::ArrayBufferVar;
16using ppapi::V8ObjectVar;
17
18namespace content {
19
20HostVarTracker::V8ObjectVarKey::V8ObjectVarKey(V8ObjectVar* object_var)
21    : instance(object_var->instance()->pp_instance()) {
22  v8::Local<v8::Object> object = object_var->GetHandle();
23  hash = object.IsEmpty() ? 0 : object->GetIdentityHash();
24}
25
26HostVarTracker::V8ObjectVarKey::V8ObjectVarKey(PP_Instance instance,
27                                               v8::Handle<v8::Object> object)
28    : instance(instance),
29      hash(object.IsEmpty() ? 0 : object->GetIdentityHash()) {}
30
31HostVarTracker::V8ObjectVarKey::~V8ObjectVarKey() {}
32
33bool HostVarTracker::V8ObjectVarKey::operator<(
34    const V8ObjectVarKey& other) const {
35  if (instance == other.instance)
36    return hash < other.hash;
37  return instance < other.instance;
38}
39
40HostVarTracker::HostVarTracker()
41    : VarTracker(SINGLE_THREADED), last_shared_memory_map_id_(0) {}
42
43HostVarTracker::~HostVarTracker() {}
44
45ArrayBufferVar* HostVarTracker::CreateArrayBuffer(uint32 size_in_bytes) {
46  return new HostArrayBufferVar(size_in_bytes);
47}
48
49ArrayBufferVar* HostVarTracker::CreateShmArrayBuffer(
50    uint32 size_in_bytes,
51    base::SharedMemoryHandle handle) {
52  return new HostArrayBufferVar(size_in_bytes, handle);
53}
54
55void HostVarTracker::AddV8ObjectVar(V8ObjectVar* object_var) {
56  CheckThreadingPreconditions();
57  v8::HandleScope handle_scope(object_var->instance()->GetIsolate());
58  DCHECK(GetForV8Object(object_var->instance()->pp_instance(),
59                        object_var->GetHandle()) == object_map_.end());
60  object_map_.insert(std::make_pair(V8ObjectVarKey(object_var), object_var));
61}
62
63void HostVarTracker::RemoveV8ObjectVar(V8ObjectVar* object_var) {
64  CheckThreadingPreconditions();
65  v8::HandleScope handle_scope(object_var->instance()->GetIsolate());
66  ObjectMap::iterator it = GetForV8Object(
67      object_var->instance()->pp_instance(), object_var->GetHandle());
68  DCHECK(it != object_map_.end());
69  object_map_.erase(it);
70}
71
72PP_Var HostVarTracker::V8ObjectVarForV8Object(PP_Instance instance,
73                                              v8::Handle<v8::Object> object) {
74  CheckThreadingPreconditions();
75  ObjectMap::const_iterator it = GetForV8Object(instance, object);
76  if (it == object_map_.end())
77    return (new V8ObjectVar(instance, object))->GetPPVar();
78  return it->second->GetPPVar();
79}
80
81int HostVarTracker::GetLiveV8ObjectVarsForTest(PP_Instance instance) {
82  CheckThreadingPreconditions();
83  int count = 0;
84  // Use a key with an empty handle to find the v8 object var in the map with
85  // the given instance and the lowest hash.
86  V8ObjectVarKey key(instance, v8::Handle<v8::Object>());
87  ObjectMap::const_iterator it = object_map_.lower_bound(key);
88  while (it != object_map_.end() && it->first.instance == instance) {
89    ++count;
90    ++it;
91  }
92  return count;
93}
94
95PP_Var HostVarTracker::MakeResourcePPVarFromMessage(
96    PP_Instance instance,
97    const IPC::Message& creation_message,
98    int pending_renderer_id,
99    int pending_browser_id) {
100  // On the host side, the creation message is ignored when creating a resource.
101  // Therefore, a call to this function indicates a null resource. Return the
102  // resource 0.
103  return MakeResourcePPVar(0);
104}
105
106ppapi::ResourceVar* HostVarTracker::MakeResourceVar(PP_Resource pp_resource) {
107  return new HostResourceVar(pp_resource);
108}
109
110void HostVarTracker::DidDeleteInstance(PP_Instance pp_instance) {
111  CheckThreadingPreconditions();
112
113  PepperPluginInstanceImpl* instance =
114      HostGlobals::Get()->GetInstance(pp_instance);
115  v8::HandleScope handle_scope(instance->GetIsolate());
116  // Force delete all var references. ForceReleaseV8Object() will cause
117  // this object, and potentially others it references, to be removed from
118  // |live_vars_|.
119
120  // Use a key with an empty handle to find the v8 object var in the map with
121  // the given instance and the lowest hash.
122  V8ObjectVarKey key(pp_instance, v8::Handle<v8::Object>());
123  ObjectMap::iterator it = object_map_.lower_bound(key);
124  while (it != object_map_.end() && it->first.instance == pp_instance) {
125    ForceReleaseV8Object(it->second);
126    object_map_.erase(it++);
127  }
128}
129
130void HostVarTracker::ForceReleaseV8Object(ppapi::V8ObjectVar* object_var) {
131  object_var->InstanceDeleted();
132  VarMap::iterator iter = live_vars_.find(object_var->GetExistingVarID());
133  if (iter == live_vars_.end()) {
134    NOTREACHED();
135    return;
136  }
137  iter->second.ref_count = 0;
138  DCHECK(iter->second.track_with_no_reference_count == 0);
139  DeleteObjectInfoIfNecessary(iter);
140}
141
142HostVarTracker::ObjectMap::iterator HostVarTracker::GetForV8Object(
143    PP_Instance instance,
144    v8::Handle<v8::Object> object) {
145  std::pair<ObjectMap::iterator, ObjectMap::iterator> range =
146      object_map_.equal_range(V8ObjectVarKey(instance, object));
147
148  for (ObjectMap::iterator it = range.first; it != range.second; ++it) {
149    if (object == it->second->GetHandle())
150      return it;
151  }
152  return object_map_.end();
153}
154
155int HostVarTracker::TrackSharedMemoryHandle(PP_Instance instance,
156                                            base::SharedMemoryHandle handle,
157                                            uint32 size_in_bytes) {
158  SharedMemoryMapEntry entry;
159  entry.instance = instance;
160  entry.handle = handle;
161  entry.size_in_bytes = size_in_bytes;
162
163  // Find a free id for our map.
164  while (shared_memory_map_.find(last_shared_memory_map_id_) !=
165         shared_memory_map_.end()) {
166    ++last_shared_memory_map_id_;
167  }
168  shared_memory_map_[last_shared_memory_map_id_] = entry;
169  return last_shared_memory_map_id_;
170}
171
172bool HostVarTracker::StopTrackingSharedMemoryHandle(
173    int id,
174    PP_Instance instance,
175    base::SharedMemoryHandle* handle,
176    uint32* size_in_bytes) {
177  SharedMemoryMap::iterator it = shared_memory_map_.find(id);
178  if (it == shared_memory_map_.end())
179    return false;
180  if (it->second.instance != instance)
181    return false;
182
183  *handle = it->second.handle;
184  *size_in_bytes = it->second.size_in_bytes;
185  shared_memory_map_.erase(it);
186  return true;
187}
188
189}  // namespace content
190