bool AJFunction::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) { if (isHostFunction()) return Base::getOwnPropertySlot(exec, propertyName, slot); if (propertyName == exec->propertyNames().prototype) { AJValue* location = getDirectLocation(propertyName); if (!location) { AJObject* prototype = new (exec) AJObject(scopeChain().globalObject()->emptyObjectStructure()); prototype->putDirect(exec->propertyNames().constructor, this, DontEnum); putDirect(exec->propertyNames().prototype, prototype, DontDelete); location = getDirectLocation(propertyName); } slot.setValueSlot(this, location, offsetForLocation(location)); } if (propertyName == exec->propertyNames().arguments) { slot.setCacheableCustom(this, argumentsGetter); return true; } if (propertyName == exec->propertyNames().length) { slot.setCacheableCustom(this, lengthGetter); return true; } if (propertyName == exec->propertyNames().caller) { slot.setCacheableCustom(this, callerGetter); return true; } return Base::getOwnPropertySlot(exec, propertyName, slot); }
bool JSFunction::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyName propertyName, PropertySlot& slot) { JSFunction* thisObject = jsCast<JSFunction*>(cell); if (thisObject->isHostFunction()) return Base::getOwnPropertySlot(thisObject, exec, propertyName, slot); if (propertyName == exec->propertyNames().prototype) { JSGlobalData& globalData = exec->globalData(); PropertyOffset offset = thisObject->getDirectOffset(globalData, propertyName); if (!isValidOffset(offset)) { JSObject* prototype = constructEmptyObject(exec); prototype->putDirect(globalData, exec->propertyNames().constructor, thisObject, DontEnum); thisObject->putDirect(globalData, exec->propertyNames().prototype, prototype, DontDelete | DontEnum); offset = thisObject->getDirectOffset(globalData, exec->propertyNames().prototype); ASSERT(isValidOffset(offset)); } slot.setValue(thisObject, thisObject->getDirect(offset), offset); } if (propertyName == exec->propertyNames().arguments) { if (thisObject->jsExecutable()->isStrictMode()) { bool result = Base::getOwnPropertySlot(thisObject, exec, propertyName, slot); if (!result) { thisObject->putDirectAccessor(exec, propertyName, thisObject->globalObject()->throwTypeErrorGetterSetter(exec), DontDelete | DontEnum | Accessor); result = Base::getOwnPropertySlot(thisObject, exec, propertyName, slot); ASSERT(result); } return result; } slot.setCacheableCustom(thisObject, argumentsGetter); return true; } if (propertyName == exec->propertyNames().length) { slot.setCacheableCustom(thisObject, lengthGetter); return true; } if (propertyName == exec->propertyNames().name) { slot.setCacheableCustom(thisObject, nameGetter); return true; } if (propertyName == exec->propertyNames().caller) { if (thisObject->jsExecutable()->isStrictMode()) { bool result = Base::getOwnPropertySlot(thisObject, exec, propertyName, slot); if (!result) { thisObject->putDirectAccessor(exec, propertyName, thisObject->globalObject()->throwTypeErrorGetterSetter(exec), DontDelete | DontEnum | Accessor); result = Base::getOwnPropertySlot(thisObject, exec, propertyName, slot); ASSERT(result); } return result; } slot.setCacheableCustom(thisObject, callerGetter); return true; } return Base::getOwnPropertySlot(thisObject, exec, propertyName, slot); }
bool JSFunction::getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identifier& propertyName, PropertySlot& slot) { JSFunction* thisObject = static_cast<JSFunction*>(cell); if (thisObject->isHostFunction()) return Base::getOwnPropertySlot(thisObject, exec, propertyName, slot); if (propertyName == exec->propertyNames().prototype) { WriteBarrierBase<Unknown>* location = thisObject->getDirectLocation(exec->globalData(), propertyName); if (!location) { JSObject* prototype = constructEmptyObject(exec, thisObject->globalObject()->emptyObjectStructure()); prototype->putDirect(exec->globalData(), exec->propertyNames().constructor, thisObject, DontEnum); PutPropertySlot slot; thisObject->putDirect(exec->globalData(), exec->propertyNames().prototype, prototype, DontDelete | DontEnum, false, slot); location = thisObject->getDirectLocation(exec->globalData(), exec->propertyNames().prototype); } slot.setValue(thisObject, location->get(), thisObject->offsetForLocation(location)); } if (propertyName == exec->propertyNames().arguments) { if (thisObject->jsExecutable()->isStrictMode()) { bool result = Base::getOwnPropertySlot(thisObject, exec, propertyName, slot); if (!result) { thisObject->initializeGetterSetterProperty(exec, propertyName, thisObject->globalObject()->throwTypeErrorGetterSetter(exec), DontDelete | DontEnum | Getter | Setter); result = Base::getOwnPropertySlot(thisObject, exec, propertyName, slot); ASSERT(result); } return result; } slot.setCacheableCustom(thisObject, argumentsGetter); return true; } if (propertyName == exec->propertyNames().length) { slot.setCacheableCustom(thisObject, lengthGetter); return true; } if (propertyName == exec->propertyNames().caller) { if (thisObject->jsExecutable()->isStrictMode()) { bool result = Base::getOwnPropertySlot(thisObject, exec, propertyName, slot); if (!result) { thisObject->initializeGetterSetterProperty(exec, propertyName, thisObject->globalObject()->throwTypeErrorGetterSetter(exec), DontDelete | DontEnum | Getter | Setter); result = Base::getOwnPropertySlot(thisObject, exec, propertyName, slot); ASSERT(result); } return result; } slot.setCacheableCustom(thisObject, callerGetter); return true; } return Base::getOwnPropertySlot(thisObject, exec, propertyName, slot); }
bool JSHTMLDocument::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot) { JSHTMLDocument* thisObject = jsCast<JSHTMLDocument*>(object); ASSERT_GC_OBJECT_INHERITS(thisObject, info()); if (propertyName == "open") { slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, nonCachingStaticFunctionGetter<jsHTMLDocumentPrototypeFunctionOpen, 2>); return true; } if (propertyName == "write") { slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, nonCachingStaticFunctionGetter<jsHTMLDocumentPrototypeFunctionWrite, 1>); return true; } if (propertyName == "writeln") { slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, nonCachingStaticFunctionGetter<jsHTMLDocumentPrototypeFunctionWriteln, 1>); return true; } if (canGetItemsForName(exec, &thisObject->impl(), propertyName)) { slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, thisObject->nameGetter); return true; } if (const HashTableValue* entry = JSHTMLDocument::info()->staticPropHashTable->entry(propertyName)) { slot.setCacheableCustom(thisObject, entry->attributes(), entry->propertyGetter()); return true; } return Base::getOwnPropertySlot(thisObject, exec, propertyName, slot); }
bool RuntimeMethod::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot &slot) { if (propertyName == exec->propertyNames().length) { slot.setCacheableCustom(this, lengthGetter); return true; } return InternalFunction::getOwnPropertySlot(exec, propertyName, slot); }
bool RuntimeMethod::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot &slot) { RuntimeMethod* thisObject = jsCast<RuntimeMethod*>(object); if (propertyName == exec->propertyNames().length) { slot.setCacheableCustom(thisObject, DontDelete | ReadOnly | DontEnum, thisObject->lengthGetter); return true; } return InternalFunction::getOwnPropertySlot(thisObject, exec, propertyName, slot); }
bool RuntimeMethod::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyName propertyName, PropertySlot &slot) { RuntimeMethod* thisObject = jsCast<RuntimeMethod*>(cell); if (propertyName == exec->propertyNames().length) { slot.setCacheableCustom(thisObject, thisObject->lengthGetter); return true; } return InternalFunction::getOwnPropertySlot(thisObject, exec, propertyName, slot); }
bool RuntimeArray::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot) { RuntimeArray* thisObject = jsCast<RuntimeArray*>(object); if (propertyName == exec->propertyNames().length) { slot.setCacheableCustom(thisObject, DontDelete | ReadOnly | DontEnum, thisObject->lengthGetter); return true; } Optional<uint32_t> index = parseIndex(propertyName); if (index && index.value() < thisObject->getLength()) { slot.setValue(thisObject, DontDelete | DontEnum, thisObject->getConcreteArray()->valueAt(exec, index.value())); return true; } return JSObject::getOwnPropertySlot(thisObject, exec, propertyName, slot); }
bool RuntimeArray::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyName propertyName, PropertySlot& slot) { RuntimeArray* thisObject = jsCast<RuntimeArray*>(cell); if (propertyName == exec->propertyNames().length) { slot.setCacheableCustom(thisObject, thisObject->lengthGetter); return true; } unsigned index = propertyName.asIndex(); if (index < thisObject->getLength()) { ASSERT(index != PropertyName::NotAnIndex); slot.setCustomIndex(thisObject, index, thisObject->indexGetter); return true; } return JSObject::getOwnPropertySlot(thisObject, exec, propertyName, slot); }
bool RuntimeArray::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) { if (propertyName == exec->propertyNames().length) { slot.setCacheableCustom(this, lengthGetter); return true; } bool ok; unsigned index = propertyName.toArrayIndex(&ok); if (ok) { if (index < getLength()) { slot.setCustomIndex(this, index, indexGetter); return true; } } return JSObject::getOwnPropertySlot(exec, propertyName, slot); }
bool RuntimeArray::getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identifier& propertyName, PropertySlot& slot) { RuntimeArray* thisObject = static_cast<RuntimeArray*>(cell); if (propertyName == exec->propertyNames().length) { slot.setCacheableCustom(thisObject, thisObject->lengthGetter); return true; } bool ok; unsigned index = propertyName.toArrayIndex(ok); if (ok) { if (index < thisObject->getLength()) { slot.setCustomIndex(thisObject, index, thisObject->indexGetter); return true; } } return JSObject::getOwnPropertySlot(thisObject, exec, propertyName, slot); }
// Property access sequence is: // (1) indexed properties, // (2) regular own properties, // (3) named properties (in fact, these shouldn't be on the window, should be on the NPO). bool JSDOMWindow::getOwnPropertySlot(JSObject* object, ExecState* state, PropertyName propertyName, PropertySlot& slot) { // (1) First, indexed properties. // Hand off all indexed access to getOwnPropertySlotByIndex, which supports the indexed getter. if (Optional<unsigned> index = parseIndex(propertyName)) return getOwnPropertySlotByIndex(object, state, index.value(), slot); auto* thisObject = jsCast<JSDOMWindow*>(object); auto* frame = thisObject->wrapped().frame(); // Hand off all cross-domain/frameless access to jsDOMWindowGetOwnPropertySlotRestrictedAccess. String errorMessage; if (!frame || !BindingSecurity::shouldAllowAccessToDOMWindow(*state, thisObject->wrapped(), errorMessage)) return jsDOMWindowGetOwnPropertySlotRestrictedAccess(thisObject, frame, state, propertyName, slot, errorMessage); // FIXME: this need more explanation. // (Particularly, is it correct that this exists here but not in getOwnPropertySlotByIndex?) slot.setWatchpointSet(thisObject->m_windowCloseWatchpoints); // (2) Regular own properties. PropertySlot slotCopy = slot; if (Base::getOwnPropertySlot(thisObject, state, propertyName, slot)) { // Detect when we're getting the property 'showModalDialog', this is disabled, and has its original value. bool isShowModalDialogAndShouldHide = propertyName == state->propertyNames().showModalDialog && !DOMWindow::canShowModalDialog(frame) && slot.isValue() && isHostFunction(slot.getValue(state, propertyName), jsDOMWindowInstanceFunctionShowModalDialog); // Unless we're in the showModalDialog special case, we're done. if (!isShowModalDialogAndShouldHide) return true; slot = slotCopy; } #if ENABLE(USER_MESSAGE_HANDLERS) if (propertyName == state->propertyNames().webkit && thisObject->wrapped().shouldHaveWebKitNamespaceForWorld(thisObject->world())) { slot.setCacheableCustom(thisObject, DontDelete | ReadOnly, jsDOMWindowWebKit); return true; } #endif return false; }
bool JSTestEventTarget::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot) { JSTestEventTarget* thisObject = jsCast<JSTestEventTarget*>(object); ASSERT_GC_OBJECT_INHERITS(thisObject, info()); const HashTableValue* entry = getStaticValueSlotEntryWithoutCaching<JSTestEventTarget>(exec, propertyName); if (entry) { slot.setCacheableCustom(thisObject, entry->attributes(), entry->propertyGetter()); return true; } unsigned index = propertyName.asIndex(); if (index != PropertyName::NotAnIndex && index < thisObject->impl().length()) { unsigned attributes = DontDelete | ReadOnly; slot.setValue(thisObject, attributes, toJS(exec, thisObject->globalObject(), thisObject->impl().item(index))); return true; } if (canGetItemsForName(exec, &thisObject->impl(), propertyName)) { slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, thisObject->nameGetter); return true; } return getStaticValueSlot<JSTestEventTarget, Base>(exec, JSTestEventTargetTable, thisObject, propertyName, slot); }
bool JSFunction::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot) { JSFunction* thisObject = jsCast<JSFunction*>(object); if (thisObject->isHostOrBuiltinFunction()) return Base::getOwnPropertySlot(thisObject, exec, propertyName, slot); if (propertyName == exec->propertyNames().prototype) { VM& vm = exec->vm(); unsigned attributes; PropertyOffset offset = thisObject->getDirectOffset(vm, propertyName, attributes); if (!isValidOffset(offset)) { JSObject* prototype = constructEmptyObject(exec); prototype->putDirect(vm, exec->propertyNames().constructor, thisObject, DontEnum); thisObject->putDirect(vm, exec->propertyNames().prototype, prototype, DontDelete | DontEnum); offset = thisObject->getDirectOffset(vm, exec->propertyNames().prototype, attributes); ASSERT(isValidOffset(offset)); } slot.setValue(thisObject, attributes, thisObject->getDirect(offset), offset); } if (propertyName == exec->propertyNames().arguments) { if (thisObject->jsExecutable()->isStrictMode()) { bool result = Base::getOwnPropertySlot(thisObject, exec, propertyName, slot); if (!result) { thisObject->putDirectAccessor(exec, propertyName, thisObject->globalObject()->throwTypeErrorGetterSetter(exec->vm()), DontDelete | DontEnum | Accessor); result = Base::getOwnPropertySlot(thisObject, exec, propertyName, slot); ASSERT(result); } return result; } slot.setCacheableCustom(thisObject, ReadOnly | DontEnum | DontDelete, argumentsGetter); return true; } if (propertyName == exec->propertyNames().length) { slot.setCacheableCustom(thisObject, ReadOnly | DontEnum | DontDelete, lengthGetter); return true; } if (propertyName == exec->propertyNames().name) { slot.setCacheableCustom(thisObject, ReadOnly | DontEnum | DontDelete, nameGetter); return true; } if (propertyName == exec->propertyNames().caller) { if (thisObject->jsExecutable()->isStrictMode()) { bool result = Base::getOwnPropertySlot(thisObject, exec, propertyName, slot); if (!result) { thisObject->putDirectAccessor(exec, propertyName, thisObject->globalObject()->throwTypeErrorGetterSetter(exec->vm()), DontDelete | DontEnum | Accessor); result = Base::getOwnPropertySlot(thisObject, exec, propertyName, slot); ASSERT(result); } return result; } slot.setCacheableCustom(thisObject, ReadOnly | DontEnum | DontDelete, callerGetter); return true; } return Base::getOwnPropertySlot(thisObject, exec, propertyName, slot); }
bool JSDOMWindow::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot) { JSDOMWindow* thisObject = jsCast<JSDOMWindow*>(object); // When accessing a Window cross-domain, functions are always the native built-in ones, and they // are not affected by properties changed on the Window or anything in its prototype chain. // This is consistent with the behavior of Firefox. // We don't want any properties other than "close" and "closed" on a frameless window (i.e. one whose page got closed, // or whose iframe got removed). // FIXME: This doesn't fully match Firefox, which allows at least toString in addition to those. if (!thisObject->impl().frame()) { // The following code is safe for cross-domain and same domain use. // It ignores any custom properties that might be set on the DOMWindow (including a custom prototype). if (propertyName == exec->propertyNames().closed) { slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, jsDOMWindowClosed); return true; } if (propertyName == exec->propertyNames().close) { slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionClose, 0>); return true; } // FIXME: We should have a message here that explains why the property access/function call was // not allowed. slot.setUndefined(); return true; } else slot.setWatchpointSet(thisObject->m_windowCloseWatchpoints); // We need to check for cross-domain access here without printing the generic warning message // because we always allow access to some function, just different ones depending whether access // is allowed. String errorMessage; bool allowsAccess = shouldAllowAccessToDOMWindow(exec, thisObject->impl(), errorMessage); // Look for overrides before looking at any of our own properties, but ignore overrides completely // if this is cross-domain access. if (allowsAccess && JSGlobalObject::getOwnPropertySlot(thisObject, exec, propertyName, slot)) return true; // We need this code here because otherwise JSDOMWindowBase will stop the search before we even get to the // prototype due to the blanket same origin (shouldAllowAccessToDOMWindow) check at the end of getOwnPropertySlot. // Also, it's important to get the implementation straight out of the DOMWindow prototype regardless of // what prototype is actually set on this object. if (propertyName == exec->propertyNames().blur) { if (!allowsAccess) { slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionBlur, 0>); return true; } } else if (propertyName == exec->propertyNames().close) { if (!allowsAccess) { slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionClose, 0>); return true; } } else if (propertyName == exec->propertyNames().focus) { if (!allowsAccess) { slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionFocus, 0>); return true; } } else if (propertyName == exec->propertyNames().postMessage) { if (!allowsAccess) { slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionPostMessage, 2>); return true; } } else if (propertyName == exec->propertyNames().showModalDialog) { if (!DOMWindow::canShowModalDialog(thisObject->impl().frame())) { slot.setUndefined(); return true; } } else if (propertyName == exec->propertyNames().toString) { // Allow access to toString() cross-domain, but always Object.prototype.toString. if (!allowsAccess) { slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, objectToStringFunctionGetter); return true; } } const HashTableValue* entry = JSDOMWindow::info()->propHashTable(exec)->entry(exec, propertyName); if (entry) { slot.setCacheableCustom(thisObject, allowsAccess ? entry->attributes() : ReadOnly | DontDelete | DontEnum, entry->propertyGetter()); return true; } #if ENABLE(USER_MESSAGE_HANDLERS) if (propertyName == exec->propertyNames().webkit && thisObject->impl().shouldHaveWebKitNamespaceForWorld(thisObject->world())) { slot.setCacheableCustom(thisObject, allowsAccess ? DontDelete | ReadOnly : ReadOnly | DontDelete | DontEnum, jsDOMWindowWebKit); return true; } #endif // Do prototype lookup early so that functions and attributes in the prototype can have // precedence over the index and name getters. JSValue proto = thisObject->prototype(); if (proto.isObject()) { if (asObject(proto)->getPropertySlot(exec, propertyName, slot)) { if (!allowsAccess) { thisObject->printErrorMessage(errorMessage); slot.setUndefined(); } return true; } } // After this point it is no longer valid to cache any results because of // the impure nature of the property accesses which follow. We can move this // statement further down when we add ways to mitigate these impurities with, // for example, watchpoints. slot.disableCaching(); // Check for child frames by name before built-in properties to // match Mozilla. This does not match IE, but some sites end up // naming frames things that conflict with window properties that // are in Moz but not IE. Since we have some of these, we have to do // it the Moz way. if (thisObject->impl().frame()->tree().scopedChild(propertyNameToAtomicString(propertyName))) { slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, childFrameGetter); return true; } // FIXME: Search the whole frame hierarchy somewhere around here. // We need to test the correct priority order. // allow window[1] or parent[1] etc. (#56983) unsigned i = propertyName.asIndex(); if (i < thisObject->impl().frame()->tree().scopedChildCount()) { ASSERT(i != PropertyName::NotAnIndex); slot.setValue(thisObject, ReadOnly | DontDelete | DontEnum, toJS(exec, thisObject->impl().frame()->tree().scopedChild(i)->document()->domWindow())); return true; } if (!allowsAccess) { thisObject->printErrorMessage(errorMessage); slot.setUndefined(); return true; } // Allow shortcuts like 'Image1' instead of document.images.Image1 Document* document = thisObject->impl().frame()->document(); if (document->isHTMLDocument()) { AtomicStringImpl* atomicPropertyName = findAtomicString(propertyName); if (atomicPropertyName && toHTMLDocument(document)->hasWindowNamedItem(*atomicPropertyName)) { slot.setCustom(thisObject, ReadOnly | DontDelete | DontEnum, namedItemGetter); return true; } } return Base::getOwnPropertySlot(thisObject, exec, propertyName, slot); }