bool JSCustomSQLStatementErrorCallback::handleEvent(SQLTransaction* transaction, SQLError* error) { ASSERT(m_callback); ASSERT(m_frame); if (!m_frame->script()->isEnabled()) return true; JSGlobalObject* globalObject = m_frame->script()->globalObject(); ExecState* exec = globalObject->globalExec(); KJS::JSLock lock; JSValue* handleEventFunction = m_callback->get(exec, Identifier(exec, "handleEvent")); CallData handleEventCallData; CallType handleEventCallType = handleEventFunction->getCallData(handleEventCallData); CallData callbackCallData; CallType callbackCallType = CallTypeNone; if (handleEventCallType == CallTypeNone) { callbackCallType = m_callback->getCallData(callbackCallData); if (callbackCallType == CallTypeNone) { // FIXME: Should an exception be thrown here? return true; } } RefPtr<JSCustomSQLStatementErrorCallback> protect(this); ArgList args; args.append(toJS(exec, transaction)); args.append(toJS(exec, error)); JSValue* result; globalObject->startTimeoutCheck(); if (handleEventCallType != CallTypeNone) result = call(exec, handleEventFunction, handleEventCallType, handleEventCallData, m_callback, args); else result = call(exec, m_callback, callbackCallType, callbackCallData, m_callback, args); globalObject->stopTimeoutCheck(); if (exec->hadException()) { JSObject* exception = exec->exception()->toObject(exec); String message = exception->get(exec, exec->propertyNames().message)->toString(exec); int lineNumber = exception->get(exec, Identifier(exec, "line"))->toInt32(exec); String sourceURL = exception->get(exec, Identifier(exec, "sourceURL"))->toString(exec); m_frame->domWindow()->console()->addMessage(JSMessageSource, ErrorMessageLevel, message, lineNumber, sourceURL); exec->clearException(); // The spec says: // "If the error callback returns false, then move on to the next statement..." // "Otherwise, the error callback did not return false, or there was no error callback" // Therefore an exception and returning true are the same thing - so, return true on an exception return true; } Document::updateDocumentsRendering(); return result->toBoolean(exec); }
bool JSCustomSQLStatementErrorCallback::handleEvent(SQLTransaction* transaction, SQLError* error) { ASSERT(m_callback); ASSERT(m_frame); if (!m_frame->script()->isEnabled()) return true; JSGlobalObject* globalObject = m_frame->script()->globalObject(); ExecState* exec = globalObject->globalExec(); JSC::JSLock lock(false); JSValue* handleEventFunction = m_callback->get(exec, Identifier(exec, "handleEvent")); CallData handleEventCallData; CallType handleEventCallType = handleEventFunction->getCallData(handleEventCallData); CallData callbackCallData; CallType callbackCallType = CallTypeNone; if (handleEventCallType == CallTypeNone) { callbackCallType = m_callback->getCallData(callbackCallData); if (callbackCallType == CallTypeNone) { // FIXME: Should an exception be thrown here? return true; } } RefPtr<JSCustomSQLStatementErrorCallback> protect(this); ArgList args; args.append(toJS(exec, transaction)); args.append(toJS(exec, error)); JSValue* result; globalObject->startTimeoutCheck(); if (handleEventCallType != CallTypeNone) result = call(exec, handleEventFunction, handleEventCallType, handleEventCallData, m_callback, args); else result = call(exec, m_callback, callbackCallType, callbackCallData, m_callback, args); globalObject->stopTimeoutCheck(); if (exec->hadException()) { reportCurrentException(exec); // The spec says: // "If the error callback returns false, then move on to the next statement..." // "Otherwise, the error callback did not return false, or there was no error callback" // Therefore an exception and returning true are the same thing - so, return true on an exception return true; } Document::updateDocumentsRendering(); return result->toBoolean(exec); }
JSObject* Error::create(ExecState* exec, ErrorType type, const UString& message, int lineNumber, int sourceId, const UString& sourceURL) { JSObject* constructor; const char* name; switch (type) { case EvalError: constructor = exec->lexicalGlobalObject()->evalErrorConstructor(); name = "Evaluation error"; break; case RangeError: constructor = exec->lexicalGlobalObject()->rangeErrorConstructor(); name = "Range error"; break; case ReferenceError: constructor = exec->lexicalGlobalObject()->referenceErrorConstructor(); name = "Reference error"; break; case SyntaxError: constructor = exec->lexicalGlobalObject()->syntaxErrorConstructor(); name = "Syntax error"; break; case TypeError: constructor = exec->lexicalGlobalObject()->typeErrorConstructor(); name = "Type error"; break; case URIError: constructor = exec->lexicalGlobalObject()->URIErrorConstructor(); name = "URI error"; break; default: constructor = exec->lexicalGlobalObject()->errorConstructor(); name = "Error"; break; } ArgList args; if (message.isEmpty()) args.append(jsString(exec, name)); else args.append(jsString(exec, message)); ConstructData constructData; ConstructType constructType = constructor->getConstructData(constructData); JSObject* error = construct(exec, constructor, constructType, constructData, args); if (lineNumber != -1) error->putWithAttributes(exec, Identifier(exec, "line"), jsNumber(exec, lineNumber), ReadOnly | DontDelete); if (sourceId != -1) error->putWithAttributes(exec, Identifier(exec, "sourceId"), jsNumber(exec, sourceId), ReadOnly | DontDelete); if (!sourceURL.isNull()) error->putWithAttributes(exec, Identifier(exec, "sourceURL"), jsString(exec, sourceURL), ReadOnly | DontDelete); return error; }
void JSLazyEventListener::parseCode() const { if (m_parsed) return; m_parsed = true; Frame* frame = window()->impl()->frame(); if (frame && frame->script()->isEnabled()) { ExecState* exec = window()->globalExec(); JSLock lock(false); ArgList args; UString sourceURL(frame->loader()->url().string()); args.append(eventParameterName()); args.append(jsString(exec, m_code)); // FIXME: Passing the document's URL to construct is not always correct, since this event listener might // have been added with setAttribute from a script, and we should pass String() in that case. m_listener = constructFunction(exec, args, Identifier(exec, m_functionName), sourceURL, m_lineNumber); // FIXME: is globalExec ok? JSFunction* listenerAsFunction = static_cast<JSFunction*>(m_listener.get()); if (exec->hadException()) { exec->clearException(); // failed to parse, so let's just make this listener a no-op m_listener = 0; } else if (m_originalNode) { // Add the event's home element to the scope // (and the document, and the form - see JSHTMLElement::eventHandlerScope) ScopeChain scope = listenerAsFunction->scope(); JSValue* thisObj = toJS(exec, m_originalNode); if (thisObj->isObject()) { static_cast<JSEventTargetNode*>(thisObj)->pushEventHandlerScope(exec, scope); listenerAsFunction->setScope(scope); } } } // no more need to keep the unparsed code around m_functionName = String(); m_code = String(); if (m_listener) { JSDOMWindow::ListenersMap& listeners = isHTMLEventListener() ? window()->jsHTMLEventListeners() : window()->jsEventListeners(); listeners.set(m_listener, const_cast<JSLazyEventListener*>(this)); } }
JSValueRef JSObjectCallAsFunction(JSContextRef ctx, JSObjectRef object, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) { JSLock lock; ExecState* exec = toJS(ctx); JSObject* jsObject = toJS(object); JSObject* jsThisObject = toJS(thisObject); if (!jsThisObject) jsThisObject = exec->globalThisValue(); ArgList argList; for (size_t i = 0; i < argumentCount; i++) argList.append(toJS(arguments[i])); CallData callData; CallType callType = jsObject->getCallData(callData); if (callType == CallTypeNone) return 0; JSValueRef result = toRef(call(exec, jsObject, callType, callData, jsThisObject, argList)); if (exec->hadException()) { if (exception) *exception = toRef(exec->exception()); exec->clearException(); result = 0; } return result; }
JSObjectRef JSObjectMakeArray(JSContextRef ctx, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) { ExecState* exec = toJS(ctx); exec->globalData().heap.registerThread(); JSLock lock(exec); JSObject* result; if (argumentCount) { ArgList argList; for (size_t i = 0; i < argumentCount; ++i) argList.append(toJS(arguments[i])); result = constructArray(exec, argList); } else result = constructEmptyArray(exec); if (exec->hadException()) { if (exception) *exception = toRef(exec->exception()); exec->clearException(); result = 0; } return toRef(result); }
JSObjectRef JSObjectCallAsConstructor(JSContextRef ctx, JSObjectRef object, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) { ExecState* exec = toJS(ctx); exec->globalData().heap->registerThread(); JSLock lock(exec); JSObject* jsObject = toJS(object); ConstructData constructData; ConstructType constructType = jsObject->getConstructData(constructData); if (constructType == ConstructTypeNone) return 0; ArgList argList; for (size_t i = 0; i < argumentCount; i++) argList.append(toJS(arguments[i])); JSObjectRef result = toRef(construct(exec, jsObject, constructType, constructData, argList)); if (exec->hadException()) { if (exception) *exception = toRef(exec->exception()); exec->clearException(); result = 0; } return result; }
short JSNodeFilterCondition::acceptNode(Node* filterNode, JSValue*& exception) const { // FIXME: It makes no sense for this to depend on the document being in a frame! Frame* frame = filterNode->document()->frame(); if (!frame) return NodeFilter::FILTER_REJECT; JSLock lock; CallData callData; CallType callType = m_filter->getCallData(callData); if (callType == CallTypeNone) return NodeFilter::FILTER_ACCEPT; ExecState* exec = frame->script()->globalObject()->globalExec(); ArgList args; args.append(toJS(exec, filterNode)); if (exec->hadException()) { exception = takeException(exec); return NodeFilter::FILTER_REJECT; } JSValue* result = call(exec, m_filter, callType, callData, m_filter, args); if (exec->hadException()) { exception = takeException(exec); return NodeFilter::FILTER_REJECT; } int intResult = result->toInt32(exec); if (exec->hadException()) { exception = takeException(exec); return NodeFilter::FILTER_REJECT; } return intResult; }
void JSCustomSQLStatementCallback::handleEvent(SQLTransaction* transaction, SQLResultSet* resultSet, bool& raisedException) { ASSERT(m_callback); ASSERT(m_frame); if (!m_frame->script()->isEnabled()) return; JSGlobalObject* globalObject = m_frame->script()->globalObject(); ExecState* exec = globalObject->globalExec(); JSC::JSLock lock(false); JSValuePtr function = m_callback->get(exec, Identifier(exec, "handleEvent")); CallData callData; CallType callType = function.getCallData(callData); if (callType == CallTypeNone) { callType = m_callback->getCallData(callData); if (callType == CallTypeNone) { // FIXME: Should an exception be thrown here? return; } function = m_callback; } RefPtr<JSCustomSQLStatementCallback> protect(this); ArgList args; args.append(toJS(exec, transaction)); args.append(toJS(exec, resultSet)); globalObject->startTimeoutCheck(); call(exec, function, callType, callData, m_callback, args); globalObject->stopTimeoutCheck(); if (exec->hadException()) { reportCurrentException(exec); raisedException = true; } Document::updateDocumentsRendering(); }
JSObjectRef JSObjectMakeFunction(JSContextRef ctx, JSStringRef name, unsigned parameterCount, const JSStringRef parameterNames[], JSStringRef body, JSStringRef sourceURL, int startingLineNumber, JSValueRef* exception) { ExecState* exec = toJS(ctx); exec->globalData().heap->registerThread(); JSLock lock(exec); Identifier nameID = name ? name->identifier(exec) : Identifier(exec, "anonymous"); ArgList args; for (unsigned i = 0; i < parameterCount; i++) args.append(jsString(exec, parameterNames[i]->ustring())); args.append(jsString(exec, body->ustring())); JSObject* result = constructFunction(exec, args, nameID, sourceURL->ustring(), startingLineNumber); if (exec->hadException()) { if (exception) *exception = toRef(exec->exception()); exec->clearException(); result = 0; } return toRef(result); }
JSValue* stringProtoFuncMatch(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args) { UString s = thisValue->toThisString(exec); JSValue* a0 = args.at(exec, 0); UString u = s; RefPtr<RegExp> reg; RegExpObject* imp = 0; if (a0->isObject() && static_cast<JSObject *>(a0)->inherits(&RegExpObject::info)) reg = static_cast<RegExpObject *>(a0)->regExp(); else { /* * ECMA 15.5.4.12 String.prototype.search (regexp) * If regexp is not an object whose [[Class]] property is "RegExp", it is * replaced with the result of the expression new RegExp(regexp). */ reg = RegExp::create(exec, a0->toString(exec)); } RegExpConstructor* regExpObj = exec->lexicalGlobalObject()->regExpConstructor(); int pos; int matchLength; regExpObj->performMatch(reg.get(), u, 0, pos, matchLength); if (!(reg->global())) { // case without 'g' flag is handled like RegExp.prototype.exec if (pos < 0) return jsNull(); return regExpObj->arrayOfMatches(exec); } // return array of matches ArgList list; int lastIndex = 0; while (pos >= 0) { list.append(jsSubstring(exec, u, pos, matchLength)); lastIndex = pos; pos += matchLength == 0 ? 1 : matchLength; regExpObj->performMatch(reg.get(), u, pos, pos, matchLength); } if (imp) imp->setLastIndex(lastIndex); if (list.isEmpty()) { // if there are no matches at all, it's important to return // Null instead of an empty array, because this matches // other browsers and because Null is a false value. return jsNull(); } return constructArray(exec, list); }
int compare_key_key(key va, key vb) { ASSERT(!va->isUndefined()); ASSERT(!vb->isUndefined()); if (m_exec->hadException()) return 1; ArgList arguments; arguments.append(va); arguments.append(vb); double compareResult = call(m_exec, m_compareFunction, m_compareCallType, *m_compareCallData, m_globalThisValue, arguments)->toNumber(m_exec); return (compareResult < 0) ? -1 : 1; // Not passing equality through, because we need to store all values, even if equivalent. }
JSValuePtr JSClipboard::types(ExecState* exec) const { Clipboard* clipboard = impl(); HashSet<String> types = clipboard->types(); if (types.isEmpty()) return jsNull(); ArgList list; HashSet<String>::const_iterator end = types.end(); for (HashSet<String>::const_iterator it = types.begin(); it != end; ++it) list.append(jsString(exec, UString(*it))); return constructArray(exec, list); }
JSObjectRef JSObjectMakeFunction(JSContextRef ctx, JSStringRef name, unsigned parameterCount, const JSStringRef parameterNames[], JSStringRef body, JSStringRef sourceURL, int startingLineNumber, JSValueRef* exception) { JSLock lock; ExecState* exec = toJS(ctx); UString::Rep* bodyRep = toJS(body); UString::Rep* sourceURLRep = sourceURL ? toJS(sourceURL) : &UString::Rep::null; Identifier nameID = name ? Identifier(exec, toJS(name)) : Identifier(exec, "anonymous"); ArgList args; for (unsigned i = 0; i < parameterCount; i++) args.append(jsString(exec, UString(toJS(parameterNames[i])))); args.append(jsString(exec, UString(bodyRep))); JSObject* result = constructFunction(exec, args, nameID, UString(sourceURLRep), startingLineNumber); if (exec->hadException()) { if (exception) *exception = toRef(exec->exception()); exec->clearException(); result = 0; } return toRef(result); }
void JSCustomSQLTransactionCallback::handleEvent(SQLTransaction* transaction, bool& raisedException) { ASSERT(m_data); ASSERT(m_data->callback()); ASSERT(m_data->frame()); if (!m_data->frame()->script()->isEnabled()) return; JSGlobalObject* globalObject = m_data->frame()->script()->globalObject(); ExecState* exec = globalObject->globalExec(); JSC::JSLock lock(false); JSValue* handleEventFunction = m_data->callback()->get(exec, Identifier(exec, "handleEvent")); CallData handleEventCallData; CallType handleEventCallType = handleEventFunction->getCallData(handleEventCallData); CallData callbackCallData; CallType callbackCallType = CallTypeNone; if (handleEventCallType == CallTypeNone) { callbackCallType = m_data->callback()->getCallData(callbackCallData); if (callbackCallType == CallTypeNone) { // FIXME: Should an exception be thrown here? return; } } RefPtr<JSCustomSQLTransactionCallback> protect(this); ArgList args; args.append(toJS(exec, transaction)); globalObject->startTimeoutCheck(); if (handleEventCallType != CallTypeNone) call(exec, handleEventFunction, handleEventCallType, handleEventCallData, m_data->callback(), args); else call(exec, m_data->callback(), callbackCallType, callbackCallData, m_data->callback(), args); globalObject->stopTimeoutCheck(); if (exec->hadException()) { m_data->frame()->domWindow()->console()->reportCurrentException(exec); raisedException = true; } Document::updateDocumentsRendering(); }
String JSCustomXPathNSResolver::lookupNamespaceURI(const String& prefix) { ASSERT(m_customResolver); if (!m_frame) return String(); if (!m_frame->script()->isEnabled()) return String(); JSLock lock(false); JSGlobalObject* globalObject = m_frame->script()->globalObject(); ExecState* exec = globalObject->globalExec(); JSValue* function = m_customResolver->get(exec, Identifier(exec, "lookupNamespaceURI")); CallData callData; CallType callType = function->getCallData(callData); if (callType == CallTypeNone) { callType = m_customResolver->getCallData(callData); if (callType == CallTypeNone) { // FIXME: Pass actual line number and source URL. m_frame->domWindow()->console()->addMessage(JSMessageSource, ErrorMessageLevel, "XPathNSResolver does not have a lookupNamespaceURI method.", 0, String()); return String(); } function = m_customResolver; } RefPtr<JSCustomXPathNSResolver> selfProtector(this); ArgList args; args.append(jsString(exec, prefix)); globalObject->startTimeoutCheck(); JSValue* retval = call(exec, function, callType, callData, m_customResolver, args); globalObject->stopTimeoutCheck(); String result; if (exec->hadException()) reportCurrentException(exec); else { if (!retval->isUndefinedOrNull()) result = retval->toString(exec); } Document::updateDocumentsRendering(); return result; }
bool JSCustomSQLTransactionErrorCallback::handleEvent(SQLError* error) { ASSERT(m_callback); ASSERT(m_frame); if (!m_frame->script()->isEnabled()) return true; JSGlobalObject* globalObject = m_frame->script()->globalObject(); ExecState* exec = globalObject->globalExec(); JSC::JSLock lock(false); JSValue* function = m_callback->get(exec, Identifier(exec, "handleEvent")); CallData callData; CallType callType = function->getCallData(callData); if (callType == CallTypeNone) { callType = m_callback->getCallData(callData); if (callType == CallTypeNone) { // FIXME: Should an exception be thrown here? return true; } function = m_callback; } RefPtr<JSCustomSQLTransactionErrorCallback> protect(this); ArgList args; args.append(toJS(exec, error)); JSValue *result; globalObject->startTimeoutCheck(); result = call(exec, function, callType, callData, m_callback, args); globalObject->stopTimeoutCheck(); if (exec->hadException()) m_frame->domWindow()->console()->reportCurrentException(exec); Document::updateDocumentsRendering(); return result->toBoolean(exec); }
JSValue* JSJavaScriptCallFrame::scopeChain(ExecState* exec) const { if (!impl()->scopeChain()) return jsNull(); const ScopeChainNode* scopeChain = impl()->scopeChain(); ScopeChainIterator iter = scopeChain->begin(); ScopeChainIterator end = scopeChain->end(); // we must always have something in the scope chain ASSERT(iter != end); ArgList list; do { list.append(*iter); ++iter; } while (iter != end); return constructArray(exec, list); }
void Console::trace(ExecState* exec) { Page* page = this->page(); if (!page) return; int signedLineNumber; intptr_t sourceID; UString urlString; JSValue* func; exec->machine()->retrieveLastCaller(exec, signedLineNumber, sourceID, urlString, func); ArgList args; while (!func->isNull()) { args.append(func); func = exec->machine()->retrieveCaller(exec, asInternalFunction(func)); } page->inspectorController()->addMessageToConsole(JSMessageSource, TraceMessageLevel, exec, args, 0, String()); }
JSValue* JSQuarantinedObjectWrapper::call(ExecState* exec, JSObject* function, JSValue* thisValue, const ArgList& args) { JSQuarantinedObjectWrapper* wrapper = static_cast<JSQuarantinedObjectWrapper*>(function); JSValue* preparedThisValue = wrapper->prepareIncomingValue(exec, thisValue); 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->getCallData // from when we called it in JSQuarantinedObjectWrapper::getCallData. CallData unwrappedCallData; CallType unwrappedCallType = wrapper->m_unwrappedObject->getCallData(unwrappedCallData); ASSERT(unwrappedCallType != CallTypeNone); JSValue* unwrappedResult = KJS::call(wrapper->unwrappedExecState(), wrapper->m_unwrappedObject, unwrappedCallType, unwrappedCallData, preparedThisValue, preparedArgs); JSValue* result = wrapper->wrapOutgoingValue(wrapper->unwrappedExecState(), unwrappedResult); wrapper->transferExceptionToExecState(exec); return result; }
void Arguments::fillArgList(ExecState* exec, ArgList& args) { if (LIKELY(!d->deletedArguments)) { if (LIKELY(!d->numParameters)) { args.initialize(d->extraArguments, d->numArguments); return; } if (d->numParameters == d->numArguments) { args.initialize(&d->registers[d->firstParameterIndex], d->numArguments); return; } unsigned parametersLength = min(d->numParameters, d->numArguments); unsigned i = 0; for (; i < parametersLength; ++i) args.append(d->registers[d->firstParameterIndex + i].jsValue(exec)); for (; i < d->numArguments; ++i) args.append(d->extraArguments[i - d->numParameters].jsValue(exec)); return; } unsigned parametersLength = min(d->numParameters, d->numArguments); unsigned i = 0; for (; i < parametersLength; ++i) { if (!d->deletedArguments[i]) args.append(d->registers[d->firstParameterIndex + i].jsValue(exec)); else args.append(get(exec, i)); } for (; i < d->numArguments; ++i) { if (!d->deletedArguments[i]) args.append(d->extraArguments[i - d->numParameters].jsValue(exec)); else args.append(get(exec, i)); } }
void JSAbstractEventListener::handleEvent(Event* event, bool isWindowEvent) { JSObject* listener = listenerObj(); if (!listener) return; JSDOMWindow* window = this->window(); // Null check as clearWindow() can clear this and we still get called back by // xmlhttprequest objects. See http://bugs.webkit.org/show_bug.cgi?id=13275 if (!window) return; Frame* frame = window->impl()->frame(); if (!frame) return; ScriptController* script = frame->script(); if (!script->isEnabled() || script->isPaused()) return; JSLock lock(false); ExecState* exec = window->globalExec(); JSValue* handleEventFunction = listener->get(exec, Identifier(exec, "handleEvent")); CallData callData; CallType callType = handleEventFunction->getCallData(callData); if (callType == CallTypeNone) { handleEventFunction = 0; callType = listener->getCallData(callData); } if (callType != CallTypeNone) { ref(); ArgList args; args.append(toJS(exec, event)); Event* savedEvent = window->currentEvent(); window->setCurrentEvent(event); JSValue* retval; if (handleEventFunction) { window->startTimeoutCheck(); retval = call(exec, handleEventFunction, callType, callData, listener, args); } else { JSValue* thisValue; if (isWindowEvent) thisValue = window->shell(); else thisValue = toJS(exec, event->currentTarget()); window->startTimeoutCheck(); retval = call(exec, listener, callType, callData, thisValue, args); } window->stopTimeoutCheck(); window->setCurrentEvent(savedEvent); if (exec->hadException()) frame->domWindow()->console()->reportCurrentException(exec); else { if (!retval->isUndefinedOrNull() && event->storesResultAsString()) event->storeResult(retval->toString(exec)); if (m_isHTML) { bool retvalbool; if (retval->getBoolean(retvalbool) && !retvalbool) event->preventDefault(); } } Document::updateDocumentsRendering(); deref(); } }
static void getListFromVariantArgs(ExecState* exec, const NPVariant* args, unsigned argCount, RootObject* rootObject, ArgList& aList) { for (unsigned i = 0; i < argCount; ++i) aList.append(convertNPVariantToValue(exec, &args[i], rootObject)); }
// 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) { JSObject* proto = value->getObject(); // Setting __proto__ to a non-object, non-null value is silently ignored to match Mozilla. if (!proto && !value->isNull()) return; while (proto) { if (proto == this) { throwError(exec, GeneralError, "cyclic __proto__ value"); return; } proto = proto->prototype() ? proto->prototype()->getObject() : 0; } setPrototype(value); return; } // Check if there are any setters or getters in the prototype chain JSValue* prototype; for (JSObject* obj = this; !obj->structureID()->hasGetterSetterProperties(); obj = asObject(prototype)) { prototype = obj->prototype(); if (prototype->isNull()) { putDirect(propertyName, value, 0, true, slot); return; } } unsigned attributes; if ((m_structureID->get(propertyName, attributes) != 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); ArgList 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; } putDirect(propertyName, value, 0, true, slot); return; }
JSValue* stringProtoFuncReplace(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args) { JSString* sourceVal = thisValue->toThisJSString(exec); const UString& source = sourceVal->value(); JSValue* pattern = args.at(exec, 0); JSValue* replacement = args.at(exec, 1); UString replacementString; CallData callData; CallType callType = replacement->getCallData(callData); if (callType == CallTypeNone) replacementString = replacement->toString(exec); if (pattern->isObject(&RegExpObject::info)) { RegExp* reg = static_cast<RegExpObject*>(pattern)->regExp(); bool global = reg->global(); RegExpConstructor* regExpObj = 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). do { int matchIndex; int matchLen; int* ovector; regExpObj->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]; ArgList 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)); } 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 < source.size()) sourceRanges.append(UString::Range(lastIndex, source.size() - lastIndex)); UString result = source.spliceSubstringsWithSeparators(sourceRanges.data(), sourceRanges.size(), replacements.data(), replacements.size()); if (result == source) return sourceVal; return jsString(exec, result); } // First arg is a string UString patternString = pattern->toString(exec); int matchPos = source.find(patternString); int matchLen = patternString.size(); // Do the replacement if (matchPos == -1) return sourceVal; if (callType != CallTypeNone) { ArgList 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); } return jsString(exec, source.substr(0, matchPos) + replacementString + source.substr(matchPos + matchLen)); }