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