bool JSFunction::defineOwnProperty(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor, bool throwException) { JSFunction* thisObject = jsCast<JSFunction*>(object); if (thisObject->isHostFunction()) return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException); if (propertyName == exec->propertyNames().prototype) { // Make sure prototype has been reified, such that it can only be overwritten // following the rules set out in ECMA-262 8.12.9. PropertySlot slot; thisObject->methodTable()->getOwnPropertySlot(thisObject, exec, propertyName, slot); } else if (propertyName == exec->propertyNames().arguments || propertyName == exec->propertyNames().length || propertyName == exec->propertyNames().caller) { if (!object->isExtensible()) { if (throwException) throwError(exec, createTypeError(exec, "Attempting to define property on object that is not extensible.")); return false; } if (descriptor.configurablePresent() && descriptor.configurable()) { if (throwException) throwError(exec, createTypeError(exec, "Attempting to configurable attribute of unconfigurable property.")); return false; } if (descriptor.enumerablePresent() && descriptor.enumerable()) { if (throwException) throwError(exec, createTypeError(exec, "Attempting to change enumerable attribute of unconfigurable property.")); return false; } if (descriptor.isAccessorDescriptor()) { if (throwException) throwError(exec, createTypeError(exec, "Attempting to change access mechanism for an unconfigurable property.")); return false; } if (descriptor.writablePresent() && descriptor.writable()) { if (throwException) throwError(exec, createTypeError(exec, "Attempting to change writable attribute of unconfigurable property.")); return false; } if (!descriptor.value()) return true; if (propertyName == exec->propertyNames().arguments && sameValue(exec, descriptor.value(), exec->interpreter()->retrieveArgumentsFromVMCode(exec, thisObject))) return true; if (propertyName == exec->propertyNames().length && sameValue(exec, descriptor.value(), jsNumber(thisObject->jsExecutable()->parameterCount()))) return true; if (propertyName == exec->propertyNames().caller && sameValue(exec, descriptor.value(), exec->interpreter()->retrieveCallerFromVMCode(exec, thisObject))) return true; if (throwException) throwError(exec, createTypeError(exec, "Attempting to change value of a readonly property.")); return false; } return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException); }
bool RegExpObject::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName propertyName, PropertyDescriptor& descriptor, bool shouldThrow) { if (propertyName == exec->propertyNames().lastIndex) { RegExpObject* regExp = asRegExpObject(object); if (descriptor.configurablePresent() && descriptor.configurable()) return reject(exec, shouldThrow, "Attempting to change configurable attribute of unconfigurable property."); if (descriptor.enumerablePresent() && descriptor.enumerable()) return reject(exec, shouldThrow, "Attempting to change enumerable attribute of unconfigurable property."); if (descriptor.isAccessorDescriptor()) return reject(exec, shouldThrow, "Attempting to change access mechanism for an unconfigurable property."); if (!regExp->m_lastIndexIsWritable) { if (descriptor.writablePresent() && descriptor.writable()) return reject(exec, shouldThrow, "Attempting to change writable attribute of unconfigurable property."); if (!sameValue(exec, regExp->getLastIndex(), descriptor.value())) return reject(exec, shouldThrow, "Attempting to change value of a readonly property."); return true; } if (descriptor.writablePresent() && !descriptor.writable()) regExp->m_lastIndexIsWritable = false; if (descriptor.value()) regExp->setLastIndex(exec, descriptor.value(), false); return true; } return Base::defineOwnProperty(object, exec, propertyName, descriptor, shouldThrow); }
bool RegExpObject::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName propertyName, const PropertyDescriptor& descriptor, bool shouldThrow) { VM& vm = exec->vm(); auto scope = DECLARE_THROW_SCOPE(vm); if (propertyName == vm.propertyNames->lastIndex) { RegExpObject* regExp = asRegExpObject(object); if (descriptor.configurablePresent() && descriptor.configurable()) return typeError(exec, scope, shouldThrow, ASCIILiteral(UnconfigurablePropertyChangeConfigurabilityError)); if (descriptor.enumerablePresent() && descriptor.enumerable()) return typeError(exec, scope, shouldThrow, ASCIILiteral(UnconfigurablePropertyChangeEnumerabilityError)); if (descriptor.isAccessorDescriptor()) return typeError(exec, scope, shouldThrow, ASCIILiteral(UnconfigurablePropertyChangeAccessMechanismError)); if (!regExp->m_lastIndexIsWritable) { if (descriptor.writablePresent() && descriptor.writable()) return typeError(exec, scope, shouldThrow, ASCIILiteral(UnconfigurablePropertyChangeWritabilityError)); if (!sameValue(exec, regExp->getLastIndex(), descriptor.value())) return typeError(exec, scope, shouldThrow, ASCIILiteral(ReadonlyPropertyChangeError)); return true; } if (descriptor.value()) { regExp->setLastIndex(exec, descriptor.value(), false); RETURN_IF_EXCEPTION(scope, false); } if (descriptor.writablePresent() && !descriptor.writable()) regExp->m_lastIndexIsWritable = false; return true; } scope.release(); return Base::defineOwnProperty(object, exec, propertyName, descriptor, shouldThrow); }
bool PropertyDescriptor::equalTo(ExecState* exec, const PropertyDescriptor& other) const { if (other.m_value.isEmpty() != m_value.isEmpty() || other.m_getter.isEmpty() != m_getter.isEmpty() || other.m_setter.isEmpty() != m_setter.isEmpty()) return false; return (!m_value || sameValue(exec, other.m_value, m_value)) && (!m_getter || JSValue::strictEqual(exec, other.m_getter, m_getter)) && (!m_setter || JSValue::strictEqual(exec, other.m_setter, m_setter)) && attributesEqual(other); }
bool StringObject::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName propertyName, PropertyDescriptor& descriptor, bool throwException) { StringObject* thisObject = jsCast<StringObject*>(object); if (propertyName == exec->propertyNames().length) { if (!object->isExtensible()) { if (throwException) throwError(exec, createTypeError(exec, ASCIILiteral("Attempting to define property on object that is not extensible."))); return false; } if (descriptor.configurablePresent() && descriptor.configurable()) { if (throwException) throwError(exec, createTypeError(exec, ASCIILiteral("Attempting to configurable attribute of unconfigurable property."))); return false; } if (descriptor.enumerablePresent() && descriptor.enumerable()) { if (throwException) throwError(exec, createTypeError(exec, ASCIILiteral("Attempting to change enumerable attribute of unconfigurable property."))); return false; } if (descriptor.isAccessorDescriptor()) { if (throwException) throwError(exec, createTypeError(exec, ASCIILiteral("Attempting to change access mechanism for an unconfigurable property."))); return false; } if (descriptor.writablePresent() && descriptor.writable()) { if (throwException) throwError(exec, createTypeError(exec, ASCIILiteral("Attempting to change writable attribute of unconfigurable property."))); return false; } if (!descriptor.value()) return true; if (propertyName == exec->propertyNames().length && sameValue(exec, descriptor.value(), jsNumber(thisObject->internalValue()->length()))) return true; if (throwException) throwError(exec, createTypeError(exec, ASCIILiteral("Attempting to change value of a readonly property."))); return false; } return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException); }
EncodedJSValue JSC_HOST_CALL JSPromiseConstructorFuncResolve(ExecState* exec) { // -- Promise.resolve(x) -- JSValue x = exec->argument(0); // 1. Let 'C' be the this value. JSValue C = exec->thisValue(); // 2. If IsPromise(x) is true, JSPromise* promise = jsDynamicCast<JSPromise*>(x); if (promise) { // i. Let 'constructor' be the value of x's [[PromiseConstructor]] internal slot. JSValue constructor = promise->constructor(); // ii. If SameValue(constructor, C) is true, return x. if (sameValue(exec, constructor, C)) return JSValue::encode(x); } // 3. Let 'deferred' be the result of calling GetDeferred(C). JSValue deferredValue = createJSPromiseDeferredFromConstructor(exec, C); // 4. ReturnIfAbrupt(deferred). if (exec->hadException()) return JSValue::encode(jsUndefined()); JSPromiseDeferred* deferred = jsCast<JSPromiseDeferred*>(deferredValue); // 5. Let 'resolveResult' be the result of calling the [[Call]] internal method // of deferred.[[Resolve]] with undefined as thisArgument and a List containing x // as argumentsList. performDeferredResolve(exec, deferred, x); // 6. ReturnIfAbrupt(resolveResult). if (exec->hadException()) return JSValue::encode(jsUndefined()); // 7. Return deferred.[[Promise]]. return JSValue::encode(deferred->promise()); }
bool JSFunction::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName propertyName, PropertyDescriptor& descriptor, bool throwException) { JSFunction* thisObject = jsCast<JSFunction*>(object); if (thisObject->isHostFunction()) return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException); if (propertyName == exec->propertyNames().prototype) { // Make sure prototype has been reified, such that it can only be overwritten // following the rules set out in ECMA-262 8.12.9. PropertySlot slot; thisObject->methodTable()->getOwnPropertySlot(thisObject, exec, propertyName, slot); thisObject->m_allocationProfile.clear(); thisObject->m_allocationProfileWatchpoint.notifyWrite(); return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException); } bool valueCheck; if (propertyName == exec->propertyNames().arguments) { if (thisObject->jsExecutable()->isStrictMode()) { if (!Base::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor)) thisObject->putDirectAccessor(exec, propertyName, thisObject->globalObject()->throwTypeErrorGetterSetter(exec), DontDelete | DontEnum | Accessor); return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException); } valueCheck = !descriptor.value() || sameValue(exec, descriptor.value(), exec->interpreter()->retrieveArgumentsFromVMCode(exec, thisObject)); } else if (propertyName == exec->propertyNames().caller) { if (thisObject->jsExecutable()->isStrictMode()) { if (!Base::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor)) thisObject->putDirectAccessor(exec, propertyName, thisObject->globalObject()->throwTypeErrorGetterSetter(exec), DontDelete | DontEnum | Accessor); return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException); } valueCheck = !descriptor.value() || sameValue(exec, descriptor.value(), exec->interpreter()->retrieveCallerFromVMCode(exec, thisObject)); } else if (propertyName == exec->propertyNames().length) valueCheck = !descriptor.value() || sameValue(exec, descriptor.value(), jsNumber(thisObject->jsExecutable()->parameterCount())); else if (propertyName == exec->propertyNames().name) valueCheck = !descriptor.value() || sameValue(exec, descriptor.value(), thisObject->jsExecutable()->nameValue()); else return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException); if (descriptor.configurablePresent() && descriptor.configurable()) { if (throwException) throwError(exec, createTypeError(exec, ASCIILiteral("Attempting to configurable attribute of unconfigurable property."))); return false; } if (descriptor.enumerablePresent() && descriptor.enumerable()) { if (throwException) throwError(exec, createTypeError(exec, ASCIILiteral("Attempting to change enumerable attribute of unconfigurable property."))); return false; } if (descriptor.isAccessorDescriptor()) { if (throwException) throwError(exec, createTypeError(exec, ASCIILiteral("Attempting to change access mechanism for an unconfigurable property."))); return false; } if (descriptor.writablePresent() && descriptor.writable()) { if (throwException) throwError(exec, createTypeError(exec, ASCIILiteral("Attempting to change writable attribute of unconfigurable property."))); return false; } if (!valueCheck) { if (throwException) throwError(exec, createTypeError(exec, ASCIILiteral("Attempting to change value of a readonly property."))); return false; } return true; }
static EncodedJSValue JSC_HOST_CALL promiseResolutionHandlerFunction(ExecState* exec) { JSValue x = exec->argument(0); VM& vm = exec->vm(); JSObject* F = exec->callee(); // 1. Let 'promise' be the value of F's [[Promise]] internal slot JSPromise* promise = jsCast<JSPromise*>(F->get(exec, vm.propertyNames->promisePrivateName)); // 2. Let 'fulfillmentHandler' be the value of F's [[FulfillmentHandler]] internal slot. JSValue fulfillmentHandler = F->get(exec, vm.propertyNames->fulfillmentHandlerPrivateName); // 3. Let 'rejectionHandler' be the value of F's [[RejectionHandler]] internal slot. JSValue rejectionHandler = F->get(exec, vm.propertyNames->rejectionHandlerPrivateName); // 4. If SameValue(x, promise) is true, if (sameValue(exec, x, promise)) { // i. Let 'selfResolutionError' be a newly-created TypeError object. JSObject* selfResolutionError = createTypeError(exec, ASCIILiteral("Resolve a promise with itself")); // ii. Return the result of calling the [[Call]] internal method of rejectionHandler with // undefined as thisArgument and a List containing selfResolutionError as argumentsList. CallData rejectCallData; CallType rejectCallType = getCallData(rejectionHandler, rejectCallData); ASSERT(rejectCallType != CallTypeNone); MarkedArgumentBuffer rejectArguments; rejectArguments.append(selfResolutionError); return JSValue::encode(call(exec, rejectionHandler, rejectCallType, rejectCallData, jsUndefined(), rejectArguments)); } // 5. Let 'C' be the value of promise's [[PromiseConstructor]] internal slot. JSValue C = promise->constructor(); // 6. Let 'deferred' be the result of calling GetDeferred(C) JSValue deferredValue = createJSPromiseDeferredFromConstructor(exec, C); // 7. ReturnIfAbrupt(deferred). if (exec->hadException()) return JSValue::encode(jsUndefined()); JSPromiseDeferred* deferred = jsCast<JSPromiseDeferred*>(deferredValue); // 8. Let 'updateResult' be the result of calling UpdateDeferredFromPotentialThenable(x, deferred). ThenableStatus updateResult = updateDeferredFromPotentialThenable(exec, x, deferred); // 9. ReturnIfAbrupt(updateResult). if (exec->hadException()) return JSValue::encode(jsUndefined()); // 10. If 'updateResult' is not "not a thenable", return the result of calling // Invoke(deferred.[[Promise]], "then", (fulfillmentHandler, rejectionHandler)). // NOTE: Invoke does not seem to be defined anywhere, so I am guessing here. if (updateResult != NotAThenable) { JSObject* deferredPromise = deferred->promise(); JSValue thenValue = deferredPromise->get(exec, exec->vm().propertyNames->then); if (exec->hadException()) return JSValue::encode(jsUndefined()); CallData thenCallData; CallType thenCallType = getCallData(thenValue, thenCallData); if (thenCallType == CallTypeNone) return JSValue::encode(throwTypeError(exec)); MarkedArgumentBuffer arguments; arguments.append(fulfillmentHandler); arguments.append(rejectionHandler); return JSValue::encode(call(exec, thenValue, thenCallType, thenCallData, deferredPromise, arguments)); } // 11. Return the result of calling the [[Call]] internal method of fulfillmentHandler // with undefined as thisArgument and a List containing x as argumentsList. CallData fulfillmentHandlerCallData; CallType fulfillmentHandlerCallType = getCallData(fulfillmentHandler, fulfillmentHandlerCallData); ASSERT(fulfillmentHandlerCallType != CallTypeNone); MarkedArgumentBuffer fulfillmentHandlerArguments; fulfillmentHandlerArguments.append(x); return JSValue::encode(call(exec, fulfillmentHandler, fulfillmentHandlerCallType, fulfillmentHandlerCallData, jsUndefined(), fulfillmentHandlerArguments)); }