JSValue JSStringJoiner::join(ExecState* exec)
{
    if (!m_isValid)
        return throwOutOfMemoryError(exec);

    if (!m_strings.size())
        return jsEmptyString(exec);

    Checked<size_t, RecordOverflow> separatorLength = m_separator.length();
    // FIXME: add special cases of joinStrings() for (separatorLength == 0) and (separatorLength == 1).
    ASSERT(m_strings.size() > 0);
    Checked<size_t, RecordOverflow> totalSeparactorsLength = separatorLength * (m_strings.size() - 1);
    Checked<size_t, RecordOverflow> outputStringSize = totalSeparactorsLength + m_accumulatedStringsLength;

    size_t finalSize;
    if (outputStringSize.safeGet(finalSize) == CheckedState::DidOverflow)
        return throwOutOfMemoryError(exec);
        
    if (!outputStringSize)
        return jsEmptyString(exec);

    RefPtr<StringImpl> outputStringImpl;
    if (m_is8Bits)
        outputStringImpl = joinStrings<LChar>(m_strings, m_separator, finalSize);
    else
        outputStringImpl = joinStrings<UChar>(m_strings, m_separator, finalSize);

    if (!outputStringImpl)
        return throwOutOfMemoryError(exec);

    return JSString::create(exec->vm(), outputStringImpl.release());
}
JSArray* createEmptyRegExpMatchesArray(JSGlobalObject* globalObject, JSString* input, RegExp* regExp)
{
    VM& vm = globalObject->vm();
    JSArray* array;

    // FIXME: This should handle array allocation errors gracefully.
    // https://bugs.webkit.org/show_bug.cgi?id=155144
    
    GCDeferralContext deferralContext(vm.heap);
    
    if (UNLIKELY(globalObject->isHavingABadTime())) {
        array = JSArray::tryCreateForInitializationPrivate(vm, &deferralContext, globalObject->regExpMatchesArrayStructure(), regExp->numSubpatterns() + 1);
        
        array->initializeIndexWithoutBarrier(0, jsEmptyString(&vm));
        
        if (unsigned numSubpatterns = regExp->numSubpatterns()) {
            for (unsigned i = 1; i <= numSubpatterns; ++i)
                array->initializeIndexWithoutBarrier(i, jsUndefined());
        }
    } else {
        array = tryCreateUninitializedRegExpMatchesArray(vm, &deferralContext, globalObject->regExpMatchesArrayStructure(), regExp->numSubpatterns() + 1);
        RELEASE_ASSERT(array);
        
        array->initializeIndexWithoutBarrier(0, jsEmptyString(&vm), ArrayWithContiguous);
        
        if (unsigned numSubpatterns = regExp->numSubpatterns()) {
            for (unsigned i = 1; i <= numSubpatterns; ++i)
                array->initializeIndexWithoutBarrier(i, jsUndefined(), ArrayWithContiguous);
        }
    }

    array->putDirectWithoutBarrier(RegExpMatchesArrayIndexPropertyOffset, jsNumber(-1));
    array->putDirectWithoutBarrier(RegExpMatchesArrayInputPropertyOffset, input);
    return array;
}
Exemple #3
0
JSValue JSStringJoiner::build(ExecState* exec)
{
    if (!m_isValid)
        return throwOutOfMemoryError(exec);

    if (!m_strings.size())
        return jsEmptyString(exec);

    size_t separatorLength = m_separator.length();
    // FIXME: add special cases of joinStrings() for (separatorLength == 0) and (separatorLength == 1).
    ASSERT(m_strings.size() > 0);
    size_t totalSeparactorsLength = separatorLength * (m_strings.size() - 1);
    size_t outputStringSize = totalSeparactorsLength + m_cumulatedStringsLength;

    if (!outputStringSize)
        return jsEmptyString(exec);

    RefPtr<StringImpl> outputStringImpl;
    if (m_is8Bits)
        outputStringImpl = joinStrings<LChar>(m_strings, m_separator, outputStringSize);
    else
        outputStringImpl = joinStrings<UChar>(m_strings, m_separator, outputStringSize);

    if (!outputStringImpl)
        return throwOutOfMemoryError(exec);

    return JSString::create(exec->globalData(), outputStringImpl.release());
}
EncodedJSValue JSC_HOST_CALL dateProtoFuncToISOString(ExecState* exec)
{
    JSValue thisValue = exec->thisValue();
    if (!thisValue.inherits(DateInstance::info()))
        return throwVMTypeError(exec);
    
    DateInstance* thisDateObj = asDateInstance(thisValue); 
    if (!std::isfinite(thisDateObj->internalNumber()))
        return throwVMError(exec, createRangeError(exec, ASCIILiteral("Invalid Date")));

    const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
    if (!gregorianDateTime)
        return JSValue::encode(jsNontrivialString(exec, String(ASCIILiteral("Invalid Date"))));
    // Maximum amount of space we need in buffer: 7 (max. digits in year) + 2 * 5 (2 characters each for month, day, hour, minute, second) + 4 (. + 3 digits for milliseconds)
    // 6 for formatting and one for null termination = 28. We add one extra character to allow us to force null termination.
    char buffer[28];
    // If the year is outside the bounds of 0 and 9999 inclusive we want to use the extended year format (ES 15.9.1.15.1).
    int ms = static_cast<int>(fmod(thisDateObj->internalNumber(), msPerSecond));
    if (ms < 0)
        ms += msPerSecond;

    int charactersWritten;
    if (gregorianDateTime->year() > 9999 || gregorianDateTime->year() < 0)
        charactersWritten = snprintf(buffer, sizeof(buffer), "%+07d-%02d-%02dT%02d:%02d:%02d.%03dZ", gregorianDateTime->year(), gregorianDateTime->month() + 1, gregorianDateTime->monthDay(), gregorianDateTime->hour(), gregorianDateTime->minute(), gregorianDateTime->second(), ms);
    else
        charactersWritten = snprintf(buffer, sizeof(buffer), "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", gregorianDateTime->year(), gregorianDateTime->month() + 1, gregorianDateTime->monthDay(), gregorianDateTime->hour(), gregorianDateTime->minute(), gregorianDateTime->second(), ms);

    ASSERT(charactersWritten > 0 && static_cast<unsigned>(charactersWritten) < sizeof(buffer));
    if (static_cast<unsigned>(charactersWritten) >= sizeof(buffer))
        return JSValue::encode(jsEmptyString(exec));

    return JSValue::encode(jsNontrivialString(exec, String(buffer, charactersWritten)));
}
JSValue JSC_HOST_CALL stringProtoFuncCharAt(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
{
    UString s = thisValue.toThisString(exec);
    unsigned len = s.size();
    JSValue a0 = args.at(0);
    if (a0.isUInt32Fast()) {
        uint32_t i = a0.getUInt32Fast();
        if (i < len)
            return jsSingleCharacterSubstring(exec, s, i);
        return jsEmptyString(exec);
    }
    double dpos = a0.toInteger(exec);
    if (dpos >= 0 && dpos < len)
        return jsSingleCharacterSubstring(exec, s, static_cast<unsigned>(dpos));
    return jsEmptyString(exec);
}
Exemple #6
0
void ErrorPrototype::finishCreation(VM& vm)
{
    Base::finishCreation(vm);
    ASSERT(inherits(vm, info()));
    putDirect(vm, vm.propertyNames->name, jsNontrivialString(&vm, String(ASCIILiteral("Error"))), DontEnum);
    putDirect(vm, vm.propertyNames->message, jsEmptyString(&vm), DontEnum);
}
void NativeErrorPrototype::finishCreation(VM& vm, const WTF::String& nameAndMessage, NativeErrorConstructor* constructor)
{
    Base::finishCreation(vm);
    putDirect(vm, vm.propertyNames->name, jsString(&vm, nameAndMessage), DontEnum);
    putDirect(vm, vm.propertyNames->message, jsEmptyString(&vm), DontEnum);
    putDirect(vm, vm.propertyNames->constructor, constructor, DontEnum);
}
Exemple #8
0
JSValue* stringProtoFuncCharAt(ExecState* exec, JSObject*, JSValue* thisValue, const ArgList& args)
{
    UString s = thisValue->toThisString(exec);
    unsigned len = s.size();
    JSValue* a0 = args.at(exec, 0);
    if (JSImmediate::isNumber(a0)) {
        uint32_t i;
        if (JSImmediate::getUInt32(a0, i) && i < len)
            return jsSingleCharacterSubstring(exec, s, i);
        return jsEmptyString(exec);
    }
    double dpos = a0->toInteger(exec);
    if (dpos >= 0 && dpos < len)
        return jsSingleCharacterSubstring(exec, s, static_cast<unsigned>(dpos));
    return jsEmptyString(exec);
}
JSValue JSDOMWindow::atob(ExecState* exec, const ArgList& args)
{
    if (args.size() < 1)
        return throwError(exec, SyntaxError, "Not enough arguments");

    JSValue v = args.at(0);
    if (v.isNull())
        return jsEmptyString(exec);

    UString s = v.toString(exec);
    if (!s.is8Bit()) {
        setDOMException(exec, INVALID_CHARACTER_ERR);
        return jsUndefined();
    }

    Vector<char> in(s.size());
    for (int i = 0; i < s.size(); ++i)
        in[i] = static_cast<char>(s.data()[i]);
    Vector<char> out;

    if (!base64Decode(in, out))
        return throwError(exec, GeneralError, "Cannot decode base64");

    return jsString(exec, String(out.data(), out.size()));
}
JSString* RegExpMatchesArray::rightContext(ExecState* exec)
{
    unsigned length = m_input->length();
    if (m_result.end == length)
        return jsEmptyString(exec);
    return jsSubstring(exec, m_input.get(), m_result.end, length - m_result.end);
}
void NativeErrorPrototype::finishCreation(ExecState* exec, JSGlobalObject* globalObject, const WTF::String& nameAndMessage, NativeErrorConstructor* constructor)
{
    Base::finishCreation(exec, globalObject);
    putDirect(exec->vm(), exec->propertyNames().name, jsString(exec, nameAndMessage), DontEnum);
    putDirect(exec->vm(), exec->propertyNames().message, jsEmptyString(exec), DontEnum);
    putDirect(exec->vm(), exec->propertyNames().constructor, constructor, DontEnum);
}
static EncodedJSValue JSC_HOST_CALL callStringConstructor(ExecState* exec)
{
    if (!exec->argumentCount())
        return JSValue::encode(jsEmptyString(exec));
    JSValue argument = exec->uncheckedArgument(0);
    if (argument.isSymbol())
        return JSValue::encode(jsString(exec, asSymbol(argument)->descriptiveString()));
    return JSValue::encode(argument.toString(exec));
}
Exemple #13
0
JSValuePtr RegExpConstructor::getBackref(ExecState* exec, unsigned i) const
{
    if (d->lastOvector && i <= d->lastNumSubPatterns) {
        int start = d->lastOvector[2 * i];
        if (start >= 0)
            return jsSubstring(exec, d->lastInput, start, d->lastOvector[2 * i + 1] - start);
    }
    return jsEmptyString(exec);
}
static JSCell* formatLocaleDate(ExecState* exec, const GregorianDateTime& gdt, LocaleDateTimeFormat format)
{
#if HAVE(LANGINFO_H)
    static const nl_item formats[] = { D_T_FMT, D_FMT, T_FMT };
#elif PLATFORM(WINCE) && !PLATFORM(QT)
    // strftime() we are using does not support #
    static const char* const formatStrings[] = { "%c", "%x", "%X" };
#else
    static const char* const formatStrings[] = { "%#c", "%#x", "%X" };
#endif
 
    // Offset year if needed
    struct tm localTM = gdt;
    int year = gdt.year + 1900;
    bool yearNeedsOffset = year < 1900 || year > 2038;
    if (yearNeedsOffset)
        localTM.tm_year = equivalentYearForDST(year) - 1900;
 
#if HAVE(LANGINFO_H)
    // We do not allow strftime to generate dates with 2-digits years,
    // both to avoid ambiguity, and a crash in strncpy, for years that
    // need offset.
    char* formatString = strdup(nl_langinfo(formats[format]));
    char* yPos = strchr(formatString, 'y');
    if (yPos)
        *yPos = 'Y';
#endif

    // Do the formatting
    const int bufsize = 128;
    char timebuffer[bufsize];

#if HAVE(LANGINFO_H)
    size_t ret = strftime(timebuffer, bufsize, formatString, &localTM);
    free(formatString);
#else
    size_t ret = strftime(timebuffer, bufsize, formatStrings[format], &localTM);
#endif
 
    if (ret == 0)
        return jsEmptyString(exec);
 
    // Copy original into the buffer
    if (yearNeedsOffset && format != LocaleTime) {
        static const int yearLen = 5;   // FIXME will be a problem in the year 10,000
        char yearString[yearLen];
 
        snprintf(yearString, yearLen, "%d", localTM.tm_year + 1900);
        char* yearLocation = strstr(timebuffer, yearString);
        snprintf(yearString, yearLen, "%d", year);
 
        strncpy(yearLocation, yearString, yearLen - 1);
    }
 
    return jsNontrivialString(exec, timebuffer);
}
static JSCell* formatLocaleDate(ExecState* exec, DateInstance*, double timeInMilliseconds, LocaleDateTimeFormat format)
{
    UDateFormatStyle timeStyle = (format != LocaleDate ? UDAT_LONG : UDAT_NONE);
    UDateFormatStyle dateStyle = (format != LocaleTime ? UDAT_LONG : UDAT_NONE);

    UErrorCode status = U_ZERO_ERROR;
    UDateFormat* df = udat_open(timeStyle, dateStyle, 0, 0, -1, 0, 0, &status);
    if (!df)
        return jsEmptyString(exec);

    UChar buffer[128];
    int32_t length;
    length = udat_format(df, timeInMilliseconds, buffer, 128, 0, &status);
    udat_close(df);
    if (status != U_ZERO_ERROR)
        return jsEmptyString(exec);

    return jsNontrivialString(exec, String(buffer, length));
}
Exemple #16
0
JSValuePtr RegExpConstructor::getLastParen(ExecState* exec) const
{
    unsigned i = d->lastNumSubPatterns;
    if (i > 0) {
        ASSERT(d->lastOvector);
        int start = d->lastOvector[2 * i];
        if (start >= 0)
            return jsSubstring(exec, d->lastInput, start, d->lastOvector[2 * i + 1] - start);
    }
    return jsEmptyString(exec);
}
JSString* JSRopeString::getIndexSlowCase(ExecState* exec, unsigned i)
{
    ASSERT(isRope());
    resolveRope(exec);
    // Return a safe no-value result, this should never be used, since the excetion will be thrown.
    if (exec->exception())
        return jsEmptyString(exec);
    ASSERT(!isRope());
    RELEASE_ASSERT(i < m_value.length());
    return jsSingleCharacterSubstring(exec, m_value, i);
}
JSValue RegExpConstructor::getBackref(ExecState* exec, unsigned i)
{
    JSArray* array = m_cachedResult.lastResult(exec, this);

    if (i < array->length()) {
        JSValue result = JSValue(array).get(exec, i);
        ASSERT(result.isString() || result.isUndefined());
        if (!result.isUndefined())
            return result;
    }
    return jsEmptyString(exec);
}
JSValue RegExpConstructor::getLastParen(ExecState* exec)
{
    JSArray* array = m_cachedResult.lastResult(exec, this);
    unsigned length = array->length();
    if (length > 1) {
        JSValue result = JSValue(array).get(exec, length - 1);
        ASSERT(result.isString() || result.isUndefined());
        if (!result.isUndefined())
            return result;
    }
    return jsEmptyString(exec);
}
Exemple #20
0
// 15.3.4.5 Function.prototype.bind (thisArg [, arg1 [, arg2, ...]])
EncodedJSValue JSC_HOST_CALL functionProtoFuncBind(ExecState* exec)
{
    VM& vm = exec->vm();
    auto scope = DECLARE_THROW_SCOPE(vm);
    JSGlobalObject* globalObject = exec->callee()->globalObject();

    // Let Target be the this value.
    JSValue target = exec->thisValue();

    // If IsCallable(Target) is false, throw a TypeError exception.
    CallData callData;
    CallType callType = getCallData(target, callData);
    if (callType == CallType::None)
        return throwVMTypeError(exec, scope);
    // Primitive values are not callable.
    ASSERT(target.isObject());
    JSObject* targetObject = asObject(target);

    // Let A be a new (possibly empty) internal list of all of the argument values provided after thisArg (arg1, arg2 etc), in order.
    size_t numBoundArgs = exec->argumentCount() > 1 ? exec->argumentCount() - 1 : 0;
    JSArray* boundArgs;
    if (numBoundArgs) {
        boundArgs = JSArray::tryCreateUninitialized(vm, globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithContiguous), numBoundArgs);
        if (!boundArgs)
            return JSValue::encode(throwOutOfMemoryError(exec, scope));
        
        for (size_t i = 0; i < numBoundArgs; ++i)
            boundArgs->initializeIndex(vm, i, exec->argument(i + 1));
    } else
        boundArgs = nullptr;

    // If the [[Class]] internal property of Target is "Function", then ...
    // Else set the length own property of F to 0.
    unsigned length = 0;
    if (targetObject->hasOwnProperty(exec, exec->propertyNames().length)) {
        if (exec->hadException())
            return JSValue::encode(jsUndefined());

        // a. Let L be the length property of Target minus the length of A.
        // b. Set the length own property of F to either 0 or L, whichever is larger.
        JSValue lengthValue = target.get(exec, exec->propertyNames().length);
        if (lengthValue.isNumber()) {
            unsigned targetLength = (unsigned)lengthValue.asNumber();
            if (targetLength > numBoundArgs)
                length = targetLength - numBoundArgs;
        }
    }

    JSValue nameProp = target.get(exec, exec->propertyNames().name);
    JSString* name = nameProp.isString() ? nameProp.toString(exec) : jsEmptyString(exec);
    return JSValue::encode(JSBoundFunction::create(vm, exec, globalObject, targetObject, exec->argument(0), boundArgs, length, name->value(exec)));
}
Exemple #21
0
JSString* JSValue::toStringSlowCase(ExecState* exec, bool returnEmptyStringOnError) const
{
    VM& vm = exec->vm();
    auto scope = DECLARE_THROW_SCOPE(vm);

    auto errorValue = [&] () -> JSString* {
        if (returnEmptyStringOnError)
            return jsEmptyString(exec);
        return nullptr;
    };
    
    ASSERT(!isString());
    if (isInt32()) {
        auto integer = asInt32();
        if (static_cast<unsigned>(integer) <= 9)
            return vm.smallStrings.singleCharacterString(integer + '0');
        return jsNontrivialString(&vm, vm.numericStrings.add(integer));
    }
    if (isDouble())
        return jsString(&vm, vm.numericStrings.add(asDouble()));
    if (isTrue())
        return vm.smallStrings.trueString();
    if (isFalse())
        return vm.smallStrings.falseString();
    if (isNull())
        return vm.smallStrings.nullString();
    if (isUndefined())
        return vm.smallStrings.undefinedString();
    if (isSymbol()) {
        throwTypeError(exec, scope, ASCIILiteral("Cannot convert a symbol to a string"));
        return errorValue();
    }

    ASSERT(isCell());
    JSValue value = asCell()->toPrimitive(exec, PreferString);
    if (vm.exception())
        return errorValue();
    ASSERT(!value.isObject());
    JSString* result = value.toString(exec);
    if (vm.exception())
        return errorValue();
    return result;
}
JSValue JSC_HOST_CALL stringProtoFuncSubstr(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
{
    UString s = thisValue.toThisString(exec);
    int len = s.size();

    JSValue a0 = args.at(0);
    JSValue a1 = args.at(1);

    double start = a0.toInteger(exec);
    double length = a1.isUndefined() ? len : a1.toInteger(exec);
    if (start >= len || length <= 0)
        return jsEmptyString(exec);
    if (start < 0) {
        start += len;
        if (start < 0)
            start = 0;
    }
    if (start + length > len)
        length = len - start;
    return jsSubstring(exec, s, static_cast<unsigned>(start), static_cast<unsigned>(length));
}
JSValue JSC_HOST_CALL stringProtoFuncSlice(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args)
{
    UString s = thisValue.toThisString(exec);
    int len = s.size();

    JSValue a0 = args.at(0);
    JSValue a1 = args.at(1);

    // The arg processing is very much like ArrayProtoFunc::Slice
    double start = a0.toInteger(exec);
    double end = a1.isUndefined() ? len : a1.toInteger(exec);
    double from = start < 0 ? len + start : start;
    double to = end < 0 ? len + end : end;
    if (to > from && to > 0 && from < len) {
        if (from < 0)
            from = 0;
        if (to > len)
            to = len;
        return jsSubstring(exec, s, static_cast<unsigned>(from), static_cast<unsigned>(to) - static_cast<unsigned>(from));
    }

    return jsEmptyString(exec);
}
Exemple #24
0
JSString* RegExpCachedResult::rightContext(ExecState* exec, JSObject* owner)
{
    // Make sure we're reified.
    lastResult(exec, owner);
    if (!m_reifiedRightContext) {
        unsigned length = m_reifiedInput->length();
        m_reifiedRightContext.set(exec->vm(), owner, m_result.end != length ? jsSubstring(exec, m_reifiedInput.get(), m_result.end, length - m_result.end) : jsEmptyString(exec));
    }
    return m_reifiedRightContext.get();
}
Exemple #25
0
JSValuePtr RegExpConstructor::getRightContext(ExecState* exec) const
{
    if (d->lastOvector)
        return jsSubstring(exec, d->lastInput, d->lastOvector[1], d->lastInput.size() - d->lastOvector[1]);
    return jsEmptyString(exec);
}
Exemple #26
0
JSValuePtr RegExpConstructor::getLeftContext(ExecState* exec) const
{
    if (d->lastOvector)
        return jsSubstring(exec, d->lastInput, 0, d->lastOvector[0]);
    return jsEmptyString(exec);
}
// ECMA 15.5.1
static EncodedJSValue JSC_HOST_CALL callStringConstructor(ExecState* exec)
{
    if (!exec->argumentCount())
        return JSValue::encode(jsEmptyString(exec));
    return JSValue::encode(jsString(exec, exec->argument(0).toString(exec)));
}
JSValue RegExpConstructor::getRightContext(ExecState* exec) const
{
    if (!d.lastOvector().isEmpty())
        return jsSubstring(exec, d.lastInput, d.lastOvector()[1], d.lastInput.length() - d.lastOvector()[1]);
    return jsEmptyString(exec);
}
JSValue RegExpConstructor::getLeftContext(ExecState* exec) const
{
    if (!d.lastOvector().isEmpty())
        return jsSubstring(exec, d.lastInput, 0, d.lastOvector()[0]);
    return jsEmptyString(exec);
}
JSString* RegExpMatchesArray::leftContext(ExecState* exec)
{
    if (!m_result.start)
        return jsEmptyString(exec);
    return jsSubstring(exec, m_input.get(), 0, m_result.start);
}