EncodedJSValue JSC_HOST_CALL mapProtoFuncForEach(CallFrame* callFrame) { MapData* data = getMapData(callFrame, callFrame->thisValue()); if (!data) return JSValue::encode(jsUndefined()); JSValue callBack = callFrame->argument(0); CallData callData; CallType callType = getCallData(callBack, callData); if (callType == CallTypeNone) return JSValue::encode(throwTypeError(callFrame, WTF::ASCIILiteral("Map.prototype.forEach called without callback"))); JSValue thisValue = callFrame->argument(1); VM* vm = &callFrame->vm(); if (callType == CallTypeJS) { JSFunction* function = jsCast<JSFunction*>(callBack); CachedCall cachedCall(callFrame, function, 2); for (auto ptr = data->begin(), end = data->end(); ptr != end && !vm->exception(); ++ptr) { cachedCall.setThis(thisValue); cachedCall.setArgument(0, ptr.value()); cachedCall.setArgument(1, ptr.key()); cachedCall.call(); } } else { for (auto ptr = data->begin(), end = data->end(); ptr != end && !vm->exception(); ++ptr) { MarkedArgumentBuffer args; args.append(ptr.value()); args.append(ptr.key()); JSC::call(callFrame, callBack, callType, callData, thisValue, args); } } return JSValue::encode(jsUndefined()); }
EncodedJSValue JSC_HOST_CALL mapProtoFuncForEach(CallFrame* callFrame) { JSMap* map = getMap(callFrame, callFrame->thisValue()); if (!map) return JSValue::encode(jsUndefined()); JSValue callBack = callFrame->argument(0); CallData callData; CallType callType = getCallData(callBack, callData); if (callType == CallTypeNone) return JSValue::encode(throwTypeError(callFrame, WTF::ASCIILiteral("Map.prototype.forEach called without callback"))); JSValue thisValue = callFrame->argument(1); VM* vm = &callFrame->vm(); JSMapIterator* iterator = JSMapIterator::create(*vm, callFrame->callee()->globalObject()->mapIteratorStructure(), map, MapIterateKeyValue); JSValue key, value; if (callType == CallTypeJS) { JSFunction* function = jsCast<JSFunction*>(callBack); CachedCall cachedCall(callFrame, function, 3); while (iterator->nextKeyValue(key, value) && !vm->exception()) { cachedCall.setThis(thisValue); cachedCall.setArgument(0, value); cachedCall.setArgument(1, key); cachedCall.setArgument(2, map); cachedCall.call(); } iterator->finish(); } else { while (iterator->nextKeyValue(key, value) && !vm->exception()) { MarkedArgumentBuffer args; args.append(value); args.append(key); args.append(map); JSC::call(callFrame, callBack, callType, callData, thisValue, args); } iterator->finish(); } return JSValue::encode(jsUndefined()); }
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))); }