• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 Apple 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
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 
26 #include "config.h"
27 #include "JSInspectedObjectWrapper.h"
28 
29 #include "JSInspectorCallbackWrapper.h"
30 #include <runtime/JSGlobalObject.h>
31 #include <wtf/StdLibExtras.h>
32 
33 using namespace JSC;
34 
35 namespace WebCore {
36 
37 ASSERT_CLASS_FITS_IN_CELL(JSInspectedObjectWrapper);
38 
39 typedef HashMap<JSObject*, JSInspectedObjectWrapper*> WrapperMap;
40 typedef HashMap<JSGlobalObject*, WrapperMap*> GlobalObjectWrapperMap;
41 
wrappers()42 static GlobalObjectWrapperMap& wrappers()
43 {
44     DEFINE_STATIC_LOCAL(GlobalObjectWrapperMap, map, ());
45     return map;
46 }
47 
48 const ClassInfo JSInspectedObjectWrapper::s_info = { "JSInspectedObjectWrapper", &JSQuarantinedObjectWrapper::s_info, 0, 0 };
49 
wrap(ExecState * unwrappedExec,JSValue unwrappedValue)50 JSValue JSInspectedObjectWrapper::wrap(ExecState* unwrappedExec, JSValue unwrappedValue)
51 {
52     if (!unwrappedValue.isObject())
53         return unwrappedValue;
54 
55     JSObject* unwrappedObject = asObject(unwrappedValue);
56 
57     if (unwrappedObject->inherits(&JSInspectedObjectWrapper::s_info))
58         return unwrappedObject;
59 
60     if (WrapperMap* wrapperMap = wrappers().get(unwrappedExec->lexicalGlobalObject()))
61         if (JSInspectedObjectWrapper* wrapper = wrapperMap->get(unwrappedObject))
62             return wrapper;
63 
64     JSValue prototype = unwrappedObject->prototype();
65     ASSERT(prototype.isNull() || prototype.isObject());
66 
67     if (prototype.isNull())
68         return new (unwrappedExec) JSInspectedObjectWrapper(unwrappedExec, unwrappedObject, JSQuarantinedObjectWrapper::createStructure(jsNull()));
69     return new (unwrappedExec) JSInspectedObjectWrapper(unwrappedExec, unwrappedObject, JSQuarantinedObjectWrapper::createStructure(asObject(wrap(unwrappedExec, prototype))));
70 }
71 
JSInspectedObjectWrapper(ExecState * unwrappedExec,JSObject * unwrappedObject,PassRefPtr<Structure> structure)72 JSInspectedObjectWrapper::JSInspectedObjectWrapper(ExecState* unwrappedExec, JSObject* unwrappedObject, PassRefPtr<Structure> structure)
73     : JSQuarantinedObjectWrapper(unwrappedExec, unwrappedObject, structure)
74 {
75     WrapperMap* wrapperMap = wrappers().get(unwrappedGlobalObject());
76     if (!wrapperMap) {
77         wrapperMap = new WrapperMap;
78         wrappers().set(unwrappedGlobalObject(), wrapperMap);
79     }
80 
81     ASSERT(!wrapperMap->contains(unwrappedObject));
82     wrapperMap->set(unwrappedObject, this);
83 }
84 
~JSInspectedObjectWrapper()85 JSInspectedObjectWrapper::~JSInspectedObjectWrapper()
86 {
87     ASSERT(wrappers().contains(unwrappedGlobalObject()));
88     WrapperMap* wrapperMap = wrappers().get(unwrappedGlobalObject());
89 
90     ASSERT(wrapperMap->contains(unwrappedObject()));
91     wrapperMap->remove(unwrappedObject());
92 
93     if (wrapperMap->isEmpty()) {
94         wrappers().remove(unwrappedGlobalObject());
95         delete wrapperMap;
96     }
97 }
98 
prepareIncomingValue(ExecState *,JSValue value) const99 JSValue JSInspectedObjectWrapper::prepareIncomingValue(ExecState*, JSValue value) const
100 {
101     // The Inspector is only allowed to pass primitive values and wrapped objects to objects from the inspected page.
102 
103     if (!value.isObject())
104         return value;
105 
106     JSQuarantinedObjectWrapper* wrapper = asWrapper(value);
107     ASSERT_WITH_MESSAGE(wrapper, "Objects passed to JSInspectedObjectWrapper must be wrapped");
108     if (!wrapper)
109         return jsUndefined();
110 
111     if (wrapper->allowsUnwrappedAccessFrom(unwrappedExecState())) {
112         ASSERT_WITH_MESSAGE(wrapper->inherits(&s_info), "A wrapper contains an object from the inspected page but is not a JSInspectedObjectWrapper");
113         if (!wrapper->inherits(&s_info))
114             return jsUndefined();
115 
116         // Return the unwrapped object so the inspected page never sees one of its own objects in wrapped form.
117         return wrapper->unwrappedObject();
118     }
119 
120     ASSERT_WITH_MESSAGE(wrapper->inherits(&JSInspectorCallbackWrapper::s_info), "A wrapper that was not from the inspected page and is not an Inspector callback was passed to a JSInspectedObjectWrapper");
121     if (!wrapper->inherits(&JSInspectorCallbackWrapper::s_info))
122         return jsUndefined();
123 
124     return wrapper;
125 }
126 
127 } // namespace WebCore
128