JSValue JSCommandLineAPIHost::getEventListeners(ExecState& state) { if (state.argumentCount() < 1) return jsUndefined(); JSValue value = state.uncheckedArgument(0); if (!value.isObject() || value.isNull()) return jsUndefined(); Node* node = JSNode::toWrapped(value); if (!node) return jsUndefined(); Vector<EventListenerInfo> listenersArray; wrapped().getEventListenersImpl(node, listenersArray); JSObject* result = constructEmptyObject(&state); for (size_t i = 0; i < listenersArray.size(); ++i) { JSArray* listeners = getJSListenerFunctions(state, &node->document(), listenersArray[i]); if (!listeners->length()) continue; AtomicString eventType = listenersArray[i].eventType; result->putDirect(state.vm(), Identifier::fromString(&state, eventType.impl()), JSValue(listeners)); } return result; }
static CryptoKeyUsageBitmap cryptoKeyUsagesFromJSValue(ExecState& state, ThrowScope& scope, JSValue value) { if (!isJSArray(value)) { throwTypeError(&state, scope); return { }; } CryptoKeyUsageBitmap result = 0; JSArray* array = asArray(value); for (unsigned i = 0; i < array->length(); ++i) { auto usageString = array->getIndex(&state, i).toWTFString(&state); RETURN_IF_EXCEPTION(scope, { }); if (usageString == "encrypt") result |= CryptoKeyUsageEncrypt; else if (usageString == "decrypt") result |= CryptoKeyUsageDecrypt; else if (usageString == "sign") result |= CryptoKeyUsageSign; else if (usageString == "verify") result |= CryptoKeyUsageVerify; else if (usageString == "deriveKey") result |= CryptoKeyUsageDeriveKey; else if (usageString == "deriveBits") result |= CryptoKeyUsageDeriveBits; else if (usageString == "wrapKey") result |= CryptoKeyUsageWrapKey; else if (usageString == "unwrapKey") result |= CryptoKeyUsageUnwrapKey; } return result; }
JSValue JSInspectorFrontendHost::showContextMenu(ExecState* execState, const ArgList& args) { if (args.size() < 2) return jsUndefined(); Event* event = toEvent(args.at(0)); JSArray* array = asArray(args.at(1)); Vector<ContextMenuItem*> items; for (size_t i = 0; i < array->length(); ++i) { JSObject* item = asObject(array->getIndex(i)); JSValue label = item->get(execState, Identifier(execState, "label")); JSValue id = item->get(execState, Identifier(execState, "id")); if (label.isUndefined() || id.isUndefined()) items.append(new ContextMenuItem(SeparatorType, ContextMenuItemTagNoAction, String())); else { ContextMenuAction typedId = static_cast<ContextMenuAction>(ContextMenuItemBaseCustomTag + id.toInt32(execState)); items.append(new ContextMenuItem(ActionType, typedId, label.toString(execState))); } } impl()->showContextMenu(event, items); return jsUndefined(); }
JSValue JSInjectedScriptHost::getEventListeners(ExecState* exec) { if (exec->argumentCount() < 1) return jsUndefined(); JSValue value = exec->argument(0); if (!value.isObject() || value.isNull()) return jsUndefined(); Node* node = toNode(value); if (!node) return jsUndefined(); // This can only happen for orphan DocumentType nodes. Document* document = node->document(); if (!node->document()) return jsUndefined(); Vector<EventListenerInfo> listenersArray; impl()->getEventListenersImpl(node, listenersArray); JSObject* result = constructEmptyObject(exec); for (size_t i = 0; i < listenersArray.size(); ++i) { JSArray* listeners = getJSListenerFunctions(exec, document, listenersArray[i]); if (!listeners->length()) continue; AtomicString eventType = listenersArray[i].eventType; result->putDirect(exec->globalData(), Identifier(exec, eventType.impl()), JSValue(listeners)); } return result; }
static bool cryptoKeyUsagesFromJSValue(ExecState* exec, JSValue value, CryptoKeyUsage& result) { if (!isJSArray(value)) { throwTypeError(exec); return false; } result = 0; JSArray* array = asArray(value); for (size_t i = 0; i < array->length(); ++i) { JSValue element = array->getIndex(exec, i); String usageString = element.toString(exec)->value(exec); if (exec->hadException()) return false; if (usageString == "encrypt") result |= CryptoKeyUsageEncrypt; else if (usageString == "decrypt") result |= CryptoKeyUsageDecrypt; else if (usageString == "sign") result |= CryptoKeyUsageSign; else if (usageString == "verify") result |= CryptoKeyUsageVerify; else if (usageString == "deriveKey") result |= CryptoKeyUsageDeriveKey; else if (usageString == "deriveBits") result |= CryptoKeyUsageDeriveBits; else if (usageString == "wrapKey") result |= CryptoKeyUsageWrapKey; else if (usageString == "unwrapKey") result |= CryptoKeyUsageUnwrapKey; } return true; }
bool JSArray::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyName propertyName, PropertySlot& slot) { JSArray* thisObject = jsCast<JSArray*>(cell); if (propertyName == exec->propertyNames().length) { slot.setValue(jsNumber(thisObject->length())); return true; } return JSObject::getOwnPropertySlot(thisObject, exec, propertyName, slot); }
bool JSArray::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, PropertyName propertyName, PropertyDescriptor& descriptor) { JSArray* thisObject = jsCast<JSArray*>(object); if (propertyName == exec->propertyNames().length) { descriptor.setDescriptor(jsNumber(thisObject->length()), thisObject->isLengthWritable() ? DontDelete | DontEnum : DontDelete | DontEnum | ReadOnly); return true; } return JSObject::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor); }
static RefPtr<InspectorValue> jsToInspectorValue(ExecState* scriptState, JSValue value, int maxDepth) { if (!value) { ASSERT_NOT_REACHED(); return nullptr; } if (!maxDepth) return nullptr; maxDepth--; if (value.isNull() || value.isUndefined()) return InspectorValue::null(); if (value.isBoolean()) return InspectorValue::create(value.asBoolean()); if (value.isNumber() && value.isDouble()) return InspectorValue::create(value.asNumber()); if (value.isNumber() && value.isMachineInt()) return InspectorValue::create(static_cast<int>(value.asMachineInt())); if (value.isString()) return InspectorValue::create(value.getString(scriptState)); if (value.isObject()) { if (isJSArray(value)) { Ref<InspectorArray> inspectorArray = InspectorArray::create(); JSArray* array = asArray(value); unsigned length = array->length(); for (unsigned i = 0; i < length; i++) { JSValue element = array->getIndex(scriptState, i); RefPtr<InspectorValue> elementValue = jsToInspectorValue(scriptState, element, maxDepth); if (!elementValue) return nullptr; inspectorArray->pushValue(WTFMove(elementValue)); } return WTFMove(inspectorArray); } Ref<InspectorObject> inspectorObject = InspectorObject::create(); JSObject* object = value.getObject(); PropertyNameArray propertyNames(scriptState, PropertyNameMode::Strings); object->methodTable()->getOwnPropertyNames(object, scriptState, propertyNames, EnumerationMode()); for (size_t i = 0; i < propertyNames.size(); i++) { const Identifier& name = propertyNames[i]; JSValue propertyValue = object->get(scriptState, name); RefPtr<InspectorValue> inspectorValue = jsToInspectorValue(scriptState, propertyValue, maxDepth); if (!inspectorValue) return nullptr; inspectorObject->setValue(name.string(), WTFMove(inspectorValue)); } return WTFMove(inspectorObject); } ASSERT_NOT_REACHED(); return nullptr; }
bool JSArray::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot) { JSArray* thisObject = jsCast<JSArray*>(object); if (propertyName == exec->propertyNames().length) { unsigned attributes = thisObject->isLengthWritable() ? DontDelete | DontEnum : DontDelete | DontEnum | ReadOnly; slot.setValue(thisObject, attributes, jsNumber(thisObject->length())); return true; } return JSObject::getOwnPropertySlot(thisObject, exec, propertyName, slot); }
static PassRefPtr<InspectorValue> jsToInspectorValue(ScriptState* scriptState, JSValue value, int maxDepth) { if (!value) { ASSERT_NOT_REACHED(); return 0; } if (!maxDepth) return 0; maxDepth--; if (value.isNull() || value.isUndefined()) return InspectorValue::null(); if (value.isBoolean()) return InspectorBasicValue::create(value.asBoolean()); if (value.isNumber()) return InspectorBasicValue::create(value.asNumber()); if (value.isString()) { String s = value.getString(scriptState); return InspectorString::create(String(s.characters(), s.length())); } if (value.isObject()) { if (isJSArray(value)) { RefPtr<InspectorArray> inspectorArray = InspectorArray::create(); JSArray* array = asArray(value); unsigned length = array->length(); for (unsigned i = 0; i < length; i++) { // FIXME: What if the array is in sparse mode? https://bugs.webkit.org/show_bug.cgi?id=95610 JSValue element = array->getIndexQuickly(i); RefPtr<InspectorValue> elementValue = jsToInspectorValue(scriptState, element, maxDepth); if (!elementValue) return 0; inspectorArray->pushValue(elementValue); } return inspectorArray; } RefPtr<InspectorObject> inspectorObject = InspectorObject::create(); JSObject* object = value.getObject(); PropertyNameArray propertyNames(scriptState); object->methodTable()->getOwnPropertyNames(object, scriptState, propertyNames, ExcludeDontEnumProperties); for (size_t i = 0; i < propertyNames.size(); i++) { const Identifier& name = propertyNames[i]; JSValue propertyValue = object->get(scriptState, name); RefPtr<InspectorValue> inspectorValue = jsToInspectorValue(scriptState, propertyValue, maxDepth); if (!inspectorValue) return 0; inspectorObject->setValue(String(name.characters(), name.length()), inspectorValue); } return inspectorObject; } ASSERT_NOT_REACHED(); return 0; }
void JSCryptoKeySerializationJWK::reconcileUsages(CryptoKeyUsage& suggestedUsages) const { CryptoKeyUsage jwkUsages = 0; JSArray* keyOps; if (getJSArrayFromJSON(m_exec, m_json.get(), "key_ops", keyOps)) { for (size_t i = 0; i < keyOps->length(); ++i) { JSValue jsValue = keyOps->getIndex(m_exec, i); String operation; if (!jsValue.getString(m_exec, operation)) { if (!m_exec->hadException()) throwTypeError(m_exec, "JWK key_ops attribute could not be processed"); return; } if (!tryJWKKeyOpsValue(m_exec, jwkUsages, operation, ASCIILiteral("sign"), CryptoKeyUsageSign)) return; if (!tryJWKKeyOpsValue(m_exec, jwkUsages, operation, ASCIILiteral("verify"), CryptoKeyUsageVerify)) return; if (!tryJWKKeyOpsValue(m_exec, jwkUsages, operation, ASCIILiteral("encrypt"), CryptoKeyUsageEncrypt)) return; if (!tryJWKKeyOpsValue(m_exec, jwkUsages, operation, ASCIILiteral("decrypt"), CryptoKeyUsageDecrypt)) return; if (!tryJWKKeyOpsValue(m_exec, jwkUsages, operation, ASCIILiteral("wrapKey"), CryptoKeyUsageWrapKey)) return; if (!tryJWKKeyOpsValue(m_exec, jwkUsages, operation, ASCIILiteral("unwrapKey"), CryptoKeyUsageUnwrapKey)) return; if (!tryJWKKeyOpsValue(m_exec, jwkUsages, operation, ASCIILiteral("deriveKey"), CryptoKeyUsageDeriveKey)) return; if (!tryJWKKeyOpsValue(m_exec, jwkUsages, operation, ASCIILiteral("deriveBits"), CryptoKeyUsageDeriveBits)) return; } } else { if (m_exec->hadException()) return; String jwkUseString; if (!getStringFromJSON(m_exec, m_json.get(), "use", jwkUseString)) { // We have neither key_ops nor use. return; } if (jwkUseString == "enc") jwkUsages |= (CryptoKeyUsageEncrypt | CryptoKeyUsageDecrypt | CryptoKeyUsageWrapKey | CryptoKeyUsageUnwrapKey); else if (jwkUseString == "sig") jwkUsages |= (CryptoKeyUsageSign | CryptoKeyUsageVerify); else { throwTypeError(m_exec, "Unsupported JWK key use value \"" + jwkUseString + "\""); return; } } suggestedUsages = suggestedUsages & jwkUsages; }
JSValue RegExpConstructor::getLastParen(ExecState* exec) { JSArray* array = m_cachedResult.lastResult(exec, this); unsigned length = array->length(); if (length > 1) { JSValue result = JSValue(array).get(exec, length - 1); ASSERT(result.isString() || result.isUndefined()); if (!result.isUndefined()) return result; } return jsEmptyString(exec); }
JSValue RegExpConstructor::getBackref(ExecState* exec, unsigned i) { JSArray* array = m_cachedResult.lastResult(exec, this); if (i < array->length()) { JSValue result = JSValue(array).get(exec, i); ASSERT(result.isString() || result.isUndefined()); if (!result.isUndefined()) return result; } return jsEmptyString(exec); }
static PassRefPtr<InspectorValue> jsToInspectorValue(ScriptState* scriptState, JSValue value) { if (!value) { ASSERT_NOT_REACHED(); return 0; } if (value.isNull() || value.isUndefined()) return InspectorValue::null(); if (value.isBoolean()) return InspectorBasicValue::create(value.getBoolean()); if (value.isNumber()) return InspectorBasicValue::create(value.uncheckedGetNumber()); if (value.isString()) { UString s = value.getString(scriptState); return InspectorString::create(String(s.characters(), s.length())); } if (value.isObject()) { if (isJSArray(&scriptState->globalData(), value)) { RefPtr<InspectorArray> inspectorArray = InspectorArray::create(); JSArray* array = asArray(value); unsigned length = array->length(); for (unsigned i = 0; i < length; i++) { JSValue element = array->getIndex(i); RefPtr<InspectorValue> elementValue = jsToInspectorValue(scriptState, element); if (!elementValue) { ASSERT_NOT_REACHED(); elementValue = InspectorValue::null(); } inspectorArray->pushValue(elementValue); } return inspectorArray; } RefPtr<InspectorObject> inspectorObject = InspectorObject::create(); JSObject* object = value.getObject(); PropertyNameArray propertyNames(scriptState); object->getOwnPropertyNames(scriptState, propertyNames); for (size_t i = 0; i < propertyNames.size(); i++) { const Identifier& name = propertyNames[i]; JSValue propertyValue = object->get(scriptState, name); RefPtr<InspectorValue> inspectorValue = jsToInspectorValue(scriptState, propertyValue); if (!inspectorValue) { ASSERT_NOT_REACHED(); inspectorValue = InspectorValue::null(); } inspectorObject->setValue(String(name.characters(), name.length()), inspectorValue); } return inspectorObject; } ASSERT_NOT_REACHED(); return 0; }
PassRefPtr<DOMStringList> toDOMStringList(ExecState* exec, JSValue value) { if (value.inherits(&JSDOMStringList::s_info)) return jsCast<JSDOMStringList*>(asObject(value))->impl(); if (!isJSArray(value)) return 0; JSArray* array = asArray(value); RefPtr<DOMStringList> stringList = DOMStringList::create(); for (unsigned i = 0; i < array->length(); ++i) stringList->append(array->getIndex(exec, i).toString(exec)->value(exec)); return stringList.release(); }
void JSInternals::setUserPreferredLanguages(ExecState* exec, JSValue value) { if (!isJSArray(value)) { throwError(exec, createSyntaxError(exec, "setUserPreferredLanguages: Expected Array")); return; } Vector<String> languages; JSArray* array = asArray(value); for (unsigned i = 0; i < array->length(); ++i) { String language = ustringToString(array->getIndex(i).toString(exec)->value(exec)); languages.append(language); } Internals* imp = static_cast<Internals*>(impl()); imp->setUserPreferredLanguages(languages); }
void JSCanvasRenderingContext2D::setWebkitLineDash(ExecState* exec, JSValue value) { if (!isJSArray(value)) return; Vector<float> dash; JSArray* valueArray = asArray(value); for (unsigned i = 0; i < valueArray->length(); ++i) { float elem = valueArray->getIndex(exec, i).toFloat(exec); if (elem <= 0 || !std::isfinite(elem)) return; dash.append(elem); } CanvasRenderingContext2D* context = static_cast<CanvasRenderingContext2D*>(impl()); context->setWebkitLineDash(dash); }
EncodedJSValue JSC_HOST_CALL boundFunctionConstruct(ExecState* exec) { JSBoundFunction* boundFunction = jsCast<JSBoundFunction*>(exec->callee()); ASSERT(isJSArray(boundFunction->boundArgs())); // Currently this is true! JSArray* boundArgs = asArray(boundFunction->boundArgs()); MarkedArgumentBuffer args; for (unsigned i = 0; i < boundArgs->length(); ++i) args.append(boundArgs->getIndexQuickly(i)); for (unsigned i = 0; i < exec->argumentCount(); ++i) args.append(exec->argument(i)); JSObject* targetFunction = boundFunction->targetFunction(); ConstructData constructData; ConstructType constructType = getConstructData(targetFunction, constructData); ASSERT(constructType != ConstructTypeNone); return JSValue::encode(construct(exec, targetFunction, constructType, constructData, args)); }
EncodedJSValue JSC_HOST_CALL boundFunctionCall(ExecState* exec) { JSBoundFunction* boundFunction = jsCast<JSBoundFunction*>(exec->jsCallee()); JSArray* boundArgs = boundFunction->boundArgs(); MarkedArgumentBuffer args; if (boundArgs) { for (unsigned i = 0; i < boundArgs->length(); ++i) args.append(boundArgs->getIndexQuickly(i)); } for (unsigned i = 0; i < exec->argumentCount(); ++i) args.append(exec->uncheckedArgument(i)); JSObject* targetFunction = boundFunction->targetFunction(); CallData callData; CallType callType = getCallData(targetFunction, callData); ASSERT(callType != CallType::None); return JSValue::encode(call(exec, targetFunction, callType, callData, boundFunction->boundThis(), args)); }
JSValue JSInspectorFrontendHost::showContextMenu(ExecState* exec) { if (exec->argumentCount() < 2) return jsUndefined(); #if ENABLE(CONTEXT_MENUS) Event* event = toEvent(exec->argument(0)); JSArray* array = asArray(exec->argument(1)); Vector<ContextMenuItem*> items; for (size_t i = 0; i < array->length(); ++i) { JSObject* item = asObject(array->getIndex(i)); JSValue label = item->get(exec, Identifier(exec, "label")); JSValue type = item->get(exec, Identifier(exec, "type")); JSValue id = item->get(exec, Identifier(exec, "id")); JSValue enabled = item->get(exec, Identifier(exec, "enabled")); JSValue checked = item->get(exec, Identifier(exec, "checked")); if (!type.isString()) continue; String typeString = ustringToString(type.toString(exec)->value(exec)); if (typeString == "separator") { items.append(new ContextMenuItem(SeparatorType, ContextMenuItemCustomTagNoAction, String())); } else { ContextMenuAction typedId = static_cast<ContextMenuAction>(ContextMenuItemBaseCustomTag + id.toInt32(exec)); ContextMenuItem* menuItem = new ContextMenuItem((typeString == "checkbox" ? CheckableActionType : ActionType), typedId, ustringToString(label.toString(exec)->value(exec))); if (!enabled.isUndefined()) menuItem->setEnabled(enabled.toBoolean(exec)); if (!checked.isUndefined()) menuItem->setChecked(checked.toBoolean(exec)); items.append(menuItem); } } impl()->showContextMenu(event, items); #endif return jsUndefined(); }
EncodedJSValue JSC_HOST_CALL JSWebSocketConstructor::constructJSWebSocket(ExecState* exec) { JSWebSocketConstructor* jsConstructor = static_cast<JSWebSocketConstructor*>(exec->callee()); ScriptExecutionContext* context = jsConstructor->scriptExecutionContext(); if (!context) return throwVMError(exec, createReferenceError(exec, "WebSocket constructor associated document is unavailable")); if (!exec->argumentCount()) return throwVMError(exec, createSyntaxError(exec, "Not enough arguments")); String urlString = ustringToString(exec->argument(0).toString(exec)->value(exec)); if (exec->hadException()) return throwVMError(exec, createSyntaxError(exec, "wrong URL")); RefPtr<WebSocket> webSocket = WebSocket::create(context); ExceptionCode ec = 0; if (exec->argumentCount() < 2) webSocket->connect(urlString, ec); else { JSValue protocolsValue = exec->argument(1); if (isJSArray(protocolsValue)) { Vector<String> protocols; JSArray* protocolsArray = asArray(protocolsValue); for (unsigned i = 0; i < protocolsArray->length(); ++i) { String protocol = ustringToString(protocolsArray->getIndex(i).toString(exec)->value(exec)); if (exec->hadException()) return JSValue::encode(JSValue()); protocols.append(protocol); } webSocket->connect(urlString, protocols, ec); } else { String protocol = ustringToString(protocolsValue.toString(exec)->value(exec)); if (exec->hadException()) return JSValue::encode(JSValue()); webSocket->connect(urlString, protocol, ec); } } setDOMException(exec, ec); return JSValue::encode(CREATE_DOM_WRAPPER(exec, jsConstructor->globalObject(), WebSocket, webSocket.get())); }
static bool cryptoKeyUsagesFromJSValue(ExecState& state, JSValue value, CryptoKeyUsageBitmap& result) { VM& vm = state.vm(); auto scope = DECLARE_THROW_SCOPE(vm); if (!isJSArray(value)) { throwTypeError(&state, scope); return false; } result = 0; JSArray* array = asArray(value); for (size_t i = 0; i < array->length(); ++i) { JSValue element = array->getIndex(&state, i); String usageString = element.toString(&state)->value(&state); RETURN_IF_EXCEPTION(scope, false); if (usageString == "encrypt") result |= CryptoKeyUsageEncrypt; else if (usageString == "decrypt") result |= CryptoKeyUsageDecrypt; else if (usageString == "sign") result |= CryptoKeyUsageSign; else if (usageString == "verify") result |= CryptoKeyUsageVerify; else if (usageString == "deriveKey") result |= CryptoKeyUsageDeriveKey; else if (usageString == "deriveBits") result |= CryptoKeyUsageDeriveBits; else if (usageString == "wrapKey") result |= CryptoKeyUsageWrapKey; else if (usageString == "unwrapKey") result |= CryptoKeyUsageUnwrapKey; } return true; }
static RefPtr<IDBKey> createIDBKeyFromValue(ExecState* exec, JSValue value, Vector<JSArray*>& stack) { if (value.isNumber() && !std::isnan(value.toNumber(exec))) return IDBKey::createNumber(value.toNumber(exec)); if (value.isString()) return IDBKey::createString(value.toString(exec)->value(exec)); if (value.inherits(DateInstance::info()) && !std::isnan(valueToDate(exec, value))) return IDBKey::createDate(valueToDate(exec, value)); if (value.isObject()) { JSObject* object = asObject(value); if (isJSArray(object) || object->inherits(JSArray::info())) { JSArray* array = asArray(object); size_t length = array->length(); if (stack.contains(array)) return nullptr; if (stack.size() >= maximumDepth) return nullptr; stack.append(array); Vector<RefPtr<IDBKey>> subkeys; for (size_t i = 0; i < length; i++) { JSValue item = array->getIndex(exec, i); RefPtr<IDBKey> subkey = createIDBKeyFromValue(exec, item, stack); if (!subkey) subkeys.append(IDBKey::createInvalid()); else subkeys.append(subkey); } stack.removeLast(); return IDBKey::createArray(subkeys); } } return nullptr; }
// Defined in ES5.1 15.4.5.1 bool JSArray::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName propertyName, const PropertyDescriptor& descriptor, bool throwException) { JSArray* array = jsCast<JSArray*>(object); // 3. If P is "length", then if (propertyName == exec->propertyNames().length) { // All paths through length definition call the default [[DefineOwnProperty]], hence: // from ES5.1 8.12.9 7.a. if (descriptor.configurablePresent() && descriptor.configurable()) return reject(exec, throwException, "Attempting to change configurable attribute of unconfigurable property."); // from ES5.1 8.12.9 7.b. if (descriptor.enumerablePresent() && descriptor.enumerable()) return reject(exec, throwException, "Attempting to change enumerable attribute of unconfigurable property."); // a. If the [[Value]] field of Desc is absent, then // a.i. Return the result of calling the default [[DefineOwnProperty]] internal method (8.12.9) on A passing "length", Desc, and Throw as arguments. if (descriptor.isAccessorDescriptor()) return reject(exec, throwException, "Attempting to change access mechanism for an unconfigurable property."); // from ES5.1 8.12.9 10.a. if (!array->isLengthWritable() && descriptor.writablePresent() && descriptor.writable()) return reject(exec, throwException, "Attempting to change writable attribute of unconfigurable property."); // This descriptor is either just making length read-only, or changing nothing! if (!descriptor.value()) { if (descriptor.writablePresent()) array->setLengthWritable(exec, descriptor.writable()); return true; } // b. Let newLenDesc be a copy of Desc. // c. Let newLen be ToUint32(Desc.[[Value]]). unsigned newLen = descriptor.value().toUInt32(exec); // d. If newLen is not equal to ToNumber( Desc.[[Value]]), throw a RangeError exception. if (newLen != descriptor.value().toNumber(exec)) { exec->vm().throwException(exec, createRangeError(exec, ASCIILiteral("Invalid array length"))); return false; } // Based on SameValue check in 8.12.9, this is always okay. // FIXME: Nothing prevents this from being called on a RuntimeArray, and the length function will always return 0 in that case. if (newLen == array->length()) { if (descriptor.writablePresent()) array->setLengthWritable(exec, descriptor.writable()); return true; } // e. Set newLenDesc.[[Value] to newLen. // f. If newLen >= oldLen, then // f.i. Return the result of calling the default [[DefineOwnProperty]] internal method (8.12.9) on A passing "length", newLenDesc, and Throw as arguments. // g. Reject if oldLenDesc.[[Writable]] is false. if (!array->isLengthWritable()) return reject(exec, throwException, "Attempting to change value of a readonly property."); // h. If newLenDesc.[[Writable]] is absent or has the value true, let newWritable be true. // i. Else, // i.i. Need to defer setting the [[Writable]] attribute to false in case any elements cannot be deleted. // i.ii. Let newWritable be false. // i.iii. Set newLenDesc.[[Writable] to true. // j. Let succeeded be the result of calling the default [[DefineOwnProperty]] internal method (8.12.9) on A passing "length", newLenDesc, and Throw as arguments. // k. If succeeded is false, return false. // l. While newLen < oldLen repeat, // l.i. Set oldLen to oldLen – 1. // l.ii. Let deleteSucceeded be the result of calling the [[Delete]] internal method of A passing ToString(oldLen) and false as arguments. // l.iii. If deleteSucceeded is false, then if (!array->setLength(exec, newLen, throwException)) { // 1. Set newLenDesc.[[Value] to oldLen+1. // 2. If newWritable is false, set newLenDesc.[[Writable] to false. // 3. Call the default [[DefineOwnProperty]] internal method (8.12.9) on A passing "length", newLenDesc, and false as arguments. // 4. Reject. if (descriptor.writablePresent()) array->setLengthWritable(exec, descriptor.writable()); return false; } // m. If newWritable is false, then // i. Call the default [[DefineOwnProperty]] internal method (8.12.9) on A passing "length", // Property Descriptor{[[Writable]]: false}, and false as arguments. This call will always // return true. if (descriptor.writablePresent()) array->setLengthWritable(exec, descriptor.writable()); // n. Return true. return true; } // 4. Else if P is an array index (15.4), then // a. Let index be ToUint32(P). if (Optional<uint32_t> optionalIndex = parseIndex(propertyName)) { // b. Reject if index >= oldLen and oldLenDesc.[[Writable]] is false. uint32_t index = optionalIndex.value(); // FIXME: Nothing prevents this from being called on a RuntimeArray, and the length function will always return 0 in that case. if (index >= array->length() && !array->isLengthWritable()) return reject(exec, throwException, "Attempting to define numeric property on array with non-writable length property."); // c. Let succeeded be the result of calling the default [[DefineOwnProperty]] internal method (8.12.9) on A passing P, Desc, and false as arguments. // d. Reject if succeeded is false. // e. If index >= oldLen // e.i. Set oldLenDesc.[[Value]] to index + 1. // e.ii. Call the default [[DefineOwnProperty]] internal method (8.12.9) on A passing "length", oldLenDesc, and false as arguments. This call will always return true. // f. Return true. return array->defineOwnIndexedProperty(exec, index, descriptor, throwException); } return array->JSObject::defineOwnNonIndexProperty(exec, propertyName, descriptor, throwException); }
JSValue collectMatches(VM& vm, ExecState* exec, JSString* string, const String& s, RegExpConstructor* constructor, RegExp* regExp, const FixEndFunc& fixEnd) { auto scope = DECLARE_THROW_SCOPE(vm); MatchResult result = constructor->performMatch(vm, regExp, string, s, 0); if (!result) return jsNull(); static unsigned maxSizeForDirectPath = 100000; JSArray* array = constructEmptyArray(exec, nullptr); if (UNLIKELY(vm.exception())) return jsUndefined(); auto iterate = [&] () { size_t end = result.end; size_t length = end - result.start; array->push(exec, JSRopeString::createSubstringOfResolved(vm, string, result.start, length)); if (!length) end = fixEnd(end); result = constructor->performMatch(vm, regExp, string, s, end); }; do { if (array->length() >= maxSizeForDirectPath) { // First do a throw-away match to see how many matches we'll get. unsigned matchCount = 0; MatchResult savedResult = result; do { if (array->length() + matchCount >= MAX_STORAGE_VECTOR_LENGTH) { throwOutOfMemoryError(exec, scope); return jsUndefined(); } size_t end = result.end; matchCount++; if (result.empty()) end = fixEnd(end); // Using RegExpConstructor::performMatch() instead of calling RegExp::match() // directly is a surprising but profitable choice: it means that when we do OOM, we // will leave the cached result in the state it ought to have had just before the // OOM! On the other hand, if this loop concludes that the result is small enough, // then the iterate() loop below will overwrite the cached result anyway. result = constructor->performMatch(vm, regExp, string, s, end); } while (result); // OK, we have a sensible number of matches. Now we can create them for reals. result = savedResult; do iterate(); while (result); return array; } iterate(); } while (result); return array; }
EncodedJSValue JSC_HOST_CALL JSBlobConstructor::constructJSBlob(ExecState* exec) { JSBlobConstructor* jsConstructor = jsCast<JSBlobConstructor*>(exec->callee()); ScriptExecutionContext* context = jsConstructor->scriptExecutionContext(); if (!context) return throwVMError(exec, createReferenceError(exec, "Blob constructor associated document is unavailable")); if (!exec->argumentCount()) { RefPtr<Blob> blob = Blob::create(); return JSValue::encode(CREATE_DOM_WRAPPER(exec, jsConstructor->globalObject(), Blob, blob.get())); } JSValue firstArg = exec->argument(0); if (!isJSArray(firstArg)) return throwVMError(exec, createTypeError(exec, "First argument of the constructor is not of type Array")); String type; String endings = "transparent"; if (exec->argumentCount() > 1) { JSValue blobPropertyBagValue = exec->argument(1); if (!blobPropertyBagValue.isObject()) return throwVMError(exec, createTypeError(exec, "Second argument of the constructor is not of type Object")); // Given the above test, this will always yield an object. JSObject* blobPropertyBagObject = blobPropertyBagValue.toObject(exec); // Create the dictionary wrapper from the initializer object. JSDictionary dictionary(exec, blobPropertyBagObject); // Attempt to get the endings property and validate it. bool containsEndings = dictionary.get("endings", endings); if (exec->hadException()) return JSValue::encode(jsUndefined()); if (containsEndings) { if (endings != "transparent" && endings != "native") return throwVMError(exec, createTypeError(exec, "The endings property must be either \"transparent\" or \"native\"")); } // Attempt to get the type property. dictionary.get("type", type); if (exec->hadException()) return JSValue::encode(jsUndefined()); } ASSERT(endings == "transparent" || endings == "native"); // FIXME: this would be better if the WebKitBlobBuilder were a stack object to avoid the allocation. RefPtr<WebKitBlobBuilder> blobBuilder = WebKitBlobBuilder::create(); JSArray* array = asArray(firstArg); unsigned length = array->length(); for (unsigned i = 0; i < length; ++i) { JSValue item = array->getIndex(i); #if ENABLE(BLOB) if (item.inherits(&JSArrayBuffer::s_info)) blobBuilder->append(toArrayBuffer(item)); else #endif if (item.inherits(&JSBlob::s_info)) blobBuilder->append(toBlob(item)); else { String string = ustringToString(item.toString(exec)->value(exec)); if (exec->hadException()) return JSValue::encode(jsUndefined()); blobBuilder->append(string, endings, ASSERT_NO_EXCEPTION); } } RefPtr<Blob> blob = blobBuilder->getBlob(type); return JSValue::encode(CREATE_DOM_WRAPPER(exec, jsConstructor->globalObject(), Blob, blob.get())); }
std::unique_ptr<CryptoKeyData> JSCryptoKeySerializationJWK::keyDataRSAComponents() const { Vector<uint8_t> modulus; Vector<uint8_t> exponent; Vector<uint8_t> privateExponent; if (!getBigIntegerVectorFromJSON(m_exec, m_json.get(), "n", modulus)) { if (!m_exec->hadException()) throwTypeError(m_exec, "Required JWK \"n\" member is missing"); return nullptr; } if (!keySizeIsValid(modulus.size() * 8)) { throwTypeError(m_exec, "Key size is not valid for " + m_jwkAlgorithmName); return nullptr; } if (!getBigIntegerVectorFromJSON(m_exec, m_json.get(), "e", exponent)) { if (!m_exec->hadException()) throwTypeError(m_exec, "Required JWK \"e\" member is missing"); return nullptr; } if (!getBigIntegerVectorFromJSON(m_exec, m_json.get(), "d", modulus)) { if (m_exec->hadException()) return nullptr; return CryptoKeyDataRSAComponents::createPublic(modulus, exponent); } CryptoKeyDataRSAComponents::PrimeInfo firstPrimeInfo; CryptoKeyDataRSAComponents::PrimeInfo secondPrimeInfo; Vector<CryptoKeyDataRSAComponents::PrimeInfo> otherPrimeInfos; if (!getBigIntegerVectorFromJSON(m_exec, m_json.get(), "p", firstPrimeInfo.primeFactor)) { if (m_exec->hadException()) return nullptr; return CryptoKeyDataRSAComponents::createPrivate(modulus, exponent, privateExponent); } if (!getBigIntegerVectorFromJSON(m_exec, m_json.get(), "dp", firstPrimeInfo.factorCRTExponent)) { if (m_exec->hadException()) return nullptr; return CryptoKeyDataRSAComponents::createPrivate(modulus, exponent, privateExponent); } if (!getBigIntegerVectorFromJSON(m_exec, m_json.get(), "q", secondPrimeInfo.primeFactor)) { if (m_exec->hadException()) return nullptr; return CryptoKeyDataRSAComponents::createPrivate(modulus, exponent, privateExponent); } if (!getBigIntegerVectorFromJSON(m_exec, m_json.get(), "dq", secondPrimeInfo.factorCRTExponent)) { if (m_exec->hadException()) return nullptr; return CryptoKeyDataRSAComponents::createPrivate(modulus, exponent, privateExponent); } if (!getBigIntegerVectorFromJSON(m_exec, m_json.get(), "qi", secondPrimeInfo.factorCRTCoefficient)) { if (m_exec->hadException()) return nullptr; return CryptoKeyDataRSAComponents::createPrivate(modulus, exponent, privateExponent); } JSArray* otherPrimeInfoJSArray; if (!getJSArrayFromJSON(m_exec, m_json.get(), "oth", otherPrimeInfoJSArray)) { if (m_exec->hadException()) return nullptr; return CryptoKeyDataRSAComponents::createPrivateWithAdditionalData(modulus, exponent, privateExponent, firstPrimeInfo, secondPrimeInfo, otherPrimeInfos); } for (size_t i = 0; i < otherPrimeInfoJSArray->length(); ++i) { CryptoKeyDataRSAComponents::PrimeInfo info; JSValue element = otherPrimeInfoJSArray->getIndex(m_exec, i); if (m_exec->hadException()) return nullptr; if (!element.isObject()) { throwTypeError(m_exec, "JWK \"oth\" array member is not an object"); return nullptr; } if (!getBigIntegerVectorFromJSON(m_exec, asObject(element), "r", info.primeFactor)) { if (!m_exec->hadException()) throwTypeError(m_exec, "Cannot get prime factor for a prime in \"oth\" dictionary"); return nullptr; } if (!getBigIntegerVectorFromJSON(m_exec, asObject(element), "d", info.factorCRTExponent)) { if (!m_exec->hadException()) throwTypeError(m_exec, "Cannot get factor CRT exponent for a prime in \"oth\" dictionary"); return nullptr; } if (!getBigIntegerVectorFromJSON(m_exec, asObject(element), "t", info.factorCRTCoefficient)) { if (!m_exec->hadException()) throwTypeError(m_exec, "Cannot get factor CRT coefficient for a prime in \"oth\" dictionary"); return nullptr; } otherPrimeInfos.append(info); } return CryptoKeyDataRSAComponents::createPrivateWithAdditionalData(modulus, exponent, privateExponent, firstPrimeInfo, secondPrimeInfo, otherPrimeInfos); }
SerializationReturnCode CloneSerializer::serialize(JSValue in) { Vector<uint32_t, 16> indexStack; Vector<uint32_t, 16> lengthStack; Vector<PropertyNameArray, 16> propertyStack; Vector<JSObject*, 16> inputObjectStack; Vector<JSArray*, 16> inputArrayStack; Vector<WalkerState, 16> stateStack; WalkerState state = StateUnknown; JSValue inValue = in; unsigned tickCount = ticksUntilNextCheck(); while (1) { switch (state) { arrayStartState: case ArrayStartState: { ASSERT(isArray(inValue)); if (inputObjectStack.size() + inputArrayStack.size() > maximumFilterRecursion) return StackOverflowError; JSArray* inArray = asArray(inValue); unsigned length = inArray->length(); if (!startArray(inArray)) break; inputArrayStack.append(inArray); indexStack.append(0); lengthStack.append(length); // fallthrough } arrayStartVisitMember: case ArrayStartVisitMember: { if (!--tickCount) { if (didTimeOut()) return InterruptedExecutionError; tickCount = ticksUntilNextCheck(); } JSArray* array = inputArrayStack.last(); uint32_t index = indexStack.last(); if (index == lengthStack.last()) { endObject(); inputArrayStack.removeLast(); indexStack.removeLast(); lengthStack.removeLast(); break; } if (array->canGetIndex(index)) inValue = array->getIndex(index); else { bool hasIndex = false; inValue = getSparseIndex(array, index, hasIndex); if (!hasIndex) { indexStack.last()++; goto arrayStartVisitMember; } } write(index); if (dumpIfTerminal(inValue)) { indexStack.last()++; goto arrayStartVisitMember; } stateStack.append(ArrayEndVisitMember); goto stateUnknown; } case ArrayEndVisitMember: { indexStack.last()++; goto arrayStartVisitMember; } objectStartState: case ObjectStartState: { ASSERT(inValue.isObject()); if (inputObjectStack.size() + inputArrayStack.size() > maximumFilterRecursion) return StackOverflowError; JSObject* inObject = asObject(inValue); if (!startObject(inObject)) break; inputObjectStack.append(inObject); indexStack.append(0); propertyStack.append(PropertyNameArray(m_exec)); inObject->methodTable()->getOwnPropertyNames(inObject, m_exec, propertyStack.last(), ExcludeDontEnumProperties); // fallthrough } objectStartVisitMember: case ObjectStartVisitMember: { if (!--tickCount) { if (didTimeOut()) return InterruptedExecutionError; tickCount = ticksUntilNextCheck(); } JSObject* object = inputObjectStack.last(); uint32_t index = indexStack.last(); PropertyNameArray& properties = propertyStack.last(); if (index == properties.size()) { endObject(); inputObjectStack.removeLast(); indexStack.removeLast(); propertyStack.removeLast(); break; } inValue = getProperty(object, properties[index]); if (shouldTerminate()) return ExistingExceptionError; if (!inValue) { // Property was removed during serialisation indexStack.last()++; goto objectStartVisitMember; } write(properties[index]); if (shouldTerminate()) return ExistingExceptionError; if (!dumpIfTerminal(inValue)) { stateStack.append(ObjectEndVisitMember); goto stateUnknown; } // fallthrough } case ObjectEndVisitMember: { if (shouldTerminate()) return ExistingExceptionError; indexStack.last()++; goto objectStartVisitMember; } stateUnknown: case StateUnknown: if (dumpIfTerminal(inValue)) break; if (isArray(inValue)) goto arrayStartState; goto objectStartState; } if (stateStack.isEmpty()) break; state = stateStack.last(); stateStack.removeLast(); if (!--tickCount) { if (didTimeOut()) return InterruptedExecutionError; tickCount = ticksUntilNextCheck(); } } if (m_failed) return UnspecifiedError; return SuccessfullyCompleted; }