WebCore/bindings/v8/npruntime.cpp
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     1 /*
       
     2  * Copyright (C) 2004, 2006 Apple Computer, Inc.  All rights reserved.
       
     3  * Copyright (C) 2007-2009 Google, Inc.  All rights reserved.
       
     4  *
       
     5  * Redistribution and use in source and binary forms, with or without
       
     6  * modification, are permitted provided that the following conditions
       
     7  * are met:
       
     8  * 1. Redistributions of source code must retain the above copyright
       
     9  *    notice, this list of conditions and the following disclaimer.
       
    10  * 2. Redistributions in binary form must reproduce the above copyright
       
    11  *    notice, this list of conditions and the following disclaimer in the
       
    12  *    documentation and/or other materials provided with the distribution.
       
    13  *
       
    14  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
       
    15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
       
    16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
       
    17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
       
    18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
       
    19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
       
    20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
       
    21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
       
    22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
       
    23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
       
    24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
       
    25  */
       
    26 
       
    27 #include "config.h"
       
    28 
       
    29 #include "NPV8Object.h"
       
    30 #include "npruntime_impl.h"
       
    31 #include "npruntime_priv.h"
       
    32 #include "V8NPObject.h"
       
    33 
       
    34 #include <wtf/HashMap.h>
       
    35 #include <wtf/HashSet.h>
       
    36 #include <wtf/Assertions.h>
       
    37 
       
    38 using namespace WebCore;
       
    39 
       
    40 // FIXME: Consider removing locks if we're singlethreaded already.
       
    41 // The static initializer here should work okay, but we want to avoid
       
    42 // static initialization in general.
       
    43 
       
    44 namespace npruntime {
       
    45 
       
    46 // We use StringKey here as the key-type to avoid a string copy to
       
    47 // construct the map key and for faster comparisons than strcmp.
       
    48 class StringKey {
       
    49 public:
       
    50     explicit StringKey(const char* str) : m_string(str), m_length(strlen(str)) { }
       
    51     StringKey() : m_string(0), m_length(0) { }
       
    52     explicit StringKey(WTF::HashTableDeletedValueType) : m_string(hashTableDeletedValue()), m_length(0) { }
       
    53 
       
    54     StringKey& operator=(const StringKey& other)
       
    55     {
       
    56         this->m_string = other.m_string;
       
    57         this->m_length = other.m_length;
       
    58         return *this;
       
    59     }
       
    60 
       
    61     bool isHashTableDeletedValue() const
       
    62     {
       
    63         return m_string == hashTableDeletedValue();
       
    64     }
       
    65 
       
    66     const char* m_string;
       
    67     size_t m_length;
       
    68 
       
    69 private:
       
    70     const char* hashTableDeletedValue() const
       
    71     {
       
    72         return reinterpret_cast<const char*>(-1);
       
    73     }
       
    74 };
       
    75 
       
    76 inline bool operator==(const StringKey& x, const StringKey& y)
       
    77 {
       
    78     if (x.m_length != y.m_length)
       
    79         return false;
       
    80     if (x.m_string == y.m_string)
       
    81         return true;
       
    82 
       
    83     ASSERT(!x.isHashTableDeletedValue() && !y.isHashTableDeletedValue());
       
    84     return !memcmp(x.m_string, y.m_string, y.m_length);
       
    85 }
       
    86 
       
    87 // Implement WTF::DefaultHash<StringKey>::Hash interface.
       
    88 struct StringKeyHash {
       
    89     static unsigned hash(const StringKey& key)
       
    90     {
       
    91         // Compute string hash.
       
    92         unsigned hash = 0;
       
    93         size_t len = key.m_length;
       
    94         const char* str = key.m_string;
       
    95         for (size_t i = 0; i < len; i++) {
       
    96             char c = str[i];
       
    97             hash += c;
       
    98             hash += (hash << 10);
       
    99             hash ^= (hash >> 6);
       
   100         }
       
   101         hash += (hash << 3);
       
   102         hash ^= (hash >> 11);
       
   103         hash += (hash << 15);
       
   104         if (hash == 0)
       
   105             hash = 27;
       
   106         return hash;
       
   107     }
       
   108 
       
   109     static bool equal(const StringKey& x, const StringKey& y)
       
   110     {
       
   111         return x == y;
       
   112     }
       
   113 
       
   114     static const bool safeToCompareToEmptyOrDeleted = true;
       
   115 };
       
   116 
       
   117 }  // namespace npruntime
       
   118 
       
   119 using npruntime::StringKey;
       
   120 using npruntime::StringKeyHash;
       
   121 
       
   122 // Implement HashTraits<StringKey>
       
   123 struct StringKeyHashTraits : WTF::GenericHashTraits<StringKey> {
       
   124     static void constructDeletedValue(StringKey& slot)
       
   125     {
       
   126         new (&slot) StringKey(WTF::HashTableDeletedValue);
       
   127     }
       
   128 
       
   129     static bool isDeletedValue(const StringKey& value)
       
   130     {
       
   131         return value.isHashTableDeletedValue();
       
   132     }
       
   133 };
       
   134 
       
   135 typedef WTF::HashMap<StringKey, PrivateIdentifier*, StringKeyHash, StringKeyHashTraits> StringIdentifierMap;
       
   136 
       
   137 static StringIdentifierMap* getStringIdentifierMap()
       
   138 {
       
   139     static StringIdentifierMap* stringIdentifierMap = 0;
       
   140     if (!stringIdentifierMap)
       
   141         stringIdentifierMap = new StringIdentifierMap();
       
   142     return stringIdentifierMap;
       
   143 }
       
   144 
       
   145 typedef WTF::HashMap<int, PrivateIdentifier*> IntIdentifierMap;
       
   146 
       
   147 static IntIdentifierMap* getIntIdentifierMap()
       
   148 {
       
   149     static IntIdentifierMap* intIdentifierMap = 0;
       
   150     if (!intIdentifierMap)
       
   151         intIdentifierMap = new IntIdentifierMap();
       
   152     return intIdentifierMap;
       
   153 }
       
   154 
       
   155 extern "C" {
       
   156 
       
   157 NPIdentifier _NPN_GetStringIdentifier(const NPUTF8* name)
       
   158 {
       
   159     ASSERT(name);
       
   160 
       
   161     if (name) {
       
   162 
       
   163         StringKey key(name);
       
   164         StringIdentifierMap* identMap = getStringIdentifierMap();
       
   165         StringIdentifierMap::iterator iter = identMap->find(key);
       
   166         if (iter != identMap->end())
       
   167             return static_cast<NPIdentifier>(iter->second);
       
   168 
       
   169         size_t nameLen = key.m_length;
       
   170 
       
   171         // We never release identifiers, so this dictionary will grow.
       
   172         PrivateIdentifier* identifier = static_cast<PrivateIdentifier*>(malloc(sizeof(PrivateIdentifier) + nameLen + 1));
       
   173         char* nameStorage = reinterpret_cast<char*>(identifier + 1);
       
   174         memcpy(nameStorage, name, nameLen + 1);
       
   175         identifier->isString = true;
       
   176         identifier->value.string = reinterpret_cast<NPUTF8*>(nameStorage);
       
   177         key.m_string = nameStorage;
       
   178         identMap->set(key, identifier);
       
   179         return (NPIdentifier)identifier;
       
   180     }
       
   181 
       
   182     return 0;
       
   183 }
       
   184 
       
   185 void _NPN_GetStringIdentifiers(const NPUTF8** names, int32_t nameCount, NPIdentifier* identifiers)
       
   186 {
       
   187     ASSERT(names);
       
   188     ASSERT(identifiers);
       
   189 
       
   190     if (names && identifiers) {
       
   191         for (int i = 0; i < nameCount; i++)
       
   192             identifiers[i] = _NPN_GetStringIdentifier(names[i]);
       
   193     }
       
   194 }
       
   195 
       
   196 NPIdentifier _NPN_GetIntIdentifier(int32_t intId)
       
   197 {
       
   198     // Special case for -1 and 0, both cannot be used as key in HashMap.
       
   199     if (!intId || intId == -1) {
       
   200         static PrivateIdentifier* minusOneOrZeroIds[2];
       
   201         PrivateIdentifier* id = minusOneOrZeroIds[intId + 1];
       
   202         if (!id) {
       
   203             id = reinterpret_cast<PrivateIdentifier*>(malloc(sizeof(PrivateIdentifier)));
       
   204             id->isString = false;
       
   205             id->value.number = intId;
       
   206             minusOneOrZeroIds[intId + 1] = id;
       
   207         }
       
   208         return (NPIdentifier) id;
       
   209     }
       
   210 
       
   211     IntIdentifierMap* identMap = getIntIdentifierMap();
       
   212     IntIdentifierMap::iterator iter = identMap->find(intId);
       
   213     if (iter != identMap->end())
       
   214         return static_cast<NPIdentifier>(iter->second);
       
   215 
       
   216     // We never release identifiers, so this dictionary will grow.
       
   217     PrivateIdentifier* identifier = reinterpret_cast<PrivateIdentifier*>(malloc(sizeof(PrivateIdentifier)));
       
   218     identifier->isString = false;
       
   219     identifier->value.number = intId;
       
   220     identMap->set(intId, identifier);
       
   221     return (NPIdentifier)identifier;
       
   222 }
       
   223 
       
   224 bool _NPN_IdentifierIsString(NPIdentifier identifier)
       
   225 {
       
   226     PrivateIdentifier* privateIdentifier = reinterpret_cast<PrivateIdentifier*>(identifier);
       
   227     return privateIdentifier->isString;
       
   228 }
       
   229 
       
   230 NPUTF8 *_NPN_UTF8FromIdentifier(NPIdentifier identifier)
       
   231 {
       
   232     PrivateIdentifier* privateIdentifier = reinterpret_cast<PrivateIdentifier*>(identifier);
       
   233     if (!privateIdentifier->isString || !privateIdentifier->value.string)
       
   234         return 0;
       
   235 
       
   236     return (NPUTF8*) strdup(privateIdentifier->value.string);
       
   237 }
       
   238 
       
   239 int32_t _NPN_IntFromIdentifier(NPIdentifier identifier)
       
   240 {
       
   241     PrivateIdentifier* privateIdentifier = reinterpret_cast<PrivateIdentifier*>(identifier);
       
   242     if (privateIdentifier->isString)
       
   243         return 0;
       
   244     return privateIdentifier->value.number;
       
   245 }
       
   246 
       
   247 void _NPN_ReleaseVariantValue(NPVariant* variant)
       
   248 {
       
   249     ASSERT(variant);
       
   250 
       
   251     if (variant->type == NPVariantType_Object) {
       
   252         _NPN_ReleaseObject(variant->value.objectValue);
       
   253         variant->value.objectValue = 0;
       
   254     } else if (variant->type == NPVariantType_String) {
       
   255         free((void*)variant->value.stringValue.UTF8Characters);
       
   256         variant->value.stringValue.UTF8Characters = 0;
       
   257         variant->value.stringValue.UTF8Length = 0;
       
   258     }
       
   259 
       
   260     variant->type = NPVariantType_Void;
       
   261 }
       
   262 
       
   263 NPObject *_NPN_CreateObject(NPP npp, NPClass* npClass)
       
   264 {
       
   265     ASSERT(npClass);
       
   266 
       
   267     if (npClass) {
       
   268         NPObject* npObject;
       
   269         if (npClass->allocate != 0)
       
   270             npObject = npClass->allocate(npp, npClass);
       
   271         else
       
   272             npObject = reinterpret_cast<NPObject*>(malloc(sizeof(NPObject)));
       
   273 
       
   274         npObject->_class = npClass;
       
   275         npObject->referenceCount = 1;
       
   276         return npObject;
       
   277     }
       
   278 
       
   279     return 0;
       
   280 }
       
   281 
       
   282 NPObject* _NPN_RetainObject(NPObject* npObject)
       
   283 {
       
   284     ASSERT(npObject);
       
   285     ASSERT(npObject->referenceCount > 0);
       
   286 
       
   287     if (npObject)
       
   288         npObject->referenceCount++;
       
   289 
       
   290     return npObject;
       
   291 }
       
   292 
       
   293 // _NPN_DeallocateObject actually deletes the object.  Technically,
       
   294 // callers should use _NPN_ReleaseObject.  Webkit exposes this function
       
   295 // to kill objects which plugins may not have properly released.
       
   296 void _NPN_DeallocateObject(NPObject* npObject)
       
   297 {
       
   298     ASSERT(npObject);
       
   299 
       
   300     if (npObject) {
       
   301         // NPObjects that remain in pure C++ may never have wrappers.
       
   302         // Hence, if it's not already alive, don't unregister it.
       
   303         // If it is alive, unregister it as the *last* thing we do
       
   304         // so that it can do as much cleanup as possible on its own.
       
   305         if (_NPN_IsAlive(npObject))
       
   306             _NPN_UnregisterObject(npObject);
       
   307 
       
   308         npObject->referenceCount = -1;
       
   309         if (npObject->_class->deallocate)
       
   310             npObject->_class->deallocate(npObject);
       
   311         else
       
   312             free(npObject);
       
   313     }
       
   314 }
       
   315 
       
   316 void _NPN_ReleaseObject(NPObject* npObject)
       
   317 {
       
   318     ASSERT(npObject);
       
   319     ASSERT(npObject->referenceCount >= 1);
       
   320 
       
   321     if (npObject && npObject->referenceCount >= 1) {
       
   322         if (!--npObject->referenceCount)
       
   323             _NPN_DeallocateObject(npObject);
       
   324     }
       
   325 }
       
   326 
       
   327 void _NPN_InitializeVariantWithStringCopy(NPVariant* variant, const NPString* value)
       
   328 {
       
   329     variant->type = NPVariantType_String;
       
   330     variant->value.stringValue.UTF8Length = value->UTF8Length;
       
   331     variant->value.stringValue.UTF8Characters = reinterpret_cast<NPUTF8*>(malloc(sizeof(NPUTF8) * value->UTF8Length));
       
   332     memcpy((void*)variant->value.stringValue.UTF8Characters, value->UTF8Characters, sizeof(NPUTF8) * value->UTF8Length);
       
   333 }
       
   334 
       
   335 
       
   336 // NPN_Registry
       
   337 //
       
   338 // The registry is designed for quick lookup of NPObjects.
       
   339 // JS needs to be able to quickly lookup a given NPObject to determine
       
   340 // if it is alive or not.
       
   341 // The browser needs to be able to quickly lookup all NPObjects which are
       
   342 // "owned" by an object.
       
   343 //
       
   344 // The liveObjectMap is a hash table of all live objects to their owner
       
   345 // objects.  Presence in this table is used primarily to determine if
       
   346 // objects are live or not.
       
   347 //
       
   348 // The rootObjectMap is a hash table of root objects to a set of
       
   349 // objects that should be deactivated in sync with the root.  A
       
   350 // root is defined as a top-level owner object.  This is used on
       
   351 // Frame teardown to deactivate all objects associated
       
   352 // with a particular plugin.
       
   353 
       
   354 typedef WTF::HashSet<NPObject*> NPObjectSet;
       
   355 typedef WTF::HashMap<NPObject*, NPObject*> NPObjectMap;
       
   356 typedef WTF::HashMap<NPObject*, NPObjectSet*> NPRootObjectMap;
       
   357 
       
   358 // A map of live NPObjects with pointers to their Roots.
       
   359 NPObjectMap liveObjectMap;
       
   360 
       
   361 // A map of the root objects and the list of NPObjects
       
   362 // associated with that object.
       
   363 NPRootObjectMap rootObjectMap;
       
   364 
       
   365 void _NPN_RegisterObject(NPObject* npObject, NPObject* owner)
       
   366 {
       
   367     ASSERT(npObject);
       
   368 
       
   369     // Check if already registered.
       
   370     if (liveObjectMap.find(npObject) != liveObjectMap.end())
       
   371         return;
       
   372 
       
   373     if (!owner) {
       
   374         // Registering a new owner object.
       
   375         ASSERT(rootObjectMap.find(npObject) == rootObjectMap.end());
       
   376         rootObjectMap.set(npObject, new NPObjectSet());
       
   377     } else {
       
   378         // Always associate this object with it's top-most parent.
       
   379         // Since we always flatten, we only have to look up one level.
       
   380         NPObjectMap::iterator ownerEntry = liveObjectMap.find(owner);
       
   381         NPObject* parent = 0;
       
   382         if (liveObjectMap.end() != ownerEntry)
       
   383             parent = ownerEntry->second;
       
   384 
       
   385         if (parent)
       
   386             owner = parent;
       
   387         ASSERT(rootObjectMap.find(npObject) == rootObjectMap.end());
       
   388         if (rootObjectMap.find(owner) != rootObjectMap.end())
       
   389             rootObjectMap.get(owner)->add(npObject);
       
   390     }
       
   391 
       
   392     ASSERT(liveObjectMap.find(npObject) == liveObjectMap.end());
       
   393     liveObjectMap.set(npObject, owner);
       
   394 }
       
   395 
       
   396 void _NPN_UnregisterObject(NPObject* npObject)
       
   397 {
       
   398     ASSERT(npObject);
       
   399     ASSERT(liveObjectMap.find(npObject) != liveObjectMap.end());
       
   400 
       
   401     NPObject* owner = 0;
       
   402     if (liveObjectMap.find(npObject) != liveObjectMap.end())
       
   403         owner = liveObjectMap.find(npObject)->second;
       
   404 
       
   405     if (!owner) {
       
   406         // Unregistering a owner object; also unregister it's descendants.
       
   407         ASSERT(rootObjectMap.find(npObject) != rootObjectMap.end());
       
   408         NPObjectSet* set = rootObjectMap.get(npObject);
       
   409         while (set->size() > 0) {
       
   410 #ifndef NDEBUG
       
   411             int size = set->size();
       
   412 #endif
       
   413             NPObject* sub_object = *(set->begin());
       
   414             // The sub-object should not be a owner!
       
   415             ASSERT(rootObjectMap.find(sub_object) == rootObjectMap.end());
       
   416 
       
   417             // First, unregister the object.
       
   418             set->remove(sub_object);
       
   419             liveObjectMap.remove(sub_object);
       
   420 
       
   421             // Remove the JS references to the object.
       
   422             forgetV8ObjectForNPObject(sub_object);
       
   423 
       
   424             ASSERT(set->size() < size);
       
   425         }
       
   426         delete set;
       
   427         rootObjectMap.remove(npObject);
       
   428     } else {
       
   429         NPRootObjectMap::iterator ownerEntry = rootObjectMap.find(owner);
       
   430         if (ownerEntry != rootObjectMap.end()) {
       
   431             NPObjectSet* list = ownerEntry->second;
       
   432             ASSERT(list->find(npObject) != list->end());
       
   433             list->remove(npObject);
       
   434         }
       
   435     }
       
   436 
       
   437     liveObjectMap.remove(npObject);
       
   438     forgetV8ObjectForNPObject(npObject);
       
   439 }
       
   440 
       
   441 bool _NPN_IsAlive(NPObject* npObject)
       
   442 {
       
   443     return liveObjectMap.find(npObject) != liveObjectMap.end();
       
   444 }
       
   445 
       
   446 }  // extern "C"