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 @@ ...@@ -34,6 +34,62 @@
namespace v8 { namespace v8 {
namespace internal { 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 // A Handle provides a reference to an object that survives relocation by
// the garbage collector. // the garbage collector.
...@@ -47,7 +103,9 @@ class Handle { ...@@ -47,7 +103,9 @@ class Handle {
INLINE(explicit Handle(T* obj)); INLINE(explicit Handle(T* obj));
INLINE(Handle(T* obj, Isolate* isolate)); 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. // Constructor for handling automatic up casting.
// Ex. Handle<JSFunction> can be passed when Handle<Object> is expected. // Ex. Handle<JSFunction> can be passed when Handle<Object> is expected.
...@@ -77,6 +135,8 @@ class Handle { ...@@ -77,6 +135,8 @@ class Handle {
return Handle<T>(reinterpret_cast<T**>(that.location_)); 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>(); } static Handle<T> null() { return Handle<T>(); }
bool is_null() const { return location_ == NULL; } bool is_null() const { return location_ == NULL; }
......
...@@ -134,12 +134,12 @@ typedef ZoneList<Handle<Object> > ZoneObjectList; ...@@ -134,12 +134,12 @@ typedef ZoneList<Handle<Object> > ZoneObjectList;
} \ } \
} while (false) } while (false)
#define RETURN_IF_EMPTY_HANDLE_VALUE(isolate, call, value) \ #define RETURN_IF_EMPTY_HANDLE_VALUE(isolate, call, value) \
do { \ do { \
if ((call).is_null()) { \ if ((call).is_null()) { \
ASSERT((isolate)->has_pending_exception()); \ ASSERT((isolate)->has_pending_exception()); \
return (value); \ return (value); \
} \ } \
} while (false) } while (false)
#define CHECK_NOT_EMPTY_HANDLE(isolate, call) \ #define CHECK_NOT_EMPTY_HANDLE(isolate, call) \
...@@ -148,9 +148,51 @@ typedef ZoneList<Handle<Object> > ZoneObjectList; ...@@ -148,9 +148,51 @@ typedef ZoneList<Handle<Object> > ZoneObjectList;
CHECK(!(call).is_null()); \ CHECK(!(call).is_null()); \
} while (false) } 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()) 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) \ #define FOR_EACH_ISOLATE_ADDRESS_NAME(C) \
C(Handler, handler) \ C(Handler, handler) \
C(CEntryFP, c_entry_fp) \ C(CEntryFP, c_entry_fp) \
...@@ -767,6 +809,14 @@ class Isolate { ...@@ -767,6 +809,14 @@ class Isolate {
// Exception throwing support. The caller should use the result // Exception throwing support. The caller should use the result
// of Throw() as its return value. // of Throw() as its return value.
Failure* Throw(Object* exception, MessageLocation* location = NULL); 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 // Re-throw an exception. This involves no error reporting since
// error reporting was handled when the exception was thrown // error reporting was handled when the exception was thrown
// originally. // originally.
......
...@@ -5519,7 +5519,7 @@ static void FreezeDictionary(Dictionary* dictionary) { ...@@ -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. // Freezing sloppy arguments should be handled elsewhere.
ASSERT(!object->HasSloppyArgumentsElements()); ASSERT(!object->HasSloppyArgumentsElements());
ASSERT(!object->map()->is_observed()); ASSERT(!object->map()->is_observed());
...@@ -5532,7 +5532,7 @@ Handle<Object> JSObject::Freeze(Handle<JSObject> object) { ...@@ -5532,7 +5532,7 @@ Handle<Object> JSObject::Freeze(Handle<JSObject> object) {
isolate->factory()->undefined_value(), isolate->factory()->undefined_value(),
v8::ACCESS_KEYS)) { v8::ACCESS_KEYS)) {
isolate->ReportFailedAccessCheckWrapper(object, 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(); return isolate->factory()->false_value();
} }
...@@ -5550,8 +5550,7 @@ Handle<Object> JSObject::Freeze(Handle<JSObject> object) { ...@@ -5550,8 +5550,7 @@ Handle<Object> JSObject::Freeze(Handle<JSObject> object) {
isolate->factory()->NewTypeError( isolate->factory()->NewTypeError(
"cant_prevent_ext_external_array_elements", "cant_prevent_ext_external_array_elements",
HandleVector(&object, 1)); HandleVector(&object, 1));
isolate->Throw(*error); return isolate->Throw<Object>(error);
return Handle<Object>();
} }
Handle<SeededNumberDictionary> new_element_dictionary; Handle<SeededNumberDictionary> new_element_dictionary;
......
...@@ -2640,7 +2640,7 @@ class JSObject: public JSReceiver { ...@@ -2640,7 +2640,7 @@ class JSObject: public JSReceiver {
static Handle<Object> PreventExtensions(Handle<JSObject> object); static Handle<Object> PreventExtensions(Handle<JSObject> object);
// ES5 Object.freeze // 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. // Called the first time an object is observed with ES7 Object.observe.
static void SetObserved(Handle<JSObject> object); static void SetObserved(Handle<JSObject> object);
......
...@@ -3231,8 +3231,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ObjectFreeze) { ...@@ -3231,8 +3231,8 @@ RUNTIME_FUNCTION(MaybeObject*, Runtime_ObjectFreeze) {
HandleScope scope(isolate); HandleScope scope(isolate);
ASSERT(args.length() == 1); ASSERT(args.length() == 1);
CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0); CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
Handle<Object> result = JSObject::Freeze(object); Handle<Object> result;
RETURN_IF_EMPTY_HANDLE(isolate, result); ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, JSObject::Freeze(object));
return *result; return *result;
} }
......
...@@ -128,6 +128,7 @@ class MemoryChunk; ...@@ -128,6 +128,7 @@ class MemoryChunk;
class SeededNumberDictionary; class SeededNumberDictionary;
class UnseededNumberDictionary; class UnseededNumberDictionary;
class NameDictionary; class NameDictionary;
template <typename T> class MaybeHandle;
template <typename T> class Handle; template <typename T> class Handle;
class Heap; class Heap;
class HeapObject; 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