diff --git a/deps/v8/include/v8.h b/deps/v8/include/v8.h index 9a577765b439ae..481cdd9e9461a4 100644 --- a/deps/v8/include/v8.h +++ b/deps/v8/include/v8.h @@ -5370,6 +5370,19 @@ class V8_EXPORT Isolate { */ static Isolate* GetCurrent(); + /** + * Custom callback used by embedders to help V8 determine if it should abort + * when it throws and no internal handler is predicted to catch the + * exception. If --abort-on-uncaught-exception is used on the command line, + * then V8 will abort if either: + * - no custom callback is set. + * - the custom callback set returns true. + * Otherwise, the custom callback will not be called and V8 will not abort. + */ + typedef bool (*AbortOnUncaughtExceptionCallback)(Isolate*); + void SetAbortOnUncaughtExceptionCallback( + AbortOnUncaughtExceptionCallback callback); + /** * Methods below this point require holding a lock (using Locker) in * a multi-threaded environment. diff --git a/deps/v8/src/accessors.cc b/deps/v8/src/accessors.cc index dfaa9388457e52..c5fcca882d3b90 100644 --- a/deps/v8/src/accessors.cc +++ b/deps/v8/src/accessors.cc @@ -99,22 +99,37 @@ bool Accessors::IsJSArrayBufferViewFieldAccessor(Handle map, Isolate* isolate = name->GetIsolate(); switch (map->instance_type()) { - case JS_TYPED_ARRAY_TYPE: - // %TypedArray%.prototype is non-configurable, and so are the following - // named properties on %TypedArray%.prototype, so we can directly inline - // the field-load for typed array maps that still use their - // %TypedArray%.prototype. - if (JSFunction::cast(map->GetConstructor())->prototype() != - map->prototype()) { + case JS_TYPED_ARRAY_TYPE: { + if (!CheckForName(name, isolate->factory()->length_string(), + JSTypedArray::kLengthOffset, object_offset) && + !CheckForName(name, isolate->factory()->byte_length_string(), + JSTypedArray::kByteLengthOffset, object_offset) && + !CheckForName(name, isolate->factory()->byte_offset_string(), + JSTypedArray::kByteOffsetOffset, object_offset)) { return false; } - return CheckForName(name, isolate->factory()->length_string(), - JSTypedArray::kLengthOffset, object_offset) || - CheckForName(name, isolate->factory()->byte_length_string(), - JSTypedArray::kByteLengthOffset, object_offset) || - CheckForName(name, isolate->factory()->byte_offset_string(), - JSTypedArray::kByteOffsetOffset, object_offset); + if (map->is_dictionary_map()) return false; + + // Check if the property is overridden on the instance. + DescriptorArray* descriptors = map->instance_descriptors(); + int descriptor = descriptors->SearchWithCache(*name, *map); + if (descriptor != DescriptorArray::kNotFound) return false; + + Handle proto = Handle(map->prototype(), isolate); + if (!proto->IsJSReceiver()) return false; + + // Check if the property is defined in the prototype chain. + LookupIterator it(proto, name); + if (!it.IsFound()) return false; + + Object* original_proto = + JSFunction::cast(map->GetConstructor())->prototype(); + + // Property is not configurable. It is enough to verify that + // the holder is the same. + return *it.GetHolder() == original_proto; + } case JS_DATA_VIEW_TYPE: return CheckForName(name, isolate->factory()->byte_length_string(), JSDataView::kByteLengthOffset, object_offset) || diff --git a/deps/v8/src/api.cc b/deps/v8/src/api.cc index fc88c5c2036536..a2feebea45545b 100644 --- a/deps/v8/src/api.cc +++ b/deps/v8/src/api.cc @@ -7160,6 +7160,13 @@ void Isolate::Exit() { } +void Isolate::SetAbortOnUncaughtExceptionCallback( + AbortOnUncaughtExceptionCallback callback) { + i::Isolate* isolate = reinterpret_cast(this); + isolate->SetAbortOnUncaughtExceptionCallback(callback); +} + + Isolate::DisallowJavascriptExecutionScope::DisallowJavascriptExecutionScope( Isolate* isolate, Isolate::DisallowJavascriptExecutionScope::OnFailure on_failure) diff --git a/deps/v8/src/isolate.cc b/deps/v8/src/isolate.cc index 155e9ead0870a7..f63d423fa741c4 100644 --- a/deps/v8/src/isolate.cc +++ b/deps/v8/src/isolate.cc @@ -1013,13 +1013,21 @@ Object* Isolate::Throw(Object* exception, MessageLocation* location) { Handle message_obj = CreateMessage(exception_handle, location); thread_local_top()->pending_message_obj_ = *message_obj; - // If the abort-on-uncaught-exception flag is specified, abort on any - // exception not caught by JavaScript, even when an external handler is - // present. This flag is intended for use by JavaScript developers, so - // print a user-friendly stack trace (not an internal one). + // For any exception not caught by JavaScript, even when an external + // handler is present: + // If the abort-on-uncaught-exception flag is specified, and if the + // embedder didn't specify a custom uncaught exception callback, + // or if the custom callback determined that V8 should abort, then + // abort. if (FLAG_abort_on_uncaught_exception && - PredictExceptionCatcher() != CAUGHT_BY_JAVASCRIPT) { - FLAG_abort_on_uncaught_exception = false; // Prevent endless recursion. + PredictExceptionCatcher() != CAUGHT_BY_JAVASCRIPT && + (!abort_on_uncaught_exception_callback_ || + abort_on_uncaught_exception_callback_( + reinterpret_cast(this)))) { + // Prevent endless recursion. + FLAG_abort_on_uncaught_exception = false; + // This flag is intended for use by JavaScript developers, so + // print a user-friendly stack trace (not an internal one). PrintF(stderr, "%s\n\nFROM\n", MessageHandler::GetLocalizedMessage(this, message_obj).get()); PrintCurrentStackTrace(stderr); @@ -1607,6 +1615,12 @@ void Isolate::SetCaptureStackTraceForUncaughtExceptions( } +void Isolate::SetAbortOnUncaughtExceptionCallback( + v8::Isolate::AbortOnUncaughtExceptionCallback callback) { + abort_on_uncaught_exception_callback_ = callback; +} + + Handle Isolate::native_context() { return handle(context()->native_context()); } @@ -1774,7 +1788,8 @@ Isolate::Isolate(bool enable_serializer) next_unique_sfi_id_(0), #endif use_counter_callback_(NULL), - basic_block_profiler_(NULL) { + basic_block_profiler_(NULL), + abort_on_uncaught_exception_callback_(NULL) { { base::LockGuard lock_guard(thread_data_table_mutex_.Pointer()); CHECK(thread_data_table_); diff --git a/deps/v8/src/isolate.h b/deps/v8/src/isolate.h index 3cc4bacfdec70f..97c23bd99ac200 100644 --- a/deps/v8/src/isolate.h +++ b/deps/v8/src/isolate.h @@ -698,6 +698,9 @@ class Isolate { int frame_limit, StackTrace::StackTraceOptions options); + void SetAbortOnUncaughtExceptionCallback( + v8::Isolate::AbortOnUncaughtExceptionCallback callback); + enum PrintStackMode { kPrintStackConcise, kPrintStackVerbose }; void PrintCurrentStackTrace(FILE* out); void PrintStack(StringStream* accumulator, @@ -1366,6 +1369,9 @@ class Isolate { std::set cancelable_tasks_; + v8::Isolate::AbortOnUncaughtExceptionCallback + abort_on_uncaught_exception_callback_; + friend class ExecutionAccess; friend class HandleScopeImplementer; friend class OptimizingCompileDispatcher; diff --git a/deps/v8/src/objects.h b/deps/v8/src/objects.h index 8ca9428710935f..3a9e7e0c767db3 100644 --- a/deps/v8/src/objects.h +++ b/deps/v8/src/objects.h @@ -3932,7 +3932,6 @@ class ScopeInfo : public FixedArray { FOR_EACH_SCOPE_INFO_NUMERIC_FIELD(FIELD_ACCESSORS) #undef FIELD_ACCESSORS - private: enum { #define DECL_INDEX(name) k##name, FOR_EACH_SCOPE_INFO_NUMERIC_FIELD(DECL_INDEX) @@ -3940,6 +3939,7 @@ class ScopeInfo : public FixedArray { kVariablePartIndex }; + private: // The layout of the variable part of a ScopeInfo is as follows: // 1. ParameterEntries: // This part stores the names of the parameters for function scopes. One diff --git a/deps/v8/test/cctest/test-api.cc b/deps/v8/test/cctest/test-api.cc index dad5d6caf5ca1e..3d5915e5a0c4b5 100644 --- a/deps/v8/test/cctest/test-api.cc +++ b/deps/v8/test/cctest/test-api.cc @@ -21826,4 +21826,34 @@ TEST(EstimatedContextSize) { v8::HandleScope scope(isolate); LocalContext env; CHECK(50000 < env->EstimatedSize()); + + +static int nb_uncaught_exception_callback_calls = 0; + + +bool NoAbortOnUncaughtException(v8::Isolate* isolate) { + ++nb_uncaught_exception_callback_calls; + return false; +} + + +TEST(AbortOnUncaughtExceptionNoAbort) { + v8::Isolate* isolate = CcTest::isolate(); + v8::HandleScope handle_scope(isolate); + v8::Handle global_template = + v8::ObjectTemplate::New(isolate); + LocalContext env(NULL, global_template); + + i::FLAG_abort_on_uncaught_exception = true; + isolate->SetAbortOnUncaughtExceptionCallback(NoAbortOnUncaughtException); + + CompileRun("function boom() { throw new Error(\"boom\") }"); + + v8::Local global_object = env->Global(); + v8::Local foo = + v8::Local::Cast(global_object->Get(v8_str("boom"))); + + foo->Call(global_object, 0, NULL); + + CHECK_EQ(1, nb_uncaught_exception_callback_calls); } diff --git a/deps/v8/test/mjsunit/regress/regress-typedarray-length.js b/deps/v8/test/mjsunit/regress/regress-typedarray-length.js index cae55731f921ce..ee853647355215 100644 --- a/deps/v8/test/mjsunit/regress/regress-typedarray-length.js +++ b/deps/v8/test/mjsunit/regress/regress-typedarray-length.js @@ -71,6 +71,43 @@ assertEquals(undefined, get(a)); assertEquals(undefined, get(a)); })(); +(function() { + "use strict"; + + class MyTypedArray extends Int32Array { + constructor(length) { + super(length); + } + } + + a = new MyTypedArray(1024); + + get = function(a) { + return a.length; + } + + assertEquals(1024, get(a)); + assertEquals(1024, get(a)); + assertEquals(1024, get(a)); + %OptimizeFunctionOnNextCall(get); + assertEquals(1024, get(a)); +})(); + +(function() { + "use strict"; + var a = new Uint8Array(4); + Object.defineProperty(a, "length", {get: function() { return "blah"; }}); + get = function(a) { + return a.length; + } + + assertEquals("blah", get(a)); + assertEquals("blah", get(a)); + assertEquals("blah", get(a)); + %OptimizeFunctionOnNextCall(get); + assertEquals("blah", get(a)); +})(); + // Ensure we cannot delete length, byteOffset, byteLength. assertTrue(Int32Array.prototype.hasOwnProperty("length")); assertTrue(Int32Array.prototype.hasOwnProperty("byteOffset")); diff --git a/deps/v8/tools/gen-postmortem-metadata.py b/deps/v8/tools/gen-postmortem-metadata.py index 29416cebd2be5e..49eb9039b88b25 100644 --- a/deps/v8/tools/gen-postmortem-metadata.py +++ b/deps/v8/tools/gen-postmortem-metadata.py @@ -132,6 +132,15 @@ 'value': 'JavaScriptFrameConstants::kFunctionOffset' }, { 'name': 'off_fp_args', 'value': 'JavaScriptFrameConstants::kLastParameterOffset' }, + + { 'name': 'scopeinfo_idx_nparams', + 'value': 'ScopeInfo::kParameterCount' }, + { 'name': 'scopeinfo_idx_nstacklocals', + 'value': 'ScopeInfo::kStackLocalCount' }, + { 'name': 'scopeinfo_idx_ncontextlocals', + 'value': 'ScopeInfo::kContextLocalCount' }, + { 'name': 'scopeinfo_idx_first_vars', + 'value': 'ScopeInfo::kVariablePartIndex' }, ]; # @@ -141,12 +150,13 @@ 'HeapObject, map, Map, kMapOffset', 'JSObject, elements, Object, kElementsOffset', 'FixedArray, data, uintptr_t, kHeaderSize', + 'JSTypedArray, length, Object, kLengthOffset', 'Map, instance_attributes, int, kInstanceAttributesOffset', 'Map, inobject_properties_of_constructor_function_index_offset, int, kInObjectPropertiesOrConstructorFunctionIndexOffset', 'Map, instance_size, int, kInstanceSizeOffset', 'Map, bit_field, char, kBitFieldOffset', 'Map, bit_field2, char, kBitField2Offset', - 'Map, bit_field3, SMI, kBitField3Offset', + 'Map, bit_field3, int, kBitField3Offset', 'Map, prototype, Object, kPrototypeOffset', 'NameDictionaryShape, prefix_size, int, kPrefixSize', 'NameDictionaryShape, entry_size, int, kEntrySize',