diff --git a/deps/v8/include/v8-version.h b/deps/v8/include/v8-version.h index 56ef22b0e609ea..98dca238c85605 100644 --- a/deps/v8/include/v8-version.h +++ b/deps/v8/include/v8-version.h @@ -11,7 +11,7 @@ #define V8_MAJOR_VERSION 4 #define V8_MINOR_VERSION 5 #define V8_BUILD_NUMBER 103 -#define V8_PATCH_LEVEL 33 +#define V8_PATCH_LEVEL 35 // Use 1 for candidates and 0 otherwise. // (Boolean macro values are not supported by all preprocessors.) diff --git a/deps/v8/src/messages.h b/deps/v8/src/messages.h index 4072300bf6a0a4..5c3e867933ce44 100644 --- a/deps/v8/src/messages.h +++ b/deps/v8/src/messages.h @@ -173,6 +173,7 @@ class CallSite { T(ObserveCallbackFrozen, \ "Object.observe cannot deliver to a frozen function object") \ T(ObserveGlobalProxy, "% cannot be called on the global proxy object") \ + T(ObserveAccessChecked, "% cannot be called on access-checked objects") \ T(ObserveInvalidAccept, \ "Third argument to Object.observe must be an array of strings.") \ T(ObserveNonFunction, "Object.% cannot deliver to non-function") \ diff --git a/deps/v8/src/object-observe.js b/deps/v8/src/object-observe.js index 56859a1c97ba9f..9c49fd38fb6093 100644 --- a/deps/v8/src/object-observe.js +++ b/deps/v8/src/object-observe.js @@ -389,6 +389,8 @@ function ObjectObserve(object, callback, acceptList) { throw MakeTypeError(kObserveNonObject, "observe", "observe"); if (%IsJSGlobalProxy(object)) throw MakeTypeError(kObserveGlobalProxy, "observe"); + if (%IsAccessCheckNeeded(object)) + throw MakeTypeError(kObserveAccessChecked, "observe"); if (!IS_SPEC_FUNCTION(callback)) throw MakeTypeError(kObserveNonFunction, "observe"); if (ObjectIsFrozen(callback)) @@ -617,6 +619,8 @@ function ObjectGetNotifier(object) { throw MakeTypeError(kObserveNonObject, "getNotifier", "getNotifier"); if (%IsJSGlobalProxy(object)) throw MakeTypeError(kObserveGlobalProxy, "getNotifier"); + if (%IsAccessCheckNeeded(object)) + throw MakeTypeError(kObserveAccessChecked, "getNotifier"); if (ObjectIsFrozen(object)) return null; diff --git a/deps/v8/src/runtime/runtime-object.cc b/deps/v8/src/runtime/runtime-object.cc index da1ec4977be36f..9536ec0cc405c3 100644 --- a/deps/v8/src/runtime/runtime-object.cc +++ b/deps/v8/src/runtime/runtime-object.cc @@ -1435,5 +1435,13 @@ RUNTIME_FUNCTION(Runtime_DefineSetterPropertyUnchecked) { setter, attrs)); return isolate->heap()->undefined_value(); } + + +RUNTIME_FUNCTION(Runtime_IsAccessCheckNeeded) { + SealHandleScope shs(isolate); + DCHECK_EQ(1, args.length()); + CONVERT_ARG_CHECKED(Object, object, 0); + return isolate->heap()->ToBoolean(object->IsAccessCheckNeeded()); +} } // namespace internal } // namespace v8 diff --git a/deps/v8/src/runtime/runtime.h b/deps/v8/src/runtime/runtime.h index da1ae40ba068cb..c4f74e7de11369 100644 --- a/deps/v8/src/runtime/runtime.h +++ b/deps/v8/src/runtime/runtime.h @@ -483,7 +483,8 @@ namespace internal { F(IsStrong, 1, 1) \ F(ClassOf, 1, 1) \ F(DefineGetterPropertyUnchecked, 4, 1) \ - F(DefineSetterPropertyUnchecked, 4, 1) + F(DefineSetterPropertyUnchecked, 4, 1) \ + F(IsAccessCheckNeeded, 1, 1) #define FOR_EACH_INTRINSIC_OBSERVE(F) \ diff --git a/deps/v8/src/scanner-character-streams.cc b/deps/v8/src/scanner-character-streams.cc index 442bc75d6cc969..eaaa9bc1f72b7f 100644 --- a/deps/v8/src/scanner-character-streams.cc +++ b/deps/v8/src/scanner-character-streams.cc @@ -346,6 +346,7 @@ size_t ExternalStreamingStream::FillBuffer(size_t position) { current_data_length_ = source_stream_->GetMoreData(¤t_data_); current_data_offset_ = 0; bool data_ends = current_data_length_ == 0; + bookmark_data_is_from_current_data_ = false; // A caveat: a data chunk might end with bytes from an incomplete UTF-8 // character (the rest of the bytes will be in the next chunk). @@ -405,6 +406,15 @@ bool ExternalStreamingStream::SetBookmark() { // - buffer_[buffer_cursor_ .. buffer_end_] => bookmark_buffer_ // - current_data_[.._offset_ .. .._length_] => bookmark_data_ // - utf8_split_char_buffer_* => bookmark_utf8_split... + // + // To make sure we don't unnecessarily copy data, we also maintain + // whether bookmark_data_ contains a copy of the current current_data_ + // block. This is done with: + // - bookmark_data_is_from_current_data_ + // - bookmark_data_offset_: offset into bookmark_data_ + // + // Note that bookmark_data_is_from_current_data_ must be maintained + // whenever current_data_ is updated. bookmark_ = pos_; @@ -414,10 +424,21 @@ bool ExternalStreamingStream::SetBookmark() { CopyCharsUnsigned(bookmark_buffer_.start(), buffer_cursor_, buffer_length); size_t data_length = current_data_length_ - current_data_offset_; - bookmark_data_.Dispose(); - bookmark_data_ = Vector::New(static_cast(data_length)); - CopyBytes(bookmark_data_.start(), current_data_ + current_data_offset_, - data_length); + size_t bookmark_data_length = static_cast(bookmark_data_.length()); + if (bookmark_data_is_from_current_data_ && + data_length < bookmark_data_length) { + // Fast case: bookmark_data_ was previously copied from the current + // data block, and we have enough data for this bookmark. + bookmark_data_offset_ = bookmark_data_length - data_length; + } else { + // Slow case: We need to copy current_data_. + bookmark_data_.Dispose(); + bookmark_data_ = Vector::New(static_cast(data_length)); + CopyBytes(bookmark_data_.start(), current_data_ + current_data_offset_, + data_length); + bookmark_data_is_from_current_data_ = true; + bookmark_data_offset_ = 0; + } bookmark_utf8_split_char_buffer_length_ = utf8_split_char_buffer_length_; for (size_t i = 0; i < utf8_split_char_buffer_length_; i++) { @@ -436,12 +457,14 @@ void ExternalStreamingStream::ResetToBookmark() { // bookmark_data_* => current_data_* // (current_data_ assumes ownership of its memory.) - uint8_t* data = new uint8_t[bookmark_data_.length()]; current_data_offset_ = 0; - current_data_length_ = bookmark_data_.length(); - CopyCharsUnsigned(data, bookmark_data_.begin(), bookmark_data_.length()); + current_data_length_ = bookmark_data_.length() - bookmark_data_offset_; + uint8_t* data = new uint8_t[current_data_length_]; + CopyCharsUnsigned(data, bookmark_data_.begin() + bookmark_data_offset_, + current_data_length_); delete[] current_data_; current_data_ = data; + bookmark_data_is_from_current_data_ = true; // bookmark_buffer_ needs to be copied to buffer_. CopyCharsUnsigned(buffer_, bookmark_buffer_.begin(), @@ -462,6 +485,7 @@ void ExternalStreamingStream::FlushCurrent() { current_data_ = NULL; current_data_length_ = 0; current_data_offset_ = 0; + bookmark_data_is_from_current_data_ = false; } diff --git a/deps/v8/src/scanner-character-streams.h b/deps/v8/src/scanner-character-streams.h index 582165710db84c..f3ee20463afe91 100644 --- a/deps/v8/src/scanner-character-streams.h +++ b/deps/v8/src/scanner-character-streams.h @@ -94,6 +94,8 @@ class ExternalStreamingStream : public BufferedUtf16CharacterStream { current_data_length_(0), utf8_split_char_buffer_length_(0), bookmark_(0), + bookmark_data_is_from_current_data_(false), + bookmark_data_offset_(0), bookmark_utf8_split_char_buffer_length_(0) {} virtual ~ExternalStreamingStream() { @@ -134,6 +136,8 @@ class ExternalStreamingStream : public BufferedUtf16CharacterStream { size_t bookmark_; Vector bookmark_buffer_; Vector bookmark_data_; + bool bookmark_data_is_from_current_data_; + size_t bookmark_data_offset_; uint8_t bookmark_utf8_split_char_buffer_[4]; size_t bookmark_utf8_split_char_buffer_length_; }; diff --git a/deps/v8/test/cctest/test-object-observe.cc b/deps/v8/test/cctest/test-object-observe.cc index abbf2b7a6c0049..0295de5e233cae 100644 --- a/deps/v8/test/cctest/test-object-observe.cc +++ b/deps/v8/test/cctest/test-object-observe.cc @@ -885,3 +885,39 @@ TEST(UseCountObjectGetNotifier) { CompileRun("Object.getNotifier(obj)"); CHECK_EQ(1, use_counts[v8::Isolate::kObjectObserve]); } + + +static bool NamedAccessCheckAlwaysAllow(Local global, + Local name, + v8::AccessType type, + Local data) { + return true; +} + + +TEST(DisallowObserveAccessCheckedObject) { + v8::Isolate* isolate = CcTest::isolate(); + v8::HandleScope scope(isolate); + LocalContext env; + v8::Local object_template = + v8::ObjectTemplate::New(isolate); + object_template->SetAccessCheckCallbacks(NamedAccessCheckAlwaysAllow, NULL); + env->Global()->Set(v8_str("obj"), object_template->NewInstance()); + v8::TryCatch try_catch(isolate); + CompileRun("Object.observe(obj, function(){})"); + CHECK(try_catch.HasCaught()); +} + + +TEST(DisallowGetNotifierAccessCheckedObject) { + v8::Isolate* isolate = CcTest::isolate(); + v8::HandleScope scope(isolate); + LocalContext env; + v8::Local object_template = + v8::ObjectTemplate::New(isolate); + object_template->SetAccessCheckCallbacks(NamedAccessCheckAlwaysAllow, NULL); + env->Global()->Set(v8_str("obj"), object_template->NewInstance()); + v8::TryCatch try_catch(isolate); + CompileRun("Object.getNotifier(obj)"); + CHECK(try_catch.HasCaught()); +}