Convert v8::Value::To* to use MaybeLocal
authordcarney <dcarney@chromium.org>
Fri, 27 Feb 2015 10:39:25 +0000 (02:39 -0800)
committerCommit bot <commit-bot@chromium.org>
Fri, 27 Feb 2015 10:39:41 +0000 (10:39 +0000)
BUG=v8:3929
LOG=y

Review URL: https://codereview.chromium.org/962983002

Cr-Commit-Position: refs/heads/master@{#26912}

include/v8.h
include/v8config.h
src/api.cc
src/api.h

index eb6ed211353b446a073cdbb26ce10baae1205e61..a6b1d4d8b2e097d8bb0a54df346f035881e2b57a 100644 (file)
@@ -106,6 +106,8 @@ class Utils;
 class Value;
 template <class T> class Handle;
 template <class T> class Local;
+template <class T>
+class MaybeLocal;
 template <class T> class Eternal;
 template<class T> class NonCopyablePersistentTraits;
 template<class T> class PersistentBase;
@@ -322,6 +324,8 @@ template <class T> class Handle {
   template<class F> friend class PersistentBase;
   template<class F> friend class Handle;
   template<class F> friend class Local;
+  template <class F>
+  friend class MaybeLocal;
   template<class F> friend class FunctionCallbackInfo;
   template<class F> friend class PropertyCallbackInfo;
   template<class F> friend class internal::CustomArguments;
@@ -399,6 +403,8 @@ template <class T> class Local : public Handle<T> {
   template<class F, class M> friend class Persistent;
   template<class F> friend class Handle;
   template<class F> friend class Local;
+  template <class F>
+  friend class MaybeLocal;
   template<class F> friend class FunctionCallbackInfo;
   template<class F> friend class PropertyCallbackInfo;
   friend class String;
@@ -416,6 +422,39 @@ template <class T> class Local : public Handle<T> {
 };
 
 
+template <class T>
+class MaybeLocal {
+ public:
+  V8_INLINE MaybeLocal() : val_(nullptr) {}
+  template <class S>
+  V8_INLINE MaybeLocal(Local<S> that)
+      : val_(reinterpret_cast<T*>(*that)) {
+    TYPE_CHECK(T, S);
+  }
+
+  V8_INLINE bool IsEmpty() { return val_ == nullptr; }
+
+  template <class S>
+  V8_WARN_UNUSED_RESULT V8_INLINE bool ToLocal(Local<S>* out) const {
+    if (val_ == NULL) {
+      out->val_ = nullptr;
+      return false;
+    } else {
+      out->val_ = this->val_;
+      return true;
+    }
+  }
+
+  V8_INLINE Local<T> ToLocalChecked() {
+    // TODO(dcarney): add DCHECK.
+    return Local<T>(val_);
+  }
+
+ private:
+  T* val_;
+};
+
+
 // Eternal handles are set-once handles that live for the life of the isolate.
 template <class T> class Eternal {
  public:
@@ -1847,6 +1886,16 @@ class V8_EXPORT Value : public Data {
    */
   bool IsDataView() const;
 
+  MaybeLocal<Boolean> ToBoolean(Local<Context> context) const;
+  MaybeLocal<Number> ToNumber(Local<Context> context) const;
+  MaybeLocal<String> ToString(Local<Context> context) const;
+  MaybeLocal<String> ToDetailString(Local<Context> context) const;
+  MaybeLocal<Object> ToObject(Local<Context> context) const;
+  MaybeLocal<Integer> ToInteger(Local<Context> context) const;
+  MaybeLocal<Uint32> ToUint32(Local<Context> context) const;
+  MaybeLocal<Int32> ToInt32(Local<Context> context) const;
+
+  // TODO(dcarney): deprecate all these.
   Local<Boolean> ToBoolean(Isolate* isolate) const;
   Local<Number> ToNumber(Isolate* isolate) const;
   Local<String> ToString(Isolate* isolate) const;
@@ -1856,7 +1905,7 @@ class V8_EXPORT Value : public Data {
   Local<Uint32> ToUint32(Isolate* isolate) const;
   Local<Int32> ToInt32(Isolate* isolate) const;
 
-  // TODO(dcarney): deprecate all these.
+  // TODO(dcarney): deprecate all these as well.
   inline Local<Boolean> ToBoolean() const;
   inline Local<Number> ToNumber() const;
   inline Local<String> ToString() const;
index f9c3ffde17cf7a6ab39167ce83ed136c360ff923..24d1ce8902e589af08aec2fdac3321c1e63c6efa 100644 (file)
@@ -421,4 +421,13 @@ namespace v8 { template <typename T> class AlignOfHelper { char c; T t; }; }
 # define V8_ALIGNOF(type) (sizeof(::v8::AlignOfHelper<type>) - sizeof(type))
 #endif
 
+// Annotate a function indicating the caller must examine the return value.
+// Use like:
+//   int foo() WARN_UNUSED_RESULT;
+#if V8_HAS_ATTRIBUTE_WARN_UNUSED_RESULT
+#define V8_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
+#else
+#define V8_WARN_UNUSED_RESULT /* NOT SUPPORTED */
+#endif
+
 #endif  // V8CONFIG_H_
index daf72e8efa7dc0f8d19af4907c2b8d74a60c3e4f..5fdc10eb2eb619198b58eea5c476a49e012a7d24 100644 (file)
@@ -2627,108 +2627,160 @@ bool Value::IsSetIterator() const {
 }
 
 
-Local<String> Value::ToString(Isolate* v8_isolate) const {
-  i::Handle<i::Object> obj = Utils::OpenHandle(this);
-  i::Handle<i::Object> str;
-  if (obj->IsString()) {
-    str = obj;
-  } else {
-    i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
-    LOG_API(isolate, "ToString");
-    ENTER_V8(isolate);
-    EXCEPTION_PREAMBLE(isolate);
-    has_pending_exception = !i::Execution::ToString(
-        isolate, obj).ToHandle(&str);
-    EXCEPTION_BAILOUT_CHECK(isolate, Local<String>());
-  }
-  return ToApiHandle<String>(str);
+#define CONTEXT_SCOPE_GET_ISOLATE(context, function_name)              \
+  v8::Context::Scope context_scope(context);                           \
+  auto isolate = reinterpret_cast<i::Isolate*>(context->GetIsolate()); \
+  LOG_API(isolate, function_name);                                     \
+  ENTER_V8(isolate);
+
+
+#define RETURN_TO_LOCAL_UNCHECKED(maybe_local, T) \
+  do {                                            \
+    Local<T> result;                              \
+    bool ignored = maybe_local.ToLocal(&result);  \
+    USE(ignored);                                 \
+    return result;                                \
+  } while (false);
+
+
+MaybeLocal<String> Value::ToString(Local<Context> context) const {
+  auto obj = Utils::OpenHandle(this);
+  if (obj->IsString()) return ToApiHandle<String>(obj);
+  CONTEXT_SCOPE_GET_ISOLATE(context, "ToString");
+  EXCEPTION_PREAMBLE(isolate);
+  Local<String> result;
+  has_pending_exception =
+      !ToLocal<String>(i::Execution::ToString(isolate, obj), &result);
+  EXCEPTION_BAILOUT_CHECK(isolate, result);
+  return result;
 }
 
 
-Local<String> Value::ToDetailString(Isolate* v8_isolate) const {
-  i::Handle<i::Object> obj = Utils::OpenHandle(this);
-  i::Handle<i::Object> str;
-  if (obj->IsString()) {
-    str = obj;
-  } else {
-    i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
-    LOG_API(isolate, "ToDetailString");
-    ENTER_V8(isolate);
-    EXCEPTION_PREAMBLE(isolate);
-    has_pending_exception = !i::Execution::ToDetailString(
-        isolate, obj).ToHandle(&str);
-    EXCEPTION_BAILOUT_CHECK(isolate, Local<String>());
-  }
-  return ToApiHandle<String>(str);
+Local<String> Value::ToString(Isolate* isolate) const {
+  RETURN_TO_LOCAL_UNCHECKED(ToString(isolate->GetCurrentContext()), String);
 }
 
 
-Local<v8::Object> Value::ToObject(Isolate* v8_isolate) const {
-  i::Handle<i::Object> obj = Utils::OpenHandle(this);
-  i::Handle<i::Object> val;
-  if (obj->IsJSObject()) {
-    val = obj;
-  } else {
-    i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
-    LOG_API(isolate, "ToObject");
-    ENTER_V8(isolate);
-    EXCEPTION_PREAMBLE(isolate);
-    has_pending_exception = !i::Execution::ToObject(
-        isolate, obj).ToHandle(&val);
-    EXCEPTION_BAILOUT_CHECK(isolate, Local<v8::Object>());
-  }
-  return ToApiHandle<Object>(val);
+MaybeLocal<String> Value::ToDetailString(Local<Context> context) const {
+  auto obj = Utils::OpenHandle(this);
+  if (obj->IsString()) return ToApiHandle<String>(obj);
+  CONTEXT_SCOPE_GET_ISOLATE(context, "ToDetailString");
+  EXCEPTION_PREAMBLE(isolate);
+  Local<String> result;
+  has_pending_exception =
+      !ToLocal<String>(i::Execution::ToDetailString(isolate, obj), &result);
+  EXCEPTION_BAILOUT_CHECK(isolate, result);
+  return result;
+}
+
+
+Local<String> Value::ToDetailString(Isolate* isolate) const {
+  RETURN_TO_LOCAL_UNCHECKED(ToDetailString(isolate->GetCurrentContext()),
+                            String);
+}
+
+
+MaybeLocal<Object> Value::ToObject(Local<Context> context) const {
+  auto obj = Utils::OpenHandle(this);
+  if (obj->IsJSObject()) return ToApiHandle<Object>(obj);
+  CONTEXT_SCOPE_GET_ISOLATE(context, "ToObject");
+  EXCEPTION_PREAMBLE(isolate);
+  Local<Object> result;
+  has_pending_exception =
+      !ToLocal<Object>(i::Execution::ToObject(isolate, obj), &result);
+  EXCEPTION_BAILOUT_CHECK(isolate, result);
+  return result;
+}
+
+
+Local<v8::Object> Value::ToObject(Isolate* isolate) const {
+  RETURN_TO_LOCAL_UNCHECKED(ToObject(isolate->GetCurrentContext()), Object);
+}
+
+
+MaybeLocal<Boolean> Value::ToBoolean(Local<Context> context) const {
+  auto obj = Utils::OpenHandle(this);
+  if (obj->IsBoolean()) return ToApiHandle<Boolean>(obj);
+  auto isolate = reinterpret_cast<i::Isolate*>(context->GetIsolate());
+  auto val = isolate->factory()->ToBoolean(obj->BooleanValue());
+  return ToApiHandle<Boolean>(val);
 }
 
 
 Local<Boolean> Value::ToBoolean(Isolate* v8_isolate) const {
-  i::Handle<i::Object> obj = Utils::OpenHandle(this);
-  if (obj->IsBoolean()) {
-    return ToApiHandle<Boolean>(obj);
-  } else {
-    i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
-    LOG_API(isolate, "ToBoolean");
-    ENTER_V8(isolate);
-    i::Handle<i::Object> val =
-        isolate->factory()->ToBoolean(obj->BooleanValue());
-    return ToApiHandle<Boolean>(val);
-  }
+  return ToBoolean(v8_isolate->GetCurrentContext()).ToLocalChecked();
 }
 
 
-Local<Number> Value::ToNumber(Isolate* v8_isolate) const {
-  i::Handle<i::Object> obj = Utils::OpenHandle(this);
-  i::Handle<i::Object> num;
-  if (obj->IsNumber()) {
-    num = obj;
-  } else {
-    i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
-    LOG_API(isolate, "ToNumber");
-    ENTER_V8(isolate);
-    EXCEPTION_PREAMBLE(isolate);
-    has_pending_exception = !i::Execution::ToNumber(
-        isolate, obj).ToHandle(&num);
-    EXCEPTION_BAILOUT_CHECK(isolate, Local<Number>());
-  }
-  return ToApiHandle<Number>(num);
+MaybeLocal<Number> Value::ToNumber(Local<Context> context) const {
+  auto obj = Utils::OpenHandle(this);
+  if (obj->IsNumber()) return ToApiHandle<Number>(obj);
+  CONTEXT_SCOPE_GET_ISOLATE(context, "ToNumber");
+  EXCEPTION_PREAMBLE(isolate);
+  Local<Number> result;
+  has_pending_exception =
+      !ToLocal<Number>(i::Execution::ToNumber(isolate, obj), &result);
+  EXCEPTION_BAILOUT_CHECK(isolate, result);
+  return result;
 }
 
 
-Local<Integer> Value::ToInteger(Isolate* v8_isolate) const {
-  i::Handle<i::Object> obj = Utils::OpenHandle(this);
-  i::Handle<i::Object> num;
-  if (obj->IsSmi()) {
-    num = obj;
-  } else {
-    i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
-    LOG_API(isolate, "ToInteger");
-    ENTER_V8(isolate);
-    EXCEPTION_PREAMBLE(isolate);
-    has_pending_exception = !i::Execution::ToInteger(
-        isolate, obj).ToHandle(&num);
-    EXCEPTION_BAILOUT_CHECK(isolate, Local<Integer>());
-  }
-  return ToApiHandle<Integer>(num);
+Local<Number> Value::ToNumber(Isolate* isolate) const {
+  RETURN_TO_LOCAL_UNCHECKED(ToNumber(isolate->GetCurrentContext()), Number);
+}
+
+
+MaybeLocal<Integer> Value::ToInteger(Local<Context> context) const {
+  auto obj = Utils::OpenHandle(this);
+  if (obj->IsSmi()) return ToApiHandle<Integer>(obj);
+  CONTEXT_SCOPE_GET_ISOLATE(context, "ToInteger");
+  EXCEPTION_PREAMBLE(isolate);
+  Local<Integer> result;
+  has_pending_exception =
+      !ToLocal<Integer>(i::Execution::ToInteger(isolate, obj), &result);
+  EXCEPTION_BAILOUT_CHECK(isolate, result);
+  return result;
+}
+
+
+Local<Integer> Value::ToInteger(Isolate* isolate) const {
+  RETURN_TO_LOCAL_UNCHECKED(ToInteger(isolate->GetCurrentContext()), Integer);
+}
+
+
+MaybeLocal<Int32> Value::ToInt32(Local<Context> context) const {
+  auto obj = Utils::OpenHandle(this);
+  if (obj->IsSmi()) return ToApiHandle<Int32>(obj);
+  CONTEXT_SCOPE_GET_ISOLATE(context, "ToInt32");
+  EXCEPTION_PREAMBLE(isolate);
+  Local<Int32> result;
+  has_pending_exception =
+      !ToLocal<Int32>(i::Execution::ToInt32(isolate, obj), &result);
+  EXCEPTION_BAILOUT_CHECK(isolate, result);
+  return result;
+}
+
+
+Local<Int32> Value::ToInt32(Isolate* isolate) const {
+  RETURN_TO_LOCAL_UNCHECKED(ToInt32(isolate->GetCurrentContext()), Int32);
+}
+
+
+MaybeLocal<Uint32> Value::ToUint32(Local<Context> context) const {
+  auto obj = Utils::OpenHandle(this);
+  if (obj->IsSmi()) return ToApiHandle<Uint32>(obj);
+  CONTEXT_SCOPE_GET_ISOLATE(context, "ToUInt32");
+  EXCEPTION_PREAMBLE(isolate);
+  Local<Uint32> result;
+  has_pending_exception =
+      !ToLocal<Uint32>(i::Execution::ToUint32(isolate, obj), &result);
+  EXCEPTION_BAILOUT_CHECK(isolate, result);
+  return result;
+}
+
+
+Local<Uint32> Value::ToUint32(Isolate* isolate) const {
+  RETURN_TO_LOCAL_UNCHECKED(ToUint32(isolate->GetCurrentContext()), Uint32);
 }
 
 
@@ -2982,41 +3034,6 @@ int64_t Value::IntegerValue() const {
 }
 
 
-Local<Int32> Value::ToInt32(Isolate* v8_isolate) const {
-  i::Handle<i::Object> obj = Utils::OpenHandle(this);
-  i::Handle<i::Object> num;
-  if (obj->IsSmi()) {
-    num = obj;
-  } else {
-    i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
-    LOG_API(isolate, "ToInt32");
-    ENTER_V8(isolate);
-    EXCEPTION_PREAMBLE(isolate);
-    has_pending_exception = !i::Execution::ToInt32(isolate, obj).ToHandle(&num);
-    EXCEPTION_BAILOUT_CHECK(isolate, Local<Int32>());
-  }
-  return ToApiHandle<Int32>(num);
-}
-
-
-Local<Uint32> Value::ToUint32(Isolate* v8_isolate) const {
-  i::Handle<i::Object> obj = Utils::OpenHandle(this);
-  i::Handle<i::Object> num;
-  if (obj->IsSmi()) {
-    num = obj;
-  } else {
-    i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
-    LOG_API(isolate, "ToUInt32");
-    ENTER_V8(isolate);
-    EXCEPTION_PREAMBLE(isolate);
-    has_pending_exception = !i::Execution::ToUint32(
-        isolate, obj).ToHandle(&num);
-    EXCEPTION_BAILOUT_CHECK(isolate, Local<Uint32>());
-  }
-  return ToApiHandle<Uint32>(num);
-}
-
-
 Local<Uint32> Value::ToArrayIndex() const {
   i::Handle<i::Object> obj = Utils::OpenHandle(this);
   if (obj->IsSmi()) {
index ee0765e78c3ef987048b6a284dd6bcbc0b8e29ef..fa8682bf572079558491ee7cba95e44e55ea73b3 100644 (file)
--- a/src/api.h
+++ b/src/api.h
@@ -319,6 +319,18 @@ inline v8::Local<T> ToApiHandle(
 }
 
 
+template <class T>
+inline bool ToLocal(v8::internal::MaybeHandle<v8::internal::Object> maybe,
+                    Local<T>* local) {
+  v8::internal::Handle<v8::internal::Object> handle;
+  if (maybe.ToHandle(&handle)) {
+    *local = Utils::Convert<v8::internal::Object, T>(handle);
+    return true;
+  }
+  return false;
+}
+
+
 // Implementations of ToLocal
 
 #define MAKE_TO_LOCAL(Name, From, To)                                       \