diff --git a/include/v8.h b/include/v8.h index a6b1d4d8b2..620d8df9bd 100644 --- a/include/v8.h +++ b/include/v8.h @@ -977,12 +977,31 @@ class V8_EXPORT EscapableHandleScope : public HandleScope { * A simple Maybe type, representing an object which may or may not have a * value. */ -template -struct Maybe { +template +class Maybe { + public: Maybe() : has_value(false) {} - explicit Maybe(T t) : has_value(true), value(t) {} - Maybe(bool has, T t) : has_value(has), value(t) {} + explicit Maybe(const T& t) : has_value(true), value(t) {} + // TODO(dcarney): remove this constructor, it makes no sense. + Maybe(bool has, const T& t) : has_value(has), value(t) {} + V8_INLINE bool HasValue() const { return has_value; } + + V8_WARN_UNUSED_RESULT V8_INLINE bool ToValue(T* out) const { + *out = has_value ? value : T(); + return has_value; + } + + V8_INLINE T ToValueChecked() const { + // TODO(dcarney): add DCHECK. + return value; + } + + V8_INLINE T From(const T& default_value) const { + return has_value ? value : default_value; + } + + // TODO(dcarney): make private. bool has_value; T value; }; @@ -1921,6 +1940,13 @@ class V8_EXPORT Value : public Data { */ Local ToArrayIndex() const; + Maybe BooleanValue(Local context) const; + Maybe NumberValue(Local context) const; + Maybe IntegerValue(Local context) const; + Maybe Uint32Value(Local context) const; + Maybe Int32Value(Local context) const; + + // TODO(dcarney): deprecate all these. bool BooleanValue() const; double NumberValue() const; int64_t IntegerValue() const; diff --git a/src/api.cc b/src/api.cc index 99b2048c5d..05a77d0d74 100644 --- a/src/api.cc +++ b/src/api.cc @@ -2643,6 +2643,12 @@ bool Value::IsSetIterator() const { } while (false); +static Local ContextFromHeapObject(i::Handle obj) { + return reinterpret_cast(i::HeapObject::cast(*obj)->GetIsolate()) + ->GetCurrentContext(); +} + + MaybeLocal Value::ToString(Local context) const { auto obj = Utils::OpenHandle(this); if (obj->IsString()) return ToApiHandle(obj); @@ -2989,51 +2995,115 @@ void v8::RegExp::CheckCast(v8::Value* that) { } +Maybe Value::BooleanValue(Local context) const { + return maybe(Utils::OpenHandle(this)->BooleanValue()); +} + + bool Value::BooleanValue() const { return Utils::OpenHandle(this)->BooleanValue(); } +Maybe Value::NumberValue(Local context) const { + auto obj = Utils::OpenHandle(this); + if (obj->IsNumber()) return maybe(obj->Number()); + CONTEXT_SCOPE_GET_ISOLATE(context, "NumberValue"); + EXCEPTION_PREAMBLE(isolate); + i::Handle num; + has_pending_exception = !i::Execution::ToNumber(isolate, obj).ToHandle(&num); + EXCEPTION_BAILOUT_CHECK(isolate, Maybe()); + return maybe(num->Number()); +} + + double Value::NumberValue() const { - i::Handle obj = Utils::OpenHandle(this); + auto obj = Utils::OpenHandle(this); + if (obj->IsNumber()) return obj->Number(); + return NumberValue(ContextFromHeapObject(obj)) + .From(std::numeric_limits::quiet_NaN()); +} + + +Maybe Value::IntegerValue(Local context) const { + auto obj = Utils::OpenHandle(this); i::Handle num; if (obj->IsNumber()) { num = obj; } else { - i::Isolate* isolate = i::HeapObject::cast(*obj)->GetIsolate(); - LOG_API(isolate, "NumberValue"); - ENTER_V8(isolate); + CONTEXT_SCOPE_GET_ISOLATE(context, "IntegerValue"); EXCEPTION_PREAMBLE(isolate); - has_pending_exception = !i::Execution::ToNumber( - isolate, obj).ToHandle(&num); - EXCEPTION_BAILOUT_CHECK(isolate, std::numeric_limits::quiet_NaN()); + has_pending_exception = + !i::Execution::ToInteger(isolate, obj).ToHandle(&num); + EXCEPTION_BAILOUT_CHECK(isolate, Maybe()); + } + if (num->IsSmi()) { + return maybe(static_cast(i::Smi::cast(*num)->value())); + } else { + return maybe(static_cast(num->Number())); } - return num->Number(); } int64_t Value::IntegerValue() const { - i::Handle obj = Utils::OpenHandle(this); - i::Handle num; + auto obj = Utils::OpenHandle(this); if (obj->IsNumber()) { - num = obj; - } else { - i::Isolate* isolate = i::HeapObject::cast(*obj)->GetIsolate(); - LOG_API(isolate, "IntegerValue"); - ENTER_V8(isolate); - EXCEPTION_PREAMBLE(isolate); - has_pending_exception = !i::Execution::ToInteger( - isolate, obj).ToHandle(&num); - EXCEPTION_BAILOUT_CHECK(isolate, 0); + if (obj->IsSmi()) { + return i::Smi::cast(*obj)->value(); + } else { + return static_cast(obj->Number()); + } } + return IntegerValue(ContextFromHeapObject(obj)).From(0); +} + + +Maybe Value::Int32Value(Local context) const { + auto obj = Utils::OpenHandle(this); + if (obj->IsNumber()) return maybe(NumberToInt32(*obj)); + CONTEXT_SCOPE_GET_ISOLATE(context, "Int32Value"); + EXCEPTION_PREAMBLE(isolate); + i::Handle num; + has_pending_exception = !i::Execution::ToInt32(isolate, obj).ToHandle(&num); + EXCEPTION_BAILOUT_CHECK(isolate, Maybe()); if (num->IsSmi()) { - return i::Smi::cast(*num)->value(); + return maybe(i::Smi::cast(*num)->value()); } else { - return static_cast(num->Number()); + return maybe(static_cast(num->Number())); } } +int32_t Value::Int32Value() const { + auto obj = Utils::OpenHandle(this); + if (obj->IsNumber()) return NumberToInt32(*obj); + return Int32Value(ContextFromHeapObject(obj)).From(0); +} + + +Maybe Value::Uint32Value(Local context) const { + auto obj = Utils::OpenHandle(this); + if (obj->IsNumber()) return maybe(NumberToUint32(*obj)); + CONTEXT_SCOPE_GET_ISOLATE(context, "Uint32Value"); + EXCEPTION_PREAMBLE(isolate); + i::Handle num; + has_pending_exception = !i::Execution::ToUint32(isolate, obj).ToHandle(&num); + EXCEPTION_BAILOUT_CHECK(isolate, Maybe()); + if (num->IsSmi()) { + return maybe(static_cast(i::Smi::cast(*num)->value())); + } else { + return maybe(static_cast(num->Number())); + } +} + + +uint32_t Value::Uint32Value() const { + auto obj = Utils::OpenHandle(this); + if (obj->IsNumber()) return NumberToUint32(*obj); + return Uint32Value(ContextFromHeapObject(obj)).From(0); +} + + Local Value::ToArrayIndex() const { i::Handle obj = Utils::OpenHandle(this); if (obj->IsSmi()) { @@ -3063,27 +3133,6 @@ Local Value::ToArrayIndex() const { } -int32_t Value::Int32Value() const { - i::Handle obj = Utils::OpenHandle(this); - if (obj->IsNumber()) { - return NumberToInt32(*obj); - } else { - i::Isolate* isolate = i::HeapObject::cast(*obj)->GetIsolate(); - LOG_API(isolate, "Int32Value (slow)"); - ENTER_V8(isolate); - EXCEPTION_PREAMBLE(isolate); - i::Handle num; - has_pending_exception = !i::Execution::ToInt32(isolate, obj).ToHandle(&num); - EXCEPTION_BAILOUT_CHECK(isolate, 0); - if (num->IsSmi()) { - return i::Smi::cast(*num)->value(); - } else { - return static_cast(num->Number()); - } - } -} - - bool Value::Equals(Handle that) const { i::Handle obj = Utils::OpenHandle(this, true); i::Handle other = Utils::OpenHandle(*that); @@ -3164,28 +3213,6 @@ bool Value::SameValue(Handle that) const { } -uint32_t Value::Uint32Value() const { - i::Handle obj = Utils::OpenHandle(this); - if (obj->IsNumber()) { - return NumberToUint32(*obj); - } else { - i::Isolate* isolate = i::HeapObject::cast(*obj)->GetIsolate(); - LOG_API(isolate, "Uint32Value"); - ENTER_V8(isolate); - EXCEPTION_PREAMBLE(isolate); - i::Handle num; - has_pending_exception = !i::Execution::ToUint32( - isolate, obj).ToHandle(&num); - EXCEPTION_BAILOUT_CHECK(isolate, 0); - if (num->IsSmi()) { - return i::Smi::cast(*num)->value(); - } else { - return static_cast(num->Number()); - } - } -} - - bool v8::Object::Set(v8::Handle key, v8::Handle value) { i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate(); ON_BAILOUT(isolate, "v8::Object::Set()", return false);