예제 #1
0
JSValue JSInjectedScriptHost::weakSetEntries(ExecState* exec)
{
    if (exec->argumentCount() < 1)
        return jsUndefined();

    JSValue value = exec->uncheckedArgument(0);
    JSWeakSet* weakSet = jsDynamicCast<JSWeakSet*>(value);
    if (!weakSet)
        return jsUndefined();

    unsigned fetched = 0;
    unsigned numberToFetch = 100;

    JSValue numberToFetchArg = exec->argument(1);
    double fetchDouble = numberToFetchArg.toInteger(exec);
    if (fetchDouble >= 0)
        numberToFetch = static_cast<unsigned>(fetchDouble);

    JSArray* array = constructEmptyArray(exec, nullptr);
    for (auto it = weakSet->weakMapData()->begin(); it != weakSet->weakMapData()->end(); ++it) {
        JSObject* entry = constructEmptyObject(exec);
        entry->putDirect(exec->vm(), Identifier::fromString(exec, "value"), it->key);
        array->putDirectIndex(exec, fetched++, entry);
        if (numberToFetch && fetched >= numberToFetch)
            break;
    }

    return array;
}
예제 #2
0
// Shared implementation used by test and exec.
MatchResult RegExpObject::match(ExecState* exec, JSString* string)
{
    RegExp* regExp = this->regExp();
    RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor();
    String input = string->value(exec);
    VM& vm = exec->vm();
    if (!regExp->global())
        return regExpConstructor->performMatch(vm, regExp, string, input, 0);

    JSValue jsLastIndex = getLastIndex();
    unsigned lastIndex;
    if (LIKELY(jsLastIndex.isUInt32())) {
        lastIndex = jsLastIndex.asUInt32();
        if (lastIndex > input.length()) {
            setLastIndex(exec, 0);
            return MatchResult::failed();
        }
    } else {
        double doubleLastIndex = jsLastIndex.toInteger(exec);
        if (doubleLastIndex < 0 || doubleLastIndex > input.length()) {
            setLastIndex(exec, 0);
            return MatchResult::failed();
        }
        lastIndex = static_cast<unsigned>(doubleLastIndex);
    }

    MatchResult result = regExpConstructor->performMatch(vm, regExp, string, input, lastIndex);
    setLastIndex(exec, result.end);
    return result;
}
예제 #3
0
JSValue JSInjectedScriptHost::iteratorEntries(ExecState* exec)
{
    if (exec->argumentCount() < 1)
        return jsUndefined();

    VM& vm = exec->vm();
    JSValue iterator;
    JSValue value = exec->uncheckedArgument(0);
    if (JSMapIterator* mapIterator = jsDynamicCast<JSMapIterator*>(value))
        iterator = mapIterator->clone(exec);
    else if (JSSetIterator* setIterator = jsDynamicCast<JSSetIterator*>(value))
        iterator = setIterator->clone(exec);
    else if (JSStringIterator* stringIterator = jsDynamicCast<JSStringIterator*>(value))
        iterator = stringIterator->clone(exec);
    else if (JSPropertyNameIterator* propertyNameIterator = jsDynamicCast<JSPropertyNameIterator*>(value)) {
        iterator = propertyNameIterator->clone(exec);
        if (UNLIKELY(vm.exception()))
            return JSValue();
    } else {
        if (JSObject* iteratorObject = jsDynamicCast<JSObject*>(value)) {
            // Array Iterators are created in JS for performance reasons. Thus the only way to know we have one is to
            // look for a property that is unique to them.
            if (JSValue nextIndex = iteratorObject->getDirect(vm, vm.propertyNames->builtinNames().arrayIteratorNextIndexPrivateName()))
                iterator = cloneArrayIteratorObject(exec, vm, iteratorObject, nextIndex);
        }
    }
    if (!iterator)
        return jsUndefined();

    unsigned numberToFetch = 5;
    JSValue numberToFetchArg = exec->argument(1);
    double fetchDouble = numberToFetchArg.toInteger(exec);
    if (fetchDouble >= 0)
        numberToFetch = static_cast<unsigned>(fetchDouble);

    JSArray* array = constructEmptyArray(exec, nullptr);
    if (UNLIKELY(vm.exception()))
        return jsUndefined();

    for (unsigned i = 0; i < numberToFetch; ++i) {
        JSValue next = iteratorStep(exec, iterator);
        if (UNLIKELY(vm.exception()))
            break;
        if (next.isFalse())
            break;

        JSValue nextValue = iteratorValue(exec, next);
        if (UNLIKELY(vm.exception()))
            break;

        JSObject* entry = constructEmptyObject(exec);
        entry->putDirect(exec->vm(), Identifier::fromString(exec, "value"), nextValue);
        array->putDirectIndex(exec, i, entry);
    }

    iteratorClose(exec, iterator);

    return array;
}
예제 #4
0
static inline int32_t extractRadixFromArgs(ExecState* exec)
{
    JSValue radixValue = exec->argument(0);
    int32_t radix;
    if (radixValue.isInt32())
        radix = radixValue.asInt32();
    else if (radixValue.isUndefined())
        radix = 10;
    else
        radix = static_cast<int32_t>(radixValue.toInteger(exec)); // nan -> 0

    return radix;
}
예제 #5
0
JSValue JSInjectedScriptHost::iteratorEntries(ExecState* exec)
{
    if (exec->argumentCount() < 1)
        return jsUndefined();

    JSValue iterator;
    JSValue value = exec->uncheckedArgument(0);
    if (JSArrayIterator* arrayIterator = jsDynamicCast<JSArrayIterator*>(value))
        iterator = arrayIterator->clone(exec);
    else if (JSMapIterator* mapIterator = jsDynamicCast<JSMapIterator*>(value))
        iterator = mapIterator->clone(exec);
    else if (JSSetIterator* setIterator = jsDynamicCast<JSSetIterator*>(value))
        iterator = setIterator->clone(exec);
    else if (JSStringIterator* stringIterator = jsDynamicCast<JSStringIterator*>(value))
        iterator = stringIterator->clone(exec);
    else if (JSPropertyNameIterator* propertyNameIterator = jsDynamicCast<JSPropertyNameIterator*>(value))
        iterator = propertyNameIterator->clone(exec);
    else
        return jsUndefined();

    unsigned numberToFetch = 5;
    JSValue numberToFetchArg = exec->argument(1);
    double fetchDouble = numberToFetchArg.toInteger(exec);
    if (fetchDouble >= 0)
        numberToFetch = static_cast<unsigned>(fetchDouble);

    JSArray* array = constructEmptyArray(exec, nullptr);

    for (unsigned i = 0; i < numberToFetch; ++i) {
        JSValue next = iteratorStep(exec, iterator);
        if (exec->hadException())
            break;
        if (next.isFalse())
            break;

        JSValue nextValue = iteratorValue(exec, next);
        if (exec->hadException())
            break;

        JSObject* entry = constructEmptyObject(exec);
        entry->putDirect(exec->vm(), Identifier::fromString(exec, "value"), nextValue);
        array->putDirectIndex(exec, i, entry);
    }

    iteratorClose(exec, iterator);

    return array;
}
예제 #6
0
// Shared implementation used by test and exec.
bool RegExpObject::match(ExecState* exec)
{
    RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor();
    UString input = exec->argument(0).toString(exec);
    JSGlobalData* globalData = &exec->globalData();
    if (!regExp()->global()) {
        int position;
        int length;
        regExpConstructor->performMatch(*globalData, d->regExp.get(), input, 0, position, length);
        return position >= 0;
    }

    JSValue jsLastIndex = getLastIndex();
    unsigned lastIndex;
    if (LIKELY(jsLastIndex.isUInt32())) {
        lastIndex = jsLastIndex.asUInt32();
        if (lastIndex > input.length()) {
            setLastIndex(0);
            return false;
        }
    } else {
        double doubleLastIndex = jsLastIndex.toInteger(exec);
        if (doubleLastIndex < 0 || doubleLastIndex > input.length()) {
            setLastIndex(0);
            return false;
        }
        lastIndex = static_cast<unsigned>(doubleLastIndex);
    }

    int position;
    int length = 0;
    regExpConstructor->performMatch(*globalData, d->regExp.get(), input, lastIndex, position, length);
    if (position < 0) {
        setLastIndex(0);
        return false;
    }

    setLastIndex(position + length);
    return true;
}
예제 #7
0
//--------------------------------------------------------------------------
// 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;
}
예제 #8
0
void setRegExpObjectLastIndex(ExecState* exec, JSObject* baseObject, JSValue value)
{
    asRegExpObject(baseObject)->setLastIndex(value.toInteger(exec));
}
EncodedJSValue JSC_HOST_CALL numberProtoFuncToString(ExecState* exec)
{
    JSValue thisValue = exec->hostThisValue();
    JSValue v = thisValue.getJSNumber();
    if (!v)
        return throwVMTypeError(exec);

    JSValue radixValue = exec->argument(0);
    int radix;
    if (radixValue.isInt32())
        radix = radixValue.asInt32();
    else if (radixValue.isUndefined())
        radix = 10;
    else
        radix = static_cast<int>(radixValue.toInteger(exec)); // nan -> 0

    if (radix == 10)
        return JSValue::encode(jsString(exec, v.toString(exec)));

    static const char* const digits = "0123456789abcdefghijklmnopqrstuvwxyz";

    // Fast path for number to character conversion.
    if (radix == 36) {
        if (v.isInt32()) {
            int x = v.asInt32();
            if (static_cast<unsigned>(x) < 36) { // Exclude negatives
                JSGlobalData* globalData = &exec->globalData();
                return JSValue::encode(globalData->smallStrings.singleCharacterString(globalData, digits[x]));
            }
        }
    }

    if (radix < 2 || radix > 36)
        return throwVMError(exec, createRangeError(exec, "toString() radix argument must be between 2 and 36"));

    // INT_MAX results in 1024 characters left of the dot with radix 2
    // give the same space on the right side. safety checks are in place
    // unless someone finds a precise rule.
    char s[2048 + 3];
    const char* lastCharInString = s + sizeof(s) - 1;
    double x = v.uncheckedGetNumber();
    if (isnan(x) || isinf(x))
        return JSValue::encode(jsString(exec, UString::number(x)));

    bool isNegative = x < 0.0;
    if (isNegative)
        x = -x;

    double integerPart = floor(x);
    char* decimalPoint = s + sizeof(s) / 2;

    // convert integer portion
    char* p = decimalPoint;
    double d = integerPart;
    do {
        int remainderDigit = static_cast<int>(fmod(d, radix));
        *--p = digits[remainderDigit];
        d /= radix;
    } while ((d <= -1.0 || d >= 1.0) && s < p);

    if (isNegative)
        *--p = '-';
    char* startOfResultString = p;
    ASSERT(s <= startOfResultString);

    d = x - integerPart;
    p = decimalPoint;
    const double epsilon = 0.001; // TODO: guessed. base on radix ?
    bool hasFractionalPart = (d < -epsilon || d > epsilon);
    if (hasFractionalPart) {
        *p++ = '.';
        do {
            d *= radix;
            const int digit = static_cast<int>(d);
            *p++ = digits[digit];
            d -= digit;
        } while ((d < -epsilon || d > epsilon) && p < lastCharInString);
    }
    *p = '\0';
    ASSERT(p < s + sizeof(s));

    return JSValue::encode(jsString(exec, startOfResultString));
}