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 "JSQuarantinedObjectWrapper.h"
28
29 #include <runtime/JSGlobalObject.h>
30
31 using namespace JSC;
32
33 namespace WebCore {
34
35 ASSERT_CLASS_FITS_IN_CELL(JSQuarantinedObjectWrapper)
36
37 const ClassInfo JSQuarantinedObjectWrapper::s_info = { "JSQuarantinedObjectWrapper", 0, 0, 0 };
38
asWrapper(JSValuePtr value)39 JSQuarantinedObjectWrapper* JSQuarantinedObjectWrapper::asWrapper(JSValuePtr value)
40 {
41 if (!value.isObject())
42 return 0;
43
44 JSObject* object = asObject(value);
45
46 if (!object->inherits(&JSQuarantinedObjectWrapper::s_info))
47 return 0;
48
49 return static_cast<JSQuarantinedObjectWrapper*>(object);
50 }
51
cachedValueGetter(ExecState *,const Identifier &,const PropertySlot & slot)52 JSValuePtr JSQuarantinedObjectWrapper::cachedValueGetter(ExecState*, const Identifier&, const PropertySlot& slot)
53 {
54 JSValuePtr v = slot.slotBase();
55 ASSERT(v);
56 return v;
57 }
58
JSQuarantinedObjectWrapper(ExecState * unwrappedExec,JSObject * unwrappedObject,PassRefPtr<Structure> structure)59 JSQuarantinedObjectWrapper::JSQuarantinedObjectWrapper(ExecState* unwrappedExec, JSObject* unwrappedObject, PassRefPtr<Structure> structure)
60 : JSObject(structure)
61 , m_unwrappedGlobalObject(unwrappedExec->dynamicGlobalObject())
62 , m_unwrappedObject(unwrappedObject)
63 {
64 ASSERT_ARG(unwrappedExec, unwrappedExec);
65 ASSERT_ARG(unwrappedObject, unwrappedObject);
66 ASSERT(this->structure());
67 }
68
~JSQuarantinedObjectWrapper()69 JSQuarantinedObjectWrapper::~JSQuarantinedObjectWrapper()
70 {
71 }
72
allowsUnwrappedAccessFrom(ExecState * exec) const73 bool JSQuarantinedObjectWrapper::allowsUnwrappedAccessFrom(ExecState* exec) const
74 {
75 return m_unwrappedGlobalObject->profileGroup() == exec->dynamicGlobalObject()->profileGroup();
76 }
77
unwrappedExecState() const78 ExecState* JSQuarantinedObjectWrapper::unwrappedExecState() const
79 {
80 return m_unwrappedGlobalObject->globalExec();
81 }
82
transferExceptionToExecState(ExecState * exec) const83 void JSQuarantinedObjectWrapper::transferExceptionToExecState(ExecState* exec) const
84 {
85 ASSERT(exec != unwrappedExecState());
86
87 if (!unwrappedExecState()->hadException())
88 return;
89
90 exec->setException(wrapOutgoingValue(unwrappedExecState(), unwrappedExecState()->exception()));
91 unwrappedExecState()->clearException();
92 }
93
mark()94 void JSQuarantinedObjectWrapper::mark()
95 {
96 JSObject::mark();
97
98 if (!m_unwrappedObject->marked())
99 m_unwrappedObject->mark();
100 if (!m_unwrappedGlobalObject->marked())
101 m_unwrappedGlobalObject->mark();
102 }
103
getOwnPropertySlot(ExecState * exec,const Identifier & identifier,PropertySlot & slot)104 bool JSQuarantinedObjectWrapper::getOwnPropertySlot(ExecState* exec, const Identifier& identifier, PropertySlot& slot)
105 {
106 if (!allowsGetProperty()) {
107 slot.setUndefined();
108 return true;
109 }
110
111 PropertySlot unwrappedSlot(m_unwrappedObject);
112 bool result = m_unwrappedObject->getOwnPropertySlot(unwrappedExecState(), identifier, unwrappedSlot);
113 if (result) {
114 JSValuePtr unwrappedValue = unwrappedSlot.getValue(unwrappedExecState(), identifier);
115 slot.setCustom(wrapOutgoingValue(unwrappedExecState(), unwrappedValue), cachedValueGetter);
116 }
117
118 transferExceptionToExecState(exec);
119
120 return result;
121 }
122
getOwnPropertySlot(ExecState * exec,unsigned identifier,PropertySlot & slot)123 bool JSQuarantinedObjectWrapper::getOwnPropertySlot(ExecState* exec, unsigned identifier, PropertySlot& slot)
124 {
125 if (!allowsGetProperty()) {
126 slot.setUndefined();
127 return true;
128 }
129
130 PropertySlot unwrappedSlot(m_unwrappedObject);
131 bool result = m_unwrappedObject->getOwnPropertySlot(unwrappedExecState(), identifier, unwrappedSlot);
132 if (result) {
133 JSValuePtr unwrappedValue = unwrappedSlot.getValue(unwrappedExecState(), identifier);
134 slot.setCustom(wrapOutgoingValue(unwrappedExecState(), unwrappedValue), cachedValueGetter);
135 }
136
137 transferExceptionToExecState(exec);
138
139 return result;
140 }
141
put(ExecState * exec,const Identifier & identifier,JSValuePtr value,PutPropertySlot & slot)142 void JSQuarantinedObjectWrapper::put(ExecState* exec, const Identifier& identifier, JSValuePtr value, PutPropertySlot& slot)
143 {
144 if (!allowsSetProperty())
145 return;
146
147 m_unwrappedObject->put(unwrappedExecState(), identifier, prepareIncomingValue(exec, value), slot);
148
149 transferExceptionToExecState(exec);
150 }
151
put(ExecState * exec,unsigned identifier,JSValuePtr value)152 void JSQuarantinedObjectWrapper::put(ExecState* exec, unsigned identifier, JSValuePtr value)
153 {
154 if (!allowsSetProperty())
155 return;
156
157 m_unwrappedObject->put(unwrappedExecState(), identifier, prepareIncomingValue(exec, value));
158
159 transferExceptionToExecState(exec);
160 }
161
deleteProperty(ExecState * exec,const Identifier & identifier)162 bool JSQuarantinedObjectWrapper::deleteProperty(ExecState* exec, const Identifier& identifier)
163 {
164 if (!allowsDeleteProperty())
165 return false;
166
167 bool result = m_unwrappedObject->deleteProperty(unwrappedExecState(), identifier);
168
169 transferExceptionToExecState(exec);
170
171 return result;
172 }
173
deleteProperty(ExecState * exec,unsigned identifier)174 bool JSQuarantinedObjectWrapper::deleteProperty(ExecState* exec, unsigned identifier)
175 {
176 if (!allowsDeleteProperty())
177 return false;
178
179 bool result = m_unwrappedObject->deleteProperty(unwrappedExecState(), identifier);
180
181 transferExceptionToExecState(exec);
182
183 return result;
184 }
185
construct(ExecState * exec,JSObject * constructor,const ArgList & args)186 JSObject* JSQuarantinedObjectWrapper::construct(ExecState* exec, JSObject* constructor, const ArgList& args)
187 {
188 JSQuarantinedObjectWrapper* wrapper = static_cast<JSQuarantinedObjectWrapper*>(constructor);
189
190 ArgList preparedArgs;
191 for (size_t i = 0; i < args.size(); ++i)
192 preparedArgs.append(wrapper->prepareIncomingValue(exec, args.at(exec, i)));
193
194 // FIXME: Would be nice to find a way to reuse the result of m_unwrappedObject->getConstructData
195 // from when we called it in JSQuarantinedObjectWrapper::getConstructData.
196 ConstructData unwrappedConstructData;
197 ConstructType unwrappedConstructType = wrapper->m_unwrappedObject->getConstructData(unwrappedConstructData);
198 ASSERT(unwrappedConstructType != ConstructTypeNone);
199
200 JSValuePtr unwrappedResult = JSC::construct(wrapper->unwrappedExecState(), wrapper->m_unwrappedObject, unwrappedConstructType, unwrappedConstructData, preparedArgs);
201
202 JSValuePtr resultValue = wrapper->wrapOutgoingValue(wrapper->unwrappedExecState(), unwrappedResult);
203 ASSERT(resultValue.isObject());
204 JSObject* result = asObject(resultValue);
205
206 wrapper->transferExceptionToExecState(exec);
207
208 return result;
209 }
210
getConstructData(ConstructData & constructData)211 ConstructType JSQuarantinedObjectWrapper::getConstructData(ConstructData& constructData)
212 {
213 if (!allowsConstruct())
214 return ConstructTypeNone;
215 ConstructData unwrappedConstructData;
216 if (m_unwrappedObject->getConstructData(unwrappedConstructData) == ConstructTypeNone)
217 return ConstructTypeNone;
218 constructData.native.function = construct;
219 return ConstructTypeHost;
220 }
221
hasInstance(ExecState * exec,JSValuePtr value,JSValuePtr proto)222 bool JSQuarantinedObjectWrapper::hasInstance(ExecState* exec, JSValuePtr value, JSValuePtr proto)
223 {
224 if (!allowsHasInstance())
225 return false;
226
227 bool result = m_unwrappedObject->hasInstance(unwrappedExecState(), prepareIncomingValue(exec, value), prepareIncomingValue(exec, proto));
228
229 transferExceptionToExecState(exec);
230
231 return result;
232 }
233
call(ExecState * exec,JSObject * function,JSValuePtr thisValue,const ArgList & args)234 JSValuePtr JSQuarantinedObjectWrapper::call(ExecState* exec, JSObject* function, JSValuePtr thisValue, const ArgList& args)
235 {
236 JSQuarantinedObjectWrapper* wrapper = static_cast<JSQuarantinedObjectWrapper*>(function);
237
238 JSValuePtr preparedThisValue = wrapper->prepareIncomingValue(exec, thisValue);
239
240 ArgList preparedArgs;
241 for (size_t i = 0; i < args.size(); ++i)
242 preparedArgs.append(wrapper->prepareIncomingValue(exec, args.at(exec, i)));
243
244 // FIXME: Would be nice to find a way to reuse the result of m_unwrappedObject->getCallData
245 // from when we called it in JSQuarantinedObjectWrapper::getCallData.
246 CallData unwrappedCallData;
247 CallType unwrappedCallType = wrapper->m_unwrappedObject->getCallData(unwrappedCallData);
248 ASSERT(unwrappedCallType != CallTypeNone);
249
250 JSValuePtr unwrappedResult = JSC::call(wrapper->unwrappedExecState(), wrapper->m_unwrappedObject, unwrappedCallType, unwrappedCallData, preparedThisValue, preparedArgs);
251
252 JSValuePtr result = wrapper->wrapOutgoingValue(wrapper->unwrappedExecState(), unwrappedResult);
253
254 wrapper->transferExceptionToExecState(exec);
255
256 return result;
257 }
258
getCallData(CallData & callData)259 CallType JSQuarantinedObjectWrapper::getCallData(CallData& callData)
260 {
261 if (!allowsCallAsFunction())
262 return CallTypeNone;
263 CallData unwrappedCallData;
264 if (m_unwrappedObject->getCallData(unwrappedCallData) == CallTypeNone)
265 return CallTypeNone;
266 callData.native.function = call;
267 return CallTypeHost;
268 }
269
getPropertyNames(ExecState *,PropertyNameArray & array)270 void JSQuarantinedObjectWrapper::getPropertyNames(ExecState*, PropertyNameArray& array)
271 {
272 if (!allowsGetPropertyNames())
273 return;
274
275 m_unwrappedObject->getPropertyNames(unwrappedExecState(), array);
276 }
277
278 } // namespace WebCore
279