15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
25d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// found in the LICENSE file.
45d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
55d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "fake_ppapi/fake_var_manager.h"
65d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "gtest/gtest.h"
85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)FakeVarManager::FakeVarManager() : debug(false), next_id_(1) {}
105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)FakeVarManager::~FakeVarManager() {
125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // The ref counts for all vars should be zero.
135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (VarMap::const_iterator iter = var_map_.begin(); iter != var_map_.end();
145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       ++iter) {
155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const FakeVarData& var_data = iter->second;
165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    EXPECT_EQ(0, var_data.ref_count) << "Non-zero refcount on "
175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                     << Describe(var_data);
185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)FakeVarData* FakeVarManager::CreateVarData() {
225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  Id id = next_id_++;
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  FakeVarData data;
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  data.id = id;
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  data.ref_count = 1;
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  var_map_[id] = data;
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return &var_map_[id];
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void FakeVarManager::AddRef(PP_Var var) {
315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // From ppb_var.h:
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  //   AddRef() adds a reference to the given var. If this is not a refcounted
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  //   object, this function will do nothing so you can always call it no matter
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  //   what the type.
355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  FakeVarData* var_data = GetVarData(var);
375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!var_data)
385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_GT(var_data->ref_count, 0)
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)       << "AddRefing freed " << Describe(*var_data);
425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  var_data->ref_count++;
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (debug)
445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    printf("AddRef of %s [new refcount=%d]\n",
455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           Describe(*var_data).c_str(),
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           var_data->ref_count);
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)std::string FakeVarManager::Describe(const FakeVarData& var_data) {
505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::stringstream rtn;
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  switch (var_data.type) {
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case PP_VARTYPE_STRING:
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      rtn << "String with id " << var_data.id <<
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)             " with value \"" << var_data.string_value << "\"";
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      break;
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case PP_VARTYPE_ARRAY:
575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      rtn << "Array of size " << var_data.array_value.size()
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          << " with id " << var_data.id;
595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      break;
605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case PP_VARTYPE_ARRAY_BUFFER:
615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      rtn << "ArrayBuffer of size " << var_data.buffer_value.length
625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          << " with id " << var_data.id;
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      break;
64f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    case PP_VARTYPE_DICTIONARY:
65f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      rtn << "Dictionary of size " << var_data.dict_value.size() << " with id "
66f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)          << var_data.id;
67f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      break;
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    default:
695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      rtn << "resource of type " << var_data.type
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          << " with id " << var_data.id;
715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      break;
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return rtn.str();
745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void FakeVarManager::DestroyVarData(FakeVarData* var_data) {
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Release each PP_Var in the array
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  switch (var_data->type) {
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    case PP_VARTYPE_ARRAY: {
810529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      FakeArrayType& vector = var_data->array_value;
820529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      for (FakeArrayType::iterator it = vector.begin();
830529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch           it != vector.end(); ++it) {
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        Release(*it);
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      }
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      vector.clear();
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      break;
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
890529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    case PP_VARTYPE_ARRAY_BUFFER: {
905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      free(var_data->buffer_value.ptr);
915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      var_data->buffer_value.ptr = NULL;
925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      var_data->buffer_value.length = 0;
930529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      break;
940529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    }
950529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    case PP_VARTYPE_DICTIONARY: {
960529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      FakeDictType& dict = var_data->dict_value;
970529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      for (FakeDictType::iterator it = dict.begin();
980529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch           it != dict.end(); it++) {
990529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch        Release(it->second);
1000529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      }
1010529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      dict.clear();
1020529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      break;
1030529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    }
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    default:
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      break;
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)FakeVarData* FakeVarManager::GetVarData(PP_Var var) {
110cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  switch (var.type) {
111cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // These types don't have any var data as their data
112cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // is stored directly in the var's value union.
113cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    case PP_VARTYPE_UNDEFINED:
114cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    case PP_VARTYPE_NULL:
115cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    case PP_VARTYPE_BOOL:
116cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    case PP_VARTYPE_INT32:
117cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    case PP_VARTYPE_DOUBLE:
118cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      return NULL;
119cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    default:
120cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      break;
121cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
122cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  VarMap::iterator iter = var_map_.find(var.value.as_id);
1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (iter == var_map_.end())
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return NULL;
1260529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  FakeVarData* var_data = &iter->second;
1270529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  EXPECT_GT(var_data->ref_count, 0)
1280529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      << "Accessing freed " << Describe(*var_data);
1290529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  return var_data;
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void FakeVarManager::Release(PP_Var var) {
1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // From ppb_var.h:
1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  //   Release() removes a reference to given var, deleting it if the internal
1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  //   reference count becomes 0. If the given var is not a refcounted object,
1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  //   this function will do nothing so you can always call it no matter what
1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  //   the type.
1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  FakeVarData* var_data = GetVarData(var);
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!var_data) {
1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (debug)
1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      printf("Releasing simple var\n");
1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return;
1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_GT(var_data->ref_count, 0)
1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      << "Releasing freed " << Describe(*var_data);
1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  var_data->ref_count--;
1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (debug)
1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    printf("Released %s [new refcount=%d]\n",
1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           Describe(*var_data).c_str(),
1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)           var_data->ref_count);
1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (var_data->ref_count == 0)
1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    DestroyVarData(var_data);
1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
157