1 /*
2 * Copyright (C) 2008, 2009 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(JSValue value)39 JSQuarantinedObjectWrapper* JSQuarantinedObjectWrapper::asWrapper(JSValue 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 JSValue JSQuarantinedObjectWrapper::cachedValueGetter(ExecState*, const Identifier&, const PropertySlot& slot)
53 {
54 JSValue 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->lexicalGlobalObject())
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->lexicalGlobalObject()->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 JSValue exception = unwrappedExecState()->exception();
91 unwrappedExecState()->clearException();
92 exec->setException(wrapOutgoingValue(unwrappedExecState(), exception));
93 }
94
markChildren(MarkStack & markStack)95 void JSQuarantinedObjectWrapper::markChildren(MarkStack& markStack)
96 {
97 JSObject::markChildren(markStack);
98
99 markStack.append(m_unwrappedObject);
100 markStack.append(m_unwrappedGlobalObject);
101 }
102
getOwnPropertySlot(ExecState * exec,const Identifier & identifier,PropertySlot & slot)103 bool JSQuarantinedObjectWrapper::getOwnPropertySlot(ExecState* exec, const Identifier& identifier, PropertySlot& slot)
104 {
105 if (!allowsGetProperty()) {
106 slot.setUndefined();
107 return true;
108 }
109
110 PropertySlot unwrappedSlot(m_unwrappedObject);
111 bool result = m_unwrappedObject->getOwnPropertySlot(unwrappedExecState(), identifier, unwrappedSlot);
112 if (result) {
113 JSValue unwrappedValue = unwrappedSlot.getValue(unwrappedExecState(), identifier);
114 slot.setCustom(wrapOutgoingValue(unwrappedExecState(), unwrappedValue), cachedValueGetter);
115 }
116
117 transferExceptionToExecState(exec);
118
119 return result;
120 }
121
getOwnPropertySlot(ExecState * exec,unsigned identifier,PropertySlot & slot)122 bool JSQuarantinedObjectWrapper::getOwnPropertySlot(ExecState* exec, unsigned identifier, PropertySlot& slot)
123 {
124 if (!allowsGetProperty()) {
125 slot.setUndefined();
126 return true;
127 }
128
129 PropertySlot unwrappedSlot(m_unwrappedObject);
130 bool result = m_unwrappedObject->getOwnPropertySlot(unwrappedExecState(), identifier, unwrappedSlot);
131 if (result) {
132 JSValue unwrappedValue = unwrappedSlot.getValue(unwrappedExecState(), identifier);
133 slot.setCustom(wrapOutgoingValue(unwrappedExecState(), unwrappedValue), cachedValueGetter);
134 }
135
136 transferExceptionToExecState(exec);
137
138 return result;
139 }
140
put(ExecState * exec,const Identifier & identifier,JSValue value,PutPropertySlot & slot)141 void JSQuarantinedObjectWrapper::put(ExecState* exec, const Identifier& identifier, JSValue value, PutPropertySlot& slot)
142 {
143 if (!allowsSetProperty())
144 return;
145
146 m_unwrappedObject->put(unwrappedExecState(), identifier, prepareIncomingValue(exec, value), slot);
147
148 transferExceptionToExecState(exec);
149 }
150
put(ExecState * exec,unsigned identifier,JSValue value)151 void JSQuarantinedObjectWrapper::put(ExecState* exec, unsigned identifier, JSValue value)
152 {
153 if (!allowsSetProperty())
154 return;
155
156 m_unwrappedObject->put(unwrappedExecState(), identifier, prepareIncomingValue(exec, value));
157
158 transferExceptionToExecState(exec);
159 }
160
deleteProperty(ExecState * exec,const Identifier & identifier)161 bool JSQuarantinedObjectWrapper::deleteProperty(ExecState* exec, const Identifier& identifier)
162 {
163 if (!allowsDeleteProperty())
164 return false;
165
166 bool result = m_unwrappedObject->deleteProperty(unwrappedExecState(), identifier);
167
168 transferExceptionToExecState(exec);
169
170 return result;
171 }
172
deleteProperty(ExecState * exec,unsigned identifier)173 bool JSQuarantinedObjectWrapper::deleteProperty(ExecState* exec, unsigned identifier)
174 {
175 if (!allowsDeleteProperty())
176 return false;
177
178 bool result = m_unwrappedObject->deleteProperty(unwrappedExecState(), identifier);
179
180 transferExceptionToExecState(exec);
181
182 return result;
183 }
184
construct(ExecState * exec,JSObject * constructor,const ArgList & args)185 JSObject* JSQuarantinedObjectWrapper::construct(ExecState* exec, JSObject* constructor, const ArgList& args)
186 {
187 JSQuarantinedObjectWrapper* wrapper = static_cast<JSQuarantinedObjectWrapper*>(constructor);
188
189 MarkedArgumentBuffer preparedArgs;
190 for (size_t i = 0; i < args.size(); ++i)
191 preparedArgs.append(wrapper->prepareIncomingValue(exec, args.at(i)));
192
193 // FIXME: Would be nice to find a way to reuse the result of m_unwrappedObject->getConstructData
194 // from when we called it in JSQuarantinedObjectWrapper::getConstructData.
195 ConstructData unwrappedConstructData;
196 ConstructType unwrappedConstructType = wrapper->m_unwrappedObject->getConstructData(unwrappedConstructData);
197 ASSERT(unwrappedConstructType != ConstructTypeNone);
198
199 JSValue unwrappedResult = JSC::construct(wrapper->unwrappedExecState(), wrapper->m_unwrappedObject, unwrappedConstructType, unwrappedConstructData, preparedArgs);
200
201 JSValue resultValue = wrapper->wrapOutgoingValue(wrapper->unwrappedExecState(), unwrappedResult);
202 ASSERT(resultValue.isObject());
203 JSObject* result = asObject(resultValue);
204
205 wrapper->transferExceptionToExecState(exec);
206
207 return result;
208 }
209
getConstructData(ConstructData & constructData)210 ConstructType JSQuarantinedObjectWrapper::getConstructData(ConstructData& constructData)
211 {
212 if (!allowsConstruct())
213 return ConstructTypeNone;
214 ConstructData unwrappedConstructData;
215 if (m_unwrappedObject->getConstructData(unwrappedConstructData) == ConstructTypeNone)
216 return ConstructTypeNone;
217 constructData.native.function = construct;
218 return ConstructTypeHost;
219 }
220
hasInstance(ExecState * exec,JSValue value,JSValue proto)221 bool JSQuarantinedObjectWrapper::hasInstance(ExecState* exec, JSValue value, JSValue proto)
222 {
223 if (!allowsHasInstance())
224 return false;
225
226 bool result = m_unwrappedObject->hasInstance(unwrappedExecState(), prepareIncomingValue(exec, value), prepareIncomingValue(exec, proto));
227
228 transferExceptionToExecState(exec);
229
230 return result;
231 }
232
call(ExecState * exec,JSObject * function,JSValue thisValue,const ArgList & args)233 JSValue JSQuarantinedObjectWrapper::call(ExecState* exec, JSObject* function, JSValue thisValue, const ArgList& args)
234 {
235 JSQuarantinedObjectWrapper* wrapper = static_cast<JSQuarantinedObjectWrapper*>(function);
236
237 JSValue preparedThisValue = wrapper->prepareIncomingValue(exec, thisValue);
238
239 MarkedArgumentBuffer preparedArgs;
240 for (size_t i = 0; i < args.size(); ++i)
241 preparedArgs.append(wrapper->prepareIncomingValue(exec, args.at(i)));
242
243 // FIXME: Would be nice to find a way to reuse the result of m_unwrappedObject->getCallData
244 // from when we called it in JSQuarantinedObjectWrapper::getCallData.
245 CallData unwrappedCallData;
246 CallType unwrappedCallType = wrapper->m_unwrappedObject->getCallData(unwrappedCallData);
247 ASSERT(unwrappedCallType != CallTypeNone);
248
249 JSValue unwrappedResult = JSC::call(wrapper->unwrappedExecState(), wrapper->m_unwrappedObject, unwrappedCallType, unwrappedCallData, preparedThisValue, preparedArgs);
250
251 JSValue result = wrapper->wrapOutgoingValue(wrapper->unwrappedExecState(), unwrappedResult);
252
253 wrapper->transferExceptionToExecState(exec);
254
255 return result;
256 }
257
getCallData(CallData & callData)258 CallType JSQuarantinedObjectWrapper::getCallData(CallData& callData)
259 {
260 if (!allowsCallAsFunction())
261 return CallTypeNone;
262 CallData unwrappedCallData;
263 if (m_unwrappedObject->getCallData(unwrappedCallData) == CallTypeNone)
264 return CallTypeNone;
265 callData.native.function = call;
266 return CallTypeHost;
267 }
268
getPropertyNames(ExecState *,PropertyNameArray & array)269 void JSQuarantinedObjectWrapper::getPropertyNames(ExecState*, PropertyNameArray& array)
270 {
271 if (!allowsGetPropertyNames())
272 return;
273
274 m_unwrappedObject->getPropertyNames(unwrappedExecState(), array);
275 }
276
277 } // namespace WebCore
278