namespace v8 {
namespace internal {
+// A Handle can be converted into a MaybeHandle. Converting a MaybeHandle
+// into a Handle requires checking that it does not point to NULL. This
+// ensures NULL checks before use.
+
+template<typename T>
+class MaybeHandle {
+ public:
+ INLINE(MaybeHandle()) : location_(NULL) { }
+
+ // Constructor for handling automatic up casting from Handle.
+ // Ex. Handle<JSArray> can be passed when MaybeHandle<Object> is expected.
+ template <class S> MaybeHandle(Handle<S> handle) {
+#ifdef DEBUG
+ T* a = NULL;
+ S* b = NULL;
+ a = b; // Fake assignment to enforce type checks.
+ USE(a);
+#endif
+ this->location_ = reinterpret_cast<T**>(handle.location());
+ }
+
+ // Constructor for handling automatic up casting.
+ // Ex. MaybeHandle<JSArray> can be passed when Handle<Object> is expected.
+ template <class S> MaybeHandle(MaybeHandle<S> maybe_handle) {
+#ifdef DEBUG
+ T* a = NULL;
+ S* b = NULL;
+ a = b; // Fake assignment to enforce type checks.
+ USE(a);
+#endif
+ location_ = reinterpret_cast<T**>(maybe_handle.location_);
+ }
+
+ INLINE(Handle<T> ToHandleChecked()) {
+ CHECK(location_ != NULL);
+ return Handle<T>(location_);
+ }
+
+ INLINE(bool ToHandle(Handle<T>* out)) {
+ if (location_ == NULL) {
+ *out = Handle<T>::null();
+ return false;
+ } else {
+ *out = Handle<T>(location_);
+ return true;
+ }
+ }
+
+ protected:
+ T** location_;
+
+ // MaybeHandles of different classes are allowed to access each
+ // other's location_.
+ template<class S> friend class MaybeHandle;
+};
+
// ----------------------------------------------------------------------------
// A Handle provides a reference to an object that survives relocation by
// the garbage collector.
INLINE(explicit Handle(T* obj));
INLINE(Handle(T* obj, Isolate* isolate));
- INLINE(Handle()) : location_(NULL) {}
+ // TODO(yangguo): Values that contain empty handles should be declared as
+ // MaybeHandle to force validation before being used as handles.
+ INLINE(Handle()) : location_(NULL) { }
// Constructor for handling automatic up casting.
// Ex. Handle<JSFunction> can be passed when Handle<Object> is expected.
return Handle<T>(reinterpret_cast<T**>(that.location_));
}
+ // TODO(yangguo): Values that contain empty handles should be declared as
+ // MaybeHandle to force validation before being used as handles.
static Handle<T> null() { return Handle<T>(); }
bool is_null() const { return location_ == NULL; }
} \
} while (false)
-#define RETURN_IF_EMPTY_HANDLE_VALUE(isolate, call, value) \
- do { \
- if ((call).is_null()) { \
- ASSERT((isolate)->has_pending_exception()); \
- return (value); \
- } \
+#define RETURN_IF_EMPTY_HANDLE_VALUE(isolate, call, value) \
+ do { \
+ if ((call).is_null()) { \
+ ASSERT((isolate)->has_pending_exception()); \
+ return (value); \
+ } \
} while (false)
#define CHECK_NOT_EMPTY_HANDLE(isolate, call) \
CHECK(!(call).is_null()); \
} while (false)
-#define RETURN_IF_EMPTY_HANDLE(isolate, call) \
+#define RETURN_IF_EMPTY_HANDLE(isolate, call) \
RETURN_IF_EMPTY_HANDLE_VALUE(isolate, call, Failure::Exception())
+
+// Macros for MaybeHandle.
+
+#define RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, T) \
+ do { \
+ Isolate* __isolate__ = (isolate); \
+ if (__isolate__->has_scheduled_exception()) { \
+ __isolate__->PromoteScheduledException(); \
+ return MaybeHandle<T>(); \
+ } \
+ } while (false)
+
+#define ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, dst, call, value) \
+ do { \
+ if (!(call).ToHandle(&dst)) { \
+ ASSERT((isolate)->has_pending_exception()); \
+ return value; \
+ } \
+ } while (false)
+
+#define ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, dst, call) \
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, dst, call, Failure::Exception())
+
+#define ASSIGN_RETURN_ON_EXCEPTION(isolate, dst, call, T) \
+ ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, dst, call, MaybeHandle<T>())
+
+#define RETURN_ON_EXCEPTION_VALUE(isolate, dst, call, value) \
+ do { \
+ if (call.is_null()) { \
+ ASSERT((isolate)->has_pending_exception()); \
+ return value; \
+ } \
+ } while (false)
+
+#define RETURN_FAILURE_ON_EXCEPTION(isolate, call) \
+ RETURN_ON_EXCEPTION_VALUE(isolate, dst, call, Failure::Exception())
+
+#define RETURN_ON_EXCEPTION(isolate, call, T) \
+ RETURN_ON_EXCEPTION_VALUE( \
+ isolate, dst, call, MaybeHandle<T>::Exception())
+
+
#define FOR_EACH_ISOLATE_ADDRESS_NAME(C) \
C(Handler, handler) \
C(CEntryFP, c_entry_fp) \
// Exception throwing support. The caller should use the result
// of Throw() as its return value.
Failure* Throw(Object* exception, MessageLocation* location = NULL);
+
+ template <typename T>
+ MUST_USE_RESULT MaybeHandle<T> Throw(Handle<Object> exception,
+ MessageLocation* location = NULL) {
+ Throw(*exception, location);
+ return MaybeHandle<T>();
+ }
+
// Re-throw an exception. This involves no error reporting since
// error reporting was handled when the exception was thrown
// originally.
}
-Handle<Object> JSObject::Freeze(Handle<JSObject> object) {
+MaybeHandle<Object> JSObject::Freeze(Handle<JSObject> object) {
// Freezing sloppy arguments should be handled elsewhere.
ASSERT(!object->HasSloppyArgumentsElements());
ASSERT(!object->map()->is_observed());
isolate->factory()->undefined_value(),
v8::ACCESS_KEYS)) {
isolate->ReportFailedAccessCheckWrapper(object, v8::ACCESS_KEYS);
- RETURN_HANDLE_IF_SCHEDULED_EXCEPTION(isolate, Object);
+ RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
return isolate->factory()->false_value();
}
isolate->factory()->NewTypeError(
"cant_prevent_ext_external_array_elements",
HandleVector(&object, 1));
- isolate->Throw(*error);
- return Handle<Object>();
+ return isolate->Throw<Object>(error);
}
Handle<SeededNumberDictionary> new_element_dictionary;
static Handle<Object> PreventExtensions(Handle<JSObject> object);
// ES5 Object.freeze
- static Handle<Object> Freeze(Handle<JSObject> object);
+ static MaybeHandle<Object> Freeze(Handle<JSObject> object);
// Called the first time an object is observed with ES7 Object.observe.
static void SetObserved(Handle<JSObject> object);
HandleScope scope(isolate);
ASSERT(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
- Handle<Object> result = JSObject::Freeze(object);
- RETURN_IF_EMPTY_HANDLE(isolate, result);
+ Handle<Object> result;
+ ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, JSObject::Freeze(object));
return *result;
}
class SeededNumberDictionary;
class UnseededNumberDictionary;
class NameDictionary;
+template <typename T> class MaybeHandle;
template <typename T> class Handle;
class Heap;
class HeapObject;