UString TiObject::toString(TiExcState* exec) const { TiValue primitive = toPrimitive(exec, PreferString); if (exec->hadException()) return ""; return primitive.toString(exec); }
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))); }
EncodedTiValue JSC_HOST_CALL errorProtoFuncToString(TiExcState* exec) { TiObject* thisObj = exec->hostThisValue().toThisObject(exec); StringRecursionChecker checker(exec, thisObj); if (EncodedTiValue earlyReturnValue = checker.earlyReturnValue()) return earlyReturnValue; TiValue name = thisObj->get(exec, exec->propertyNames().name); TiValue message = thisObj->get(exec, exec->propertyNames().message); // Mozilla-compatible format. if (!name.isUndefined()) { if (!message.isUndefined()) return TiValue::encode(jsMakeNontrivialString(exec, name.toString(exec), ": ", message.toString(exec))); return TiValue::encode(jsNontrivialString(exec, name.toString(exec))); } if (!message.isUndefined()) return TiValue::encode(jsMakeNontrivialString(exec, "Error: ", message.toString(exec))); return TiValue::encode(jsNontrivialString(exec, "Error")); }
ALWAYS_INLINE static void operationPutByValInternal(TiExcState* exec, EncodedTiValue encodedBase, EncodedTiValue encodedProperty, EncodedTiValue encodedValue) { TiGlobalData* globalData = &exec->globalData(); TiValue baseValue = TiValue::decode(encodedBase); TiValue property = TiValue::decode(encodedProperty); TiValue value = TiValue::decode(encodedValue); if (LIKELY(property.isUInt32())) { uint32_t i = property.asUInt32(); if (isTiArray(globalData, baseValue)) { TiArray* jsArray = asArray(baseValue); if (jsArray->canSetIndex(i)) { jsArray->setIndex(*globalData, i, value); return; } jsArray->TiArray::put(exec, i, value); return; } if (isTiArrayArray(globalData, baseValue) && asByteArray(baseValue)->canAccessIndex(i)) { TiArrayArray* jsByteArray = asByteArray(baseValue); // FIXME: the JITstub used to relink this to an optimized form! if (value.isInt32()) { jsByteArray->setIndex(i, value.asInt32()); return; } double dValue = 0; if (value.getNumber(dValue)) { jsByteArray->setIndex(i, dValue); return; } } baseValue.put(exec, i, value); return; } // Don't put to an object if toString throws an exception. Identifier ident(exec, property.toString(exec)); if (!globalData->exception) { PutPropertySlot slot(strict); baseValue.put(exec, ident, value, slot); } }
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(); }
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)); }
EncodedTiValue JSC_HOST_CALL numberProtoFuncToString(TiExcState* exec) { TiValue thisValue = exec->hostThisValue(); TiValue v = thisValue.getJSNumber(); if (!v) return throwVMTypeError(exec); TiValue 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 TiValue::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 TiGlobalData* globalData = &exec->globalData(); return TiValue::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 TiValue::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 TiValue::encode(jsString(exec, startOfResultString)); }