// toPrecision converts a number to a string, takeing an argument specifying a
// number of significant figures to round the significand to. For positive
// exponent, all values that can be represented using a decimal fraction will
// be, e.g. when rounding to 3 s.f. any value up to 999 will be formated as a
// decimal, whilst 1000 is converted to the exponential representation 1.00e+3.
// For negative exponents values >= 1e-6 are formated as decimal fractions,
// with smaller values converted to exponential representation.
EncodedTiValue JSC_HOST_CALL numberProtoFuncToPrecision(TiExcState* exec)
{
    // Get x (the double value of this, which should be a Number).
    TiValue thisValue = exec->hostThisValue();
    TiValue v = thisValue.getJSNumber();
    if (!v)
        return throwVMTypeError(exec);
    double x = v.uncheckedGetNumber();

    // Get the argument. 
    int significantFigures;
    bool isUndefined;
    if (!getIntegerArgumentInRange(exec, 1, 21, significantFigures, isUndefined))
        return throwVMError(exec, createRangeError(exec, "toPrecision() argument must be between 1 and 21"));

    // To precision called with no argument is treated as ToString.
    if (isUndefined)
        return TiValue::encode(jsString(exec, UString::number(x)));

    // Handle NaN and Infinity.
    if (isnan(x) || isinf(x))
        return TiValue::encode(jsString(exec, UString::number(x)));

    // Convert to decimal with rounding.
    DecimalNumber number(x, RoundingSignificantFigures, significantFigures);
    // If number is in the range 1e-6 <= x < pow(10, significantFigures) then format
    // as decimal. Otherwise, format the number as an exponential.  Decimal format
    // demands a minimum of (exponent + 1) digits to represent a number, for example
    // 1234 (1.234e+3) requires 4 digits. (See ECMA-262 15.7.4.7.10.c)
    NumberToStringBuffer buffer;
    unsigned length = number.exponent() >= -6 && number.exponent() < significantFigures
        ? number.toStringDecimal(buffer, WTI::NumberToStringBufferLength)
        : number.toStringExponential(buffer, WTI::NumberToStringBufferLength);
    return TiValue::encode(jsString(exec, UString(buffer, length)));
}
// toFixed converts a number to a string, always formatting as an a decimal fraction.
// This method takes an argument specifying a number of decimal places to round the
// significand to. However when converting large values (1e+21 and above) this
// method will instead fallback to calling ToString. 
EncodedTiValue JSC_HOST_CALL numberProtoFuncToFixed(TiExcState* exec)
{
    // Get x (the double value of this, which should be a Number).
    TiValue thisValue = exec->hostThisValue();
    TiValue v = thisValue.getJSNumber();
    if (!v)
        return throwVMTypeError(exec);
    double x = v.uncheckedGetNumber();

    // Get the argument. 
    int decimalPlaces;
    bool isUndefined; // This is ignored; undefined treated as 0.
    if (!getIntegerArgumentInRange(exec, 0, 20, decimalPlaces, isUndefined))
        return throwVMError(exec, createRangeError(exec, "toFixed() argument must be between 0 and 20"));

    // 15.7.4.5.7 states "If x >= 10^21, then let m = ToString(x)"
    // This also covers Ininity, and structure the check so that NaN
    // values are also handled by numberToString
    if (!(fabs(x) < 1e+21))
        return TiValue::encode(jsString(exec, UString::number(x)));

    // The check above will return false for NaN or Infinity, these will be
    // handled by numberToString.
    ASSERT(!isnan(x) && !isinf(x));

    // Convert to decimal with rounding, and format as decimal.
    NumberToStringBuffer buffer;
    unsigned length = DecimalNumber(x, RoundingDecimalPlaces, decimalPlaces).toStringDecimal(buffer, WTI::NumberToStringBufferLength);
    return TiValue::encode(jsString(exec, UString(buffer, length)));
}
Exemple #3
0
void TiObject::defineSetter(TiExcState* exec, const Identifier& propertyName, TiObject* setterFunction, unsigned attributes)
{
    TiValue object = getDirect(propertyName);
    if (object && object.isGetterSetter()) {
        ASSERT(m_structure->hasGetterSetterProperties());
        asGetterSetter(object)->setSetter(setterFunction);
        return;
    }

    PutPropertySlot slot;
    GetterSetter* getterSetter = new (exec) GetterSetter(exec);
    putDirectInternal(exec->globalData(), propertyName, getterSetter, attributes | Setter, true, slot);

    // putDirect will change our Structure if we add a new property. For
    // getters and setters, though, we also need to change our Structure
    // if we override an existing non-getter or non-setter.
    if (slot.type() != PutPropertySlot::NewProperty) {
        if (!m_structure->isDictionary()) {
            RefPtr<Structure> structure = Structure::getterSetterTransition(m_structure);
            setStructure(structure.release());
        }
    }

    m_structure->setHasGetterSetterProperties(true);
    getterSetter->setSetter(setterFunction);
}
EncodedTiValue JSC_HOST_CALL functionProtoFuncApply(TiExcState* exec)
{
    TiValue thisValue = exec->hostThisValue();
    CallData callData;
    CallType callType = getCallData(thisValue, callData);
    if (callType == CallTypeNone)
        return throwVMTypeError(exec);

    TiValue array = exec->argument(1);

    MarkedArgumentBuffer applyArgs;
    if (!array.isUndefinedOrNull()) {
        if (!array.isObject())
            return throwVMTypeError(exec);
        if (asObject(array)->classInfo() == &Arguments::s_info)
            asArguments(array)->fillArgList(exec, applyArgs);
        else if (isTiArray(&exec->globalData(), array))
            asArray(array)->fillArgList(exec, applyArgs);
        else if (asObject(array)->inherits(&TiArray::s_info)) {
            unsigned length = asArray(array)->get(exec, exec->propertyNames().length).toUInt32(exec);
            for (unsigned i = 0; i < length; ++i)
                applyArgs.append(asArray(array)->get(exec, i));
        } else
            return throwVMTypeError(exec);
    }

    return TiValue::encode(call(exec, thisValue, callType, callData, exec->argument(0), applyArgs));
}
Exemple #5
0
double TiObject::toNumber(TiExcState* exec) const
{
    TiValue primitive = toPrimitive(exec, PreferNumber);
    if (exec->hadException()) // should be picked up soon in Nodes.cpp
        return 0.0;
    return primitive.toNumber(exec);
}
Exemple #6
0
UString TiObject::toString(TiExcState* exec) const
{
    TiValue primitive = toPrimitive(exec, PreferString);
    if (exec->hadException())
        return "";
    return primitive.toString(exec);
}
static ALWAYS_INLINE bool toThisNumber(TiValue thisValue, double &x)
{
    TiValue v = thisValue.getJSNumber();
    if (UNLIKELY(!v))
        return false;
    x = v.uncheckedGetNumber();
    return true;
}
Exemple #8
0
bool TiValueIsBoolean(TiContextRef ctx, TiValueRef value)
{
    TiExcState* exec = toJS(ctx);
    APIEntryShim entryShim(exec);

    TiValue jsValue = toJS(exec, value);
    return jsValue.isBoolean();
}
Exemple #9
0
bool TiValueIsDate(TiContextRef ctx, TiValueRef value)
{
    TiExcState* exec = toJS(ctx);
    exec->globalData().heap.registerThread();
    TiLock lock(exec);
    
    TiValue jsValue = toJS(exec, value);
    return jsValue.inherits(&DateInstance::info);
}
EncodedTiValue JSC_HOST_CALL numberProtoFuncValueOf(TiExcState* exec)
{
    TiValue thisValue = exec->hostThisValue();
    TiValue v = thisValue.getJSNumber();
    if (!v)
        return throwVMTypeError(exec);

    return TiValue::encode(v);
}
TiValue JSC_HOST_CALL booleanProtoFuncValueOf(TiExcState* exec, TiObject*, TiValue thisValue, const ArgList&)
{
    if (thisValue.isBoolean())
        return thisValue;

    if (!thisValue.inherits(&BooleanObject::info))
        return throwError(exec, TypeError);

    return asBooleanObject(thisValue)->internalValue();
}
EncodedTiValue JSC_HOST_CALL numberProtoFuncToLocaleString(TiExcState* exec)
{
    TiValue thisValue = exec->hostThisValue();
    // FIXME: Not implemented yet.

    TiValue v = thisValue.getJSNumber();
    if (!v)
        return throwVMTypeError(exec);

    return TiValue::encode(jsString(exec, v.toString(exec)));
}
Exemple #13
0
bool TiObject::getPropertyDescriptor(TiExcState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
{
    TiObject* object = this;
    while (true) {
        if (object->getOwnPropertyDescriptor(exec, propertyName, descriptor))
            return true;
        TiValue prototype = object->prototype();
        if (!prototype.isObject())
            return false;
        object = asObject(prototype);
    }
}
Exemple #14
0
bool TiValueIsObjectOfClass(TiContextRef ctx, TiValueRef value, TiClassRef jsClass)
{
    TiExcState* exec = toJS(ctx);
    APIEntryShim entryShim(exec);

    TiValue jsValue = toJS(exec, value);
    
    if (TiObject* o = jsValue.getObject()) {
        if (o->inherits(&TiCallbackObject<TiGlobalObject>::info))
            return static_cast<TiCallbackObject<TiGlobalObject>*>(o)->inherits(jsClass);
        else if (o->inherits(&TiCallbackObject<TiObject>::info))
            return static_cast<TiCallbackObject<TiObject>*>(o)->inherits(jsClass);
    }
    return false;
}
Exemple #15
0
TiObject* TiFunction::construct(TiExcState* exec, const ArgList& args)
{
    ASSERT(!isHostFunction());
    Structure* structure;
    TiValue prototype = get(exec, exec->propertyNames().prototype);
    if (prototype.isObject())
        structure = asObject(prototype)->inheritorID();
    else
        structure = exec->lexicalGlobalObject()->emptyObjectStructure();
    TiObject* thisObj = new (exec) TiObject(structure);

    TiValue result = exec->interpreter()->execute(jsExecutable(), exec, this, thisObj, args, scopeChain().node(), exec->exceptionSlot());
    if (exec->hadException() || !result.isObject())
        return thisObj;
    return asObject(result);
}
Exemple #16
0
TiStringRef TiValueToStringCopy(TiContextRef ctx, TiValueRef value, TiValueRef* exception)
{
    TiExcState* exec = toJS(ctx);
    APIEntryShim entryShim(exec);

    TiValue jsValue = toJS(exec, value);
    
    RefPtr<OpaqueTiString> stringRef(OpaqueTiString::create(jsValue.toString(exec)));
    if (exec->hadException()) {
        if (exception)
            *exception = toRef(exec, exec->exception());
        exec->clearException();
        stringRef.clear();
    }
    return stringRef.release().releaseRef();
}
Exemple #17
0
double TiValueToNumber(TiContextRef ctx, TiValueRef value, TiValueRef* exception)
{
    TiExcState* exec = toJS(ctx);
    APIEntryShim entryShim(exec);

    TiValue jsValue = toJS(exec, value);

    double number = jsValue.toNumber(exec);
    if (exec->hadException()) {
        if (exception)
            *exception = toRef(exec, exec->exception());
        exec->clearException();
        number = NaN;
    }
    return number;
}
Exemple #18
0
TiObjectRef TiValueToObject(TiContextRef ctx, TiValueRef value, TiValueRef* exception)
{
    TiExcState* exec = toJS(ctx);
    APIEntryShim entryShim(exec);

    TiValue jsValue = toJS(exec, value);
    
    TiObjectRef objectRef = toRef(jsValue.toObject(exec));
    if (exec->hadException()) {
        if (exception)
            *exception = toRef(exec, exec->exception());
        exec->clearException();
        objectRef = 0;
    }
    return objectRef;
}    
Exemple #19
0
bool TiObject::hasInstance(TiExcState* exec, TiValue value, TiValue proto)
{
    if (!value.isObject())
        return false;

    if (!proto.isObject()) {
        throwError(exec, TypeError, "instanceof called on an object with an invalid prototype property.");
        return false;
    }

    TiObject* object = asObject(value);
    while ((object = object->prototype().getObject())) {
        if (proto == object)
            return true;
    }
    return false;
}
TiValue JSC_HOST_CALL objectProtoFuncDefineSetter(TiExcState* exec, TiObject*, TiValue thisValue, const ArgList& args)
{
    CallData callData;
    if (args.at(1).getCallData(callData) == CallTypeNone)
        return throwError(exec, SyntaxError, "invalid setter usage");
    thisValue.toThisObject(exec)->defineSetter(exec, Identifier(exec, args.at(0).toString(exec)), asObject(args.at(1)));
    return jsUndefined();
}
TiValue JSC_HOST_CALL objectProtoFuncIsPrototypeOf(TiExcState* exec, TiObject*, TiValue thisValue, const ArgList& args)
{
    TiObject* thisObj = thisValue.toThisObject(exec);

    if (!args.at(0).isObject())
        return jsBoolean(false);

    TiValue v = asObject(args.at(0))->prototype();

    while (true) {
        if (!v.isObject())
            return jsBoolean(false);
        if (v == thisObj)
            return jsBoolean(true);
        v = asObject(v)->prototype();
    }
}
Exemple #22
0
// ECMA 15.9.3
TiObject* constructDate(TiExcState* exec, const ArgList& args)
{
    int numArgs = args.size();

    double value;

    if (numArgs == 0) // new Date() ECMA 15.9.3.3
        value = jsCurrentTime();
    else if (numArgs == 1) {
        if (args.at(0).inherits(&DateInstance::info))
            value = asDateInstance(args.at(0))->internalNumber();
        else {
            TiValue primitive = args.at(0).toPrimitive(exec);
            if (primitive.isString())
                value = parseDate(exec, primitive.getString(exec));
            else
                value = primitive.toNumber(exec);
        }
    } else {
        if (isnan(args.at(0).toNumber(exec))
                || isnan(args.at(1).toNumber(exec))
                || (numArgs >= 3 && isnan(args.at(2).toNumber(exec)))
                || (numArgs >= 4 && isnan(args.at(3).toNumber(exec)))
                || (numArgs >= 5 && isnan(args.at(4).toNumber(exec)))
                || (numArgs >= 6 && isnan(args.at(5).toNumber(exec)))
                || (numArgs >= 7 && isnan(args.at(6).toNumber(exec))))
            value = NaN;
        else {
            GregorianDateTime t;
            int year = args.at(0).toInt32(exec);
            t.year = (year >= 0 && year <= 99) ? year : year - 1900;
            t.month = args.at(1).toInt32(exec);
            t.monthDay = (numArgs >= 3) ? args.at(2).toInt32(exec) : 1;
            t.hour = args.at(3).toInt32(exec);
            t.minute = args.at(4).toInt32(exec);
            t.second = args.at(5).toInt32(exec);
            t.isDST = -1;
            double ms = (numArgs >= 7) ? args.at(6).toNumber(exec) : 0;
            value = gregorianDateTimeToMS(exec, t, ms, false);
        }
    }

    return new (exec) DateInstance(exec, value);
}
EncodedTiValue JSC_HOST_CALL functionProtoFuncToString(TiExcState* exec)
{
    TiValue thisValue = exec->hostThisValue();
    if (thisValue.inherits(&TiFunction::s_info)) {
        TiFunction* function = asFunction(thisValue);
        if (function->isHostFunction())
            return TiValue::encode(jsMakeNontrivialString(exec, "function ", function->name(exec), "() {\n    [native code]\n}"));
        FunctionExecutable* executable = function->jsExecutable();
        UString sourceString = executable->source().toString();
        insertSemicolonIfNeeded(sourceString);
        return TiValue::encode(jsMakeNontrivialString(exec, "function ", function->name(exec), "(", executable->paramString(), ") ", sourceString));
    }

    if (thisValue.inherits(&InternalFunction::s_info)) {
        InternalFunction* function = asInternalFunction(thisValue);
        return TiValue::encode(jsMakeNontrivialString(exec, "function ", function->name(exec), "() {\n    [native code]\n}"));
    }

    return throwVMTypeError(exec);
}
Exemple #24
0
bool TiString::getOwnPropertySlot(TiExcState* exec, const Identifier& propertyName, PropertySlot& slot)
{
    // The semantics here are really getPropertySlot, not getOwnPropertySlot.
    // This function should only be called by TiValue::get.
    if (getStringPropertySlot(exec, propertyName, slot))
        return true;
    if (propertyName == exec->propertyNames().underscoreProto) {
        slot.setValue(exec->lexicalGlobalObject()->stringPrototype());
        return true;
    }
    slot.setBase(this);
    TiObject* object;
    for (TiValue prototype = exec->lexicalGlobalObject()->stringPrototype(); !prototype.isNull(); prototype = object->prototype()) {
        object = asObject(prototype);
        if (object->getOwnPropertySlot(exec, propertyName, slot))
            return true;
    }
    slot.setUndefined();
    return true;
}
void ProfileGenerator::addParentForConsoleStart(TiExcState* exec)
{
    int lineNumber;
    intptr_t sourceID;
    UString sourceURL;
    TiValue function;

    exec->interpreter()->retrieveLastCaller(exec, lineNumber, sourceID, sourceURL, function);
    m_currentNode = ProfileNode::create(Profiler::createCallIdentifier(&exec->globalData(), function ? function.toThisObject(exec) : 0, sourceURL, lineNumber), m_head.get(), m_head.get());
    m_head->insertNode(m_currentNode.get());
}
Exemple #26
0
void TiObject::getPropertyNames(TiExcState* exec, PropertyNameArray& propertyNames)
{
    getOwnPropertyNames(exec, propertyNames);

    if (prototype().isNull())
        return;

    TiObject* prototype = asObject(this->prototype());
    while(1) {
        if (prototype->structure()->typeInfo().overridesGetPropertyNames()) {
            prototype->getPropertyNames(exec, propertyNames);
            break;
        }
        prototype->getOwnPropertyNames(exec, propertyNames);
        TiValue nextProto = prototype->prototype();
        if (nextProto.isNull())
            break;
        prototype = asObject(nextProto);
    }
}
Exemple #27
0
static ALWAYS_INLINE TiValue callDefaultValueFunction(TiExcState* exec, const TiObject* object, const Identifier& propertyName)
{
    TiValue function = object->get(exec, propertyName);
    CallData callData;
    CallType callType = function.getCallData(callData);
    if (callType == CallTypeNone)
        return exec->exception();

    // Prevent "toString" and "valueOf" from observing execution if an exception
    // is pending.
    if (exec->hadException())
        return exec->exception();

    TiValue result = call(exec, function, callType, callData, const_cast<TiObject*>(object), exec->emptyList());
    ASSERT(!result.isGetterSetter());
    if (exec->hadException())
        return exec->exception();
    if (result.isObject())
        return TiValue();
    return result;
}
// Shared implementation used by test and exec.
bool RegExpObject::match(TiExcState* exec)
{
    RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor();
    UString input = exec->argument(0).toString(exec);
    TiGlobalData* globalData = &exec->globalData();
    if (!regExp()->global()) {
        int position;
        int length;
        regExpConstructor->performMatch(*globalData, d->regExp.get(), input, 0, position, length);
        return position >= 0;
    }

    TiValue 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;
}
EncodedTiValue operationGetByVal(TiExcState* exec, EncodedTiValue encodedBase, EncodedTiValue encodedProperty)
{
    TiValue baseValue = TiValue::decode(encodedBase);
    TiValue property = TiValue::decode(encodedProperty);

    if (LIKELY(baseValue.isCell())) {
        TiCell* base = baseValue.asCell();

        if (property.isUInt32()) {
            TiGlobalData* globalData = &exec->globalData();
            uint32_t i = property.asUInt32();

            // FIXME: the JIT used to handle these in compiled code!
            if (isTiArray(globalData, base) && asArray(base)->canGetIndex(i))
                return TiValue::encode(asArray(base)->getIndex(i));

            // FIXME: the JITstub used to relink this to an optimized form!
            if (isTiString(globalData, base) && asString(base)->canGetIndex(i))
                return TiValue::encode(asString(base)->getIndex(exec, i));

            // FIXME: the JITstub used to relink this to an optimized form!
            if (isTiArrayArray(globalData, base) && asByteArray(base)->canAccessIndex(i))
                return TiValue::encode(asByteArray(base)->getIndex(exec, i));

            return TiValue::encode(baseValue.get(exec, i));
        }

        if (property.isString()) {
            Identifier propertyName(exec, asString(property)->value(exec));
            PropertySlot slot(base);
            if (base->fastGetOwnPropertySlot(exec, propertyName, slot))
                return TiValue::encode(slot.getValue(exec, propertyName));
        }
    }

    Identifier ident(exec, property.toString(exec));
    return TiValue::encode(baseValue.get(exec, ident));
}
Exemple #30
0
CallIdentifier Profiler::createCallIdentifier(TiExcState* exec, TiValue functionValue, const UString& defaultSourceURL, int defaultLineNumber)
{
    if (!functionValue)
        return CallIdentifier(GlobalCodeExecution, defaultSourceURL, defaultLineNumber);
    if (!functionValue.isObject())
        return CallIdentifier("(unknown)", defaultSourceURL, defaultLineNumber);
    if (asObject(functionValue)->inherits(&TiFunction::info)) {
        TiFunction* function = asFunction(functionValue);
        if (!function->executable()->isHostFunction())
            return createCallIdentifierFromFunctionImp(exec, function);
    }
    if (asObject(functionValue)->inherits(&InternalFunction::info))
        return CallIdentifier(static_cast<InternalFunction*>(asObject(functionValue))->name(exec), defaultSourceURL, defaultLineNumber);
    return CallIdentifier(makeString("(", asObject(functionValue)->className(), " object)"), defaultSourceURL, defaultLineNumber);
}