OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 4337 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4348 ASSERT(args.length() == 4); | 4348 ASSERT(args.length() == 4); |
4349 HandleScope scope(isolate); | 4349 HandleScope scope(isolate); |
4350 CONVERT_ARG_HANDLE_CHECKED(JSObject, js_object, 0); | 4350 CONVERT_ARG_HANDLE_CHECKED(JSObject, js_object, 0); |
4351 CONVERT_ARG_HANDLE_CHECKED(String, name, 1); | 4351 CONVERT_ARG_HANDLE_CHECKED(String, name, 1); |
4352 Handle<Object> obj_value = args.at<Object>(2); | 4352 Handle<Object> obj_value = args.at<Object>(2); |
4353 CONVERT_SMI_ARG_CHECKED(unchecked, 3); | 4353 CONVERT_SMI_ARG_CHECKED(unchecked, 3); |
4354 | 4354 |
4355 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0); | 4355 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0); |
4356 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked); | 4356 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked); |
4357 | 4357 |
4358 // Check if this is an element. | |
4359 uint32_t index; | |
4360 bool is_element = name->AsArrayIndex(&index); | |
4361 | |
4362 // Special case for elements if any of the flags might be involved. | |
4363 // If elements are in fast case we always implicitly assume that: | |
4364 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false. | |
4365 if (is_element && (attr != NONE || | |
4366 js_object->HasLocalElement(index) == JSObject::DICTIONARY_ELEMENT)) { | |
4367 // Normalize the elements to enable attributes on the property. | |
4368 if (js_object->IsJSGlobalProxy()) { | |
4369 // We do not need to do access checks here since these has already | |
4370 // been performed by the call to GetOwnProperty. | |
4371 Handle<Object> proto(js_object->GetPrototype()); | |
4372 // If proxy is detached, ignore the assignment. Alternatively, | |
4373 // we could throw an exception. | |
4374 if (proto->IsNull()) return *obj_value; | |
4375 js_object = Handle<JSObject>::cast(proto); | |
4376 } | |
4377 | |
4378 // Don't allow element properties to be redefined on objects with external | |
4379 // array elements. | |
4380 if (js_object->HasExternalArrayElements()) { | |
4381 Handle<Object> args[2] = { js_object, name }; | |
4382 Handle<Object> error = | |
4383 isolate->factory()->NewTypeError("redef_external_array_element", | |
4384 HandleVector(args, 2)); | |
4385 return isolate->Throw(*error); | |
4386 } | |
4387 | |
4388 Handle<SeededNumberDictionary> dictionary = | |
4389 JSObject::NormalizeElements(js_object); | |
4390 // Make sure that we never go back to fast case. | |
4391 dictionary->set_requires_slow_elements(); | |
4392 PropertyDetails details = PropertyDetails(attr, NORMAL); | |
4393 Handle<SeededNumberDictionary> extended_dictionary = | |
4394 SeededNumberDictionary::Set(dictionary, index, obj_value, details); | |
4395 if (*extended_dictionary != *dictionary) { | |
4396 if (js_object->GetElementsKind() == NON_STRICT_ARGUMENTS_ELEMENTS) { | |
4397 FixedArray::cast(js_object->elements())->set(1, *extended_dictionary); | |
4398 } else { | |
4399 js_object->set_elements(*extended_dictionary); | |
4400 } | |
4401 } | |
4402 return *obj_value; | |
4403 } | |
4404 | |
4405 LookupResult result(isolate); | 4358 LookupResult result(isolate); |
4406 js_object->LocalLookupRealNamedProperty(*name, &result); | 4359 js_object->LocalLookupRealNamedProperty(*name, &result); |
4407 | 4360 |
4408 // Special case for callback properties. | 4361 // Special case for callback properties. |
4409 if (result.IsFound() && result.type() == CALLBACKS) { | 4362 if (result.IsFound() && result.type() == CALLBACKS) { |
4410 Object* callback = result.GetCallbackObject(); | 4363 Object* callback = result.GetCallbackObject(); |
4411 // To be compatible with Safari we do not change the value on API objects | 4364 // To be compatible with Safari we do not change the value on API objects |
4412 // in Object.defineProperty(). Firefox disagrees here, and actually changes | 4365 // in Object.defineProperty(). Firefox disagrees here, and actually changes |
4413 // the value. | 4366 // the value. |
4414 if (callback->IsAccessorInfo()) { | 4367 if (callback->IsAccessorInfo()) { |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4450 } | 4403 } |
4451 | 4404 |
4452 return Runtime::ForceSetObjectProperty(isolate, | 4405 return Runtime::ForceSetObjectProperty(isolate, |
4453 js_object, | 4406 js_object, |
4454 name, | 4407 name, |
4455 obj_value, | 4408 obj_value, |
4456 attr); | 4409 attr); |
4457 } | 4410 } |
4458 | 4411 |
4459 | 4412 |
4460 // Special case for elements if any of the flags are true. | |
4461 // If elements are in fast case we always implicitly assume that: | |
4462 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false. | |
4463 static MaybeObject* NormalizeObjectSetElement(Isolate* isolate, | |
4464 Handle<JSObject> js_object, | |
4465 uint32_t index, | |
4466 Handle<Object> value, | |
4467 PropertyAttributes attr) { | |
4468 // Normalize the elements to enable attributes on the property. | |
4469 Handle<SeededNumberDictionary> dictionary = | |
4470 JSObject::NormalizeElements(js_object); | |
4471 // Make sure that we never go back to fast case. | |
4472 dictionary->set_requires_slow_elements(); | |
4473 PropertyDetails details = PropertyDetails(attr, NORMAL); | |
4474 Handle<SeededNumberDictionary> extended_dictionary = | |
4475 SeededNumberDictionary::Set(dictionary, index, value, details); | |
4476 if (*extended_dictionary != *dictionary) { | |
4477 js_object->set_elements(*extended_dictionary); | |
4478 } | |
4479 return *value; | |
4480 } | |
4481 | |
4482 | |
4483 MaybeObject* Runtime::SetObjectProperty(Isolate* isolate, | 4413 MaybeObject* Runtime::SetObjectProperty(Isolate* isolate, |
4484 Handle<Object> object, | 4414 Handle<Object> object, |
4485 Handle<Object> key, | 4415 Handle<Object> key, |
4486 Handle<Object> value, | 4416 Handle<Object> value, |
4487 PropertyAttributes attr, | 4417 PropertyAttributes attr, |
4488 StrictModeFlag strict_mode) { | 4418 StrictModeFlag strict_mode) { |
| 4419 SetPropertyMode set_mode = attr == NONE ? SET_PROPERTY : DEFINE_PROPERTY; |
4489 HandleScope scope(isolate); | 4420 HandleScope scope(isolate); |
4490 | 4421 |
4491 if (object->IsUndefined() || object->IsNull()) { | 4422 if (object->IsUndefined() || object->IsNull()) { |
4492 Handle<Object> args[2] = { key, object }; | 4423 Handle<Object> args[2] = { key, object }; |
4493 Handle<Object> error = | 4424 Handle<Object> error = |
4494 isolate->factory()->NewTypeError("non_object_property_store", | 4425 isolate->factory()->NewTypeError("non_object_property_store", |
4495 HandleVector(args, 2)); | 4426 HandleVector(args, 2)); |
4496 return isolate->Throw(*error); | 4427 return isolate->Throw(*error); |
4497 } | 4428 } |
4498 | 4429 |
(...skipping 17 matching lines...) Expand all Loading... |
4516 // of a string using [] notation. We need to support this too in | 4447 // of a string using [] notation. We need to support this too in |
4517 // JavaScript. | 4448 // JavaScript. |
4518 // In the case of a String object we just need to redirect the assignment to | 4449 // In the case of a String object we just need to redirect the assignment to |
4519 // the underlying string if the index is in range. Since the underlying | 4450 // the underlying string if the index is in range. Since the underlying |
4520 // string does nothing with the assignment then we can ignore such | 4451 // string does nothing with the assignment then we can ignore such |
4521 // assignments. | 4452 // assignments. |
4522 if (js_object->IsStringObjectWithCharacterAt(index)) { | 4453 if (js_object->IsStringObjectWithCharacterAt(index)) { |
4523 return *value; | 4454 return *value; |
4524 } | 4455 } |
4525 | 4456 |
4526 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) { | 4457 Handle<Object> result = JSObject::SetElement( |
4527 return NormalizeObjectSetElement(isolate, js_object, index, value, attr); | 4458 js_object, index, value, attr, strict_mode, set_mode); |
4528 } | |
4529 | |
4530 Handle<Object> result = | |
4531 JSObject::SetElement(js_object, index, value, strict_mode); | |
4532 if (result.is_null()) return Failure::Exception(); | 4459 if (result.is_null()) return Failure::Exception(); |
4533 return *value; | 4460 return *value; |
4534 } | 4461 } |
4535 | 4462 |
4536 if (key->IsString()) { | 4463 if (key->IsString()) { |
4537 Handle<Object> result; | 4464 Handle<Object> result; |
4538 if (Handle<String>::cast(key)->AsArrayIndex(&index)) { | 4465 if (Handle<String>::cast(key)->AsArrayIndex(&index)) { |
4539 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) { | 4466 result = JSObject::SetElement( |
4540 return NormalizeObjectSetElement(isolate, | 4467 js_object, index, value, attr, strict_mode, set_mode); |
4541 js_object, | |
4542 index, | |
4543 value, | |
4544 attr); | |
4545 } | |
4546 result = | |
4547 JSObject::SetElement(js_object, index, value, strict_mode); | |
4548 } else { | 4468 } else { |
4549 Handle<String> key_string = Handle<String>::cast(key); | 4469 Handle<String> key_string = Handle<String>::cast(key); |
4550 key_string->TryFlatten(); | 4470 key_string->TryFlatten(); |
4551 result = JSReceiver::SetProperty( | 4471 result = JSReceiver::SetProperty( |
4552 js_object, key_string, value, attr, strict_mode); | 4472 js_object, key_string, value, attr, strict_mode); |
4553 } | 4473 } |
4554 if (result.is_null()) return Failure::Exception(); | 4474 if (result.is_null()) return Failure::Exception(); |
4555 return *value; | 4475 return *value; |
4556 } | 4476 } |
4557 | 4477 |
4558 // Call-back into JavaScript to convert the key to a string. | 4478 // Call-back into JavaScript to convert the key to a string. |
4559 bool has_pending_exception = false; | 4479 bool has_pending_exception = false; |
4560 Handle<Object> converted = Execution::ToString(key, &has_pending_exception); | 4480 Handle<Object> converted = Execution::ToString(key, &has_pending_exception); |
4561 if (has_pending_exception) return Failure::Exception(); | 4481 if (has_pending_exception) return Failure::Exception(); |
4562 Handle<String> name = Handle<String>::cast(converted); | 4482 Handle<String> name = Handle<String>::cast(converted); |
4563 | 4483 |
4564 if (name->AsArrayIndex(&index)) { | 4484 if (name->AsArrayIndex(&index)) { |
4565 return js_object->SetElement(index, *value, strict_mode, true); | 4485 return js_object->SetElement( |
| 4486 index, *value, attr, strict_mode, true, set_mode); |
4566 } else { | 4487 } else { |
4567 return js_object->SetProperty(*name, *value, attr, strict_mode); | 4488 return js_object->SetProperty(*name, *value, attr, strict_mode); |
4568 } | 4489 } |
4569 } | 4490 } |
4570 | 4491 |
4571 | 4492 |
4572 MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate, | 4493 MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate, |
4573 Handle<JSObject> js_object, | 4494 Handle<JSObject> js_object, |
4574 Handle<Object> key, | 4495 Handle<Object> key, |
4575 Handle<Object> value, | 4496 Handle<Object> value, |
4576 PropertyAttributes attr) { | 4497 PropertyAttributes attr) { |
4577 HandleScope scope(isolate); | 4498 HandleScope scope(isolate); |
4578 | 4499 |
4579 // Check if the given key is an array index. | 4500 // Check if the given key is an array index. |
4580 uint32_t index; | 4501 uint32_t index; |
4581 if (key->ToArrayIndex(&index)) { | 4502 if (key->ToArrayIndex(&index)) { |
4582 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters | 4503 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters |
4583 // of a string using [] notation. We need to support this too in | 4504 // of a string using [] notation. We need to support this too in |
4584 // JavaScript. | 4505 // JavaScript. |
4585 // In the case of a String object we just need to redirect the assignment to | 4506 // In the case of a String object we just need to redirect the assignment to |
4586 // the underlying string if the index is in range. Since the underlying | 4507 // the underlying string if the index is in range. Since the underlying |
4587 // string does nothing with the assignment then we can ignore such | 4508 // string does nothing with the assignment then we can ignore such |
4588 // assignments. | 4509 // assignments. |
4589 if (js_object->IsStringObjectWithCharacterAt(index)) { | 4510 if (js_object->IsStringObjectWithCharacterAt(index)) { |
4590 return *value; | 4511 return *value; |
4591 } | 4512 } |
4592 | 4513 |
4593 return js_object->SetElement(index, *value, kNonStrictMode, true); | 4514 return js_object->SetElement( |
| 4515 index, *value, attr, kNonStrictMode, false, DEFINE_PROPERTY); |
4594 } | 4516 } |
4595 | 4517 |
4596 if (key->IsString()) { | 4518 if (key->IsString()) { |
4597 if (Handle<String>::cast(key)->AsArrayIndex(&index)) { | 4519 if (Handle<String>::cast(key)->AsArrayIndex(&index)) { |
4598 return js_object->SetElement(index, *value, kNonStrictMode, true); | 4520 return js_object->SetElement( |
| 4521 index, *value, attr, kNonStrictMode, false, DEFINE_PROPERTY); |
4599 } else { | 4522 } else { |
4600 Handle<String> key_string = Handle<String>::cast(key); | 4523 Handle<String> key_string = Handle<String>::cast(key); |
4601 key_string->TryFlatten(); | 4524 key_string->TryFlatten(); |
4602 return js_object->SetLocalPropertyIgnoreAttributes(*key_string, | 4525 return js_object->SetLocalPropertyIgnoreAttributes(*key_string, |
4603 *value, | 4526 *value, |
4604 attr); | 4527 attr); |
4605 } | 4528 } |
4606 } | 4529 } |
4607 | 4530 |
4608 // Call-back into JavaScript to convert the key to a string. | 4531 // Call-back into JavaScript to convert the key to a string. |
4609 bool has_pending_exception = false; | 4532 bool has_pending_exception = false; |
4610 Handle<Object> converted = Execution::ToString(key, &has_pending_exception); | 4533 Handle<Object> converted = Execution::ToString(key, &has_pending_exception); |
4611 if (has_pending_exception) return Failure::Exception(); | 4534 if (has_pending_exception) return Failure::Exception(); |
4612 Handle<String> name = Handle<String>::cast(converted); | 4535 Handle<String> name = Handle<String>::cast(converted); |
4613 | 4536 |
4614 if (name->AsArrayIndex(&index)) { | 4537 if (name->AsArrayIndex(&index)) { |
4615 return js_object->SetElement(index, *value, kNonStrictMode, true); | 4538 return js_object->SetElement( |
| 4539 index, *value, attr, kNonStrictMode, false, DEFINE_PROPERTY); |
4616 } else { | 4540 } else { |
4617 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr); | 4541 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr); |
4618 } | 4542 } |
4619 } | 4543 } |
4620 | 4544 |
4621 | 4545 |
4622 MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate, | 4546 MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate, |
4623 Handle<JSReceiver> receiver, | 4547 Handle<JSReceiver> receiver, |
4624 Handle<Object> key) { | 4548 Handle<Object> key) { |
4625 HandleScope scope(isolate); | 4549 HandleScope scope(isolate); |
(...skipping 5683 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10309 return isolate->ThrowIllegalOperation(); | 10233 return isolate->ThrowIllegalOperation(); |
10310 } | 10234 } |
10311 | 10235 |
10312 Handle<JSObject> jsobject = Handle<JSObject>::cast(object); | 10236 Handle<JSObject> jsobject = Handle<JSObject>::cast(object); |
10313 Handle<Object> tmp1 = Object::GetElement(jsobject, index1); | 10237 Handle<Object> tmp1 = Object::GetElement(jsobject, index1); |
10314 RETURN_IF_EMPTY_HANDLE(isolate, tmp1); | 10238 RETURN_IF_EMPTY_HANDLE(isolate, tmp1); |
10315 Handle<Object> tmp2 = Object::GetElement(jsobject, index2); | 10239 Handle<Object> tmp2 = Object::GetElement(jsobject, index2); |
10316 RETURN_IF_EMPTY_HANDLE(isolate, tmp2); | 10240 RETURN_IF_EMPTY_HANDLE(isolate, tmp2); |
10317 | 10241 |
10318 RETURN_IF_EMPTY_HANDLE( | 10242 RETURN_IF_EMPTY_HANDLE( |
10319 isolate, JSObject::SetElement(jsobject, index1, tmp2, kStrictMode)); | 10243 isolate, JSObject::SetElement(jsobject, index1, tmp2, NONE, kStrictMode)); |
10320 RETURN_IF_EMPTY_HANDLE( | 10244 RETURN_IF_EMPTY_HANDLE( |
10321 isolate, JSObject::SetElement(jsobject, index2, tmp1, kStrictMode)); | 10245 isolate, JSObject::SetElement(jsobject, index2, tmp1, NONE, kStrictMode)); |
10322 | 10246 |
10323 return isolate->heap()->undefined_value(); | 10247 return isolate->heap()->undefined_value(); |
10324 } | 10248 } |
10325 | 10249 |
10326 | 10250 |
10327 // Returns an array that tells you where in the [0, length) interval an array | 10251 // Returns an array that tells you where in the [0, length) interval an array |
10328 // might have elements. Can either return keys (positive integers) or | 10252 // might have elements. Can either return keys (positive integers) or |
10329 // intervals (pair of a negative integer (-start-1) followed by a | 10253 // intervals (pair of a negative integer (-start-1) followed by a |
10330 // positive (length)) or undefined values. | 10254 // positive (length)) or undefined values. |
10331 // Intervals can span over some keys that are not in the object. | 10255 // Intervals can span over some keys that are not in the object. |
(...skipping 3357 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
13689 // Handle last resort GC and make sure to allow future allocations | 13613 // Handle last resort GC and make sure to allow future allocations |
13690 // to grow the heap without causing GCs (if possible). | 13614 // to grow the heap without causing GCs (if possible). |
13691 isolate->counters()->gc_last_resort_from_js()->Increment(); | 13615 isolate->counters()->gc_last_resort_from_js()->Increment(); |
13692 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, | 13616 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, |
13693 "Runtime::PerformGC"); | 13617 "Runtime::PerformGC"); |
13694 } | 13618 } |
13695 } | 13619 } |
13696 | 13620 |
13697 | 13621 |
13698 } } // namespace v8::internal | 13622 } } // namespace v8::internal |
OLD | NEW |