static inline EncodedJSValue JSC_HOST_CALL arrayIteratorNext(CallFrame* callFrame) { JSArrayIterator* iterator = jsDynamicCast<JSArrayIterator*>(callFrame->thisValue()); if (!iterator) { ASSERT_NOT_REACHED(); return JSValue::encode(throwTypeError(callFrame, ASCIILiteral("Cannot call ArrayIterator.next() on a non-ArrayIterator object"))); } JSObject* iteratedObject = iterator->iteratedObject(); size_t index = iterator->nextIndex(); ArrayIterationKind kind = iterator->iterationKind(); JSValue jsLength = JSValue(iteratedObject).get(callFrame, callFrame->propertyNames().length); if (callFrame->hadException()) return JSValue::encode(jsNull()); size_t length = jsLength.toUInt32(callFrame); if (callFrame->hadException()) return JSValue::encode(jsNull()); if (index >= length) { iterator->finish(); return createIteratorResult(callFrame, kind, index, jsUndefined(), true); } if (JSValue result = iteratedObject->tryGetIndexQuickly(index)) { iterator->setNextIndex(index + 1); return createIteratorResult(callFrame, kind, index, result, false); } JSValue result = jsUndefined(); PropertySlot slot(iteratedObject); if (kind > ArrayIterateSparseTag) { // We assume that the indexed property will be an own property so cache the getOwnProperty // method locally auto getOwnPropertySlotByIndex = iteratedObject->methodTable()->getOwnPropertySlotByIndex; while (index < length) { if (getOwnPropertySlotByIndex(iteratedObject, callFrame, index, slot)) { result = slot.getValue(callFrame, index); break; } if (iteratedObject->getPropertySlot(callFrame, index, slot)) { result = slot.getValue(callFrame, index); break; } index++; } } else if (iteratedObject->getPropertySlot(callFrame, index, slot)) result = slot.getValue(callFrame, index); if (index == length) iterator->finish(); else iterator->setNextIndex(index + 1); return createIteratorResult(callFrame, kind, index, jsUndefined(), index == length); }
bool DebuggerScope::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot) { DebuggerScope* scope = jsCast<DebuggerScope*>(object); ASSERT(scope->isValid()); if (!scope->isValid()) return false; JSObject* thisObject = JSScope::objectAtScope(scope->jsScope()); slot.setThisValue(JSValue(thisObject)); // By default, JSObject::getPropertySlot() will look in the DebuggerScope's prototype // chain and not the wrapped scope, and JSObject::getPropertySlot() cannot be overridden // to behave differently for the DebuggerScope. // // Instead, we'll treat all properties in the wrapped scope and its prototype chain as // the own properties of the DebuggerScope. This is fine because the WebInspector // does not presently need to distinguish between what's owned at each level in the // prototype chain. Hence, we'll invoke getPropertySlot() on the wrapped scope here // instead of getOwnPropertySlot(). bool result = thisObject->getPropertySlot(exec, propertyName, slot); if (result && slot.isValue() && slot.getValue(exec, propertyName) == jsTDZValue()) { // FIXME: // We hit a scope property that has the TDZ empty value. // Currently, we just lie to the inspector and claim that this property is undefined. // This is not ideal and we should fix it. // https://bugs.webkit.org/show_bug.cgi?id=144977 slot.setValue(slot.slotBase(), DontEnum, jsUndefined()); return true; } return result; }
bool JSCell::getOwnPropertySlot(ExecState* exec, unsigned identifier, PropertySlot& slot) { // This is not a general purpose implementation of getOwnPropertySlot. // It should only be called by JSValue::get. // It calls getPropertySlot, not getOwnPropertySlot. JSObject* object = toObject(exec, exec->lexicalGlobalObject()); slot.setBase(object); if (!object->getPropertySlot(exec, identifier, slot)) slot.setUndefined(); return true; }
EncodedJSValue JSC_HOST_CALL objectProtoFuncLookupSetter(ExecState* exec) { JSObject* thisObject = exec->hostThisValue().toThis(exec, StrictMode).toObject(exec); if (exec->hadException()) return JSValue::encode(jsUndefined()); PropertySlot slot(thisObject); if (thisObject->getPropertySlot(exec, Identifier(exec, exec->argument(0).toString(exec)->value(exec)), slot) && slot.isAccessor()) return JSValue::encode(slot.getterSetter()->setter()); return JSValue::encode(jsUndefined()); }
EncodedJSValue DFG_OPERATION operationResolve(ExecState* exec, Identifier* propertyName) { ScopeChainNode* scopeChain = exec->scopeChain(); ScopeChainIterator iter = scopeChain->begin(); ScopeChainIterator end = scopeChain->end(); ASSERT(iter != end); do { JSObject* record = iter->get(); PropertySlot slot(record); if (record->getPropertySlot(exec, *propertyName, slot)) return JSValue::encode(slot.getValue(exec, *propertyName)); } while (++iter != end); return throwVMError(exec, createUndefinedVariableError(exec, *propertyName)); }
EncodedJSValue JSC_HOST_CALL objectProtoFuncLookupSetter(ExecState* exec) { JSObject* thisObject = exec->thisValue().toThis(exec, StrictMode).toObject(exec); if (exec->hadException()) return JSValue::encode(jsUndefined()); auto propertyName = exec->argument(0).toPropertyKey(exec); if (exec->hadException()) return JSValue::encode(jsUndefined()); PropertySlot slot(thisObject); if (thisObject->getPropertySlot(exec, propertyName, slot) && slot.isAccessor()) { GetterSetter* getterSetter = slot.getterSetter(); return getterSetter->isSetterNull() ? JSValue::encode(jsUndefined()) : JSValue::encode(getterSetter->setter()); } return JSValue::encode(jsUndefined()); }
JSValue* JSValue::getByIndex(ExecState* exec, unsigned propertyName) const { switch (type()) { case StringType: { UString s = static_cast<const StringImp*>(asCell())->value(); if (propertyName < static_cast<unsigned>(s.size())) { return jsString(s.substr(propertyName, 1)); } // fall through } default: { JSObject* obj = toObject(exec); PropertySlot slot; if (obj->getPropertySlot(exec, propertyName, slot)) return slot.getValue(exec, obj, propertyName); return jsUndefined(); } } }
bool DebuggerScope::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot) { DebuggerScope* scope = jsCast<DebuggerScope*>(object); ASSERT(scope->isValid()); if (!scope->isValid()) return false; JSObject* thisObject = JSScope::objectAtScope(scope->jsScope()); slot.setThisValue(JSValue(thisObject)); // By default, JSObject::getPropertySlot() will look in the DebuggerScope's prototype // chain and not the wrapped scope, and JSObject::getPropertySlot() cannot be overridden // to behave differently for the DebuggerScope. // // Instead, we'll treat all properties in the wrapped scope and its prototype chain as // the own properties of the DebuggerScope. This is fine because the WebInspector // does not presently need to distinguish between what's owned at each level in the // prototype chain. Hence, we'll invoke getPropertySlot() on the wrapped scope here // instead of getOwnPropertySlot(). return thisObject->getPropertySlot(exec, propertyName, slot); }
bool UserObjectImp::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot) { if (!fJSUserObject) return false; CFStringRef cfPropName = IdentifierToCFString(propertyName); JSUserObject *jsResult = fJSUserObject->CopyProperty(cfPropName); ReleaseCFType(cfPropName); if (jsResult) { slot.setCustom(this, userObjectGetter); jsResult->Release(); return true; } else { JSValue *kjsValue = toPrimitive(exec); if (kjsValue->type() != NullType && kjsValue->type() != UndefinedType) { JSObject *kjsObject = kjsValue->toObject(exec); if (kjsObject->getPropertySlot(exec, propertyName, slot)) return true; } } return JSObject::getOwnPropertySlot(exec, propertyName, slot); }
// ES5 8.10.5 ToPropertyDescriptor static bool toPropertyDescriptor(ExecState* exec, JSValue in, PropertyDescriptor& desc) { if (!in.isObject()) { throwError(exec, createTypeError(exec, ASCIILiteral("Property description must be an object."))); return false; } JSObject* description = asObject(in); PropertySlot enumerableSlot(description); if (description->getPropertySlot(exec, exec->propertyNames().enumerable, enumerableSlot)) { desc.setEnumerable(enumerableSlot.getValue(exec, exec->propertyNames().enumerable).toBoolean(exec)); if (exec->hadException()) return false; } PropertySlot configurableSlot(description); if (description->getPropertySlot(exec, exec->propertyNames().configurable, configurableSlot)) { desc.setConfigurable(configurableSlot.getValue(exec, exec->propertyNames().configurable).toBoolean(exec)); if (exec->hadException()) return false; } JSValue value; PropertySlot valueSlot(description); if (description->getPropertySlot(exec, exec->propertyNames().value, valueSlot)) { desc.setValue(valueSlot.getValue(exec, exec->propertyNames().value)); if (exec->hadException()) return false; } PropertySlot writableSlot(description); if (description->getPropertySlot(exec, exec->propertyNames().writable, writableSlot)) { desc.setWritable(writableSlot.getValue(exec, exec->propertyNames().writable).toBoolean(exec)); if (exec->hadException()) return false; } PropertySlot getSlot(description); if (description->getPropertySlot(exec, exec->propertyNames().get, getSlot)) { JSValue get = getSlot.getValue(exec, exec->propertyNames().get); if (exec->hadException()) return false; if (!get.isUndefined()) { CallData callData; if (getCallData(get, callData) == CallTypeNone) { throwError(exec, createTypeError(exec, ASCIILiteral("Getter must be a function."))); return false; } } desc.setGetter(get); } PropertySlot setSlot(description); if (description->getPropertySlot(exec, exec->propertyNames().set, setSlot)) { JSValue set = setSlot.getValue(exec, exec->propertyNames().set); if (exec->hadException()) return false; if (!set.isUndefined()) { CallData callData; if (getCallData(set, callData) == CallTypeNone) { throwError(exec, createTypeError(exec, ASCIILiteral("Setter must be a function."))); return false; } } desc.setSetter(set); } if (!desc.isAccessorDescriptor()) return true; if (desc.value()) { throwError(exec, createTypeError(exec, ASCIILiteral("Invalid property. 'value' present on property with getter or setter."))); return false; } if (desc.writablePresent()) { throwError(exec, createTypeError(exec, ASCIILiteral("Invalid property. 'writable' present on property with getter or setter."))); return false; } return true; }