JSValue iteratorNext(ExecState* exec, JSValue iterator, JSValue value) { JSValue nextFunction = iterator.get(exec, exec->vm().propertyNames->next); if (exec->hadException()) return jsUndefined(); CallData nextFunctionCallData; CallType nextFunctionCallType = getCallData(nextFunction, nextFunctionCallData); if (nextFunctionCallType == CallTypeNone) return throwTypeError(exec); MarkedArgumentBuffer nextFunctionArguments; if (!value.isEmpty()) nextFunctionArguments.append(value); JSValue result = call(exec, nextFunction, nextFunctionCallType, nextFunctionCallData, iterator, nextFunctionArguments); if (exec->hadException()) return jsUndefined(); if (!result.isObject()) return throwTypeError(exec, ASCIILiteral("Iterator result interface is not an object.")); return result; }
bool JSStorage::putDelegate(ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot&) { // Only perform the custom put if the object doesn't have a native property by this name. // Since hasProperty() would end up calling canGetItemsForName() and be fooled, we need to check // the native property slots manually. PropertySlot slot(this); if (getStaticValueSlot<JSStorage, Base>(exec, *s_info.staticPropHashTable, this, propertyName, slot)) return false; JSValue prototype = this->prototype(); if (prototype.isObject() && asObject(prototype)->getPropertySlot(exec, propertyName, slot)) return false; String stringValue = value.toString(exec)->value(exec); if (exec->hadException()) return true; ExceptionCode ec = 0; impl().setItem(propertyNameToString(propertyName), stringValue, ec); setDOMException(exec, ec); return true; }
void reportException(ExecState* exec, JSValue exception) { if (exception.isObject() && asObject(exception)->exceptionType() == Terminated) return; UString errorMessage = exception.toString(exec); JSObject* exceptionObject = exception.toObject(exec); int lineNumber = exceptionObject->get(exec, Identifier(exec, "line")).toInt32(exec); UString exceptionSourceURL = exceptionObject->get(exec, Identifier(exec, "sourceURL")).toString(exec); exec->clearException(); if (ExceptionBase* exceptionBase = toExceptionBase(exception)) errorMessage = stringToUString(exceptionBase->message() + ": " + exceptionBase->description()); ScriptExecutionContext* scriptExecutionContext = static_cast<JSDOMGlobalObject*>(exec->lexicalGlobalObject())->scriptExecutionContext(); ASSERT(scriptExecutionContext); // Crash data indicates null-dereference crashes at this point in the Safari 4 Public Beta. // It's harmless to return here without reporting the exception to the log and the debugger in this case. if (!scriptExecutionContext) return; scriptExecutionContext->reportException(ustringToString(errorMessage), lineNumber, ustringToString(exceptionSourceURL), 0); }
RuntimeType TypeSet::getRuntimeTypeForValue(JSValue v) { RuntimeType ret; if (v.isFunction()) ret = TypeFunction; else if (v.isUndefined()) ret = TypeUndefined; else if (v.isNull()) ret = TypeNull; else if (v.isBoolean()) ret = TypeBoolean; else if (v.isMachineInt()) ret = TypeMachineInt; else if (v.isNumber()) ret = TypeNumber; else if (v.isString()) ret = TypeString; else if (v.isObject()) ret = TypeObject; else ret = TypeNothing; return ret; }
JSValue JSIDBDatabase::createObjectStore(ExecState* exec) { if (exec->argumentCount() < 1) return exec->vm().throwException(exec, createNotEnoughArgumentsError(exec)); String name = exec->argument(0).toString(exec)->value(exec); if (exec->hadException()) return jsUndefined(); JSValue optionsValue = exec->argument(1); if (!optionsValue.isUndefinedOrNull() && !optionsValue.isObject()) return throwTypeError(exec, "Not an object."); IDBKeyPath keyPath; bool autoIncrement = false; if (!optionsValue.isUndefinedOrNull()) { JSValue keyPathValue = optionsValue.get(exec, Identifier(exec, "keyPath")); if (exec->hadException()) return jsUndefined(); if (!keyPathValue.isUndefinedOrNull()) { keyPath = idbKeyPathFromValue(exec, keyPathValue); if (exec->hadException()) return jsUndefined(); } autoIncrement = optionsValue.get(exec, Identifier(exec, "autoIncrement")).toBoolean(exec); if (exec->hadException()) return jsUndefined(); } ExceptionCode ec = 0; JSValue result = toJS(exec, globalObject(), impl()->createObjectStore(name, keyPath, autoIncrement, ec).get()); setDOMException(exec, ec); return result; }
static JSValue setNewValueFromDateArgs(ExecState* exec, JSValue thisValue, const ArgList& args, int numArgsToUse, bool inputIsUTC) { if (!thisValue.isObject(&DateInstance::info)) return throwError(exec, TypeError); DateInstance* thisDateObj = asDateInstance(thisValue); if (args.isEmpty()) { JSValue result = jsNaN(exec); thisDateObj->setInternalValue(result); return result; } double milli = thisDateObj->internalNumber(); double ms = 0; GregorianDateTime t; if (numArgsToUse == 3 && isnan(milli)) // Based on ECMA 262 15.9.5.40 - .41 (set[UTC]FullYear) // the time must be reset to +0 if it is NaN. thisDateObj->msToGregorianDateTime(0, true, t); else { double secs = floor(milli / msPerSecond); ms = milli - secs * msPerSecond; thisDateObj->msToGregorianDateTime(milli, inputIsUTC, t); } if (!fillStructuresUsingDateArgs(exec, args, numArgsToUse, &ms, &t)) { JSValue result = jsNaN(exec); thisDateObj->setInternalValue(result); return result; } JSValue result = jsNumber(exec, gregorianDateTimeToMS(t, ms, inputIsUTC)); thisDateObj->setInternalValue(result); return result; }
JSObject* JSQuarantinedObjectWrapper::construct(ExecState* exec, JSObject* constructor, const ArgList& args) { JSQuarantinedObjectWrapper* wrapper = static_cast<JSQuarantinedObjectWrapper*>(constructor); ArgList preparedArgs; for (size_t i = 0; i < args.size(); ++i) preparedArgs.append(wrapper->prepareIncomingValue(exec, args.at(exec, i))); // FIXME: Would be nice to find a way to reuse the result of m_unwrappedObject->getConstructData // from when we called it in JSQuarantinedObjectWrapper::getConstructData. ConstructData unwrappedConstructData; ConstructType unwrappedConstructType = wrapper->m_unwrappedObject->getConstructData(unwrappedConstructData); ASSERT(unwrappedConstructType != ConstructTypeNone); JSValue* unwrappedResult = KJS::construct(wrapper->unwrappedExecState(), wrapper->m_unwrappedObject, unwrappedConstructType, unwrappedConstructData, preparedArgs); JSValue* resultValue = wrapper->wrapOutgoingValue(wrapper->unwrappedExecState(), unwrappedResult); ASSERT(resultValue->isObject()); JSObject* result = static_cast<JSObject*>(resultValue); wrapper->transferExceptionToExecState(exec); return result; }
EncodedJSValue JSC_HOST_CALL objectConstructorSeal(ExecState* exec) { // 1. If Type(O) is not Object throw a TypeError exception. JSValue obj = exec->argument(0); if (!obj.isObject()) return throwVMError(exec, createTypeError(exec, ASCIILiteral("Object.seal can only be called on Objects."))); JSObject* object = asObject(obj); if (isJSFinalObject(object)) { object->seal(exec->vm()); return JSValue::encode(obj); } // 2. For each named own property name P of O, PropertyNameArray properties(exec); object->methodTable()->getOwnPropertyNames(object, exec, properties, IncludeDontEnumProperties); PropertyNameArray::const_iterator end = properties.end(); for (PropertyNameArray::const_iterator iter = properties.begin(); iter != end; ++iter) { // a. Let desc be the result of calling the [[GetOwnProperty]] internal method of O with P. PropertyDescriptor desc; if (!object->methodTable()->getOwnPropertyDescriptor(object, exec, *iter, desc)) continue; // b. If desc.[[Configurable]] is true, set desc.[[Configurable]] to false. desc.setConfigurable(false); // c. Call the [[DefineOwnProperty]] internal method of O with P, desc, and true as arguments. object->methodTable()->defineOwnProperty(object, exec, *iter, desc, true); if (exec->hadException()) return JSValue::encode(obj); } // 3. Set the [[Extensible]] internal property of O to false. object->preventExtensions(exec->vm()); // 4. Return O. return JSValue::encode(obj); }
JSValue iteratorNext(ExecState* exec, JSValue iterator, JSValue value) { VM& vm = exec->vm(); auto scope = DECLARE_THROW_SCOPE(vm); JSValue nextFunction = iterator.get(exec, vm.propertyNames->next); RETURN_IF_EXCEPTION(scope, JSValue()); CallData nextFunctionCallData; CallType nextFunctionCallType = getCallData(nextFunction, nextFunctionCallData); if (nextFunctionCallType == CallType::None) return throwTypeError(exec, scope); MarkedArgumentBuffer nextFunctionArguments; if (!value.isEmpty()) nextFunctionArguments.append(value); JSValue result = call(exec, nextFunction, nextFunctionCallType, nextFunctionCallData, iterator, nextFunctionArguments); RETURN_IF_EXCEPTION(scope, JSValue()); if (!result.isObject()) return throwTypeError(exec, scope, ASCIILiteral("Iterator result interface is not an object.")); return result; }
bool JSNamedNodeMap::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) { ASSERT_GC_OBJECT_INHERITS(this, &s_info); JSValue proto = prototype(); if (proto.isObject() && static_cast<JSObject*>(asObject(proto))->hasProperty(exec, propertyName)) return false; const HashEntry* entry = JSNamedNodeMapTable.entry(exec, propertyName); if (entry) { slot.setCustom(this, entry->propertyGetter()); return true; } bool ok; unsigned index = propertyName.toUInt32(ok); if (ok && index < static_cast<NamedNodeMap*>(impl())->length()) { slot.setCustomIndex(this, index, indexGetter); return true; } if (canGetItemsForName(exec, static_cast<NamedNodeMap*>(impl()), propertyName)) { slot.setCustom(this, nameGetter); return true; } return getStaticValueSlot<JSNamedNodeMap, Base>(exec, &JSNamedNodeMapTable, this, propertyName, slot); }
ScriptObject InjectedScriptHost::createInjectedScript(const String& source, ScriptState* scriptState, long id) { SourceCode sourceCode = makeSource(source); JSLock lock(SilenceAssertionsOnly); JSDOMGlobalObject* globalObject = static_cast<JSDOMGlobalObject*>(scriptState->lexicalGlobalObject()); JSValue globalThisValue = scriptState->globalThisValue(); Completion comp = JSC::evaluate(scriptState, globalObject->globalScopeChain(), sourceCode, globalThisValue); if (comp.complType() != JSC::Normal && comp.complType() != JSC::ReturnValue) return ScriptObject(); JSValue functionValue = comp.value(); CallData callData; CallType callType = functionValue.getCallData(callData); if (callType == CallTypeNone) return ScriptObject(); MarkedArgumentBuffer args; args.append(toJS(scriptState, globalObject, this)); args.append(globalThisValue); args.append(jsNumber(scriptState, id)); JSValue result = JSC::call(scriptState, functionValue, callType, callData, globalThisValue, args); if (result.isObject()) return ScriptObject(scriptState, result.getObject()); return ScriptObject(); }
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; }
NPObject* HTMLPlugInElement::createNPObject() { // This shouldn't ever happen, but might as well check anyway if (!document() || !document()->frame()) return _NPN_CreateNoScriptObject(); // Can't create NPObjects when JavaScript is disabled Frame* frame = document()->frame(); if (!frame->settings()->isJavaScriptEnabled()) return _NPN_CreateNoScriptObject(); #ifdef __OWB_JS__ // Create a JSObject bound to this element JSLock lock; ExecState *exec = frame->scriptProxy()->interpreter()->globalExec(); JSValue* jsElementValue = toJS(exec, this); if (!jsElementValue || !jsElementValue->isObject()) return _NPN_CreateNoScriptObject(); // Wrap the JSObject in an NPObject RootObject* rootObject = frame->bindingRootObject(); return _NPN_CreateScriptObject(0, jsElementValue->getObject(), rootObject, rootObject); #endif //__OWB_JS__ }
::JSType JSValueGetType(JSContextRef ctx, JSValueRef value) { if (!ctx) { ASSERT_NOT_REACHED(); return kJSTypeUndefined; } ExecState* exec = toJS(ctx); JSLockHolder locker(exec); JSValue jsValue = toJS(exec, value); if (jsValue.isUndefined()) return kJSTypeUndefined; if (jsValue.isNull()) return kJSTypeNull; if (jsValue.isBoolean()) return kJSTypeBoolean; if (jsValue.isNumber()) return kJSTypeNumber; if (jsValue.isString()) return kJSTypeString; ASSERT(jsValue.isObject()); return kJSTypeObject; }
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())); }
static bool canSet(JSValue object, const String& keyPathElement) { UNUSED_PARAM(keyPathElement); return object.isObject(); }
//-------------------------------------------------------------------------- // KJSValueToCFTypeInternal //-------------------------------------------------------------------------- // Caller is responsible for releasing the returned CFTypeRef CFTypeRef KJSValueToCFTypeInternal(JSValue inValue, ExecState *exec, ObjectImpList* inImps) { if (!inValue) return 0; CFTypeRef result = 0; JSGlueAPIEntry entry; if (inValue.isBoolean()) { result = inValue.toBoolean(exec) ? kCFBooleanTrue : kCFBooleanFalse; RetainCFType(result); return result; } if (inValue.isString()) { UString uString = inValue.toString(exec); result = UStringToCFString(uString); return result; } if (inValue.isNumber()) { double number1 = inValue.toNumber(exec); double number2 = (double)inValue.toInteger(exec); if (number1 == number2) { int intValue = (int)number2; result = CFNumberCreate(0, kCFNumberIntType, &intValue); } else { result = CFNumberCreate(0, kCFNumberDoubleType, &number1); } return result; } if (inValue.isObject()) { if (inValue.inherits(&UserObjectImp::info)) { UserObjectImp* userObjectImp = static_cast<UserObjectImp *>(asObject(inValue)); JSUserObject* ptr = userObjectImp->GetJSUserObject(); if (ptr) { result = ptr->CopyCFValue(); } } else { JSObject *object = inValue.toObject(exec); UInt8 isArray = false; // if two objects reference each JSObject* imp = object; ObjectImpList* temp = inImps; while (temp) { if (imp == temp->imp) { return CFRetain(GetCFNull()); } temp = temp->next; } ObjectImpList imps; imps.next = inImps; imps.imp = imp; //[...] HACK since we do not have access to the class info we use class name instead #if 0 if (object->inherits(&ArrayInstanceImp::info)) #else if (object->className() == "Array") #endif { isArray = true; JSGlueGlobalObject* globalObject = static_cast<JSGlueGlobalObject*>(exec->dynamicGlobalObject()); if (globalObject && (globalObject->Flags() & kJSFlagConvertAssociativeArray)) { PropertyNameArray propNames(exec); object->getPropertyNames(exec, propNames); PropertyNameArray::const_iterator iter = propNames.begin(); PropertyNameArray::const_iterator end = propNames.end(); while(iter != end && isArray) { Identifier propName = *iter; UString ustr = propName.ustring(); const UniChar* uniChars = (const UniChar*)ustr.characters(); int size = ustr.length(); while (size--) { if (uniChars[size] < '0' || uniChars[size] > '9') { isArray = false; break; } } iter++; } } } if (isArray) { // This is an KJS array unsigned int length = object->get(exec, Identifier(exec, "length")).toUInt32(exec); result = CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks); if (result) { for (unsigned i = 0; i < length; i++) { CFTypeRef cfValue = KJSValueToCFTypeInternal(object->get(exec, i), exec, &imps); CFArrayAppendValue((CFMutableArrayRef)result, cfValue); ReleaseCFType(cfValue); } } } else { // Not an array, just treat it like a dictionary which contains (property name, property value) pairs PropertyNameArray propNames(exec); object->getPropertyNames(exec, propNames); { result = CFDictionaryCreateMutable(0, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); if (result) { PropertyNameArray::const_iterator iter = propNames.begin(); PropertyNameArray::const_iterator end = propNames.end(); while(iter != end) { Identifier propName = *iter; if (object->hasProperty(exec, propName)) { CFStringRef cfKey = IdentifierToCFString(propName); CFTypeRef cfValue = KJSValueToCFTypeInternal(object->get(exec, propName), exec, &imps); if (cfKey && cfValue) { CFDictionaryAddValue((CFMutableDictionaryRef)result, cfKey, cfValue); } ReleaseCFType(cfKey); ReleaseCFType(cfValue); } iter++; } } } } } return result; } if (inValue.isUndefinedOrNull()) { result = RetainCFType(GetCFNull()); return result; } ASSERT_NOT_REACHED(); return 0; }
jvalue convertValueToJValue(ExecState* exec, RootObject* rootObject, JSValue value, JavaType javaType, const char* javaClassName) { JSLock lock(SilenceAssertionsOnly); jvalue result; memset(&result, 0, sizeof(jvalue)); switch (javaType) { case JavaTypeArray: case JavaTypeObject: { // FIXME: JavaJSObject::convertValueToJObject functionality is almost exactly the same, // these functions should use common code. if (value.isObject()) { JSObject* object = asObject(value); if (object->inherits(&JavaRuntimeObject::s_info)) { // Unwrap a Java instance. JavaRuntimeObject* runtimeObject = static_cast<JavaRuntimeObject*>(object); JavaInstance* instance = runtimeObject->getInternalJavaInstance(); if (instance) result.l = instance->javaInstance(); } else if (object->classInfo() == &RuntimeArray::s_info) { // Input is a JavaScript Array that was originally created from a Java Array RuntimeArray* imp = static_cast<RuntimeArray*>(object); JavaArray* array = static_cast<JavaArray*>(imp->getConcreteArray()); result.l = array->javaArray(); } else if (object->classInfo() == &JSArray::s_info) { // Input is a Javascript Array. We need to create it to a Java Array. result.l = convertArrayInstanceToJavaArray(exec, asArray(value), javaClassName); } else if ((!result.l && (!strcmp(javaClassName, "java.lang.Object"))) || (!strcmp(javaClassName, "netscape.javascript.JSObject"))) { // Wrap objects in JSObject instances. JNIEnv* env = getJNIEnv(); jclass jsObjectClass = env->FindClass("sun/plugin/javascript/webkit/JSObject"); jmethodID constructorID = env->GetMethodID(jsObjectClass, "<init>", "(J)V"); if (constructorID) { jlong nativeHandle = ptr_to_jlong(object); rootObject->gcProtect(object); result.l = env->NewObject(jsObjectClass, constructorID, nativeHandle); } } } // Create an appropriate Java object if target type is java.lang.Object. if (!result.l && !strcmp(javaClassName, "java.lang.Object")) { if (value.isString()) { UString stringValue = asString(value)->value(exec); JNIEnv* env = getJNIEnv(); jobject javaString = env->functions->NewString(env, (const jchar*)stringValue.characters(), stringValue.length()); result.l = javaString; } else if (value.isNumber()) { double doubleValue = value.asNumber(); JNIEnv* env = getJNIEnv(); jclass clazz = env->FindClass("java/lang/Double"); jmethodID constructor = env->GetMethodID(clazz, "<init>", "(D)V"); jobject javaDouble = env->functions->NewObject(env, clazz, constructor, doubleValue); result.l = javaDouble; } else if (value.isBoolean()) { bool boolValue = value.asBoolean(); JNIEnv* env = getJNIEnv(); jclass clazz = env->FindClass("java/lang/Boolean"); jmethodID constructor = env->GetMethodID(clazz, "<init>", "(Z)V"); jobject javaBoolean = env->functions->NewObject(env, clazz, constructor, boolValue); result.l = javaBoolean; } else if (value.isUndefined()) { UString stringValue = "undefined"; JNIEnv* env = getJNIEnv(); jobject javaString = env->functions->NewString(env, (const jchar*)stringValue.characters(), stringValue.length()); result.l = javaString; } } // Convert value to a string if the target type is a java.lang.String, and we're not // converting from a null. if (!result.l && !strcmp(javaClassName, "java.lang.String")) { if (!value.isNull()) { UString stringValue = value.toString(exec); JNIEnv* env = getJNIEnv(); jobject javaString = env->functions->NewString(env, (const jchar*)stringValue.characters(), stringValue.length()); result.l = javaString; } } } break; case JavaTypeBoolean: { result.z = (jboolean)value.toNumber(exec); } break; case JavaTypeByte: { result.b = (jbyte)value.toNumber(exec); } break; case JavaTypeChar: { result.c = (jchar)value.toNumber(exec); } break; case JavaTypeShort: { result.s = (jshort)value.toNumber(exec); } break; case JavaTypeInt: { result.i = (jint)value.toNumber(exec); } break; case JavaTypeLong: { result.j = (jlong)value.toNumber(exec); } break; case JavaTypeFloat: { result.f = (jfloat)value.toNumber(exec); } break; case JavaTypeDouble: { result.d = (jdouble)value.toNumber(exec); } break; case JavaTypeInvalid: case JavaTypeVoid: break; } return result; }
JSObject* ProgramExecutable::initializeGlobalProperties(VM& vm, CallFrame* callFrame, JSScope* scope) { auto throwScope = DECLARE_THROW_SCOPE(vm); RELEASE_ASSERT(scope); JSGlobalObject* globalObject = scope->globalObject(); RELEASE_ASSERT(globalObject); ASSERT(&globalObject->vm() == &vm); ParserError error; JSParserStrictMode strictMode = isStrictMode() ? JSParserStrictMode::Strict : JSParserStrictMode::NotStrict; DebuggerMode debuggerMode = globalObject->hasInteractiveDebugger() ? DebuggerOn : DebuggerOff; UnlinkedProgramCodeBlock* unlinkedCodeBlock = vm.codeCache()->getUnlinkedProgramCodeBlock( vm, this, source(), strictMode, debuggerMode, error); if (globalObject->hasDebugger()) globalObject->debugger()->sourceParsed(callFrame, source().provider(), error.line(), error.message()); if (error.isValid()) return error.toErrorObject(globalObject, source()); JSValue nextPrototype = globalObject->getPrototypeDirect(); while (nextPrototype && nextPrototype.isObject()) { if (UNLIKELY(asObject(nextPrototype)->type() == ProxyObjectType)) { ExecState* exec = globalObject->globalExec(); return createTypeError(exec, ASCIILiteral("Proxy is not allowed in the global prototype chain.")); } nextPrototype = asObject(nextPrototype)->getPrototypeDirect(); } JSGlobalLexicalEnvironment* globalLexicalEnvironment = globalObject->globalLexicalEnvironment(); const VariableEnvironment& variableDeclarations = unlinkedCodeBlock->variableDeclarations(); const VariableEnvironment& lexicalDeclarations = unlinkedCodeBlock->lexicalDeclarations(); // The ES6 spec says that no vars/global properties/let/const can be duplicated in the global scope. // This carried out section 15.1.8 of the ES6 spec: http://www.ecma-international.org/ecma-262/6.0/index.html#sec-globaldeclarationinstantiation { ExecState* exec = globalObject->globalExec(); // Check for intersection of "var" and "let"/"const"/"class" for (auto& entry : lexicalDeclarations) { if (variableDeclarations.contains(entry.key)) return createSyntaxError(exec, makeString("Can't create duplicate variable: '", String(entry.key.get()), "'")); } // Check if any new "let"/"const"/"class" will shadow any pre-existing global property names, or "var"/"let"/"const" variables. // It's an error to introduce a shadow. for (auto& entry : lexicalDeclarations) { bool hasProperty = globalObject->hasProperty(exec, entry.key.get()); RETURN_IF_EXCEPTION(throwScope, throwScope.exception()); if (hasProperty) { // The ES6 spec says that just RestrictedGlobalProperty can't be shadowed // This carried out section 8.1.1.4.14 of the ES6 spec: http://www.ecma-international.org/ecma-262/6.0/index.html#sec-hasrestrictedglobalproperty PropertyDescriptor descriptor; globalObject->getOwnPropertyDescriptor(exec, entry.key.get(), descriptor); if (descriptor.value() != jsUndefined() && !descriptor.configurable()) return createSyntaxError(exec, makeString("Can't create duplicate variable that shadows a global property: '", String(entry.key.get()), "'")); } hasProperty = globalLexicalEnvironment->hasProperty(exec, entry.key.get()); RETURN_IF_EXCEPTION(throwScope, throwScope.exception()); if (hasProperty) { if (UNLIKELY(entry.value.isConst() && !vm.globalConstRedeclarationShouldThrow() && !isStrictMode())) { // We only allow "const" duplicate declarations under this setting. // For example, we don't "let" variables to be overridden by "const" variables. if (globalLexicalEnvironment->isConstVariable(entry.key.get())) continue; } return createSyntaxError(exec, makeString("Can't create duplicate variable: '", String(entry.key.get()), "'")); } } // Check if any new "var"s will shadow any previous "let"/"const"/"class" names. // It's an error to introduce a shadow. if (!globalLexicalEnvironment->isEmpty()) { for (auto& entry : variableDeclarations) { bool hasProperty = globalLexicalEnvironment->hasProperty(exec, entry.key.get()); RETURN_IF_EXCEPTION(throwScope, throwScope.exception()); if (hasProperty) return createSyntaxError(exec, makeString("Can't create duplicate variable: '", String(entry.key.get()), "'")); } } } m_unlinkedProgramCodeBlock.set(vm, this, unlinkedCodeBlock); BatchedTransitionOptimizer optimizer(vm, globalObject); for (size_t i = 0, numberOfFunctions = unlinkedCodeBlock->numberOfFunctionDecls(); i < numberOfFunctions; ++i) { UnlinkedFunctionExecutable* unlinkedFunctionExecutable = unlinkedCodeBlock->functionDecl(i); ASSERT(!unlinkedFunctionExecutable->name().isEmpty()); globalObject->addFunction(callFrame, unlinkedFunctionExecutable->name()); if (vm.typeProfiler() || vm.controlFlowProfiler()) { vm.functionHasExecutedCache()->insertUnexecutedRange(sourceID(), unlinkedFunctionExecutable->typeProfilingStartOffset(), unlinkedFunctionExecutable->typeProfilingEndOffset()); } } for (auto& entry : variableDeclarations) { ASSERT(entry.value.isVar()); globalObject->addVar(callFrame, Identifier::fromUid(&vm, entry.key.get())); ASSERT(!throwScope.exception()); } { JSGlobalLexicalEnvironment* globalLexicalEnvironment = jsCast<JSGlobalLexicalEnvironment*>(globalObject->globalScope()); SymbolTable* symbolTable = globalLexicalEnvironment->symbolTable(); ConcurrentJSLocker locker(symbolTable->m_lock); for (auto& entry : lexicalDeclarations) { if (UNLIKELY(entry.value.isConst() && !vm.globalConstRedeclarationShouldThrow() && !isStrictMode())) { if (symbolTable->contains(locker, entry.key.get())) continue; } ScopeOffset offset = symbolTable->takeNextScopeOffset(locker); SymbolTableEntry newEntry(VarOffset(offset), entry.value.isConst() ? ReadOnly : 0); newEntry.prepareToWatch(); symbolTable->add(locker, entry.key.get(), newEntry); ScopeOffset offsetForAssert = globalLexicalEnvironment->addVariables(1, jsTDZValue()); RELEASE_ASSERT(offsetForAssert == offset); } } return nullptr; }
JSValue JSCanvasRenderingContext2D::drawImage(ExecState* exec, const ArgList& args) { CanvasRenderingContext2D* context = impl(); // DrawImage has three variants: // drawImage(img, dx, dy) // drawImage(img, dx, dy, dw, dh) // drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh) // Composite operation is specified with globalCompositeOperation. // The img parameter can be a <img> or <canvas> element. JSValue value = args.at(0); if (!value.isObject()) return throwError(exec, TypeError); JSObject* o = asObject(value); ExceptionCode ec = 0; if (o->inherits(&JSHTMLImageElement::s_info)) { HTMLImageElement* imgElt = static_cast<HTMLImageElement*>(static_cast<JSHTMLElement*>(o)->impl()); switch (args.size()) { case 3: context->drawImage(imgElt, args.at(1).toFloat(exec), args.at(2).toFloat(exec)); break; case 5: context->drawImage(imgElt, args.at(1).toFloat(exec), args.at(2).toFloat(exec), args.at(3).toFloat(exec), args.at(4).toFloat(exec), ec); setDOMException(exec, ec); break; case 9: context->drawImage(imgElt, FloatRect(args.at(1).toFloat(exec), args.at(2).toFloat(exec), args.at(3).toFloat(exec), args.at(4).toFloat(exec)), FloatRect(args.at(5).toFloat(exec), args.at(6).toFloat(exec), args.at(7).toFloat(exec), args.at(8).toFloat(exec)), ec); setDOMException(exec, ec); break; default: return throwError(exec, SyntaxError); } } else if (o->inherits(&JSHTMLCanvasElement::s_info)) { HTMLCanvasElement* canvas = static_cast<HTMLCanvasElement*>(static_cast<JSHTMLElement*>(o)->impl()); switch (args.size()) { case 3: context->drawImage(canvas, args.at(1).toFloat(exec), args.at(2).toFloat(exec)); break; case 5: context->drawImage(canvas, args.at(1).toFloat(exec), args.at(2).toFloat(exec), args.at(3).toFloat(exec), args.at(4).toFloat(exec), ec); setDOMException(exec, ec); break; case 9: context->drawImage(canvas, FloatRect(args.at(1).toFloat(exec), args.at(2).toFloat(exec), args.at(3).toFloat(exec), args.at(4).toFloat(exec)), FloatRect(args.at(5).toFloat(exec), args.at(6).toFloat(exec), args.at(7).toFloat(exec), args.at(8).toFloat(exec)), ec); setDOMException(exec, ec); break; default: return throwError(exec, SyntaxError); } #if ENABLE(VIDEO) } else if (o->inherits(&JSHTMLVideoElement::s_info)) { HTMLVideoElement* video = static_cast<HTMLVideoElement*>(static_cast<JSHTMLElement*>(o)->impl()); switch (args.size()) { case 3: context->drawImage(video, args.at(1).toFloat(exec), args.at(2).toFloat(exec)); break; case 5: context->drawImage(video, args.at(1).toFloat(exec), args.at(2).toFloat(exec), args.at(3).toFloat(exec), args.at(4).toFloat(exec), ec); setDOMException(exec, ec); break; case 9: context->drawImage(video, FloatRect(args.at(1).toFloat(exec), args.at(2).toFloat(exec), args.at(3).toFloat(exec), args.at(4).toFloat(exec)), FloatRect(args.at(5).toFloat(exec), args.at(6).toFloat(exec), args.at(7).toFloat(exec), args.at(8).toFloat(exec)), ec); setDOMException(exec, ec); break; default: return throwError(exec, SyntaxError); } #endif } else { setDOMException(exec, TYPE_MISMATCH_ERR); } return jsUndefined(); }
// 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; }
static EncodedJSValue JSC_HOST_CALL constructJSWebAssemblyInstance(ExecState* exec) { auto& vm = exec->vm(); auto throwScope = DECLARE_THROW_SCOPE(vm); auto* globalObject = exec->lexicalGlobalObject(); // If moduleObject is not a WebAssembly.Module instance, a TypeError is thrown. JSWebAssemblyModule* jsModule = jsDynamicCast<JSWebAssemblyModule*>(vm, exec->argument(0)); if (!jsModule) return JSValue::encode(throwException(exec, throwScope, createTypeError(exec, ASCIILiteral("first argument to WebAssembly.Instance must be a WebAssembly.Module"), defaultSourceAppender, runtimeTypeForValue(exec->argument(0))))); const Wasm::ModuleInformation& moduleInformation = jsModule->moduleInformation(); // If the importObject parameter is not undefined and Type(importObject) is not Object, a TypeError is thrown. JSValue importArgument = exec->argument(1); JSObject* importObject = importArgument.getObject(); if (!importArgument.isUndefined() && !importObject) return JSValue::encode(throwException(exec, throwScope, createTypeError(exec, ASCIILiteral("second argument to WebAssembly.Instance must be undefined or an Object"), defaultSourceAppender, runtimeTypeForValue(importArgument)))); // If the list of module.imports is not empty and Type(importObject) is not Object, a TypeError is thrown. if (moduleInformation.imports.size() && !importObject) return JSValue::encode(throwException(exec, throwScope, createTypeError(exec, ASCIILiteral("second argument to WebAssembly.Instance must be Object because the WebAssembly.Module has imports"), defaultSourceAppender, runtimeTypeForValue(importArgument)))); Identifier moduleKey = Identifier::fromUid(PrivateName(PrivateName::Description, "WebAssemblyInstance")); WebAssemblyModuleRecord* moduleRecord = WebAssemblyModuleRecord::create(exec, vm, globalObject->webAssemblyModuleRecordStructure(), moduleKey, moduleInformation); RETURN_IF_EXCEPTION(throwScope, encodedJSValue()); Structure* instanceStructure = InternalFunction::createSubclassStructure(exec, exec->newTarget(), globalObject->WebAssemblyInstanceStructure()); RETURN_IF_EXCEPTION(throwScope, encodedJSValue()); JSWebAssemblyInstance* instance = JSWebAssemblyInstance::create(vm, instanceStructure, jsModule, moduleRecord->getModuleNamespace(exec)); RETURN_IF_EXCEPTION(throwScope, encodedJSValue()); { // Always start with a dummy Memory, so that wasm -> wasm thunks avoid checking for a nullptr Memory when trying to set pinned registers. Wasm::Memory memory; instance->setMemory(vm, JSWebAssemblyMemory::create(vm, exec->lexicalGlobalObject()->WebAssemblyMemoryStructure(), WTFMove(memory))); } // Let funcs, memories and tables be initially-empty lists of callable JavaScript objects, WebAssembly.Memory objects and WebAssembly.Table objects, respectively. // Let imports be an initially-empty list of external values. unsigned numImportFunctions = 0; unsigned numImportGlobals = 0; bool hasMemoryImport = false; bool hasTableImport = false; // For each import i in module.imports: for (auto& import : moduleInformation.imports) { // 1. Let o be the resultant value of performing Get(importObject, i.module_name). JSValue importModuleValue = importObject->get(exec, import.module); RETURN_IF_EXCEPTION(throwScope, encodedJSValue()); // 2. If Type(o) is not Object, throw a TypeError. if (!importModuleValue.isObject()) return JSValue::encode(throwException(exec, throwScope, createTypeError(exec, ASCIILiteral("import must be an object"), defaultSourceAppender, runtimeTypeForValue(importModuleValue)))); // 3. Let v be the value of performing Get(o, i.item_name) JSObject* object = jsCast<JSObject*>(importModuleValue); JSValue value = object->get(exec, import.field); RETURN_IF_EXCEPTION(throwScope, encodedJSValue()); switch (import.kind) { case Wasm::ExternalKind::Function: { // 4. If i is a function import: // i. If IsCallable(v) is false, throw a WebAssembly.LinkError. if (!value.isFunction()) return JSValue::encode(throwException(exec, throwScope, createJSWebAssemblyLinkError(exec, vm, ASCIILiteral("import function must be callable")))); JSCell* cell = value.asCell(); // ii. If v is an Exported Function Exotic Object: if (WebAssemblyFunction* importedExport = jsDynamicCast<WebAssemblyFunction*>(vm, cell)) { // a. If the signature of v does not match the signature of i, throw a WebAssembly.LinkError. Wasm::SignatureIndex importedSignatureIndex = importedExport->signatureIndex(); Wasm::SignatureIndex expectedSignatureIndex = moduleInformation.importFunctionSignatureIndices[import.kindIndex]; if (importedSignatureIndex != expectedSignatureIndex) return JSValue::encode(throwException(exec, throwScope, createJSWebAssemblyLinkError(exec, vm, ASCIILiteral("imported function's signature doesn't match the provided WebAssembly function's signature")))); // b. Let closure be v.[[Closure]]. } // iii. Otherwise: // a. Let closure be a new host function of the given signature which calls v by coercing WebAssembly arguments to JavaScript arguments via ToJSValue and returns the result, if any, by coercing via ToWebAssemblyValue. // Note: done as part of Plan compilation. // iv. Append v to funcs. // Note: adding the JSCell to the instance list fulfills closure requirements b. above (the WebAssembly.Instance wil be kept alive) and v. below (the JSFunction). instance->setImportFunction(vm, cell, numImportFunctions++); // v. Append closure to imports. break; } case Wasm::ExternalKind::Table: { RELEASE_ASSERT(!hasTableImport); // This should be guaranteed by a validation failure. // 7. Otherwise (i is a table import): hasTableImport = true; JSWebAssemblyTable* table = jsDynamicCast<JSWebAssemblyTable*>(vm, value); // i. If v is not a WebAssembly.Table object, throw a WebAssembly.LinkError. if (!table) return JSValue::encode(throwException(exec, throwScope, createJSWebAssemblyLinkError(exec, vm, ASCIILiteral("Table import is not an instance of WebAssembly.Table")))); uint32_t expectedInitial = moduleInformation.tableInformation.initial(); uint32_t actualInitial = table->size(); if (actualInitial < expectedInitial) return JSValue::encode(throwException(exec, throwScope, createJSWebAssemblyLinkError(exec, vm, ASCIILiteral("Table import provided an 'initial' that is too small")))); if (std::optional<uint32_t> expectedMaximum = moduleInformation.tableInformation.maximum()) { std::optional<uint32_t> actualMaximum = table->maximum(); if (!actualMaximum) { return JSValue::encode( throwException(exec, throwScope, createJSWebAssemblyLinkError(exec, vm, ASCIILiteral("Table import does not have a 'maximum' but the module requires that it does")))); } if (*actualMaximum > *expectedMaximum) { return JSValue::encode( throwException(exec, throwScope, createJSWebAssemblyLinkError(exec, vm, ASCIILiteral("Imported Table's 'maximum' is larger than the module's expected 'maximum'")))); } } // ii. Append v to tables. // iii. Append v.[[Table]] to imports. instance->setTable(vm, table); break; } case Wasm::ExternalKind::Memory: { // 6. If i is a memory import: RELEASE_ASSERT(!hasMemoryImport); // This should be guaranteed by a validation failure. RELEASE_ASSERT(moduleInformation.memory); hasMemoryImport = true; JSWebAssemblyMemory* memory = jsDynamicCast<JSWebAssemblyMemory*>(vm, value); // i. If v is not a WebAssembly.Memory object, throw a WebAssembly.LinkError. if (!memory) return JSValue::encode(throwException(exec, throwScope, createJSWebAssemblyLinkError(exec, vm, ASCIILiteral("Memory import is not an instance of WebAssembly.Memory")))); Wasm::PageCount expectedInitial = moduleInformation.memory.initial(); Wasm::PageCount actualInitial = memory->memory()->initial(); if (actualInitial < expectedInitial) return JSValue::encode(throwException(exec, throwScope, createJSWebAssemblyLinkError(exec, vm, ASCIILiteral("Memory import provided an 'initial' that is too small")))); if (Wasm::PageCount expectedMaximum = moduleInformation.memory.maximum()) { Wasm::PageCount actualMaximum = memory->memory()->maximum(); if (!actualMaximum) { return JSValue::encode( throwException(exec, throwScope, createJSWebAssemblyLinkError(exec, vm, ASCIILiteral("Memory import did not have a 'maximum' but the module requires that it does")))); } if (actualMaximum > expectedMaximum) { return JSValue::encode( throwException(exec, throwScope, createJSWebAssemblyLinkError(exec, vm, ASCIILiteral("Memory imports 'maximum' is larger than the module's expected 'maximum'")))); } } // ii. Append v to memories. // iii. Append v.[[Memory]] to imports. instance->setMemory(vm, memory); break; } case Wasm::ExternalKind::Global: { // 5. If i is a global import: // i. If i is not an immutable global, throw a TypeError. ASSERT(moduleInformation.globals[import.kindIndex].mutability == Wasm::Global::Immutable); // ii. If Type(v) is not Number, throw a TypeError. if (!value.isNumber()) return JSValue::encode(throwException(exec, throwScope, createJSWebAssemblyLinkError(exec, vm, ASCIILiteral("imported global must be a number")))); // iii. Append ToWebAssemblyValue(v) to imports. switch (moduleInformation.globals[import.kindIndex].type) { case Wasm::I32: instance->setGlobal(numImportGlobals++, value.toInt32(exec)); break; case Wasm::F32: instance->setGlobal(numImportGlobals++, bitwise_cast<uint32_t>(value.toFloat(exec))); break; case Wasm::F64: instance->setGlobal(numImportGlobals++, bitwise_cast<uint64_t>(value.asNumber())); break; default: RELEASE_ASSERT_NOT_REACHED(); } ASSERT(!throwScope.exception()); break; } } } { if (!!moduleInformation.memory && moduleInformation.memory.isImport()) { // We should either have a Memory import or we should have thrown an exception. RELEASE_ASSERT(hasMemoryImport); } if (moduleInformation.memory && !hasMemoryImport) { RELEASE_ASSERT(!moduleInformation.memory.isImport()); // We create a memory when it's a memory definition. bool failed; Wasm::Memory memory(moduleInformation.memory.initial(), moduleInformation.memory.maximum(), failed); if (failed) return JSValue::encode(throwException(exec, throwScope, createOutOfMemoryError(exec))); instance->setMemory(vm, JSWebAssemblyMemory::create(vm, exec->lexicalGlobalObject()->WebAssemblyMemoryStructure(), WTFMove(memory))); } } { if (!!moduleInformation.tableInformation && moduleInformation.tableInformation.isImport()) { // We should either have a Table import or we should have thrown an exception. RELEASE_ASSERT(hasTableImport); } if (!!moduleInformation.tableInformation && !hasTableImport) { RELEASE_ASSERT(!moduleInformation.tableInformation.isImport()); // We create a Table when it's a Table definition. JSWebAssemblyTable* table = JSWebAssemblyTable::create(exec, vm, exec->lexicalGlobalObject()->WebAssemblyTableStructure(), moduleInformation.tableInformation.initial(), moduleInformation.tableInformation.maximum()); // We should always be able to allocate a JSWebAssemblyTable we've defined. // If it's defined to be too large, we should have thrown a validation error. ASSERT(!throwScope.exception()); ASSERT(table); instance->setTable(vm, table); } } // Globals { ASSERT(numImportGlobals == moduleInformation.firstInternalGlobal); for (size_t globalIndex = numImportGlobals; globalIndex < moduleInformation.globals.size(); ++globalIndex) { const auto& global = moduleInformation.globals[globalIndex]; ASSERT(global.initializationType != Wasm::Global::IsImport); if (global.initializationType == Wasm::Global::FromGlobalImport) { ASSERT(global.initialBitsOrImportNumber < numImportGlobals); instance->setGlobal(globalIndex, instance->loadI64Global(global.initialBitsOrImportNumber)); } else instance->setGlobal(globalIndex, global.initialBitsOrImportNumber); } } moduleRecord->link(exec, instance); RETURN_IF_EXCEPTION(throwScope, encodedJSValue()); if (verbose) moduleRecord->dump(); JSValue startResult = moduleRecord->evaluate(exec); UNUSED_PARAM(startResult); RETURN_IF_EXCEPTION(throwScope, encodedJSValue()); return JSValue::encode(instance); }
static bool canSet(JSValue object, const String& keyPathElement) { return object.isObject(); }
JSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) { JSString* sourceVal = thisValue.toThisJSString(exec); const UString& source = sourceVal->value(); JSValue pattern = args.at(0); JSValue replacement = args.at(1); UString replacementString; CallData callData; CallType callType = replacement.getCallData(callData); if (callType == CallTypeNone) replacementString = replacement.toString(exec); if (pattern.isObject(&RegExpObject::info)) { RegExp* reg = asRegExpObject(pattern)->regExp(); bool global = reg->global(); RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor(); int lastIndex = 0; int startPosition = 0; Vector<UString::Range, 16> sourceRanges; Vector<UString, 16> replacements; // This is either a loop (if global is set) or a one-way (if not). if (global && callType == CallTypeJS) { // reg->numSubpatterns() + 1 for pattern args, + 2 for match start and sourceValue int argCount = reg->numSubpatterns() + 1 + 2; JSFunction* func = asFunction(replacement); CachedCall cachedCall(exec, func, argCount, exec->exceptionSlot()); if (exec->hadException()) return jsNull(); while (true) { int matchIndex; int matchLen; int* ovector; regExpConstructor->performMatch(reg, source, startPosition, matchIndex, matchLen, &ovector); if (matchIndex < 0) break; sourceRanges.append(UString::Range(lastIndex, matchIndex - lastIndex)); int completeMatchStart = ovector[0]; unsigned i = 0; for (; i < reg->numSubpatterns() + 1; ++i) { int matchStart = ovector[i * 2]; int matchLen = ovector[i * 2 + 1] - matchStart; if (matchStart < 0) cachedCall.setArgument(i, jsUndefined()); else cachedCall.setArgument(i, jsSubstring(exec, source, matchStart, matchLen)); } cachedCall.setArgument(i++, jsNumber(exec, completeMatchStart)); cachedCall.setArgument(i++, sourceVal); cachedCall.setThis(exec->globalThisValue()); replacements.append(cachedCall.call().toString(cachedCall.newCallFrame())); if (exec->hadException()) break; lastIndex = matchIndex + matchLen; startPosition = lastIndex; // special case of empty match if (matchLen == 0) { startPosition++; if (startPosition > source.size()) break; } } } else { do { int matchIndex; int matchLen; int* ovector; regExpConstructor->performMatch(reg, source, startPosition, matchIndex, matchLen, &ovector); if (matchIndex < 0) break; sourceRanges.append(UString::Range(lastIndex, matchIndex - lastIndex)); if (callType != CallTypeNone) { int completeMatchStart = ovector[0]; MarkedArgumentBuffer args; for (unsigned i = 0; i < reg->numSubpatterns() + 1; ++i) { int matchStart = ovector[i * 2]; int matchLen = ovector[i * 2 + 1] - matchStart; if (matchStart < 0) args.append(jsUndefined()); else args.append(jsSubstring(exec, source, matchStart, matchLen)); } args.append(jsNumber(exec, completeMatchStart)); args.append(sourceVal); replacements.append(call(exec, replacement, callType, callData, exec->globalThisValue(), args).toString(exec)); if (exec->hadException()) break; } else replacements.append(substituteBackreferences(replacementString, source, ovector, reg)); lastIndex = matchIndex + matchLen; startPosition = lastIndex; // special case of empty match if (matchLen == 0) { startPosition++; if (startPosition > source.size()) break; } } while (global); } if (!lastIndex && replacements.isEmpty()) return sourceVal; if (lastIndex < source.size()) sourceRanges.append(UString::Range(lastIndex, source.size() - lastIndex)); return jsString(exec, source.spliceSubstringsWithSeparators(sourceRanges.data(), sourceRanges.size(), replacements.data(), replacements.size())); } // Not a regular expression, so treat the pattern as a string. UString patternString = pattern.toString(exec); int matchPos = source.find(patternString); if (matchPos == -1) return sourceVal; int matchLen = patternString.size(); if (callType != CallTypeNone) { MarkedArgumentBuffer args; args.append(jsSubstring(exec, source, matchPos, matchLen)); args.append(jsNumber(exec, matchPos)); args.append(sourceVal); replacementString = call(exec, replacement, callType, callData, exec->globalThisValue(), args).toString(exec); } int ovector[2] = { matchPos, matchPos + matchLen }; return jsString(exec, source.replaceRange(matchPos, matchLen, substituteBackreferences(replacementString, source, ovector, 0))); }
EncodedJSValue JSC_HOST_CALL constructJSHTMLElement(ExecState& exec) { VM& vm = exec.vm(); auto scope = DECLARE_THROW_SCOPE(vm); auto* jsConstructor = jsCast<JSDOMConstructorBase*>(exec.jsCallee()); ASSERT(jsConstructor); auto* context = jsConstructor->scriptExecutionContext(); if (!context) return throwConstructorScriptExecutionContextUnavailableError(exec, scope, "HTMLElement"); ASSERT(context->isDocument()); JSValue newTargetValue = exec.thisValue(); auto* newTarget = newTargetValue.getObject(); auto* globalObject = jsCast<JSDOMGlobalObject*>(newTarget->globalObject(vm)); JSValue htmlElementConstructorValue = JSHTMLElement::getConstructor(vm, globalObject); if (newTargetValue == htmlElementConstructorValue) return throwVMTypeError(&exec, scope, "new.target is not a valid custom element constructor"_s); auto& document = downcast<Document>(*context); auto* window = document.domWindow(); if (!window) return throwVMTypeError(&exec, scope, "new.target is not a valid custom element constructor"_s); auto* registry = window->customElementRegistry(); if (!registry) return throwVMTypeError(&exec, scope, "new.target is not a valid custom element constructor"_s); auto* elementInterface = registry->findInterface(newTarget); if (!elementInterface) return throwVMTypeError(&exec, scope, "new.target does not define a custom element"_s); if (!elementInterface->isUpgradingElement()) { Structure* baseStructure = getDOMStructure<JSHTMLElement>(vm, *globalObject); auto* newElementStructure = InternalFunction::createSubclassStructure(&exec, newTargetValue, baseStructure); RETURN_IF_EXCEPTION(scope, encodedJSValue()); Ref<HTMLElement> element = HTMLElement::create(elementInterface->name(), document); element->setIsDefinedCustomElement(*elementInterface); auto* jsElement = JSHTMLElement::create(newElementStructure, globalObject, element.get()); cacheWrapper(globalObject->world(), element.ptr(), jsElement); return JSValue::encode(jsElement); } Element* elementToUpgrade = elementInterface->lastElementInConstructionStack(); if (!elementToUpgrade) { throwInvalidStateError(exec, scope, "Cannot instantiate a custom element inside its own constructor during upgrades"_s); return JSValue::encode(jsUndefined()); } JSValue elementWrapperValue = toJS(&exec, jsConstructor->globalObject(), *elementToUpgrade); ASSERT(elementWrapperValue.isObject()); JSValue newPrototype = newTarget->get(&exec, vm.propertyNames->prototype); RETURN_IF_EXCEPTION(scope, encodedJSValue()); JSObject* elementWrapperObject = asObject(elementWrapperValue); JSObject::setPrototype(elementWrapperObject, &exec, newPrototype, true /* shouldThrowIfCantSet */); RETURN_IF_EXCEPTION(scope, encodedJSValue()); elementInterface->didUpgradeLastElementInConstructionStack(); return JSValue::encode(elementWrapperValue); }
// ECMA 8.6.2.2 void JSObject::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot) { ASSERT(value); ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this)); if (propertyName == exec->propertyNames().underscoreProto) { // Setting __proto__ to a non-object, non-null value is silently ignored to match Mozilla. if (!value.isObject() && !value.isNull()) return; JSValue nextPrototypeValue = value; while (nextPrototypeValue && nextPrototypeValue.isObject()) { JSObject* nextPrototype = asObject(nextPrototypeValue)->unwrappedObject(); if (nextPrototype == this) { throwError(exec, GeneralError, "cyclic __proto__ value"); return; } nextPrototypeValue = nextPrototype->prototype(); } setPrototype(value); return; } // Check if there are any setters or getters in the prototype chain JSValue prototype; for (JSObject* obj = this; !obj->structure()->hasGetterSetterProperties(); obj = asObject(prototype)) { prototype = obj->prototype(); if (prototype.isNull()) { putDirectInternal(exec->globalData(), propertyName, value, 0, true, slot); return; } } unsigned attributes; JSCell* specificValue; if ((m_structure->get(propertyName, attributes, specificValue) != WTF::notFound) && attributes & ReadOnly) return; for (JSObject* obj = this; ; obj = asObject(prototype)) { if (JSValue gs = obj->getDirect(propertyName)) { if (gs.isGetterSetter()) { JSObject* setterFunc = asGetterSetter(gs)->setter(); if (!setterFunc) { throwSetterError(exec); return; } CallData callData; CallType callType = setterFunc->getCallData(callData); MarkedArgumentBuffer args; args.append(value); call(exec, setterFunc, callType, callData, this, args); return; } // If there's an existing property on the object or one of its // prototypes it should be replaced, so break here. break; } prototype = obj->prototype(); if (prototype.isNull()) break; } putDirectInternal(exec->globalData(), propertyName, value, 0, true, slot); return; }
JSValue* JSCanvasRenderingContext2D::drawImage(ExecState* exec, const ArgList& args) { CanvasRenderingContext2D* context = impl(); // DrawImage has three variants: // drawImage(img, dx, dy) // drawImage(img, dx, dy, dw, dh) // drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh) // Composite operation is specified with globalCompositeOperation. // The img parameter can be a <img> or <canvas> element. JSValue* value = args[0]; if (!value->isObject()) return throwError(exec, TypeError); JSObject* o = static_cast<JSObject*>(value); ExceptionCode ec = 0; if (o->inherits(&JSHTMLImageElement::s_info)) { HTMLImageElement* imgElt = static_cast<HTMLImageElement*>(static_cast<JSHTMLElement*>(args[0])->impl()); switch (args.size()) { case 3: context->drawImage(imgElt, args[1]->toFloat(exec), args[2]->toFloat(exec)); break; case 5: context->drawImage(imgElt, args[1]->toFloat(exec), args[2]->toFloat(exec), args[3]->toFloat(exec), args[4]->toFloat(exec), ec); setDOMException(exec, ec); break; case 9: context->drawImage(imgElt, FloatRect(args[1]->toFloat(exec), args[2]->toFloat(exec), args[3]->toFloat(exec), args[4]->toFloat(exec)), FloatRect(args[5]->toFloat(exec), args[6]->toFloat(exec), args[7]->toFloat(exec), args[8]->toFloat(exec)), ec); setDOMException(exec, ec); break; default: return throwError(exec, SyntaxError); } } else if (o->inherits(&JSHTMLCanvasElement::s_info)) { HTMLCanvasElement* canvas = static_cast<HTMLCanvasElement*>(static_cast<JSHTMLElement*>(args[0])->impl()); switch (args.size()) { case 3: context->drawImage(canvas, args[1]->toFloat(exec), args[2]->toFloat(exec)); break; case 5: context->drawImage(canvas, args[1]->toFloat(exec), args[2]->toFloat(exec), args[3]->toFloat(exec), args[4]->toFloat(exec), ec); setDOMException(exec, ec); break; case 9: context->drawImage(canvas, FloatRect(args[1]->toFloat(exec), args[2]->toFloat(exec), args[3]->toFloat(exec), args[4]->toFloat(exec)), FloatRect(args[5]->toFloat(exec), args[6]->toFloat(exec), args[7]->toFloat(exec), args[8]->toFloat(exec)), ec); setDOMException(exec, ec); break; default: return throwError(exec, SyntaxError); } } else { setDOMException(exec, TYPE_MISMATCH_ERR); return 0; } return jsUndefined(); }
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); }
JSNodeFilterCondition::JSNodeFilterCondition(JSGlobalData&, NodeFilter* owner, JSValue filter) : m_filter(filter.isObject() ? PassWeak<JSObject>(jsCast<JSObject*>(filter), &m_weakOwner, owner) : 0) { }
JSValue *ObjectProtoFunc::callAsFunction(ExecState *exec, JSObject *thisObj, const List &args) { switch (id) { case ValueOf: return thisObj; case HasOwnProperty: { PropertySlot slot; return jsBoolean(thisObj->getOwnPropertySlot(exec, Identifier(args[0]->toString(exec)), slot)); } case IsPrototypeOf: { if (!args[0]->isObject()) return jsBoolean(false); JSValue *v = static_cast<JSObject *>(args[0])->prototype(); while (true) { if (!v->isObject()) return jsBoolean(false); if (thisObj == static_cast<JSObject *>(v)) return jsBoolean(true); v = static_cast<JSObject *>(v)->prototype(); } } case DefineGetter: case DefineSetter: { if (!args[1]->isObject() || !static_cast<JSObject *>(args[1])->implementsCall()) { if (id == DefineGetter) return throwError(exec, SyntaxError, "invalid getter usage"); else return throwError(exec, SyntaxError, "invalid setter usage"); } if (id == DefineGetter) thisObj->defineGetter(exec, Identifier(args[0]->toString(exec)), static_cast<JSObject *>(args[1])); else thisObj->defineSetter(exec, Identifier(args[0]->toString(exec)), static_cast<JSObject *>(args[1])); return jsUndefined(); } case LookupGetter: case LookupSetter: { Identifier propertyName = Identifier(args[0]->toString(exec)); JSObject *obj = thisObj; while (true) { JSValue *v = obj->getDirect(propertyName); if (v) { if (v->type() != GetterSetterType) return jsUndefined(); JSObject *funcObj; if (id == LookupGetter) funcObj = static_cast<GetterSetterImp *>(v)->getGetter(); else funcObj = static_cast<GetterSetterImp *>(v)->getSetter(); if (!funcObj) return jsUndefined(); else return funcObj; } if (!obj->prototype() || !obj->prototype()->isObject()) return jsUndefined(); obj = static_cast<JSObject *>(obj->prototype()); } } case PropertyIsEnumerable: return jsBoolean(thisObj->propertyIsEnumerable(exec, Identifier(args[0]->toString(exec)))); case ToLocaleString: return jsString(thisObj->toString(exec)); case ToString: default: return jsString("[object " + thisObj->className() + "]"); } }