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