Commit dc20bb49 authored by yangguo@chromium.org's avatar yangguo@chromium.org

Introduce MaybeHandle to police exception checking in handlified code.

R=ishell@chromium.org

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@20457 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 36aa2c17
......@@ -34,6 +34,62 @@
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.
......@@ -47,7 +103,9 @@ class Handle {
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.
......@@ -77,6 +135,8 @@ class Handle {
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; }
......
......@@ -134,12 +134,12 @@ typedef ZoneList<Handle<Object> > ZoneObjectList;
} \
} 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) \
......@@ -148,9 +148,51 @@ typedef ZoneList<Handle<Object> > ZoneObjectList;
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) \
......@@ -767,6 +809,14 @@ class Isolate {
// 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.
......
......@@ -5519,7 +5519,7 @@ static void FreezeDictionary(Dictionary* dictionary) {
}
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());
......@@ -5532,7 +5532,7 @@ Handle<Object> JSObject::Freeze(Handle<JSObject> object) {
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();
}
......@@ -5550,8 +5550,7 @@ Handle<Object> JSObject::Freeze(Handle<JSObject> object) {
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;
......
......@@ -2640,7 +2640,7 @@ class JSObject: public JSReceiver {
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);
......
......@@ -3231,8 +3231,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ObjectFreeze) {
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;
}
......
......@@ -128,6 +128,7 @@ class MemoryChunk;
class SeededNumberDictionary;
class UnseededNumberDictionary;
class NameDictionary;
template <typename T> class MaybeHandle;
template <typename T> class Handle;
class Heap;
class HeapObject;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment