From 2fc51d9cfa8d1b5e1a3a5b82b9af34994e286879 Mon Sep 17 00:00:00 2001 From: dcarney Date: Fri, 27 Feb 2015 02:39:25 -0800 Subject: [PATCH] Convert v8::Value::To* to use MaybeLocal BUG=v8:3929 LOG=y Review URL: https://codereview.chromium.org/962983002 Cr-Commit-Position: refs/heads/master@{#26912} --- include/v8.h | 51 ++++++++- include/v8config.h | 9 ++ src/api.cc | 259 ++++++++++++++++++++++++--------------------- src/api.h | 12 +++ 4 files changed, 209 insertions(+), 122 deletions(-) diff --git a/include/v8.h b/include/v8.h index eb6ed2113..a6b1d4d8b 100644 --- a/include/v8.h +++ b/include/v8.h @@ -106,6 +106,8 @@ class Utils; class Value; template class Handle; template class Local; +template +class MaybeLocal; template class Eternal; template class NonCopyablePersistentTraits; template class PersistentBase; @@ -322,6 +324,8 @@ template class Handle { template friend class PersistentBase; template friend class Handle; template friend class Local; + template + friend class MaybeLocal; template friend class FunctionCallbackInfo; template friend class PropertyCallbackInfo; template friend class internal::CustomArguments; @@ -399,6 +403,8 @@ template class Local : public Handle { template friend class Persistent; template friend class Handle; template friend class Local; + template + friend class MaybeLocal; template friend class FunctionCallbackInfo; template friend class PropertyCallbackInfo; friend class String; @@ -416,6 +422,39 @@ template class Local : public Handle { }; +template +class MaybeLocal { + public: + V8_INLINE MaybeLocal() : val_(nullptr) {} + template + V8_INLINE MaybeLocal(Local that) + : val_(reinterpret_cast(*that)) { + TYPE_CHECK(T, S); + } + + V8_INLINE bool IsEmpty() { return val_ == nullptr; } + + template + V8_WARN_UNUSED_RESULT V8_INLINE bool ToLocal(Local* out) const { + if (val_ == NULL) { + out->val_ = nullptr; + return false; + } else { + out->val_ = this->val_; + return true; + } + } + + V8_INLINE Local ToLocalChecked() { + // TODO(dcarney): add DCHECK. + return Local(val_); + } + + private: + T* val_; +}; + + // Eternal handles are set-once handles that live for the life of the isolate. template class Eternal { public: @@ -1847,6 +1886,16 @@ class V8_EXPORT Value : public Data { */ bool IsDataView() const; + MaybeLocal ToBoolean(Local context) const; + MaybeLocal ToNumber(Local context) const; + MaybeLocal ToString(Local context) const; + MaybeLocal ToDetailString(Local context) const; + MaybeLocal ToObject(Local context) const; + MaybeLocal ToInteger(Local context) const; + MaybeLocal ToUint32(Local context) const; + MaybeLocal ToInt32(Local context) const; + + // TODO(dcarney): deprecate all these. Local ToBoolean(Isolate* isolate) const; Local ToNumber(Isolate* isolate) const; Local ToString(Isolate* isolate) const; @@ -1856,7 +1905,7 @@ class V8_EXPORT Value : public Data { Local ToUint32(Isolate* isolate) const; Local ToInt32(Isolate* isolate) const; - // TODO(dcarney): deprecate all these. + // TODO(dcarney): deprecate all these as well. inline Local ToBoolean() const; inline Local ToNumber() const; inline Local ToString() const; diff --git a/include/v8config.h b/include/v8config.h index f9c3ffde1..24d1ce890 100644 --- a/include/v8config.h +++ b/include/v8config.h @@ -421,4 +421,13 @@ namespace v8 { template class AlignOfHelper { char c; T t; }; } # define V8_ALIGNOF(type) (sizeof(::v8::AlignOfHelper) - 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_ diff --git a/src/api.cc b/src/api.cc index daf72e8ef..5fdc10eb2 100644 --- a/src/api.cc +++ b/src/api.cc @@ -2627,108 +2627,160 @@ bool Value::IsSetIterator() const { } -Local Value::ToString(Isolate* v8_isolate) const { - i::Handle obj = Utils::OpenHandle(this); - i::Handle str; - if (obj->IsString()) { - str = obj; - } else { - i::Isolate* isolate = reinterpret_cast(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()); - } - return ToApiHandle(str); +#define CONTEXT_SCOPE_GET_ISOLATE(context, function_name) \ + v8::Context::Scope context_scope(context); \ + auto isolate = reinterpret_cast(context->GetIsolate()); \ + LOG_API(isolate, function_name); \ + ENTER_V8(isolate); + + +#define RETURN_TO_LOCAL_UNCHECKED(maybe_local, T) \ + do { \ + Local result; \ + bool ignored = maybe_local.ToLocal(&result); \ + USE(ignored); \ + return result; \ + } while (false); + + +MaybeLocal Value::ToString(Local context) const { + auto obj = Utils::OpenHandle(this); + if (obj->IsString()) return ToApiHandle(obj); + CONTEXT_SCOPE_GET_ISOLATE(context, "ToString"); + EXCEPTION_PREAMBLE(isolate); + Local result; + has_pending_exception = + !ToLocal(i::Execution::ToString(isolate, obj), &result); + EXCEPTION_BAILOUT_CHECK(isolate, result); + return result; } -Local Value::ToDetailString(Isolate* v8_isolate) const { - i::Handle obj = Utils::OpenHandle(this); - i::Handle str; - if (obj->IsString()) { - str = obj; - } else { - i::Isolate* isolate = reinterpret_cast(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()); - } - return ToApiHandle(str); +Local Value::ToString(Isolate* isolate) const { + RETURN_TO_LOCAL_UNCHECKED(ToString(isolate->GetCurrentContext()), String); } -Local Value::ToObject(Isolate* v8_isolate) const { - i::Handle obj = Utils::OpenHandle(this); - i::Handle val; - if (obj->IsJSObject()) { - val = obj; - } else { - i::Isolate* isolate = reinterpret_cast(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()); - } - return ToApiHandle(val); +MaybeLocal Value::ToDetailString(Local context) const { + auto obj = Utils::OpenHandle(this); + if (obj->IsString()) return ToApiHandle(obj); + CONTEXT_SCOPE_GET_ISOLATE(context, "ToDetailString"); + EXCEPTION_PREAMBLE(isolate); + Local result; + has_pending_exception = + !ToLocal(i::Execution::ToDetailString(isolate, obj), &result); + EXCEPTION_BAILOUT_CHECK(isolate, result); + return result; +} + + +Local Value::ToDetailString(Isolate* isolate) const { + RETURN_TO_LOCAL_UNCHECKED(ToDetailString(isolate->GetCurrentContext()), + String); +} + + +MaybeLocal Value::ToObject(Local context) const { + auto obj = Utils::OpenHandle(this); + if (obj->IsJSObject()) return ToApiHandle(obj); + CONTEXT_SCOPE_GET_ISOLATE(context, "ToObject"); + EXCEPTION_PREAMBLE(isolate); + Local result; + has_pending_exception = + !ToLocal(i::Execution::ToObject(isolate, obj), &result); + EXCEPTION_BAILOUT_CHECK(isolate, result); + return result; +} + + +Local Value::ToObject(Isolate* isolate) const { + RETURN_TO_LOCAL_UNCHECKED(ToObject(isolate->GetCurrentContext()), Object); +} + + +MaybeLocal Value::ToBoolean(Local context) const { + auto obj = Utils::OpenHandle(this); + if (obj->IsBoolean()) return ToApiHandle(obj); + auto isolate = reinterpret_cast(context->GetIsolate()); + auto val = isolate->factory()->ToBoolean(obj->BooleanValue()); + return ToApiHandle(val); } Local Value::ToBoolean(Isolate* v8_isolate) const { - i::Handle obj = Utils::OpenHandle(this); - if (obj->IsBoolean()) { - return ToApiHandle(obj); - } else { - i::Isolate* isolate = reinterpret_cast(v8_isolate); - LOG_API(isolate, "ToBoolean"); - ENTER_V8(isolate); - i::Handle val = - isolate->factory()->ToBoolean(obj->BooleanValue()); - return ToApiHandle(val); - } + return ToBoolean(v8_isolate->GetCurrentContext()).ToLocalChecked(); } -Local Value::ToNumber(Isolate* v8_isolate) const { - i::Handle obj = Utils::OpenHandle(this); - i::Handle num; - if (obj->IsNumber()) { - num = obj; - } else { - i::Isolate* isolate = reinterpret_cast(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()); - } - return ToApiHandle(num); +MaybeLocal Value::ToNumber(Local context) const { + auto obj = Utils::OpenHandle(this); + if (obj->IsNumber()) return ToApiHandle(obj); + CONTEXT_SCOPE_GET_ISOLATE(context, "ToNumber"); + EXCEPTION_PREAMBLE(isolate); + Local result; + has_pending_exception = + !ToLocal(i::Execution::ToNumber(isolate, obj), &result); + EXCEPTION_BAILOUT_CHECK(isolate, result); + return result; } -Local Value::ToInteger(Isolate* v8_isolate) const { - i::Handle obj = Utils::OpenHandle(this); - i::Handle num; - if (obj->IsSmi()) { - num = obj; - } else { - i::Isolate* isolate = reinterpret_cast(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()); - } - return ToApiHandle(num); +Local Value::ToNumber(Isolate* isolate) const { + RETURN_TO_LOCAL_UNCHECKED(ToNumber(isolate->GetCurrentContext()), Number); +} + + +MaybeLocal Value::ToInteger(Local context) const { + auto obj = Utils::OpenHandle(this); + if (obj->IsSmi()) return ToApiHandle(obj); + CONTEXT_SCOPE_GET_ISOLATE(context, "ToInteger"); + EXCEPTION_PREAMBLE(isolate); + Local result; + has_pending_exception = + !ToLocal(i::Execution::ToInteger(isolate, obj), &result); + EXCEPTION_BAILOUT_CHECK(isolate, result); + return result; +} + + +Local Value::ToInteger(Isolate* isolate) const { + RETURN_TO_LOCAL_UNCHECKED(ToInteger(isolate->GetCurrentContext()), Integer); +} + + +MaybeLocal Value::ToInt32(Local context) const { + auto obj = Utils::OpenHandle(this); + if (obj->IsSmi()) return ToApiHandle(obj); + CONTEXT_SCOPE_GET_ISOLATE(context, "ToInt32"); + EXCEPTION_PREAMBLE(isolate); + Local result; + has_pending_exception = + !ToLocal(i::Execution::ToInt32(isolate, obj), &result); + EXCEPTION_BAILOUT_CHECK(isolate, result); + return result; +} + + +Local Value::ToInt32(Isolate* isolate) const { + RETURN_TO_LOCAL_UNCHECKED(ToInt32(isolate->GetCurrentContext()), Int32); +} + + +MaybeLocal Value::ToUint32(Local context) const { + auto obj = Utils::OpenHandle(this); + if (obj->IsSmi()) return ToApiHandle(obj); + CONTEXT_SCOPE_GET_ISOLATE(context, "ToUInt32"); + EXCEPTION_PREAMBLE(isolate); + Local result; + has_pending_exception = + !ToLocal(i::Execution::ToUint32(isolate, obj), &result); + EXCEPTION_BAILOUT_CHECK(isolate, result); + return result; +} + + +Local Value::ToUint32(Isolate* isolate) const { + RETURN_TO_LOCAL_UNCHECKED(ToUint32(isolate->GetCurrentContext()), Uint32); } @@ -2982,41 +3034,6 @@ int64_t Value::IntegerValue() const { } -Local Value::ToInt32(Isolate* v8_isolate) const { - i::Handle obj = Utils::OpenHandle(this); - i::Handle num; - if (obj->IsSmi()) { - num = obj; - } else { - i::Isolate* isolate = reinterpret_cast(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()); - } - return ToApiHandle(num); -} - - -Local Value::ToUint32(Isolate* v8_isolate) const { - i::Handle obj = Utils::OpenHandle(this); - i::Handle num; - if (obj->IsSmi()) { - num = obj; - } else { - i::Isolate* isolate = reinterpret_cast(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()); - } - return ToApiHandle(num); -} - - Local Value::ToArrayIndex() const { i::Handle obj = Utils::OpenHandle(this); if (obj->IsSmi()) { diff --git a/src/api.h b/src/api.h index ee0765e78..fa8682bf5 100644 --- a/src/api.h +++ b/src/api.h @@ -319,6 +319,18 @@ inline v8::Local ToApiHandle( } +template +inline bool ToLocal(v8::internal::MaybeHandle maybe, + Local* local) { + v8::internal::Handle handle; + if (maybe.ToHandle(&handle)) { + *local = Utils::Convert(handle); + return true; + } + return false; +} + + // Implementations of ToLocal #define MAKE_TO_LOCAL(Name, From, To) \ -- 2.34.1