Added implementation if Uint32::Value.
authorlrn@chromium.org <lrn@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 3 Mar 2010 13:44:20 +0000 (13:44 +0000)
committerlrn@chromium.org <lrn@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 3 Mar 2010 13:44:20 +0000 (13:44 +0000)
Review URL: http://codereview.chromium.org/661275

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4008 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

include/v8.h
src/api.cc
src/conversions-inl.h
src/conversions.h
test/cctest/test-api.cc

index f77c56a..92e1bb6 100644 (file)
@@ -550,13 +550,13 @@ class V8EXPORT Script {
    * Compiles the specified script (context-independent).
    *
    * \param source Script source code.
-   * \param origin Script origin, owned by caller, no references are kept 
+   * \param origin Script origin, owned by caller, no references are kept
    *   when New() returns
    * \param pre_data Pre-parsing data, as obtained by ScriptData::PreCompile()
    *   using pre_data speeds compilation if it's done multiple times.
    *   Owned by caller, no references are kept when New() returns.
    * \param script_data Arbitrary data associated with script. Using
-   *   this has same effect as calling SetData(), but allows data to be 
+   *   this has same effect as calling SetData(), but allows data to be
    *   available to compile event handlers.
    * \return Compiled script object (context independent; when run it
    *   will use the currently entered context).
@@ -571,7 +571,7 @@ class V8EXPORT Script {
    * object (typically a string) as the script's origin.
    *
    * \param source Script source code.
-   * \patam file_name file name object (typically a string) to be used 
+   * \param file_name file name object (typically a string) to be used
    *   as the script's origin.
    * \return Compiled script object (context independent; when run it
    *   will use the currently entered context).
@@ -583,7 +583,7 @@ class V8EXPORT Script {
    * Compiles the specified script (bound to current context).
    *
    * \param source Script source code.
-   * \param origin Script origin, owned by caller, no references are kept 
+   * \param origin Script origin, owned by caller, no references are kept
    *   when Compile() returns
    * \param pre_data Pre-parsing data, as obtained by ScriptData::PreCompile()
    *   using pre_data speeds compilation if it's done multiple times.
@@ -767,6 +767,11 @@ class V8EXPORT Value : public Data {
   bool IsInt32() const;
 
   /**
+   * Returns true if this value is a 32-bit signed integer.
+   */
+  bool IsUint32() const;
+
+  /**
    * Returns true if this value is a Date.
    */
   bool IsDate() const;
index bb40079..cc81091 100644 (file)
@@ -1569,6 +1569,18 @@ bool Value::IsInt32() const {
 }
 
 
+bool Value::IsUint32() const {
+  if (IsDeadCheck("v8::Value::IsUint32()")) return false;
+  i::Handle<i::Object> obj = Utils::OpenHandle(this);
+  if (obj->IsSmi()) return i::Smi::cast(*obj)->value() >= 0;
+  if (obj->IsNumber()) {
+    double value = obj->Number();
+    return i::FastUI2D(i::FastD2UI(value)) == value;
+  }
+  return false;
+}
+
+
 bool Value::IsDate() const {
   if (IsDeadCheck("v8::Value::IsDate()")) return false;
   i::Handle<i::Object> obj = Utils::OpenHandle(this);
@@ -2756,6 +2768,17 @@ int32_t Int32::Value() const {
 }
 
 
+uint32_t Uint32::Value() const {
+  if (IsDeadCheck("v8::Uint32::Value()")) return 0;
+  i::Handle<i::Object> obj = Utils::OpenHandle(this);
+  if (obj->IsSmi()) {
+    return i::Smi::cast(*obj)->value();
+  } else {
+    return static_cast<uint32_t>(obj->Number());
+  }
+}
+
+
 int v8::Object::InternalFieldCount() {
   if (IsDeadCheck("v8::Object::InternalFieldCount()")) return 0;
   i::Handle<i::JSObject> obj = Utils::OpenHandle(this);
index ba7220a..f7210d5 100644 (file)
@@ -59,6 +59,32 @@ static inline int FastD2I(double x) {
 }
 
 
+// The fast double-to-unsigned-int conversion routine does not guarantee
+// rounding towards zero.
+static inline unsigned int FastD2UI(double x) {
+  // There is no unsigned version of lrint, so there is no fast path
+  // in this function as there is in FastD2I. Using lrint doesn't work
+  // for values of 2^31 and above.
+
+  // Convert "small enough" doubles to uint32_t by fixing the 32
+  // least significant non-fractional bits in the low 32 bits of the
+  // double, and reading them from there.
+  const double k2Pow52 = 4503599627370496.0;
+  bool negative = x < 0;
+  if (negative) {
+    x = -x;
+  }
+  if (x < k2Pow52) {
+    x += k2Pow52;
+    uint32_t result;
+    memcpy(&result, &x, sizeof(result));  // Copy low 32 bits.
+    return negative ? ~result + 1 : result;
+  }
+  // Large number (outside uint32 range), Infinity or NaN.
+  return 0x80000000u;  // Return integer indefinite.
+}
+
+
 static inline double DoubleToInteger(double x) {
   if (isnan(x)) return 0;
   if (!isfinite(x) || x == 0) return x;
index 67f7d53..bdc7e44 100644 (file)
@@ -32,11 +32,12 @@ namespace v8 {
 namespace internal {
 
 
-// The fast double-to-int conversion routine does not guarantee
+// The fast double-to-(unsigned-)int conversion routine does not guarantee
 // rounding towards zero.
 // The result is unspecified if x is infinite or NaN, or if the rounded
 // integer value is outside the range of type int.
 static inline int FastD2I(double x);
+static inline unsigned int FastD2UI(double x);
 
 
 static inline double FastI2D(int x) {
index 820586d..b3c88a5 100644 (file)
@@ -1960,6 +1960,95 @@ static void CheckUncle(v8::TryCatch* try_catch) {
 }
 
 
+THREADED_TEST(ConversionNumber) {
+  v8::HandleScope scope;
+  LocalContext env;
+  // Very large number.
+  CompileRun("var obj = Math.pow(2,32) * 1237;");
+  Local<Value> obj = env->Global()->Get(v8_str("obj"));
+  CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
+  CHECK_EQ(0, obj->ToInt32()->Value());
+  CHECK(0u == obj->ToUint32()->Value());  // NOLINT - no CHECK_EQ for unsigned.
+  // Large number.
+  CompileRun("var obj = -1234567890123;");
+  obj = env->Global()->Get(v8_str("obj"));
+  CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
+  CHECK_EQ(-1912276171, obj->ToInt32()->Value());
+  CHECK(2382691125u == obj->ToUint32()->Value());  // NOLINT
+  // Small positive integer.
+  CompileRun("var obj = 42;");
+  obj = env->Global()->Get(v8_str("obj"));
+  CHECK_EQ(42.0, obj->ToNumber()->Value());
+  CHECK_EQ(42, obj->ToInt32()->Value());
+  CHECK(42u == obj->ToUint32()->Value());  // NOLINT
+  // Negative integer.
+  CompileRun("var obj = -37;");
+  obj = env->Global()->Get(v8_str("obj"));
+  CHECK_EQ(-37.0, obj->ToNumber()->Value());
+  CHECK_EQ(-37, obj->ToInt32()->Value());
+  CHECK(4294967259u == obj->ToUint32()->Value());  // NOLINT
+  // Positive non-int32 integer.
+  CompileRun("var obj = 0x81234567;");
+  obj = env->Global()->Get(v8_str("obj"));
+  CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
+  CHECK_EQ(-2128394905, obj->ToInt32()->Value());
+  CHECK(2166572391u == obj->ToUint32()->Value());  // NOLINT
+  // Fraction.
+  CompileRun("var obj = 42.3;");
+  obj = env->Global()->Get(v8_str("obj"));
+  CHECK_EQ(42.3, obj->ToNumber()->Value());
+  CHECK_EQ(42, obj->ToInt32()->Value());
+  CHECK(42u == obj->ToUint32()->Value());  // NOLINT
+  // Large negative fraction.
+  CompileRun("var obj = -5726623061.75;");
+  obj = env->Global()->Get(v8_str("obj"));
+  CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
+  CHECK_EQ(-1431655765, obj->ToInt32()->Value());
+  CHECK(2863311531u == obj->ToUint32()->Value());  // NOLINT
+}
+
+
+THREADED_TEST(isNumberType) {
+  v8::HandleScope scope;
+  LocalContext env;
+  // Very large number.
+  CompileRun("var obj = Math.pow(2,32) * 1237;");
+  Local<Value> obj = env->Global()->Get(v8_str("obj"));
+  CHECK(!obj->IsInt32());
+  CHECK(!obj->IsUint32());
+  // Large negative number.
+  CompileRun("var obj = -1234567890123;");
+  obj = env->Global()->Get(v8_str("obj"));
+  CHECK(!obj->IsInt32());
+  CHECK(!obj->IsUint32());
+  // Small positive integer.
+  CompileRun("var obj = 42;");
+  obj = env->Global()->Get(v8_str("obj"));
+  CHECK(obj->IsInt32());
+  CHECK(obj->IsUint32());
+  // Negative integer.
+  CompileRun("var obj = -37;");
+  obj = env->Global()->Get(v8_str("obj"));
+  CHECK(obj->IsInt32());
+  CHECK(!obj->IsUint32());
+  // Positive non-int32 integer.
+  CompileRun("var obj = 0x81234567;");
+  obj = env->Global()->Get(v8_str("obj"));
+  CHECK(!obj->IsInt32());
+  CHECK(obj->IsUint32());
+  // Fraction.
+  CompileRun("var obj = 42.3;");
+  obj = env->Global()->Get(v8_str("obj"));
+  CHECK(!obj->IsInt32());
+  CHECK(!obj->IsUint32());
+  // Large negative fraction.
+  CompileRun("var obj = -5726623061.75;");
+  obj = env->Global()->Get(v8_str("obj"));
+  CHECK(!obj->IsInt32());
+  CHECK(!obj->IsUint32());
+}
+
+
 THREADED_TEST(ConversionException) {
   v8::HandleScope scope;
   LocalContext env;