1 | /* |
2 | * Copyright (C) 2006, 2008 Apple Inc. All rights reserved. |
3 | * Copyright (C) 2007 Eric Seidel <eric@webkit.org> |
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 "APIShims.h" |
28 | #include "APICast.h" |
29 | #include "Error.h" |
30 | #include "JSCallbackFunction.h" |
31 | #include "JSClassRef.h" |
32 | #include "JSGlobalObject.h" |
33 | #include "JSLock.h" |
34 | #include "JSObjectRef.h" |
35 | #include "JSString.h" |
36 | #include "JSStringRef.h" |
37 | #include "OpaqueJSString.h" |
38 | #include "PropertyNameArray.h" |
39 | #include <wtf/Vector.h> |
40 | |
41 | namespace JSC { |
42 | |
43 | template <class Base> |
44 | inline JSCallbackObject<Base>* JSCallbackObject<Base>::asCallbackObject(JSValue value) |
45 | { |
46 | ASSERT(asObject(value)->inherits(&info)); |
47 | return static_cast<JSCallbackObject*>(asObject(value)); |
48 | } |
49 | |
50 | template <class Base> |
51 | JSCallbackObject<Base>::JSCallbackObject(ExecState* exec, NonNullPassRefPtr<Structure> structure, JSClassRef jsClass, void* data) |
52 | : Base(structure) |
53 | , m_callbackObjectData(new JSCallbackObjectData(data, jsClass)) |
54 | { |
55 | init(exec); |
56 | } |
57 | |
58 | // Global object constructor. |
59 | // FIXME: Move this into a separate JSGlobalCallbackObject class derived from this one. |
60 | template <class Base> |
61 | JSCallbackObject<Base>::JSCallbackObject(JSClassRef jsClass) |
62 | : Base() |
63 | , m_callbackObjectData(new JSCallbackObjectData(0, jsClass)) |
64 | { |
65 | ASSERT(Base::isGlobalObject()); |
66 | init(static_cast<JSGlobalObject*>(this)->globalExec()); |
67 | } |
68 | |
69 | template <class Base> |
70 | void JSCallbackObject<Base>::init(ExecState* exec) |
71 | { |
72 | ASSERT(exec); |
73 | |
74 | Vector<JSObjectInitializeCallback, 16> initRoutines; |
75 | JSClassRef jsClass = classRef(); |
76 | do { |
77 | if (JSObjectInitializeCallback initialize = jsClass->initialize) |
78 | initRoutines.append(val: initialize); |
79 | } while ((jsClass = jsClass->parentClass)); |
80 | |
81 | // initialize from base to derived |
82 | for (int i = static_cast<int>(initRoutines.size()) - 1; i >= 0; i--) { |
83 | APICallbackShim callbackShim(exec); |
84 | JSObjectInitializeCallback initialize = initRoutines[i]; |
85 | initialize(toRef(e: exec), toRef(this)); |
86 | } |
87 | } |
88 | |
89 | template <class Base> |
90 | JSCallbackObject<Base>::~JSCallbackObject() |
91 | { |
92 | JSObjectRef thisRef = toRef(this); |
93 | |
94 | for (JSClassRef jsClass = classRef(); jsClass; jsClass = jsClass->parentClass) |
95 | if (JSObjectFinalizeCallback finalize = jsClass->finalize) |
96 | finalize(thisRef); |
97 | } |
98 | |
99 | template <class Base> |
100 | UString JSCallbackObject<Base>::className() const |
101 | { |
102 | UString thisClassName = classRef()->className(); |
103 | if (!thisClassName.isEmpty()) |
104 | return thisClassName; |
105 | |
106 | return Base::className(); |
107 | } |
108 | |
109 | template <class Base> |
110 | bool JSCallbackObject<Base>::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) |
111 | { |
112 | JSContextRef ctx = toRef(e: exec); |
113 | JSObjectRef thisRef = toRef(this); |
114 | RefPtr<OpaqueJSString> propertyNameRef; |
115 | |
116 | for (JSClassRef jsClass = classRef(); jsClass; jsClass = jsClass->parentClass) { |
117 | // optional optimization to bypass getProperty in cases when we only need to know if the property exists |
118 | if (JSObjectHasPropertyCallback hasProperty = jsClass->hasProperty) { |
119 | if (!propertyNameRef) |
120 | propertyNameRef = OpaqueJSString::create(propertyName.ustring()); |
121 | APICallbackShim callbackShim(exec); |
122 | if (hasProperty(ctx, thisRef, propertyNameRef.get())) { |
123 | slot.setCustom(slotBase: this, getValue: callbackGetter); |
124 | return true; |
125 | } |
126 | } else if (JSObjectGetPropertyCallback getProperty = jsClass->getProperty) { |
127 | if (!propertyNameRef) |
128 | propertyNameRef = OpaqueJSString::create(propertyName.ustring()); |
129 | JSValueRef exception = 0; |
130 | JSValueRef value; |
131 | { |
132 | APICallbackShim callbackShim(exec); |
133 | value = getProperty(ctx, thisRef, propertyNameRef.get(), &exception); |
134 | } |
135 | if (exception) { |
136 | exec->setException(toJS(exec, v: exception)); |
137 | slot.setValue(jsUndefined()); |
138 | return true; |
139 | } |
140 | if (value) { |
141 | slot.setValue(toJS(exec, v: value)); |
142 | return true; |
143 | } |
144 | } |
145 | |
146 | if (OpaqueJSClassStaticValuesTable* staticValues = jsClass->staticValues(exec)) { |
147 | if (staticValues->contains(key: propertyName.ustring().rep())) { |
148 | slot.setCustom(slotBase: this, getValue: staticValueGetter); |
149 | return true; |
150 | } |
151 | } |
152 | |
153 | if (OpaqueJSClassStaticFunctionsTable* staticFunctions = jsClass->staticFunctions(exec)) { |
154 | if (staticFunctions->contains(key: propertyName.ustring().rep())) { |
155 | slot.setCustom(slotBase: this, getValue: staticFunctionGetter); |
156 | return true; |
157 | } |
158 | } |
159 | } |
160 | |
161 | return Base::getOwnPropertySlot(exec, propertyName, slot); |
162 | } |
163 | |
164 | template <class Base> |
165 | bool JSCallbackObject<Base>::getOwnPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot) |
166 | { |
167 | return getOwnPropertySlot(exec, Identifier::from(exec, y: propertyName), slot); |
168 | } |
169 | |
170 | template <class Base> |
171 | bool JSCallbackObject<Base>::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor) |
172 | { |
173 | PropertySlot slot; |
174 | if (getOwnPropertySlot(exec, propertyName, slot)) { |
175 | // Ideally we should return an access descriptor, but returning a value descriptor is better than nothing. |
176 | JSValue value = slot.getValue(exec, propertyName); |
177 | if (!exec->hadException()) |
178 | descriptor.setValue(value); |
179 | // We don't know whether the property is configurable, but assume it is. |
180 | descriptor.setConfigurable(true); |
181 | // We don't know whether the property is enumerable (we could call getOwnPropertyNames() to find out), but assume it isn't. |
182 | descriptor.setEnumerable(false); |
183 | return true; |
184 | } |
185 | |
186 | return Base::getOwnPropertyDescriptor(exec, propertyName, descriptor); |
187 | } |
188 | |
189 | template <class Base> |
190 | void JSCallbackObject<Base>::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot) |
191 | { |
192 | JSContextRef ctx = toRef(e: exec); |
193 | JSObjectRef thisRef = toRef(this); |
194 | RefPtr<OpaqueJSString> propertyNameRef; |
195 | JSValueRef valueRef = toRef(exec, v: value); |
196 | |
197 | for (JSClassRef jsClass = classRef(); jsClass; jsClass = jsClass->parentClass) { |
198 | if (JSObjectSetPropertyCallback setProperty = jsClass->setProperty) { |
199 | if (!propertyNameRef) |
200 | propertyNameRef = OpaqueJSString::create(propertyName.ustring()); |
201 | JSValueRef exception = 0; |
202 | bool result; |
203 | { |
204 | APICallbackShim callbackShim(exec); |
205 | result = setProperty(ctx, thisRef, propertyNameRef.get(), valueRef, &exception); |
206 | } |
207 | if (exception) |
208 | exec->setException(toJS(exec, v: exception)); |
209 | if (result || exception) |
210 | return; |
211 | } |
212 | |
213 | if (OpaqueJSClassStaticValuesTable* staticValues = jsClass->staticValues(exec)) { |
214 | if (StaticValueEntry* entry = staticValues->get(key: propertyName.ustring().rep())) { |
215 | if (entry->attributes & kJSPropertyAttributeReadOnly) |
216 | return; |
217 | if (JSObjectSetPropertyCallback setProperty = entry->setProperty) { |
218 | if (!propertyNameRef) |
219 | propertyNameRef = OpaqueJSString::create(propertyName.ustring()); |
220 | JSValueRef exception = 0; |
221 | bool result; |
222 | { |
223 | APICallbackShim callbackShim(exec); |
224 | result = setProperty(ctx, thisRef, propertyNameRef.get(), valueRef, &exception); |
225 | } |
226 | if (exception) |
227 | exec->setException(toJS(exec, v: exception)); |
228 | if (result || exception) |
229 | return; |
230 | } else |
231 | throwError(exec, ReferenceError, message: "Attempt to set a property that is not settable." ); |
232 | } |
233 | } |
234 | |
235 | if (OpaqueJSClassStaticFunctionsTable* staticFunctions = jsClass->staticFunctions(exec)) { |
236 | if (StaticFunctionEntry* entry = staticFunctions->get(key: propertyName.ustring().rep())) { |
237 | if (entry->attributes & kJSPropertyAttributeReadOnly) |
238 | return; |
239 | JSCallbackObject<Base>::putDirect(propertyName, value); // put as override property |
240 | return; |
241 | } |
242 | } |
243 | } |
244 | |
245 | return Base::put(exec, propertyName, value, slot); |
246 | } |
247 | |
248 | template <class Base> |
249 | bool JSCallbackObject<Base>::deleteProperty(ExecState* exec, const Identifier& propertyName) |
250 | { |
251 | JSContextRef ctx = toRef(e: exec); |
252 | JSObjectRef thisRef = toRef(this); |
253 | RefPtr<OpaqueJSString> propertyNameRef; |
254 | |
255 | for (JSClassRef jsClass = classRef(); jsClass; jsClass = jsClass->parentClass) { |
256 | if (JSObjectDeletePropertyCallback deleteProperty = jsClass->deleteProperty) { |
257 | if (!propertyNameRef) |
258 | propertyNameRef = OpaqueJSString::create(propertyName.ustring()); |
259 | JSValueRef exception = 0; |
260 | bool result; |
261 | { |
262 | APICallbackShim callbackShim(exec); |
263 | result = deleteProperty(ctx, thisRef, propertyNameRef.get(), &exception); |
264 | } |
265 | if (exception) |
266 | exec->setException(toJS(exec, v: exception)); |
267 | if (result || exception) |
268 | return true; |
269 | } |
270 | |
271 | if (OpaqueJSClassStaticValuesTable* staticValues = jsClass->staticValues(exec)) { |
272 | if (StaticValueEntry* entry = staticValues->get(key: propertyName.ustring().rep())) { |
273 | if (entry->attributes & kJSPropertyAttributeDontDelete) |
274 | return false; |
275 | return true; |
276 | } |
277 | } |
278 | |
279 | if (OpaqueJSClassStaticFunctionsTable* staticFunctions = jsClass->staticFunctions(exec)) { |
280 | if (StaticFunctionEntry* entry = staticFunctions->get(key: propertyName.ustring().rep())) { |
281 | if (entry->attributes & kJSPropertyAttributeDontDelete) |
282 | return false; |
283 | return true; |
284 | } |
285 | } |
286 | } |
287 | |
288 | return Base::deleteProperty(exec, propertyName); |
289 | } |
290 | |
291 | template <class Base> |
292 | bool JSCallbackObject<Base>::deleteProperty(ExecState* exec, unsigned propertyName) |
293 | { |
294 | return deleteProperty(exec, Identifier::from(exec, y: propertyName)); |
295 | } |
296 | |
297 | template <class Base> |
298 | ConstructType JSCallbackObject<Base>::getConstructData(ConstructData& constructData) |
299 | { |
300 | for (JSClassRef jsClass = classRef(); jsClass; jsClass = jsClass->parentClass) { |
301 | if (jsClass->callAsConstructor) { |
302 | constructData.native.function = construct; |
303 | return ConstructTypeHost; |
304 | } |
305 | } |
306 | return ConstructTypeNone; |
307 | } |
308 | |
309 | template <class Base> |
310 | JSObject* JSCallbackObject<Base>::construct(ExecState* exec, JSObject* constructor, const ArgList& args) |
311 | { |
312 | JSContextRef execRef = toRef(e: exec); |
313 | JSObjectRef constructorRef = toRef(o: constructor); |
314 | |
315 | for (JSClassRef jsClass = static_cast<JSCallbackObject<Base>*>(constructor)->classRef(); jsClass; jsClass = jsClass->parentClass) { |
316 | if (JSObjectCallAsConstructorCallback callAsConstructor = jsClass->callAsConstructor) { |
317 | int argumentCount = static_cast<int>(args.size()); |
318 | Vector<JSValueRef, 16> arguments(argumentCount); |
319 | for (int i = 0; i < argumentCount; i++) |
320 | arguments[i] = toRef(exec, v: args.at(idx: i)); |
321 | JSValueRef exception = 0; |
322 | JSObject* result; |
323 | { |
324 | APICallbackShim callbackShim(exec); |
325 | result = toJS(o: callAsConstructor(execRef, constructorRef, argumentCount, arguments.data(), &exception)); |
326 | } |
327 | if (exception) |
328 | exec->setException(toJS(exec, v: exception)); |
329 | return result; |
330 | } |
331 | } |
332 | |
333 | ASSERT_NOT_REACHED(); // getConstructData should prevent us from reaching here |
334 | return 0; |
335 | } |
336 | |
337 | template <class Base> |
338 | bool JSCallbackObject<Base>::hasInstance(ExecState* exec, JSValue value, JSValue) |
339 | { |
340 | JSContextRef execRef = toRef(e: exec); |
341 | JSObjectRef thisRef = toRef(this); |
342 | |
343 | for (JSClassRef jsClass = classRef(); jsClass; jsClass = jsClass->parentClass) { |
344 | if (JSObjectHasInstanceCallback hasInstance = jsClass->hasInstance) { |
345 | JSValueRef valueRef = toRef(exec, v: value); |
346 | JSValueRef exception = 0; |
347 | bool result; |
348 | { |
349 | APICallbackShim callbackShim(exec); |
350 | result = hasInstance(execRef, thisRef, valueRef, &exception); |
351 | } |
352 | if (exception) |
353 | exec->setException(toJS(exec, v: exception)); |
354 | return result; |
355 | } |
356 | } |
357 | return false; |
358 | } |
359 | |
360 | template <class Base> |
361 | CallType JSCallbackObject<Base>::getCallData(CallData& callData) |
362 | { |
363 | for (JSClassRef jsClass = classRef(); jsClass; jsClass = jsClass->parentClass) { |
364 | if (jsClass->callAsFunction) { |
365 | callData.native.function = call; |
366 | return CallTypeHost; |
367 | } |
368 | } |
369 | return CallTypeNone; |
370 | } |
371 | |
372 | template <class Base> |
373 | JSValue JSCallbackObject<Base>::call(ExecState* exec, JSObject* functionObject, JSValue thisValue, const ArgList& args) |
374 | { |
375 | JSContextRef execRef = toRef(e: exec); |
376 | JSObjectRef functionRef = toRef(o: functionObject); |
377 | JSObjectRef thisObjRef = toRef(o: thisValue.toThisObject(exec)); |
378 | |
379 | for (JSClassRef jsClass = static_cast<JSCallbackObject<Base>*>(functionObject)->classRef(); jsClass; jsClass = jsClass->parentClass) { |
380 | if (JSObjectCallAsFunctionCallback callAsFunction = jsClass->callAsFunction) { |
381 | int argumentCount = static_cast<int>(args.size()); |
382 | Vector<JSValueRef, 16> arguments(argumentCount); |
383 | for (int i = 0; i < argumentCount; i++) |
384 | arguments[i] = toRef(exec, v: args.at(idx: i)); |
385 | JSValueRef exception = 0; |
386 | JSValue result; |
387 | { |
388 | APICallbackShim callbackShim(exec); |
389 | result = toJS(exec, v: callAsFunction(execRef, functionRef, thisObjRef, argumentCount, arguments.data(), &exception)); |
390 | } |
391 | if (exception) |
392 | exec->setException(toJS(exec, v: exception)); |
393 | return result; |
394 | } |
395 | } |
396 | |
397 | ASSERT_NOT_REACHED(); // getCallData should prevent us from reaching here |
398 | return JSValue(); |
399 | } |
400 | |
401 | template <class Base> |
402 | void JSCallbackObject<Base>::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) |
403 | { |
404 | JSContextRef execRef = toRef(e: exec); |
405 | JSObjectRef thisRef = toRef(this); |
406 | |
407 | for (JSClassRef jsClass = classRef(); jsClass; jsClass = jsClass->parentClass) { |
408 | if (JSObjectGetPropertyNamesCallback getPropertyNames = jsClass->getPropertyNames) { |
409 | APICallbackShim callbackShim(exec); |
410 | getPropertyNames(execRef, thisRef, toRef(l: &propertyNames)); |
411 | } |
412 | |
413 | if (OpaqueJSClassStaticValuesTable* staticValues = jsClass->staticValues(exec)) { |
414 | typedef OpaqueJSClassStaticValuesTable::const_iterator iterator; |
415 | iterator end = staticValues->end(); |
416 | for (iterator it = staticValues->begin(); it != end; ++it) { |
417 | UString::Rep* name = it->first.get(); |
418 | StaticValueEntry* entry = it->second; |
419 | if (entry->getProperty && (!(entry->attributes & kJSPropertyAttributeDontEnum) || (mode == IncludeDontEnumProperties))) |
420 | propertyNames.add(identifier: Identifier(exec, name)); |
421 | } |
422 | } |
423 | |
424 | if (OpaqueJSClassStaticFunctionsTable* staticFunctions = jsClass->staticFunctions(exec)) { |
425 | typedef OpaqueJSClassStaticFunctionsTable::const_iterator iterator; |
426 | iterator end = staticFunctions->end(); |
427 | for (iterator it = staticFunctions->begin(); it != end; ++it) { |
428 | UString::Rep* name = it->first.get(); |
429 | StaticFunctionEntry* entry = it->second; |
430 | if (!(entry->attributes & kJSPropertyAttributeDontEnum) || (mode == IncludeDontEnumProperties)) |
431 | propertyNames.add(identifier: Identifier(exec, name)); |
432 | } |
433 | } |
434 | } |
435 | |
436 | Base::getOwnPropertyNames(exec, propertyNames, mode); |
437 | } |
438 | |
439 | template <class Base> |
440 | double JSCallbackObject<Base>::toNumber(ExecState* exec) const |
441 | { |
442 | // We need this check to guard against the case where this object is rhs of |
443 | // a binary expression where lhs threw an exception in its conversion to |
444 | // primitive |
445 | if (exec->hadException()) |
446 | return NaN; |
447 | JSContextRef ctx = toRef(e: exec); |
448 | JSObjectRef thisRef = toRef(this); |
449 | |
450 | for (JSClassRef jsClass = classRef(); jsClass; jsClass = jsClass->parentClass) |
451 | if (JSObjectConvertToTypeCallback convertToType = jsClass->convertToType) { |
452 | JSValueRef exception = 0; |
453 | JSValueRef value; |
454 | { |
455 | APICallbackShim callbackShim(exec); |
456 | value = convertToType(ctx, thisRef, kJSTypeNumber, &exception); |
457 | } |
458 | if (exception) { |
459 | exec->setException(toJS(exec, v: exception)); |
460 | return 0; |
461 | } |
462 | |
463 | double dValue; |
464 | if (value) |
465 | return toJS(exec, v: value).getNumber(result&: dValue) ? dValue : NaN; |
466 | } |
467 | |
468 | return Base::toNumber(exec); |
469 | } |
470 | |
471 | template <class Base> |
472 | UString JSCallbackObject<Base>::toString(ExecState* exec) const |
473 | { |
474 | JSContextRef ctx = toRef(e: exec); |
475 | JSObjectRef thisRef = toRef(this); |
476 | |
477 | for (JSClassRef jsClass = classRef(); jsClass; jsClass = jsClass->parentClass) |
478 | if (JSObjectConvertToTypeCallback convertToType = jsClass->convertToType) { |
479 | JSValueRef exception = 0; |
480 | JSValueRef value; |
481 | { |
482 | APICallbackShim callbackShim(exec); |
483 | value = convertToType(ctx, thisRef, kJSTypeString, &exception); |
484 | } |
485 | if (exception) { |
486 | exec->setException(toJS(exec, v: exception)); |
487 | return "" ; |
488 | } |
489 | if (value) |
490 | return toJS(exec, v: value).getString(exec); |
491 | } |
492 | |
493 | return Base::toString(exec); |
494 | } |
495 | |
496 | template <class Base> |
497 | void JSCallbackObject<Base>::setPrivate(void* data) |
498 | { |
499 | m_callbackObjectData->privateData = data; |
500 | } |
501 | |
502 | template <class Base> |
503 | void* JSCallbackObject<Base>::getPrivate() |
504 | { |
505 | return m_callbackObjectData->privateData; |
506 | } |
507 | |
508 | template <class Base> |
509 | bool JSCallbackObject<Base>::inherits(JSClassRef c) const |
510 | { |
511 | for (JSClassRef jsClass = classRef(); jsClass; jsClass = jsClass->parentClass) |
512 | if (jsClass == c) |
513 | return true; |
514 | |
515 | return false; |
516 | } |
517 | |
518 | template <class Base> |
519 | JSValue JSCallbackObject<Base>::staticValueGetter(ExecState* exec, const Identifier& propertyName, const PropertySlot& slot) |
520 | { |
521 | JSCallbackObject* thisObj = asCallbackObject(value: slot.slotBase()); |
522 | |
523 | JSObjectRef thisRef = toRef(thisObj); |
524 | RefPtr<OpaqueJSString> propertyNameRef; |
525 | |
526 | for (JSClassRef jsClass = thisObj->classRef(); jsClass; jsClass = jsClass->parentClass) |
527 | if (OpaqueJSClassStaticValuesTable* staticValues = jsClass->staticValues(exec)) |
528 | if (StaticValueEntry* entry = staticValues->get(key: propertyName.ustring().rep())) |
529 | if (JSObjectGetPropertyCallback getProperty = entry->getProperty) { |
530 | if (!propertyNameRef) |
531 | propertyNameRef = OpaqueJSString::create(propertyName.ustring()); |
532 | JSValueRef exception = 0; |
533 | JSValueRef value; |
534 | { |
535 | APICallbackShim callbackShim(exec); |
536 | value = getProperty(toRef(e: exec), thisRef, propertyNameRef.get(), &exception); |
537 | } |
538 | if (exception) { |
539 | exec->setException(toJS(exec, v: exception)); |
540 | return jsUndefined(); |
541 | } |
542 | if (value) |
543 | return toJS(exec, v: value); |
544 | } |
545 | |
546 | return throwError(exec, ReferenceError, message: "Static value property defined with NULL getProperty callback." ); |
547 | } |
548 | |
549 | template <class Base> |
550 | JSValue JSCallbackObject<Base>::staticFunctionGetter(ExecState* exec, const Identifier& propertyName, const PropertySlot& slot) |
551 | { |
552 | JSCallbackObject* thisObj = asCallbackObject(value: slot.slotBase()); |
553 | |
554 | // Check for cached or override property. |
555 | PropertySlot slot2(thisObj); |
556 | if (thisObj->Base::getOwnPropertySlot(exec, propertyName, slot2)) |
557 | return slot2.getValue(exec, propertyName); |
558 | |
559 | for (JSClassRef jsClass = thisObj->classRef(); jsClass; jsClass = jsClass->parentClass) { |
560 | if (OpaqueJSClassStaticFunctionsTable* staticFunctions = jsClass->staticFunctions(exec)) { |
561 | if (StaticFunctionEntry* entry = staticFunctions->get(key: propertyName.ustring().rep())) { |
562 | if (JSObjectCallAsFunctionCallback callAsFunction = entry->callAsFunction) { |
563 | JSObject* o = new (exec) JSCallbackFunction(exec, callAsFunction, propertyName); |
564 | thisObj->putDirect(propertyName, o, entry->attributes); |
565 | return o; |
566 | } |
567 | } |
568 | } |
569 | } |
570 | |
571 | return throwError(exec, ReferenceError, message: "Static function property defined with NULL callAsFunction callback." ); |
572 | } |
573 | |
574 | template <class Base> |
575 | JSValue JSCallbackObject<Base>::callbackGetter(ExecState* exec, const Identifier& propertyName, const PropertySlot& slot) |
576 | { |
577 | JSCallbackObject* thisObj = asCallbackObject(value: slot.slotBase()); |
578 | |
579 | JSObjectRef thisRef = toRef(thisObj); |
580 | RefPtr<OpaqueJSString> propertyNameRef; |
581 | |
582 | for (JSClassRef jsClass = thisObj->classRef(); jsClass; jsClass = jsClass->parentClass) |
583 | if (JSObjectGetPropertyCallback getProperty = jsClass->getProperty) { |
584 | if (!propertyNameRef) |
585 | propertyNameRef = OpaqueJSString::create(propertyName.ustring()); |
586 | JSValueRef exception = 0; |
587 | JSValueRef value; |
588 | { |
589 | APICallbackShim callbackShim(exec); |
590 | value = getProperty(toRef(e: exec), thisRef, propertyNameRef.get(), &exception); |
591 | } |
592 | if (exception) { |
593 | exec->setException(toJS(exec, v: exception)); |
594 | return jsUndefined(); |
595 | } |
596 | if (value) |
597 | return toJS(exec, v: value); |
598 | } |
599 | |
600 | return throwError(exec, ReferenceError, message: "hasProperty callback returned true for a property that doesn't exist." ); |
601 | } |
602 | |
603 | } // namespace JSC |
604 | |