| 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 |