OLD | NEW |
1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/objects.h" | 5 #include "src/objects.h" |
6 | 6 |
7 #include <cmath> | 7 #include <cmath> |
8 #include <iomanip> | 8 #include <iomanip> |
9 #include <sstream> | 9 #include <sstream> |
10 | 10 |
(...skipping 2603 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2614 } else { | 2614 } else { |
2615 Handle<NameDictionary> dict(object->property_dictionary()); | 2615 Handle<NameDictionary> dict(object->property_dictionary()); |
2616 PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell); | 2616 PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell); |
2617 Handle<NameDictionary> result = | 2617 Handle<NameDictionary> result = |
2618 NameDictionary::Add(dict, name, value, details); | 2618 NameDictionary::Add(dict, name, value, details); |
2619 if (*dict != *result) object->set_properties(*result); | 2619 if (*dict != *result) object->set_properties(*result); |
2620 } | 2620 } |
2621 } | 2621 } |
2622 | 2622 |
2623 | 2623 |
2624 MaybeHandle<Object> JSObject::EnqueueChangeRecord(Handle<JSObject> object, | |
2625 const char* type_str, | |
2626 Handle<Name> name, | |
2627 Handle<Object> old_value) { | |
2628 DCHECK(!object->IsJSGlobalProxy()); | |
2629 DCHECK(!object->IsJSGlobalObject()); | |
2630 Isolate* isolate = object->GetIsolate(); | |
2631 HandleScope scope(isolate); | |
2632 Handle<String> type = isolate->factory()->InternalizeUtf8String(type_str); | |
2633 Handle<Object> args[] = { type, object, name, old_value }; | |
2634 int argc = name.is_null() ? 2 : old_value->IsTheHole() ? 3 : 4; | |
2635 | |
2636 return Execution::Call(isolate, | |
2637 Handle<JSFunction>(isolate->observers_notify_change()), | |
2638 isolate->factory()->undefined_value(), argc, args); | |
2639 } | |
2640 | |
2641 | |
2642 const char* Representation::Mnemonic() const { | 2624 const char* Representation::Mnemonic() const { |
2643 switch (kind_) { | 2625 switch (kind_) { |
2644 case kNone: return "v"; | 2626 case kNone: return "v"; |
2645 case kTagged: return "t"; | 2627 case kTagged: return "t"; |
2646 case kSmi: return "s"; | 2628 case kSmi: return "s"; |
2647 case kDouble: return "d"; | 2629 case kDouble: return "d"; |
2648 case kInteger32: return "i"; | 2630 case kInteger32: return "i"; |
2649 case kHeapObject: return "h"; | 2631 case kHeapObject: return "h"; |
2650 case kExternal: return "x"; | 2632 case kExternal: return "x"; |
2651 default: | 2633 default: |
(...skipping 1731 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4383 | 4365 |
4384 | 4366 |
4385 Maybe<bool> Object::SetDataProperty(LookupIterator* it, Handle<Object> value) { | 4367 Maybe<bool> Object::SetDataProperty(LookupIterator* it, Handle<Object> value) { |
4386 // Proxies are handled elsewhere. Other non-JSObjects cannot have own | 4368 // Proxies are handled elsewhere. Other non-JSObjects cannot have own |
4387 // properties. | 4369 // properties. |
4388 Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver()); | 4370 Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver()); |
4389 | 4371 |
4390 // Store on the holder which may be hidden behind the receiver. | 4372 // Store on the holder which may be hidden behind the receiver. |
4391 DCHECK(it->HolderIsReceiverOrHiddenPrototype()); | 4373 DCHECK(it->HolderIsReceiverOrHiddenPrototype()); |
4392 | 4374 |
4393 // Old value for the observation change record. | |
4394 // Fetch before transforming the object since the encoding may become | |
4395 // incompatible with what's cached in |it|. | |
4396 bool is_observed = receiver->map()->is_observed() && | |
4397 (it->IsElement() || !it->name()->IsPrivate()); | |
4398 MaybeHandle<Object> maybe_old; | |
4399 if (is_observed) maybe_old = it->GetDataValue(); | |
4400 | |
4401 Handle<Object> to_assign = value; | 4375 Handle<Object> to_assign = value; |
4402 // Convert the incoming value to a number for storing into typed arrays. | 4376 // Convert the incoming value to a number for storing into typed arrays. |
4403 if (it->IsElement() && receiver->HasFixedTypedArrayElements()) { | 4377 if (it->IsElement() && receiver->HasFixedTypedArrayElements()) { |
4404 if (!value->IsNumber() && !value->IsUndefined()) { | 4378 if (!value->IsNumber() && !value->IsUndefined()) { |
4405 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | 4379 ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
4406 it->isolate(), to_assign, Object::ToNumber(value), Nothing<bool>()); | 4380 it->isolate(), to_assign, Object::ToNumber(value), Nothing<bool>()); |
4407 // We have to recheck the length. However, it can only change if the | 4381 // We have to recheck the length. However, it can only change if the |
4408 // underlying buffer was neutered, so just check that. | 4382 // underlying buffer was neutered, so just check that. |
4409 if (Handle<JSArrayBufferView>::cast(receiver)->WasNeutered()) { | 4383 if (Handle<JSArrayBufferView>::cast(receiver)->WasNeutered()) { |
4410 return Just(true); | 4384 return Just(true); |
4411 // TODO(neis): According to the spec, this should throw a TypeError. | 4385 // TODO(neis): According to the spec, this should throw a TypeError. |
4412 } | 4386 } |
4413 } | 4387 } |
4414 } | 4388 } |
4415 | 4389 |
4416 // Possibly migrate to the most up-to-date map that will be able to store | 4390 // Possibly migrate to the most up-to-date map that will be able to store |
4417 // |value| under it->name(). | 4391 // |value| under it->name(). |
4418 it->PrepareForDataProperty(to_assign); | 4392 it->PrepareForDataProperty(to_assign); |
4419 | 4393 |
4420 // Write the property value. | 4394 // Write the property value. |
4421 it->WriteDataValue(to_assign); | 4395 it->WriteDataValue(to_assign); |
4422 | 4396 |
4423 // Send the change record if there are observers. | |
4424 if (is_observed && !value->SameValue(*maybe_old.ToHandleChecked())) { | |
4425 RETURN_ON_EXCEPTION_VALUE( | |
4426 it->isolate(), | |
4427 JSObject::EnqueueChangeRecord(receiver, "update", it->GetName(), | |
4428 maybe_old.ToHandleChecked()), | |
4429 Nothing<bool>()); | |
4430 } | |
4431 | |
4432 #if VERIFY_HEAP | 4397 #if VERIFY_HEAP |
4433 if (FLAG_verify_heap) { | 4398 if (FLAG_verify_heap) { |
4434 receiver->JSObjectVerify(); | 4399 receiver->JSObjectVerify(); |
4435 } | 4400 } |
4436 #endif | 4401 #endif |
4437 return Just(true); | 4402 return Just(true); |
4438 } | 4403 } |
4439 | 4404 |
4440 | 4405 |
4441 MUST_USE_RESULT static MaybeHandle<Object> BeginPerformSplice( | |
4442 Handle<JSArray> object) { | |
4443 Isolate* isolate = object->GetIsolate(); | |
4444 HandleScope scope(isolate); | |
4445 Handle<Object> args[] = {object}; | |
4446 | |
4447 return Execution::Call( | |
4448 isolate, Handle<JSFunction>(isolate->observers_begin_perform_splice()), | |
4449 isolate->factory()->undefined_value(), arraysize(args), args); | |
4450 } | |
4451 | |
4452 | |
4453 MUST_USE_RESULT static MaybeHandle<Object> EndPerformSplice( | |
4454 Handle<JSArray> object) { | |
4455 Isolate* isolate = object->GetIsolate(); | |
4456 HandleScope scope(isolate); | |
4457 Handle<Object> args[] = {object}; | |
4458 | |
4459 return Execution::Call( | |
4460 isolate, Handle<JSFunction>(isolate->observers_end_perform_splice()), | |
4461 isolate->factory()->undefined_value(), arraysize(args), args); | |
4462 } | |
4463 | |
4464 | |
4465 MUST_USE_RESULT static MaybeHandle<Object> EnqueueSpliceRecord( | |
4466 Handle<JSArray> object, uint32_t index, Handle<JSArray> deleted, | |
4467 uint32_t add_count) { | |
4468 Isolate* isolate = object->GetIsolate(); | |
4469 HandleScope scope(isolate); | |
4470 Handle<Object> index_object = isolate->factory()->NewNumberFromUint(index); | |
4471 Handle<Object> add_count_object = | |
4472 isolate->factory()->NewNumberFromUint(add_count); | |
4473 | |
4474 Handle<Object> args[] = {object, index_object, deleted, add_count_object}; | |
4475 | |
4476 return Execution::Call( | |
4477 isolate, Handle<JSFunction>(isolate->observers_enqueue_splice()), | |
4478 isolate->factory()->undefined_value(), arraysize(args), args); | |
4479 } | |
4480 | |
4481 | |
4482 Maybe<bool> Object::AddDataProperty(LookupIterator* it, Handle<Object> value, | 4406 Maybe<bool> Object::AddDataProperty(LookupIterator* it, Handle<Object> value, |
4483 PropertyAttributes attributes, | 4407 PropertyAttributes attributes, |
4484 ShouldThrow should_throw, | 4408 ShouldThrow should_throw, |
4485 StoreFromKeyed store_mode) { | 4409 StoreFromKeyed store_mode) { |
4486 if (!it->GetReceiver()->IsJSObject()) { | 4410 if (!it->GetReceiver()->IsJSObject()) { |
4487 if (it->GetReceiver()->IsJSProxy() && it->GetName()->IsPrivate()) { | 4411 if (it->GetReceiver()->IsJSProxy() && it->GetName()->IsPrivate()) { |
4488 RETURN_FAILURE(it->isolate(), should_throw, | 4412 RETURN_FAILURE(it->isolate(), should_throw, |
4489 NewTypeError(MessageTemplate::kProxyPrivate)); | 4413 NewTypeError(MessageTemplate::kProxyPrivate)); |
4490 } | 4414 } |
4491 return CannotCreateProperty(it->isolate(), it->GetReceiver(), it->GetName(), | 4415 return CannotCreateProperty(it->isolate(), it->GetReceiver(), it->GetName(), |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4542 | 4466 |
4543 // TODO(verwaest): Encapsulate dictionary handling better. | 4467 // TODO(verwaest): Encapsulate dictionary handling better. |
4544 if (receiver->map()->is_dictionary_map()) { | 4468 if (receiver->map()->is_dictionary_map()) { |
4545 // TODO(dcarney): just populate TransitionPropertyCell here? | 4469 // TODO(dcarney): just populate TransitionPropertyCell here? |
4546 JSObject::AddSlowProperty(receiver, it->name(), value, attributes); | 4470 JSObject::AddSlowProperty(receiver, it->name(), value, attributes); |
4547 } else { | 4471 } else { |
4548 // Write the property value. | 4472 // Write the property value. |
4549 it->WriteDataValue(value); | 4473 it->WriteDataValue(value); |
4550 } | 4474 } |
4551 | 4475 |
4552 // Send the change record if there are observers. | |
4553 if (receiver->map()->is_observed() && !it->name()->IsPrivate()) { | |
4554 RETURN_ON_EXCEPTION_VALUE(isolate, JSObject::EnqueueChangeRecord( | |
4555 receiver, "add", it->name(), | |
4556 it->factory()->the_hole_value()), | |
4557 Nothing<bool>()); | |
4558 } | |
4559 #if VERIFY_HEAP | 4476 #if VERIFY_HEAP |
4560 if (FLAG_verify_heap) { | 4477 if (FLAG_verify_heap) { |
4561 receiver->JSObjectVerify(); | 4478 receiver->JSObjectVerify(); |
4562 } | 4479 } |
4563 #endif | 4480 #endif |
4564 } | 4481 } |
4565 | 4482 |
4566 return Just(true); | 4483 return Just(true); |
4567 } | 4484 } |
4568 | 4485 |
(...skipping 735 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5304 it, value, attributes, THROW_ON_ERROR, handling)); | 5221 it, value, attributes, THROW_ON_ERROR, handling)); |
5305 return value; | 5222 return value; |
5306 } | 5223 } |
5307 | 5224 |
5308 | 5225 |
5309 Maybe<bool> JSObject::DefineOwnPropertyIgnoreAttributes( | 5226 Maybe<bool> JSObject::DefineOwnPropertyIgnoreAttributes( |
5310 LookupIterator* it, Handle<Object> value, PropertyAttributes attributes, | 5227 LookupIterator* it, Handle<Object> value, PropertyAttributes attributes, |
5311 ShouldThrow should_throw, AccessorInfoHandling handling) { | 5228 ShouldThrow should_throw, AccessorInfoHandling handling) { |
5312 it->UpdateProtector(); | 5229 it->UpdateProtector(); |
5313 Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver()); | 5230 Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver()); |
5314 bool is_observed = object->map()->is_observed() && | |
5315 (it->IsElement() || !it->name()->IsPrivate()); | |
5316 | 5231 |
5317 for (; it->IsFound(); it->Next()) { | 5232 for (; it->IsFound(); it->Next()) { |
5318 switch (it->state()) { | 5233 switch (it->state()) { |
5319 case LookupIterator::JSPROXY: | 5234 case LookupIterator::JSPROXY: |
5320 case LookupIterator::NOT_FOUND: | 5235 case LookupIterator::NOT_FOUND: |
5321 case LookupIterator::TRANSITION: | 5236 case LookupIterator::TRANSITION: |
5322 UNREACHABLE(); | 5237 UNREACHABLE(); |
5323 | 5238 |
5324 case LookupIterator::ACCESS_CHECK: | 5239 case LookupIterator::ACCESS_CHECK: |
5325 if (!it->HasAccess()) { | 5240 if (!it->HasAccess()) { |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5365 JSObject::SetPropertyWithAccessor(it, value, should_throw); | 5280 JSObject::SetPropertyWithAccessor(it, value, should_throw); |
5366 | 5281 |
5367 if (current_attributes == attributes || result.IsNothing()) { | 5282 if (current_attributes == attributes || result.IsNothing()) { |
5368 return result; | 5283 return result; |
5369 } | 5284 } |
5370 | 5285 |
5371 } else { | 5286 } else { |
5372 it->ReconfigureDataProperty(value, attributes); | 5287 it->ReconfigureDataProperty(value, attributes); |
5373 } | 5288 } |
5374 | 5289 |
5375 if (is_observed) { | |
5376 RETURN_ON_EXCEPTION_VALUE( | |
5377 it->isolate(), | |
5378 EnqueueChangeRecord(object, "reconfigure", it->GetName(), | |
5379 it->factory()->the_hole_value()), | |
5380 Nothing<bool>()); | |
5381 } | |
5382 | |
5383 return Just(true); | 5290 return Just(true); |
5384 } | 5291 } |
5385 case LookupIterator::INTEGER_INDEXED_EXOTIC: | 5292 case LookupIterator::INTEGER_INDEXED_EXOTIC: |
5386 return RedefineIncompatibleProperty(it->isolate(), it->GetName(), value, | 5293 return RedefineIncompatibleProperty(it->isolate(), it->GetName(), value, |
5387 should_throw); | 5294 should_throw); |
5388 | 5295 |
5389 case LookupIterator::DATA: { | 5296 case LookupIterator::DATA: { |
5390 // Regular property update if the attributes match. | 5297 // Regular property update if the attributes match. |
5391 if (it->property_attributes() == attributes) { | 5298 if (it->property_attributes() == attributes) { |
5392 return SetDataProperty(it, value); | 5299 return SetDataProperty(it, value); |
5393 } | 5300 } |
5394 | 5301 |
5395 // Special case: properties of typed arrays cannot be reconfigured to | 5302 // Special case: properties of typed arrays cannot be reconfigured to |
5396 // non-writable nor to non-enumerable. | 5303 // non-writable nor to non-enumerable. |
5397 if (it->IsElement() && object->HasFixedTypedArrayElements()) { | 5304 if (it->IsElement() && object->HasFixedTypedArrayElements()) { |
5398 return RedefineIncompatibleProperty(it->isolate(), it->GetName(), | 5305 return RedefineIncompatibleProperty(it->isolate(), it->GetName(), |
5399 value, should_throw); | 5306 value, should_throw); |
5400 } | 5307 } |
5401 | 5308 |
5402 // Reconfigure the data property if the attributes mismatch. | 5309 // Reconfigure the data property if the attributes mismatch. |
5403 Handle<Object> old_value = it->factory()->the_hole_value(); | |
5404 if (is_observed) old_value = it->GetDataValue(); | |
5405 | |
5406 it->ReconfigureDataProperty(value, attributes); | 5310 it->ReconfigureDataProperty(value, attributes); |
5407 | 5311 |
5408 if (is_observed) { | |
5409 if (old_value->SameValue(*value)) { | |
5410 old_value = it->factory()->the_hole_value(); | |
5411 } | |
5412 RETURN_ON_EXCEPTION_VALUE( | |
5413 it->isolate(), EnqueueChangeRecord(object, "reconfigure", | |
5414 it->GetName(), old_value), | |
5415 Nothing<bool>()); | |
5416 } | |
5417 return Just(true); | 5312 return Just(true); |
5418 } | 5313 } |
5419 } | 5314 } |
5420 } | 5315 } |
5421 | 5316 |
5422 return AddDataProperty(it, value, attributes, should_throw, | 5317 return AddDataProperty(it, value, attributes, should_throw, |
5423 CERTAINLY_NOT_STORE_FROM_KEYED); | 5318 CERTAINLY_NOT_STORE_FROM_KEYED); |
5424 } | 5319 } |
5425 | 5320 |
5426 MaybeHandle<Object> JSObject::SetOwnPropertyIgnoreAttributes( | 5321 MaybeHandle<Object> JSObject::SetOwnPropertyIgnoreAttributes( |
(...skipping 709 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6136 if (it->GetReceiver()->IsJSProxy()) { | 6031 if (it->GetReceiver()->IsJSProxy()) { |
6137 if (it->state() != LookupIterator::NOT_FOUND) { | 6032 if (it->state() != LookupIterator::NOT_FOUND) { |
6138 DCHECK_EQ(LookupIterator::DATA, it->state()); | 6033 DCHECK_EQ(LookupIterator::DATA, it->state()); |
6139 DCHECK(it->name()->IsPrivate()); | 6034 DCHECK(it->name()->IsPrivate()); |
6140 it->Delete(); | 6035 it->Delete(); |
6141 } | 6036 } |
6142 return Just(true); | 6037 return Just(true); |
6143 } | 6038 } |
6144 Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver()); | 6039 Handle<JSObject> receiver = Handle<JSObject>::cast(it->GetReceiver()); |
6145 | 6040 |
6146 bool is_observed = receiver->map()->is_observed() && | |
6147 (it->IsElement() || !it->name()->IsPrivate()); | |
6148 | |
6149 Handle<Object> old_value = it->factory()->the_hole_value(); | |
6150 | |
6151 for (; it->IsFound(); it->Next()) { | 6041 for (; it->IsFound(); it->Next()) { |
6152 switch (it->state()) { | 6042 switch (it->state()) { |
6153 case LookupIterator::JSPROXY: | 6043 case LookupIterator::JSPROXY: |
6154 case LookupIterator::NOT_FOUND: | 6044 case LookupIterator::NOT_FOUND: |
6155 case LookupIterator::TRANSITION: | 6045 case LookupIterator::TRANSITION: |
6156 UNREACHABLE(); | 6046 UNREACHABLE(); |
6157 case LookupIterator::ACCESS_CHECK: | 6047 case LookupIterator::ACCESS_CHECK: |
6158 if (it->HasAccess()) break; | 6048 if (it->HasAccess()) break; |
6159 isolate->ReportFailedAccessCheck(it->GetHolder<JSObject>()); | 6049 isolate->ReportFailedAccessCheck(it->GetHolder<JSObject>()); |
6160 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>()); | 6050 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>()); |
6161 return Just(false); | 6051 return Just(false); |
6162 case LookupIterator::INTERCEPTOR: { | 6052 case LookupIterator::INTERCEPTOR: { |
6163 ShouldThrow should_throw = | 6053 ShouldThrow should_throw = |
6164 is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR; | 6054 is_sloppy(language_mode) ? DONT_THROW : THROW_ON_ERROR; |
6165 Maybe<bool> result = | 6055 Maybe<bool> result = |
6166 JSObject::DeletePropertyWithInterceptor(it, should_throw); | 6056 JSObject::DeletePropertyWithInterceptor(it, should_throw); |
6167 // An exception was thrown in the interceptor. Propagate. | 6057 // An exception was thrown in the interceptor. Propagate. |
6168 if (isolate->has_pending_exception()) return Nothing<bool>(); | 6058 if (isolate->has_pending_exception()) return Nothing<bool>(); |
6169 // Delete with interceptor succeeded. Return result. | 6059 // Delete with interceptor succeeded. Return result. |
6170 // TODO(neis): In strict mode, we should probably throw if the | 6060 // TODO(neis): In strict mode, we should probably throw if the |
6171 // interceptor returns false. | 6061 // interceptor returns false. |
6172 if (result.IsJust()) return result; | 6062 if (result.IsJust()) return result; |
6173 break; | 6063 break; |
6174 } | 6064 } |
6175 case LookupIterator::INTEGER_INDEXED_EXOTIC: | 6065 case LookupIterator::INTEGER_INDEXED_EXOTIC: |
6176 return Just(true); | 6066 return Just(true); |
6177 case LookupIterator::DATA: | 6067 case LookupIterator::DATA: |
6178 if (is_observed) { | |
6179 old_value = it->GetDataValue(); | |
6180 } | |
6181 // Fall through. | |
6182 case LookupIterator::ACCESSOR: { | 6068 case LookupIterator::ACCESSOR: { |
6183 if (!it->IsConfigurable()) { | 6069 if (!it->IsConfigurable()) { |
6184 // Fail if the property is not configurable. | 6070 // Fail if the property is not configurable. |
6185 if (is_strict(language_mode)) { | 6071 if (is_strict(language_mode)) { |
6186 isolate->Throw(*isolate->factory()->NewTypeError( | 6072 isolate->Throw(*isolate->factory()->NewTypeError( |
6187 MessageTemplate::kStrictDeleteProperty, it->GetName(), | 6073 MessageTemplate::kStrictDeleteProperty, it->GetName(), |
6188 receiver)); | 6074 receiver)); |
6189 return Nothing<bool>(); | 6075 return Nothing<bool>(); |
6190 } | 6076 } |
6191 return Just(false); | 6077 return Just(false); |
6192 } | 6078 } |
6193 | 6079 |
6194 it->Delete(); | 6080 it->Delete(); |
6195 | 6081 |
6196 if (is_observed) { | |
6197 RETURN_ON_EXCEPTION_VALUE( | |
6198 isolate, JSObject::EnqueueChangeRecord(receiver, "delete", | |
6199 it->GetName(), old_value), | |
6200 Nothing<bool>()); | |
6201 } | |
6202 | |
6203 return Just(true); | 6082 return Just(true); |
6204 } | 6083 } |
6205 } | 6084 } |
6206 } | 6085 } |
6207 | 6086 |
6208 return Just(true); | 6087 return Just(true); |
6209 } | 6088 } |
6210 | 6089 |
6211 | 6090 |
6212 Maybe<bool> JSReceiver::DeleteElement(Handle<JSReceiver> object, uint32_t index, | 6091 Maybe<bool> JSReceiver::DeleteElement(Handle<JSReceiver> object, uint32_t index, |
(...skipping 728 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6941 new_writable = true; | 6820 new_writable = true; |
6942 } else { | 6821 } else { |
6943 // 15. Else, | 6822 // 15. Else, |
6944 // 15a. Need to defer setting the [[Writable]] attribute to false in case | 6823 // 15a. Need to defer setting the [[Writable]] attribute to false in case |
6945 // any elements cannot be deleted. | 6824 // any elements cannot be deleted. |
6946 // 15b. Let newWritable be false. (It's initialized as "false" anyway.) | 6825 // 15b. Let newWritable be false. (It's initialized as "false" anyway.) |
6947 // 15c. Set newLenDesc.[[Writable]] to true. | 6826 // 15c. Set newLenDesc.[[Writable]] to true. |
6948 // (Not needed.) | 6827 // (Not needed.) |
6949 } | 6828 } |
6950 // Most of steps 16 through 19 is implemented by JSArray::SetLength. | 6829 // Most of steps 16 through 19 is implemented by JSArray::SetLength. |
6951 if (JSArray::ObservableSetLength(a, new_len).is_null()) { | 6830 JSArray::SetLength(a, new_len); |
6952 DCHECK(isolate->has_pending_exception()); | |
6953 return Nothing<bool>(); | |
6954 } | |
6955 // Steps 19d-ii, 20. | 6831 // Steps 19d-ii, 20. |
6956 if (!new_writable) { | 6832 if (!new_writable) { |
6957 PropertyDescriptor readonly; | 6833 PropertyDescriptor readonly; |
6958 readonly.set_writable(false); | 6834 readonly.set_writable(false); |
6959 Maybe<bool> success = OrdinaryDefineOwnProperty( | 6835 Maybe<bool> success = OrdinaryDefineOwnProperty( |
6960 isolate, a, isolate->factory()->length_string(), &readonly, | 6836 isolate, a, isolate->factory()->length_string(), &readonly, |
6961 should_throw); | 6837 should_throw); |
6962 DCHECK(success.FromJust()); | 6838 DCHECK(success.FromJust()); |
6963 USE(success); | 6839 USE(success); |
6964 } | 6840 } |
(...skipping 486 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7451 } | 7327 } |
7452 | 7328 |
7453 | 7329 |
7454 Maybe<bool> JSReceiver::SetIntegrityLevel(Handle<JSReceiver> receiver, | 7330 Maybe<bool> JSReceiver::SetIntegrityLevel(Handle<JSReceiver> receiver, |
7455 IntegrityLevel level, | 7331 IntegrityLevel level, |
7456 ShouldThrow should_throw) { | 7332 ShouldThrow should_throw) { |
7457 DCHECK(level == SEALED || level == FROZEN); | 7333 DCHECK(level == SEALED || level == FROZEN); |
7458 | 7334 |
7459 if (receiver->IsJSObject()) { | 7335 if (receiver->IsJSObject()) { |
7460 Handle<JSObject> object = Handle<JSObject>::cast(receiver); | 7336 Handle<JSObject> object = Handle<JSObject>::cast(receiver); |
7461 if (!object->HasSloppyArgumentsElements() && | 7337 if (!object->HasSloppyArgumentsElements()) { // Fast path. |
7462 !object->map()->is_observed()) { // Fast path. | |
7463 if (level == SEALED) { | 7338 if (level == SEALED) { |
7464 return JSObject::PreventExtensionsWithTransition<SEALED>(object, | 7339 return JSObject::PreventExtensionsWithTransition<SEALED>(object, |
7465 should_throw); | 7340 should_throw); |
7466 } else { | 7341 } else { |
7467 return JSObject::PreventExtensionsWithTransition<FROZEN>(object, | 7342 return JSObject::PreventExtensionsWithTransition<FROZEN>(object, |
7468 should_throw); | 7343 should_throw); |
7469 } | 7344 } |
7470 } | 7345 } |
7471 } | 7346 } |
7472 | 7347 |
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7603 return Nothing<bool>(); | 7478 return Nothing<bool>(); |
7604 } | 7479 } |
7605 return Just(true); | 7480 return Just(true); |
7606 } | 7481 } |
7607 | 7482 |
7608 | 7483 |
7609 Maybe<bool> JSObject::PreventExtensions(Handle<JSObject> object, | 7484 Maybe<bool> JSObject::PreventExtensions(Handle<JSObject> object, |
7610 ShouldThrow should_throw) { | 7485 ShouldThrow should_throw) { |
7611 Isolate* isolate = object->GetIsolate(); | 7486 Isolate* isolate = object->GetIsolate(); |
7612 | 7487 |
7613 if (!object->HasSloppyArgumentsElements() && !object->map()->is_observed()) { | 7488 if (!object->HasSloppyArgumentsElements()) { |
7614 return PreventExtensionsWithTransition<NONE>(object, should_throw); | 7489 return PreventExtensionsWithTransition<NONE>(object, should_throw); |
7615 } | 7490 } |
7616 | 7491 |
7617 if (object->IsAccessCheckNeeded() && | 7492 if (object->IsAccessCheckNeeded() && |
7618 !isolate->MayAccess(handle(isolate->context()), object)) { | 7493 !isolate->MayAccess(handle(isolate->context()), object)) { |
7619 isolate->ReportFailedAccessCheck(object); | 7494 isolate->ReportFailedAccessCheck(object); |
7620 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>()); | 7495 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>()); |
7621 RETURN_FAILURE(isolate, should_throw, | 7496 RETURN_FAILURE(isolate, should_throw, |
7622 NewTypeError(MessageTemplate::kNoAccess)); | 7497 NewTypeError(MessageTemplate::kNoAccess)); |
7623 } | 7498 } |
(...skipping 20 matching lines...) Expand all Loading... |
7644 | 7519 |
7645 // Do a map transition, other objects with this map may still | 7520 // Do a map transition, other objects with this map may still |
7646 // be extensible. | 7521 // be extensible. |
7647 // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps. | 7522 // TODO(adamk): Extend the NormalizedMapCache to handle non-extensible maps. |
7648 Handle<Map> new_map = Map::Copy(handle(object->map()), "PreventExtensions"); | 7523 Handle<Map> new_map = Map::Copy(handle(object->map()), "PreventExtensions"); |
7649 | 7524 |
7650 new_map->set_is_extensible(false); | 7525 new_map->set_is_extensible(false); |
7651 JSObject::MigrateToMap(object, new_map); | 7526 JSObject::MigrateToMap(object, new_map); |
7652 DCHECK(!object->map()->is_extensible()); | 7527 DCHECK(!object->map()->is_extensible()); |
7653 | 7528 |
7654 if (object->map()->is_observed()) { | |
7655 RETURN_ON_EXCEPTION_VALUE( | |
7656 isolate, | |
7657 EnqueueChangeRecord(object, "preventExtensions", Handle<Name>(), | |
7658 isolate->factory()->the_hole_value()), | |
7659 Nothing<bool>()); | |
7660 } | |
7661 return Just(true); | 7529 return Just(true); |
7662 } | 7530 } |
7663 | 7531 |
7664 | 7532 |
7665 Maybe<bool> JSReceiver::IsExtensible(Handle<JSReceiver> object) { | 7533 Maybe<bool> JSReceiver::IsExtensible(Handle<JSReceiver> object) { |
7666 if (object->IsJSProxy()) { | 7534 if (object->IsJSProxy()) { |
7667 return JSProxy::IsExtensible(Handle<JSProxy>::cast(object)); | 7535 return JSProxy::IsExtensible(Handle<JSProxy>::cast(object)); |
7668 } | 7536 } |
7669 return Just(JSObject::IsExtensible(Handle<JSObject>::cast(object))); | 7537 return Just(JSObject::IsExtensible(Handle<JSObject>::cast(object))); |
7670 } | 7538 } |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7751 } | 7619 } |
7752 | 7620 |
7753 | 7621 |
7754 template <PropertyAttributes attrs> | 7622 template <PropertyAttributes attrs> |
7755 Maybe<bool> JSObject::PreventExtensionsWithTransition( | 7623 Maybe<bool> JSObject::PreventExtensionsWithTransition( |
7756 Handle<JSObject> object, ShouldThrow should_throw) { | 7624 Handle<JSObject> object, ShouldThrow should_throw) { |
7757 STATIC_ASSERT(attrs == NONE || attrs == SEALED || attrs == FROZEN); | 7625 STATIC_ASSERT(attrs == NONE || attrs == SEALED || attrs == FROZEN); |
7758 | 7626 |
7759 // Sealing/freezing sloppy arguments should be handled elsewhere. | 7627 // Sealing/freezing sloppy arguments should be handled elsewhere. |
7760 DCHECK(!object->HasSloppyArgumentsElements()); | 7628 DCHECK(!object->HasSloppyArgumentsElements()); |
7761 DCHECK(!object->map()->is_observed()); | |
7762 | 7629 |
7763 Isolate* isolate = object->GetIsolate(); | 7630 Isolate* isolate = object->GetIsolate(); |
7764 if (object->IsAccessCheckNeeded() && | 7631 if (object->IsAccessCheckNeeded() && |
7765 !isolate->MayAccess(handle(isolate->context()), object)) { | 7632 !isolate->MayAccess(handle(isolate->context()), object)) { |
7766 isolate->ReportFailedAccessCheck(object); | 7633 isolate->ReportFailedAccessCheck(object); |
7767 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>()); | 7634 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>()); |
7768 RETURN_FAILURE(isolate, should_throw, | 7635 RETURN_FAILURE(isolate, should_throw, |
7769 NewTypeError(MessageTemplate::kNoAccess)); | 7636 NewTypeError(MessageTemplate::kNoAccess)); |
7770 } | 7637 } |
7771 | 7638 |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7870 object->RequireSlowElements(dictionary); | 7737 object->RequireSlowElements(dictionary); |
7871 if (attrs != NONE) { | 7738 if (attrs != NONE) { |
7872 ApplyAttributesToDictionary(dictionary, attrs); | 7739 ApplyAttributesToDictionary(dictionary, attrs); |
7873 } | 7740 } |
7874 } | 7741 } |
7875 | 7742 |
7876 return Just(true); | 7743 return Just(true); |
7877 } | 7744 } |
7878 | 7745 |
7879 | 7746 |
7880 void JSObject::SetObserved(Handle<JSObject> object) { | |
7881 DCHECK(!object->IsJSGlobalProxy()); | |
7882 DCHECK(!object->IsJSGlobalObject()); | |
7883 Isolate* isolate = object->GetIsolate(); | |
7884 Handle<Map> new_map; | |
7885 Handle<Map> old_map(object->map(), isolate); | |
7886 DCHECK(!old_map->is_observed()); | |
7887 Map* transition = TransitionArray::SearchSpecial( | |
7888 *old_map, isolate->heap()->observed_symbol()); | |
7889 if (transition != NULL) { | |
7890 new_map = handle(transition, isolate); | |
7891 DCHECK(new_map->is_observed()); | |
7892 } else if (TransitionArray::CanHaveMoreTransitions(old_map)) { | |
7893 new_map = Map::CopyForObserved(old_map); | |
7894 } else { | |
7895 new_map = Map::Copy(old_map, "SlowObserved"); | |
7896 new_map->set_is_observed(); | |
7897 } | |
7898 JSObject::MigrateToMap(object, new_map); | |
7899 } | |
7900 | |
7901 | |
7902 Handle<Object> JSObject::FastPropertyAt(Handle<JSObject> object, | 7747 Handle<Object> JSObject::FastPropertyAt(Handle<JSObject> object, |
7903 Representation representation, | 7748 Representation representation, |
7904 FieldIndex index) { | 7749 FieldIndex index) { |
7905 Isolate* isolate = object->GetIsolate(); | 7750 Isolate* isolate = object->GetIsolate(); |
7906 if (object->IsUnboxedDoubleField(index)) { | 7751 if (object->IsUnboxedDoubleField(index)) { |
7907 double value = object->RawFastDoublePropertyAt(index); | 7752 double value = object->RawFastDoublePropertyAt(index); |
7908 return isolate->factory()->NewHeapNumber(value); | 7753 return isolate->factory()->NewHeapNumber(value); |
7909 } | 7754 } |
7910 Handle<Object> raw_value(object->RawFastPropertyAt(index), isolate); | 7755 Handle<Object> raw_value(object->RawFastPropertyAt(index), isolate); |
7911 return Object::WrapForRead(isolate, raw_value, representation); | 7756 return Object::WrapForRead(isolate, raw_value, representation); |
(...skipping 1077 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8989 } | 8834 } |
8990 it->Next(); | 8835 it->Next(); |
8991 } | 8836 } |
8992 | 8837 |
8993 Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver()); | 8838 Handle<JSObject> object = Handle<JSObject>::cast(it->GetReceiver()); |
8994 // Ignore accessors on typed arrays. | 8839 // Ignore accessors on typed arrays. |
8995 if (it->IsElement() && object->HasFixedTypedArrayElements()) { | 8840 if (it->IsElement() && object->HasFixedTypedArrayElements()) { |
8996 return it->factory()->undefined_value(); | 8841 return it->factory()->undefined_value(); |
8997 } | 8842 } |
8998 | 8843 |
8999 Handle<Object> old_value = isolate->factory()->the_hole_value(); | |
9000 bool is_observed = object->map()->is_observed() && | |
9001 (it->IsElement() || !it->name()->IsPrivate()); | |
9002 bool preexists = false; | |
9003 if (is_observed) { | |
9004 CHECK(GetPropertyAttributes(it).IsJust()); | |
9005 preexists = it->IsFound(); | |
9006 if (preexists && (it->state() == LookupIterator::DATA || | |
9007 it->GetAccessors()->IsAccessorInfo())) { | |
9008 old_value = Object::GetProperty(it).ToHandleChecked(); | |
9009 } | |
9010 } | |
9011 | |
9012 DCHECK(getter->IsCallable() || getter->IsUndefined() || getter->IsNull() || | 8844 DCHECK(getter->IsCallable() || getter->IsUndefined() || getter->IsNull() || |
9013 getter->IsFunctionTemplateInfo()); | 8845 getter->IsFunctionTemplateInfo()); |
9014 DCHECK(setter->IsCallable() || setter->IsUndefined() || setter->IsNull() || | 8846 DCHECK(setter->IsCallable() || setter->IsUndefined() || setter->IsNull() || |
9015 getter->IsFunctionTemplateInfo()); | 8847 getter->IsFunctionTemplateInfo()); |
9016 // At least one of the accessors needs to be a new value. | 8848 // At least one of the accessors needs to be a new value. |
9017 DCHECK(!getter->IsNull() || !setter->IsNull()); | 8849 DCHECK(!getter->IsNull() || !setter->IsNull()); |
9018 if (!getter->IsNull()) { | 8850 if (!getter->IsNull()) { |
9019 it->TransitionToAccessorProperty(ACCESSOR_GETTER, getter, attributes); | 8851 it->TransitionToAccessorProperty(ACCESSOR_GETTER, getter, attributes); |
9020 } | 8852 } |
9021 if (!setter->IsNull()) { | 8853 if (!setter->IsNull()) { |
9022 it->TransitionToAccessorProperty(ACCESSOR_SETTER, setter, attributes); | 8854 it->TransitionToAccessorProperty(ACCESSOR_SETTER, setter, attributes); |
9023 } | 8855 } |
9024 | 8856 |
9025 if (is_observed) { | |
9026 // Make sure the top context isn't changed. | |
9027 AssertNoContextChange ncc(isolate); | |
9028 const char* type = preexists ? "reconfigure" : "add"; | |
9029 RETURN_ON_EXCEPTION( | |
9030 isolate, EnqueueChangeRecord(object, type, it->GetName(), old_value), | |
9031 Object); | |
9032 } | |
9033 | |
9034 return isolate->factory()->undefined_value(); | 8857 return isolate->factory()->undefined_value(); |
9035 } | 8858 } |
9036 | 8859 |
9037 | 8860 |
9038 MaybeHandle<Object> JSObject::SetAccessor(Handle<JSObject> object, | 8861 MaybeHandle<Object> JSObject::SetAccessor(Handle<JSObject> object, |
9039 Handle<AccessorInfo> info) { | 8862 Handle<AccessorInfo> info) { |
9040 Isolate* isolate = object->GetIsolate(); | 8863 Isolate* isolate = object->GetIsolate(); |
9041 Handle<Name> name(Name::cast(info->name()), isolate); | 8864 Handle<Name> name(Name::cast(info->name()), isolate); |
9042 | 8865 |
9043 LookupIterator it = LookupIterator::PropertyOrElement( | 8866 LookupIterator it = LookupIterator::PropertyOrElement( |
(...skipping 588 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
9632 map->set_prototype(initial_map->prototype()); | 9455 map->set_prototype(initial_map->prototype()); |
9633 | 9456 |
9634 if (TransitionArray::CanHaveMoreTransitions(initial_map)) { | 9457 if (TransitionArray::CanHaveMoreTransitions(initial_map)) { |
9635 Map::ConnectTransition(initial_map, map, transition_symbol, | 9458 Map::ConnectTransition(initial_map, map, transition_symbol, |
9636 SPECIAL_TRANSITION); | 9459 SPECIAL_TRANSITION); |
9637 } | 9460 } |
9638 return map; | 9461 return map; |
9639 } | 9462 } |
9640 | 9463 |
9641 | 9464 |
9642 Handle<Map> Map::CopyForObserved(Handle<Map> map) { | |
9643 DCHECK(!map->is_observed()); | |
9644 | |
9645 Isolate* isolate = map->GetIsolate(); | |
9646 | |
9647 bool insert_transition = | |
9648 TransitionArray::CanHaveMoreTransitions(map) && !map->is_prototype_map(); | |
9649 | |
9650 if (insert_transition) { | |
9651 Handle<Map> new_map = CopyForTransition(map, "CopyForObserved"); | |
9652 new_map->set_is_observed(); | |
9653 | |
9654 Handle<Name> name = isolate->factory()->observed_symbol(); | |
9655 ConnectTransition(map, new_map, name, SPECIAL_TRANSITION); | |
9656 return new_map; | |
9657 } | |
9658 | |
9659 // Create a new free-floating map only if we are not allowed to store it. | |
9660 Handle<Map> new_map = Map::Copy(map, "CopyForObserved"); | |
9661 new_map->set_is_observed(); | |
9662 return new_map; | |
9663 } | |
9664 | |
9665 | |
9666 Handle<Map> Map::CopyForTransition(Handle<Map> map, const char* reason) { | 9465 Handle<Map> Map::CopyForTransition(Handle<Map> map, const char* reason) { |
9667 DCHECK(!map->is_prototype_map()); | 9466 DCHECK(!map->is_prototype_map()); |
9668 Handle<Map> new_map = CopyDropDescriptors(map); | 9467 Handle<Map> new_map = CopyDropDescriptors(map); |
9669 | 9468 |
9670 if (map->owns_descriptors()) { | 9469 if (map->owns_descriptors()) { |
9671 // In case the map owned its own descriptors, share the descriptors and | 9470 // In case the map owned its own descriptors, share the descriptors and |
9672 // transfer ownership to the new map. | 9471 // transfer ownership to the new map. |
9673 // The properties did not change, so reuse descriptors. | 9472 // The properties did not change, so reuse descriptors. |
9674 new_map->InitializeDescriptors(map->instance_descriptors(), | 9473 new_map->InitializeDescriptors(map->instance_descriptors(), |
9675 map->GetLayoutDescriptor()); | 9474 map->GetLayoutDescriptor()); |
(...skipping 5040 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
14716 } | 14515 } |
14717 | 14516 |
14718 // static | 14517 // static |
14719 void JSArray::Initialize(Handle<JSArray> array, int capacity, int length) { | 14518 void JSArray::Initialize(Handle<JSArray> array, int capacity, int length) { |
14720 DCHECK(capacity >= 0); | 14519 DCHECK(capacity >= 0); |
14721 array->GetIsolate()->factory()->NewJSArrayStorage( | 14520 array->GetIsolate()->factory()->NewJSArrayStorage( |
14722 array, length, capacity, INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE); | 14521 array, length, capacity, INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE); |
14723 } | 14522 } |
14724 | 14523 |
14725 | 14524 |
14726 // Returns false if the passed-in index is marked non-configurable, which will | |
14727 // cause the truncation operation to halt, and thus no further old values need | |
14728 // be collected. | |
14729 static bool GetOldValue(Isolate* isolate, | |
14730 Handle<JSObject> object, | |
14731 uint32_t index, | |
14732 List<Handle<Object> >* old_values, | |
14733 List<uint32_t>* indices) { | |
14734 LookupIterator it(isolate, object, index, object, LookupIterator::HIDDEN); | |
14735 CHECK(JSReceiver::GetPropertyAttributes(&it).IsJust()); | |
14736 DCHECK(it.IsFound()); | |
14737 if (!it.IsConfigurable()) return false; | |
14738 Handle<Object> value = | |
14739 it.state() == LookupIterator::ACCESSOR | |
14740 ? Handle<Object>::cast(isolate->factory()->the_hole_value()) | |
14741 : JSReceiver::GetDataProperty(&it); | |
14742 old_values->Add(value); | |
14743 indices->Add(index); | |
14744 return true; | |
14745 } | |
14746 | |
14747 | |
14748 void JSArray::SetLength(Handle<JSArray> array, uint32_t new_length) { | 14525 void JSArray::SetLength(Handle<JSArray> array, uint32_t new_length) { |
14749 // We should never end in here with a pixel or external array. | 14526 // We should never end in here with a pixel or external array. |
14750 DCHECK(array->AllowsSetLength()); | 14527 DCHECK(array->AllowsSetLength()); |
14751 if (array->SetLengthWouldNormalize(new_length)) { | 14528 if (array->SetLengthWouldNormalize(new_length)) { |
14752 JSObject::NormalizeElements(array); | 14529 JSObject::NormalizeElements(array); |
14753 } | 14530 } |
14754 array->GetElementsAccessor()->SetLength(array, new_length); | 14531 array->GetElementsAccessor()->SetLength(array, new_length); |
14755 } | 14532 } |
14756 | 14533 |
14757 | 14534 |
14758 MaybeHandle<Object> JSArray::ObservableSetLength(Handle<JSArray> array, | |
14759 uint32_t new_length) { | |
14760 if (!array->map()->is_observed()) { | |
14761 SetLength(array, new_length); | |
14762 return array; | |
14763 } | |
14764 | |
14765 Isolate* isolate = array->GetIsolate(); | |
14766 List<uint32_t> indices; | |
14767 List<Handle<Object> > old_values; | |
14768 Handle<Object> old_length_handle(array->length(), isolate); | |
14769 uint32_t old_length = 0; | |
14770 CHECK(old_length_handle->ToArrayLength(&old_length)); | |
14771 | |
14772 int num_elements = array->NumberOfOwnElements(ALL_PROPERTIES); | |
14773 if (num_elements > 0) { | |
14774 if (old_length == static_cast<uint32_t>(num_elements)) { | |
14775 // Simple case for arrays without holes. | |
14776 for (uint32_t i = old_length - 1; i + 1 > new_length; --i) { | |
14777 if (!GetOldValue(isolate, array, i, &old_values, &indices)) break; | |
14778 } | |
14779 } else { | |
14780 // For sparse arrays, only iterate over existing elements. | |
14781 // TODO(rafaelw): For fast, sparse arrays, we can avoid iterating over | |
14782 // the to-be-removed indices twice. | |
14783 Handle<FixedArray> keys = isolate->factory()->NewFixedArray(num_elements); | |
14784 array->GetOwnElementKeys(*keys, ALL_PROPERTIES); | |
14785 while (num_elements-- > 0) { | |
14786 uint32_t index = NumberToUint32(keys->get(num_elements)); | |
14787 if (index < new_length) break; | |
14788 if (!GetOldValue(isolate, array, index, &old_values, &indices)) break; | |
14789 } | |
14790 } | |
14791 } | |
14792 | |
14793 SetLength(array, new_length); | |
14794 | |
14795 CHECK(array->length()->ToArrayLength(&new_length)); | |
14796 if (old_length == new_length) return array; | |
14797 | |
14798 RETURN_ON_EXCEPTION(isolate, BeginPerformSplice(array), Object); | |
14799 | |
14800 for (int i = 0; i < indices.length(); ++i) { | |
14801 // For deletions where the property was an accessor, old_values[i] | |
14802 // will be the hole, which instructs EnqueueChangeRecord to elide | |
14803 // the "oldValue" property. | |
14804 RETURN_ON_EXCEPTION( | |
14805 isolate, | |
14806 JSObject::EnqueueChangeRecord( | |
14807 array, "delete", isolate->factory()->Uint32ToString(indices[i]), | |
14808 old_values[i]), | |
14809 Object); | |
14810 } | |
14811 | |
14812 RETURN_ON_EXCEPTION(isolate, | |
14813 JSObject::EnqueueChangeRecord( | |
14814 array, "update", isolate->factory()->length_string(), | |
14815 old_length_handle), | |
14816 Object); | |
14817 | |
14818 RETURN_ON_EXCEPTION(isolate, EndPerformSplice(array), Object); | |
14819 | |
14820 uint32_t index = Min(old_length, new_length); | |
14821 uint32_t add_count = new_length > old_length ? new_length - old_length : 0; | |
14822 uint32_t delete_count = new_length < old_length ? old_length - new_length : 0; | |
14823 Handle<JSArray> deleted = isolate->factory()->NewJSArray(0); | |
14824 if (delete_count > 0) { | |
14825 for (int i = indices.length() - 1; i >= 0; i--) { | |
14826 // Skip deletions where the property was an accessor, leaving holes | |
14827 // in the array of old values. | |
14828 if (old_values[i]->IsTheHole()) continue; | |
14829 JSObject::AddDataElement(deleted, indices[i] - index, old_values[i], NONE) | |
14830 .Assert(); | |
14831 } | |
14832 | |
14833 JSArray::SetLength(deleted, delete_count); | |
14834 } | |
14835 | |
14836 RETURN_ON_EXCEPTION( | |
14837 isolate, EnqueueSpliceRecord(array, index, deleted, add_count), Object); | |
14838 | |
14839 return array; | |
14840 } | |
14841 | |
14842 | |
14843 // static | 14535 // static |
14844 void Map::AddDependentCode(Handle<Map> map, | 14536 void Map::AddDependentCode(Handle<Map> map, |
14845 DependentCode::DependencyGroup group, | 14537 DependentCode::DependencyGroup group, |
14846 Handle<Code> code) { | 14538 Handle<Code> code) { |
14847 Handle<WeakCell> cell = Code::WeakCellFor(code); | 14539 Handle<WeakCell> cell = Code::WeakCellFor(code); |
14848 Handle<DependentCode> codes = DependentCode::InsertWeakCode( | 14540 Handle<DependentCode> codes = DependentCode::InsertWeakCode( |
14849 Handle<DependentCode>(map->dependent_code()), group, cell); | 14541 Handle<DependentCode>(map->dependent_code()), group, cell); |
14850 if (*codes != map->dependent_code()) map->set_dependent_code(*codes); | 14542 if (*codes != map->dependent_code()) map->set_dependent_code(*codes); |
14851 } | 14543 } |
14852 | 14544 |
(...skipping 388 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
15241 // Setting the prototype of an Array instance invalidates the species | 14933 // Setting the prototype of an Array instance invalidates the species |
15242 // protector | 14934 // protector |
15243 // because it could change the constructor property of the instance, which | 14935 // because it could change the constructor property of the instance, which |
15244 // could change the @@species constructor. | 14936 // could change the @@species constructor. |
15245 if (object->IsJSArray() && isolate->IsArraySpeciesLookupChainIntact()) { | 14937 if (object->IsJSArray() && isolate->IsArraySpeciesLookupChainIntact()) { |
15246 isolate->CountUsage( | 14938 isolate->CountUsage( |
15247 v8::Isolate::UseCounterFeature::kArrayInstanceProtoModified); | 14939 v8::Isolate::UseCounterFeature::kArrayInstanceProtoModified); |
15248 isolate->InvalidateArraySpeciesProtector(); | 14940 isolate->InvalidateArraySpeciesProtector(); |
15249 } | 14941 } |
15250 | 14942 |
15251 const bool observed = from_javascript && object->map()->is_observed(); | |
15252 Handle<Object> old_value; | |
15253 if (observed) { | |
15254 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, old_value, | |
15255 JSReceiver::GetPrototype(isolate, object), | |
15256 Nothing<bool>()); | |
15257 } | |
15258 | |
15259 Maybe<bool> result = | |
15260 SetPrototypeUnobserved(object, value, from_javascript, should_throw); | |
15261 MAYBE_RETURN(result, Nothing<bool>()); | |
15262 | |
15263 if (result.FromJust() && observed) { | |
15264 Handle<Object> new_value; | |
15265 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, new_value, | |
15266 JSReceiver::GetPrototype(isolate, object), | |
15267 Nothing<bool>()); | |
15268 if (!new_value->SameValue(*old_value)) { | |
15269 RETURN_ON_EXCEPTION_VALUE( | |
15270 isolate, JSObject::EnqueueChangeRecord( | |
15271 object, "setPrototype", | |
15272 isolate->factory()->proto_string(), old_value), | |
15273 Nothing<bool>()); | |
15274 } | |
15275 } | |
15276 | |
15277 return result; | |
15278 } | |
15279 | |
15280 | |
15281 Maybe<bool> JSObject::SetPrototypeUnobserved(Handle<JSObject> object, | |
15282 Handle<Object> value, | |
15283 bool from_javascript, | |
15284 ShouldThrow should_throw) { | |
15285 #ifdef DEBUG | 14943 #ifdef DEBUG |
15286 int size = object->Size(); | 14944 int size = object->Size(); |
15287 #endif | 14945 #endif |
15288 | 14946 |
15289 Isolate* isolate = object->GetIsolate(); | |
15290 | |
15291 if (from_javascript) { | 14947 if (from_javascript) { |
15292 if (object->IsAccessCheckNeeded() && | 14948 if (object->IsAccessCheckNeeded() && |
15293 !isolate->MayAccess(handle(isolate->context()), object)) { | 14949 !isolate->MayAccess(handle(isolate->context()), object)) { |
15294 isolate->ReportFailedAccessCheck(object); | 14950 isolate->ReportFailedAccessCheck(object); |
15295 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>()); | 14951 RETURN_VALUE_IF_SCHEDULED_EXCEPTION(isolate, Nothing<bool>()); |
15296 RETURN_FAILURE(isolate, should_throw, | 14952 RETURN_FAILURE(isolate, should_throw, |
15297 NewTypeError(MessageTemplate::kNoAccess)); | 14953 NewTypeError(MessageTemplate::kNoAccess)); |
15298 } | 14954 } |
15299 } else { | 14955 } else { |
15300 DCHECK(!object->IsAccessCheckNeeded()); | 14956 DCHECK(!object->IsAccessCheckNeeded()); |
(...skipping 215 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
15516 Handle<Object> value, | 15172 Handle<Object> value, |
15517 PropertyAttributes attributes, | 15173 PropertyAttributes attributes, |
15518 ShouldThrow should_throw) { | 15174 ShouldThrow should_throw) { |
15519 DCHECK(object->map()->is_extensible()); | 15175 DCHECK(object->map()->is_extensible()); |
15520 | 15176 |
15521 Isolate* isolate = object->GetIsolate(); | 15177 Isolate* isolate = object->GetIsolate(); |
15522 | 15178 |
15523 uint32_t old_length = 0; | 15179 uint32_t old_length = 0; |
15524 uint32_t new_capacity = 0; | 15180 uint32_t new_capacity = 0; |
15525 | 15181 |
15526 Handle<Object> old_length_handle; | |
15527 if (object->IsJSArray()) { | 15182 if (object->IsJSArray()) { |
15528 CHECK(JSArray::cast(*object)->length()->ToArrayLength(&old_length)); | 15183 CHECK(JSArray::cast(*object)->length()->ToArrayLength(&old_length)); |
15529 if (object->map()->is_observed()) { | |
15530 old_length_handle = handle(JSArray::cast(*object)->length(), isolate); | |
15531 } | |
15532 } | 15184 } |
15533 | 15185 |
15534 ElementsKind kind = object->GetElementsKind(); | 15186 ElementsKind kind = object->GetElementsKind(); |
15535 FixedArrayBase* elements = object->elements(); | 15187 FixedArrayBase* elements = object->elements(); |
15536 ElementsKind dictionary_kind = DICTIONARY_ELEMENTS; | 15188 ElementsKind dictionary_kind = DICTIONARY_ELEMENTS; |
15537 if (IsSloppyArgumentsElements(kind)) { | 15189 if (IsSloppyArgumentsElements(kind)) { |
15538 elements = FixedArrayBase::cast(FixedArray::cast(elements)->get(1)); | 15190 elements = FixedArrayBase::cast(FixedArray::cast(elements)->get(1)); |
15539 dictionary_kind = SLOW_SLOPPY_ARGUMENTS_ELEMENTS; | 15191 dictionary_kind = SLOW_SLOPPY_ARGUMENTS_ELEMENTS; |
15540 } else if (IsStringWrapperElementsKind(kind)) { | 15192 } else if (IsStringWrapperElementsKind(kind)) { |
15541 dictionary_kind = SLOW_STRING_WRAPPER_ELEMENTS; | 15193 dictionary_kind = SLOW_STRING_WRAPPER_ELEMENTS; |
(...skipping 23 matching lines...) Expand all Loading... |
15565 accessor->Add(object, index, value, attributes, new_capacity); | 15217 accessor->Add(object, index, value, attributes, new_capacity); |
15566 | 15218 |
15567 uint32_t new_length = old_length; | 15219 uint32_t new_length = old_length; |
15568 Handle<Object> new_length_handle; | 15220 Handle<Object> new_length_handle; |
15569 if (object->IsJSArray() && index >= old_length) { | 15221 if (object->IsJSArray() && index >= old_length) { |
15570 new_length = index + 1; | 15222 new_length = index + 1; |
15571 new_length_handle = isolate->factory()->NewNumberFromUint(new_length); | 15223 new_length_handle = isolate->factory()->NewNumberFromUint(new_length); |
15572 JSArray::cast(*object)->set_length(*new_length_handle); | 15224 JSArray::cast(*object)->set_length(*new_length_handle); |
15573 } | 15225 } |
15574 | 15226 |
15575 if (!old_length_handle.is_null() && new_length != old_length) { | |
15576 // |old_length_handle| is kept null above unless the object is observed. | |
15577 DCHECK(object->map()->is_observed()); | |
15578 Handle<JSArray> array = Handle<JSArray>::cast(object); | |
15579 Handle<String> name = isolate->factory()->Uint32ToString(index); | |
15580 | |
15581 RETURN_ON_EXCEPTION_VALUE(isolate, BeginPerformSplice(array), | |
15582 Nothing<bool>()); | |
15583 RETURN_ON_EXCEPTION_VALUE( | |
15584 isolate, EnqueueChangeRecord(array, "add", name, | |
15585 isolate->factory()->the_hole_value()), | |
15586 Nothing<bool>()); | |
15587 RETURN_ON_EXCEPTION_VALUE( | |
15588 isolate, EnqueueChangeRecord(array, "update", | |
15589 isolate->factory()->length_string(), | |
15590 old_length_handle), | |
15591 Nothing<bool>()); | |
15592 RETURN_ON_EXCEPTION_VALUE(isolate, EndPerformSplice(array), | |
15593 Nothing<bool>()); | |
15594 Handle<JSArray> deleted = isolate->factory()->NewJSArray(0); | |
15595 RETURN_ON_EXCEPTION_VALUE(isolate, | |
15596 EnqueueSpliceRecord(array, old_length, deleted, | |
15597 new_length - old_length), | |
15598 Nothing<bool>()); | |
15599 } else if (object->map()->is_observed()) { | |
15600 Handle<String> name = isolate->factory()->Uint32ToString(index); | |
15601 RETURN_ON_EXCEPTION_VALUE( | |
15602 isolate, EnqueueChangeRecord(object, "add", name, | |
15603 isolate->factory()->the_hole_value()), | |
15604 Nothing<bool>()); | |
15605 } | |
15606 | |
15607 return Just(true); | 15227 return Just(true); |
15608 } | 15228 } |
15609 | 15229 |
15610 | 15230 |
15611 bool JSArray::SetLengthWouldNormalize(uint32_t new_length) { | 15231 bool JSArray::SetLengthWouldNormalize(uint32_t new_length) { |
15612 if (!HasFastElements()) return false; | 15232 if (!HasFastElements()) return false; |
15613 uint32_t capacity = static_cast<uint32_t>(elements()->length()); | 15233 uint32_t capacity = static_cast<uint32_t>(elements()->length()); |
15614 uint32_t new_capacity; | 15234 uint32_t new_capacity; |
15615 return JSArray::SetLengthWouldNormalize(GetHeap(), new_length) && | 15235 return JSArray::SetLengthWouldNormalize(GetHeap(), new_length) && |
15616 ShouldConvertToSlowElements(this, capacity, new_length - 1, | 15236 ShouldConvertToSlowElements(this, capacity, new_length - 1, |
(...skipping 1630 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
17247 } | 16867 } |
17248 | 16868 |
17249 | 16869 |
17250 // Collects all defined (non-hole) and non-undefined (array) elements at | 16870 // Collects all defined (non-hole) and non-undefined (array) elements at |
17251 // the start of the elements array. | 16871 // the start of the elements array. |
17252 // If the object is in dictionary mode, it is converted to fast elements | 16872 // If the object is in dictionary mode, it is converted to fast elements |
17253 // mode. | 16873 // mode. |
17254 Handle<Object> JSObject::PrepareElementsForSort(Handle<JSObject> object, | 16874 Handle<Object> JSObject::PrepareElementsForSort(Handle<JSObject> object, |
17255 uint32_t limit) { | 16875 uint32_t limit) { |
17256 Isolate* isolate = object->GetIsolate(); | 16876 Isolate* isolate = object->GetIsolate(); |
17257 if (object->HasSloppyArgumentsElements() || | 16877 if (object->HasSloppyArgumentsElements()) { |
17258 object->map()->is_observed()) { | |
17259 return handle(Smi::FromInt(-1), isolate); | 16878 return handle(Smi::FromInt(-1), isolate); |
17260 } | 16879 } |
17261 | 16880 |
17262 if (object->HasStringWrapperElements()) { | 16881 if (object->HasStringWrapperElements()) { |
17263 int len = String::cast(Handle<JSValue>::cast(object)->value())->length(); | 16882 int len = String::cast(Handle<JSValue>::cast(object)->value())->length(); |
17264 return handle(Smi::FromInt(len), isolate); | 16883 return handle(Smi::FromInt(len), isolate); |
17265 } | 16884 } |
17266 | 16885 |
17267 if (object->HasDictionaryElements()) { | 16886 if (object->HasDictionaryElements()) { |
17268 // Convert to fast elements containing only the existing properties. | 16887 // Convert to fast elements containing only the existing properties. |
(...skipping 2166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
19435 if (cell->value() != *new_value) { | 19054 if (cell->value() != *new_value) { |
19436 cell->set_value(*new_value); | 19055 cell->set_value(*new_value); |
19437 Isolate* isolate = cell->GetIsolate(); | 19056 Isolate* isolate = cell->GetIsolate(); |
19438 cell->dependent_code()->DeoptimizeDependentCodeGroup( | 19057 cell->dependent_code()->DeoptimizeDependentCodeGroup( |
19439 isolate, DependentCode::kPropertyCellChangedGroup); | 19058 isolate, DependentCode::kPropertyCellChangedGroup); |
19440 } | 19059 } |
19441 } | 19060 } |
19442 | 19061 |
19443 } // namespace internal | 19062 } // namespace internal |
19444 } // namespace v8 | 19063 } // namespace v8 |
OLD | NEW |