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 2841 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2852 *value, | 2852 *value, |
2853 result->holder(), | 2853 result->holder(), |
2854 strict_mode); | 2854 strict_mode); |
2855 } | 2855 } |
2856 case INTERCEPTOR: | 2856 case INTERCEPTOR: |
2857 return self->SetPropertyWithInterceptor(*name, | 2857 return self->SetPropertyWithInterceptor(*name, |
2858 *value, | 2858 *value, |
2859 attributes, | 2859 attributes, |
2860 strict_mode); | 2860 strict_mode); |
2861 case TRANSITION: { | 2861 case TRANSITION: { |
2862 Object* transition = result->GetTransitionValue(); | 2862 Map* transition_map = result->GetTransitionTarget(); |
2863 | 2863 |
2864 if (transition->IsAccessorPair()) { | |
2865 ASSERT(!AccessorPair::cast(transition)->ContainsAccessor()); | |
2866 return ConvertDescriptorToField(*name, *value, attributes); | |
2867 } | |
2868 | |
2869 Map* transition_map = Map::cast(transition); | |
2870 DescriptorArray* descriptors = transition_map->instance_descriptors(); | 2864 DescriptorArray* descriptors = transition_map->instance_descriptors(); |
2871 int descriptor = descriptors->LastAdded(); | 2865 int descriptor = descriptors->LastAdded(); |
2872 PropertyDetails details = descriptors->GetDetails(descriptor); | 2866 PropertyDetails details = descriptors->GetDetails(descriptor); |
2873 ASSERT(details.type() == FIELD || details.type() == CONSTANT_FUNCTION); | |
2874 | 2867 |
2875 if (details.type() == FIELD) { | 2868 if (details.type() == FIELD) { |
2876 if (attributes == details.attributes()) { | 2869 if (attributes == details.attributes()) { |
2877 int field_index = descriptors->GetFieldIndex(descriptor); | 2870 int field_index = descriptors->GetFieldIndex(descriptor); |
2878 return self->AddFastPropertyUsingMap(transition_map, | 2871 return self->AddFastPropertyUsingMap(transition_map, |
2879 *name, | 2872 *name, |
2880 *value, | 2873 *value, |
2881 field_index); | 2874 field_index); |
2882 } | 2875 } |
2883 return self->ConvertDescriptorToField(*name, *value, attributes); | 2876 return self->ConvertDescriptorToField(*name, *value, attributes); |
| 2877 } else if (details.type() == CALLBACKS) { |
| 2878 return ConvertDescriptorToField(*name, *value, attributes); |
2884 } | 2879 } |
2885 | 2880 |
2886 // Is transition to CONSTANT_FUNCTION. | 2881 ASSERT(details.type() == CONSTANT_FUNCTION); |
| 2882 |
2887 Object* constant_function = descriptors->GetValue(descriptor); | 2883 Object* constant_function = descriptors->GetValue(descriptor); |
2888 // If the same constant function is being added we can simply | 2884 // If the same constant function is being added we can simply |
2889 // transition to the target map. | 2885 // transition to the target map. |
2890 if (constant_function == *value) { | 2886 if (constant_function == *value) { |
2891 self->set_map(transition_map); | 2887 self->set_map(transition_map); |
2892 return constant_function; | 2888 return constant_function; |
2893 } | 2889 } |
2894 // Otherwise, replace with a map transition to a new map with a FIELD, | 2890 // Otherwise, replace with a map transition to a new map with a FIELD, |
2895 // even if the value is a constant function. | 2891 // even if the value is a constant function. |
2896 return ConvertTransitionToMapTransition( | 2892 return ConvertTransitionToMapTransition( |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2976 // Only replace the function if necessary. | 2972 // Only replace the function if necessary. |
2977 if (value == result.GetConstantFunction()) return value; | 2973 if (value == result.GetConstantFunction()) return value; |
2978 // Preserve the attributes of this existing property. | 2974 // Preserve the attributes of this existing property. |
2979 attributes = result.GetAttributes(); | 2975 attributes = result.GetAttributes(); |
2980 return ConvertDescriptorToField(name, value, attributes); | 2976 return ConvertDescriptorToField(name, value, attributes); |
2981 case CALLBACKS: | 2977 case CALLBACKS: |
2982 case INTERCEPTOR: | 2978 case INTERCEPTOR: |
2983 // Override callback in clone | 2979 // Override callback in clone |
2984 return ConvertDescriptorToField(name, value, attributes); | 2980 return ConvertDescriptorToField(name, value, attributes); |
2985 case TRANSITION: { | 2981 case TRANSITION: { |
2986 Object* transition = result.GetTransitionValue(); | 2982 Map* transition_map = result.GetTransitionTarget(); |
2987 | 2983 |
2988 if (transition->IsAccessorPair()) { | |
2989 ASSERT(!AccessorPair::cast(transition)->ContainsAccessor()); | |
2990 return ConvertDescriptorToField(name, value, attributes); | |
2991 } | |
2992 | |
2993 Map* transition_map = Map::cast(transition); | |
2994 DescriptorArray* descriptors = transition_map->instance_descriptors(); | 2984 DescriptorArray* descriptors = transition_map->instance_descriptors(); |
2995 int descriptor = descriptors->LastAdded(); | 2985 int descriptor = descriptors->LastAdded(); |
2996 PropertyDetails details = descriptors->GetDetails(descriptor); | 2986 PropertyDetails details = descriptors->GetDetails(descriptor); |
2997 ASSERT(details.type() == FIELD || details.type() == CONSTANT_FUNCTION); | |
2998 | 2987 |
2999 if (details.type() == FIELD) { | 2988 if (details.type() == FIELD) { |
3000 if (attributes == details.attributes()) { | 2989 if (attributes == details.attributes()) { |
3001 int field_index = descriptors->GetFieldIndex(descriptor); | 2990 int field_index = descriptors->GetFieldIndex(descriptor); |
3002 return AddFastPropertyUsingMap(transition_map, | 2991 return AddFastPropertyUsingMap(transition_map, |
3003 name, | 2992 name, |
3004 value, | 2993 value, |
3005 field_index); | 2994 field_index); |
3006 } | 2995 } |
3007 return ConvertDescriptorToField(name, value, attributes); | 2996 return ConvertDescriptorToField(name, value, attributes); |
| 2997 } else if (details.type() == CALLBACKS) { |
| 2998 return ConvertDescriptorToField(name, value, attributes); |
3008 } | 2999 } |
3009 | 3000 |
3010 // Was transition to CONSTANT_FUNCTION. Replace with a map transition to a | 3001 ASSERT(details.type() == CONSTANT_FUNCTION); |
3011 // new map with a FIELD, even if the value is a function. | 3002 |
| 3003 // Replace transition to CONSTANT FUNCTION with a map transition to a new |
| 3004 // map with a FIELD, even if the value is a function. |
3012 return ConvertTransitionToMapTransition( | 3005 return ConvertTransitionToMapTransition( |
3013 result.GetTransitionIndex(), name, value, attributes); | 3006 result.GetTransitionIndex(), name, value, attributes); |
3014 } | 3007 } |
3015 case HANDLER: | 3008 case HANDLER: |
3016 case NONEXISTENT: | 3009 case NONEXISTENT: |
3017 UNREACHABLE(); | 3010 UNREACHABLE(); |
3018 } | 3011 } |
3019 UNREACHABLE(); // keep the compiler happy | 3012 UNREACHABLE(); // keep the compiler happy |
3020 return value; | 3013 return value; |
3021 } | 3014 } |
(...skipping 265 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3287 PropertyDetails d = | 3280 PropertyDetails d = |
3288 PropertyDetails(details.attributes(), NORMAL, details.index()); | 3281 PropertyDetails(details.attributes(), NORMAL, details.index()); |
3289 Object* value = FastPropertyAt(descs->GetFieldIndex(i)); | 3282 Object* value = FastPropertyAt(descs->GetFieldIndex(i)); |
3290 MaybeObject* maybe_dictionary = | 3283 MaybeObject* maybe_dictionary = |
3291 dictionary->Add(descs->GetKey(i), value, d); | 3284 dictionary->Add(descs->GetKey(i), value, d); |
3292 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary; | 3285 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary; |
3293 break; | 3286 break; |
3294 } | 3287 } |
3295 case CALLBACKS: { | 3288 case CALLBACKS: { |
3296 Object* value = descs->GetCallbacksObject(i); | 3289 Object* value = descs->GetCallbacksObject(i); |
3297 if (value->IsAccessorPair()) { | |
3298 MaybeObject* maybe_copy = | |
3299 AccessorPair::cast(value)->CopyWithoutTransitions(); | |
3300 if (!maybe_copy->To(&value)) return maybe_copy; | |
3301 } | |
3302 MaybeObject* maybe_dictionary = | 3290 MaybeObject* maybe_dictionary = |
3303 dictionary->Add(descs->GetKey(i), value, details); | 3291 dictionary->Add(descs->GetKey(i), value, details); |
3304 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary; | 3292 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary; |
3305 break; | 3293 break; |
3306 } | 3294 } |
3307 case INTERCEPTOR: | 3295 case INTERCEPTOR: |
3308 break; | 3296 break; |
3309 case HANDLER: | 3297 case HANDLER: |
3310 case NORMAL: | 3298 case NORMAL: |
3311 case TRANSITION: | 3299 case TRANSITION: |
(...skipping 912 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4224 } | 4212 } |
4225 | 4213 |
4226 | 4214 |
4227 // Search object and its prototype chain for callback properties. | 4215 // Search object and its prototype chain for callback properties. |
4228 void JSObject::LookupCallback(String* name, LookupResult* result) { | 4216 void JSObject::LookupCallback(String* name, LookupResult* result) { |
4229 Heap* heap = GetHeap(); | 4217 Heap* heap = GetHeap(); |
4230 for (Object* current = this; | 4218 for (Object* current = this; |
4231 current != heap->null_value() && current->IsJSObject(); | 4219 current != heap->null_value() && current->IsJSObject(); |
4232 current = JSObject::cast(current)->GetPrototype()) { | 4220 current = JSObject::cast(current)->GetPrototype()) { |
4233 JSObject::cast(current)->LocalLookupRealNamedProperty(name, result); | 4221 JSObject::cast(current)->LocalLookupRealNamedProperty(name, result); |
4234 if (result->IsCallbacks()) return; | 4222 if (result->IsPropertyCallbacks()) return; |
4235 } | 4223 } |
4236 result->NotFound(); | 4224 result->NotFound(); |
4237 } | 4225 } |
4238 | 4226 |
4239 | 4227 |
4240 // Try to update an accessor in an elements dictionary. Return true if the | 4228 // Try to update an accessor in an elements dictionary. Return true if the |
4241 // update succeeded, and false otherwise. | 4229 // update succeeded, and false otherwise. |
4242 static bool UpdateGetterSetterInDictionary( | 4230 static bool UpdateGetterSetterInDictionary( |
4243 SeededNumberDictionary* dictionary, | 4231 SeededNumberDictionary* dictionary, |
4244 uint32_t index, | 4232 uint32_t index, |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4336 LocalLookupRealNamedProperty(name, &result); | 4324 LocalLookupRealNamedProperty(name, &result); |
4337 if (result.IsPropertyCallbacks()) { | 4325 if (result.IsPropertyCallbacks()) { |
4338 // Note that the result can actually have IsDontDelete() == true when we | 4326 // Note that the result can actually have IsDontDelete() == true when we |
4339 // e.g. have to fall back to the slow case while adding a setter after | 4327 // e.g. have to fall back to the slow case while adding a setter after |
4340 // successfully reusing a map transition for a getter. Nevertheless, this is | 4328 // successfully reusing a map transition for a getter. Nevertheless, this is |
4341 // OK, because the assertion only holds for the whole addition of both | 4329 // OK, because the assertion only holds for the whole addition of both |
4342 // accessors, not for the addition of each part. See first comment in | 4330 // accessors, not for the addition of each part. See first comment in |
4343 // DefinePropertyAccessor below. | 4331 // DefinePropertyAccessor below. |
4344 Object* obj = result.GetCallbackObject(); | 4332 Object* obj = result.GetCallbackObject(); |
4345 if (obj->IsAccessorPair()) { | 4333 if (obj->IsAccessorPair()) { |
4346 return AccessorPair::cast(obj)->CopyWithoutTransitions(); | 4334 return AccessorPair::cast(obj)->Copy(); |
4347 } | 4335 } |
4348 } | 4336 } |
4349 return GetHeap()->AllocateAccessorPair(); | 4337 return GetHeap()->AllocateAccessorPair(); |
4350 } | 4338 } |
4351 | 4339 |
4352 | 4340 |
4353 MaybeObject* JSObject::DefinePropertyAccessor(String* name, | 4341 MaybeObject* JSObject::DefinePropertyAccessor(String* name, |
4354 Object* getter, | 4342 Object* getter, |
4355 Object* setter, | 4343 Object* setter, |
4356 PropertyAttributes attributes) { | 4344 PropertyAttributes attributes) { |
(...skipping 13 matching lines...) Expand all Loading... |
4370 setterOk = DefineFastAccessor(name, ACCESSOR_SETTER, setter, attributes); | 4358 setterOk = DefineFastAccessor(name, ACCESSOR_SETTER, setter, attributes); |
4371 if (setterOk->IsFailure()) return setterOk; | 4359 if (setterOk->IsFailure()) return setterOk; |
4372 } | 4360 } |
4373 | 4361 |
4374 if (getterOk != heap->null_value() && setterOk != heap->null_value()) { | 4362 if (getterOk != heap->null_value() && setterOk != heap->null_value()) { |
4375 return heap->undefined_value(); | 4363 return heap->undefined_value(); |
4376 } | 4364 } |
4377 } | 4365 } |
4378 | 4366 |
4379 AccessorPair* accessors; | 4367 AccessorPair* accessors; |
4380 { MaybeObject* maybe_accessors = CreateAccessorPairFor(name); | 4368 MaybeObject* maybe_accessors = CreateAccessorPairFor(name); |
4381 if (!maybe_accessors->To(&accessors)) return maybe_accessors; | 4369 if (!maybe_accessors->To(&accessors)) return maybe_accessors; |
4382 } | 4370 |
4383 accessors->SetComponents(getter, setter); | 4371 accessors->SetComponents(getter, setter); |
4384 return SetPropertyCallback(name, accessors, attributes); | 4372 return SetPropertyCallback(name, accessors, attributes); |
4385 } | 4373 } |
4386 | 4374 |
4387 | 4375 |
4388 bool JSObject::CanSetCallback(String* name) { | 4376 bool JSObject::CanSetCallback(String* name) { |
4389 ASSERT(!IsAccessCheckNeeded() || | 4377 ASSERT(!IsAccessCheckNeeded() || |
4390 GetIsolate()->MayNamedAccess(this, name, v8::ACCESS_SET)); | 4378 GetIsolate()->MayNamedAccess(this, name, v8::ACCESS_SET)); |
4391 | 4379 |
4392 // Check if there is an API defined callback object which prohibits | 4380 // Check if there is an API defined callback object which prohibits |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4444 } | 4432 } |
4445 | 4433 |
4446 return GetHeap()->undefined_value(); | 4434 return GetHeap()->undefined_value(); |
4447 } | 4435 } |
4448 | 4436 |
4449 | 4437 |
4450 MaybeObject* JSObject::SetPropertyCallback(String* name, | 4438 MaybeObject* JSObject::SetPropertyCallback(String* name, |
4451 Object* structure, | 4439 Object* structure, |
4452 PropertyAttributes attributes) { | 4440 PropertyAttributes attributes) { |
4453 // Normalize object to make this operation simple. | 4441 // Normalize object to make this operation simple. |
4454 { MaybeObject* maybe_ok = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); | 4442 MaybeObject* maybe_ok = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); |
4455 if (maybe_ok->IsFailure()) return maybe_ok; | 4443 if (maybe_ok->IsFailure()) return maybe_ok; |
4456 } | |
4457 | 4444 |
4458 // For the global object allocate a new map to invalidate the global inline | 4445 // For the global object allocate a new map to invalidate the global inline |
4459 // caches which have a global property cell reference directly in the code. | 4446 // caches which have a global property cell reference directly in the code. |
4460 if (IsGlobalObject()) { | 4447 if (IsGlobalObject()) { |
4461 Map* new_map; | 4448 Map* new_map; |
4462 { MaybeObject* maybe_new_map = map()->CopyDropDescriptors(); | 4449 MaybeObject* maybe_new_map = map()->CopyDropDescriptors(); |
4463 if (!maybe_new_map->To(&new_map)) return maybe_new_map; | 4450 if (!maybe_new_map->To(&new_map)) return maybe_new_map; |
4464 } | 4451 |
4465 set_map(new_map); | 4452 set_map(new_map); |
4466 // When running crankshaft, changing the map is not enough. We | 4453 // When running crankshaft, changing the map is not enough. We |
4467 // need to deoptimize all functions that rely on this global | 4454 // need to deoptimize all functions that rely on this global |
4468 // object. | 4455 // object. |
4469 Deoptimizer::DeoptimizeGlobalObject(this); | 4456 Deoptimizer::DeoptimizeGlobalObject(this); |
4470 } | 4457 } |
4471 | 4458 |
4472 // Update the dictionary with the new CALLBACKS property. | 4459 // Update the dictionary with the new CALLBACKS property. |
4473 PropertyDetails details = PropertyDetails(attributes, CALLBACKS); | 4460 PropertyDetails details = PropertyDetails(attributes, CALLBACKS); |
4474 { MaybeObject* maybe_ok = SetNormalizedProperty(name, structure, details); | 4461 maybe_ok = SetNormalizedProperty(name, structure, details); |
4475 if (maybe_ok->IsFailure()) return maybe_ok; | 4462 if (maybe_ok->IsFailure()) return maybe_ok; |
4476 } | |
4477 | 4463 |
4478 return GetHeap()->undefined_value(); | 4464 return GetHeap()->undefined_value(); |
4479 } | 4465 } |
4480 | 4466 |
4481 | 4467 |
4482 void JSObject::DefineAccessor(Handle<JSObject> object, | 4468 void JSObject::DefineAccessor(Handle<JSObject> object, |
4483 Handle<String> name, | 4469 Handle<String> name, |
4484 Handle<Object> getter, | 4470 Handle<Object> getter, |
4485 Handle<Object> setter, | 4471 Handle<Object> setter, |
4486 PropertyAttributes attributes) { | 4472 PropertyAttributes attributes) { |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4518 | 4504 |
4519 if (!CanSetCallback(name)) return isolate->heap()->undefined_value(); | 4505 if (!CanSetCallback(name)) return isolate->heap()->undefined_value(); |
4520 | 4506 |
4521 uint32_t index = 0; | 4507 uint32_t index = 0; |
4522 return name->AsArrayIndex(&index) ? | 4508 return name->AsArrayIndex(&index) ? |
4523 DefineElementAccessor(index, getter, setter, attributes) : | 4509 DefineElementAccessor(index, getter, setter, attributes) : |
4524 DefinePropertyAccessor(name, getter, setter, attributes); | 4510 DefinePropertyAccessor(name, getter, setter, attributes); |
4525 } | 4511 } |
4526 | 4512 |
4527 | 4513 |
4528 static MaybeObject* CreateFreshAccessor(JSObject* obj, | 4514 static MaybeObject* TryAccessorTransition(JSObject* self, |
4529 String* name, | 4515 Map* transitioned_map, |
4530 AccessorComponent component, | 4516 String* name, |
4531 Object* accessor, | 4517 AccessorComponent component, |
4532 PropertyAttributes attributes) { | 4518 Object* accessor, |
4533 // step 1: create a new getter/setter pair with only the accessor in it | 4519 PropertyAttributes attributes) { |
4534 Heap* heap = obj->GetHeap(); | 4520 DescriptorArray* descs = transitioned_map->instance_descriptors(); |
4535 AccessorPair* accessors2; | 4521 int number = descs->LastAdded(); |
4536 { MaybeObject* maybe_accessors2 = heap->AllocateAccessorPair(); | 4522 PropertyDetails details = descs->GetDetails(number); |
4537 if (!maybe_accessors2->To(&accessors2)) return maybe_accessors2; | |
4538 } | |
4539 accessors2->set(component, accessor); | |
4540 | 4523 |
4541 // step 2: create a copy of the descriptors, incl. the new getter/setter pair | 4524 // If the transition target was not callbacks, fall back to the slow case. |
4542 Map* map1 = obj->map(); | 4525 if (details.type() != CALLBACKS) return self->GetHeap()->null_value(); |
4543 CallbacksDescriptor callbacks_descr2(name, accessors2, attributes, 0); | 4526 |
4544 DescriptorArray* descriptors2; | 4527 Object* target_accessor = |
4545 { MaybeObject* maybe_descriptors2 = | 4528 AccessorPair::cast(descs->GetCallbacksObject(number))->get(component); |
4546 map1->instance_descriptors()->CopyAdd(&callbacks_descr2); | 4529 PropertyAttributes target_attributes = details.attributes(); |
4547 if (!maybe_descriptors2->To(&descriptors2)) return maybe_descriptors2; | 4530 |
| 4531 // Reuse transition if adding same accessor with same attributes. |
| 4532 if (target_accessor == accessor && target_attributes == attributes) { |
| 4533 self->set_map(transitioned_map); |
| 4534 return self; |
4548 } | 4535 } |
4549 | 4536 |
4550 // step 3: create a new map with the new descriptors | 4537 // If either not the same accessor, or not the same attributes, fall back to |
4551 Map* map2; | 4538 // the slow case. |
4552 { MaybeObject* maybe_map2 = map1->CopyReplaceDescriptors(descriptors2); | 4539 return self->GetHeap()->null_value(); |
4553 if (!maybe_map2->To(&map2)) return maybe_map2; | |
4554 } | |
4555 | |
4556 // step 4: create a new getter/setter pair with a transition to the new map | |
4557 AccessorPair* accessors1; | |
4558 { MaybeObject* maybe_accessors1 = heap->AllocateAccessorPair(); | |
4559 if (!maybe_accessors1->To(&accessors1)) return maybe_accessors1; | |
4560 } | |
4561 accessors1->set(component, map2); | |
4562 | |
4563 // step 5: create a copy of the descriptors, incl. the new getter/setter pair | |
4564 // with the transition | |
4565 TransitionArray* new_transitions; | |
4566 { MaybeObject* maybe_new_transitions = map1->AddTransition(name, accessors1); | |
4567 if (!maybe_new_transitions->To(&new_transitions)) { | |
4568 return maybe_new_transitions; | |
4569 } | |
4570 } | |
4571 | |
4572 // step 6: everything went well so far, so we make our changes visible | |
4573 { MaybeObject* transition_added = map1->set_transitions(new_transitions); | |
4574 if (transition_added->IsFailure()) return transition_added; | |
4575 } | |
4576 | |
4577 map2->SetBackPointer(map1); | |
4578 obj->set_map(map2); | |
4579 return obj; | |
4580 } | 4540 } |
4581 | 4541 |
4582 | 4542 |
4583 static bool TransitionToSameAccessor(Object* map, | |
4584 String* name, | |
4585 AccessorComponent component, | |
4586 Object* accessor, | |
4587 PropertyAttributes attributes ) { | |
4588 Map* transitioned_map = Map::cast(map); | |
4589 DescriptorArray* descs = transitioned_map->instance_descriptors(); | |
4590 int number = descs->LastAdded(); | |
4591 Object* target_accessor = | |
4592 AccessorPair::cast(descs->GetCallbacksObject(number))->get(component); | |
4593 PropertyAttributes target_attributes = descs->GetDetails(number).attributes(); | |
4594 return target_accessor == accessor && target_attributes == attributes; | |
4595 } | |
4596 | |
4597 | |
4598 static MaybeObject* NewCallbackTransition(JSObject* obj, | 4543 static MaybeObject* NewCallbackTransition(JSObject* obj, |
4599 String* name, | 4544 String* name, |
4600 AccessorComponent component, | 4545 AccessorComponent component, |
4601 Object* accessor, | 4546 Object* accessor, |
4602 PropertyAttributes attributes, | 4547 PropertyAttributes attributes, |
4603 AccessorPair* accessors2) { | 4548 AccessorPair* new_accessors) { |
4604 // step 1: copy the old getter/setter pair and set the new accessor | 4549 // step 1: create a copy of the descriptors, incl. the new getter/setter pair |
4605 AccessorPair* accessors3; | 4550 Map* old_map = obj->map(); |
4606 { MaybeObject* maybe_accessors3 = accessors2->CopyWithoutTransitions(); | 4551 CallbacksDescriptor new_accessors_desc(name, new_accessors, attributes); |
4607 if (!maybe_accessors3->To(&accessors3)) return maybe_accessors3; | 4552 DescriptorArray* descriptors; |
4608 } | 4553 MaybeObject* maybe_descriptors = |
4609 accessors3->set(component, accessor); | 4554 old_map->instance_descriptors()->CopyInsert(&new_accessors_desc); |
| 4555 if (!maybe_descriptors->To(&descriptors)) return maybe_descriptors; |
4610 | 4556 |
4611 // step 2: create a copy of the descriptors, incl. the new getter/setter pair | 4557 // step 2: create a new map with the new descriptors |
4612 Map* map2 = obj->map(); | 4558 Map* new_map; |
4613 CallbacksDescriptor callbacks_descr3(name, accessors3, attributes, 0); | 4559 MaybeObject* maybe_new_map = old_map->CopyReplaceDescriptors(descriptors); |
4614 DescriptorArray* descriptors3; | 4560 if (!maybe_new_map->To(&new_map)) return maybe_new_map; |
4615 { MaybeObject* maybe_descriptors3 = | |
4616 map2->instance_descriptors()->CopyInsert(&callbacks_descr3); | |
4617 if (!maybe_descriptors3->To(&descriptors3)) return maybe_descriptors3; | |
4618 } | |
4619 | 4561 |
4620 // step 3: create a new map with the new descriptors | 4562 // step 3: add a new transition to the new map |
4621 Map* map3; | 4563 TransitionArray* transitions; |
4622 { MaybeObject* maybe_map3 = map2->CopyReplaceDescriptors(descriptors3); | 4564 MaybeObject* maybe_transitions = old_map->AddTransition(name, new_map); |
4623 if (!maybe_map3->To(&map3)) return maybe_map3; | 4565 if (!maybe_transitions->To(&transitions)) return maybe_transitions; |
4624 } | |
4625 | 4566 |
4626 // step 4: add a new transition to the new map | 4567 // step 4: everything went well so far, so we make our changes visible |
4627 TransitionArray* new_transitions; | 4568 MaybeObject* transition_added = old_map->set_transitions(transitions); |
4628 { MaybeObject* maybe_transitions = map2->AddTransition(name, accessors2); | 4569 if (transition_added->IsFailure()) return transition_added; |
4629 if (!maybe_transitions->To(&new_transitions)) return maybe_transitions; | |
4630 } | |
4631 | 4570 |
4632 // step 5: everything went well so far, so we make our changes visible | 4571 new_map->SetBackPointer(old_map); |
4633 { MaybeObject* transition_added = map2->set_transitions(new_transitions); | 4572 obj->set_map(new_map); |
4634 if (transition_added->IsFailure()) return transition_added; | |
4635 } | |
4636 | |
4637 map3->SetBackPointer(map2); | |
4638 obj->set_map(map3); | |
4639 accessors2->set(component, map3); | |
4640 return obj; | 4573 return obj; |
4641 } | 4574 } |
4642 | 4575 |
4643 | 4576 |
4644 MaybeObject* JSObject::DefineFastAccessor(String* name, | 4577 MaybeObject* JSObject::DefineFastAccessor(String* name, |
4645 AccessorComponent component, | 4578 AccessorComponent component, |
4646 Object* accessor, | 4579 Object* accessor, |
4647 PropertyAttributes attributes) { | 4580 PropertyAttributes attributes) { |
4648 ASSERT(accessor->IsSpecFunction() || accessor->IsUndefined()); | 4581 ASSERT(accessor->IsSpecFunction() || accessor->IsUndefined()); |
4649 LookupResult result(GetIsolate()); | 4582 LookupResult result(GetIsolate()); |
4650 LocalLookup(name, &result); | 4583 LocalLookup(name, &result); |
4651 | 4584 |
4652 // If we have a new property, create a fresh accessor plus a transition to it. | 4585 if (result.IsFound() |
4653 if (!result.IsFound()) { | 4586 && !result.IsPropertyCallbacks() |
4654 return CreateFreshAccessor(this, name, component, accessor, attributes); | 4587 && !result.IsTransition()) return GetHeap()->null_value(); |
| 4588 |
| 4589 // Return success if the same accessor with the same attributes already exist. |
| 4590 AccessorPair* source_accessors = NULL; |
| 4591 if (result.IsPropertyCallbacks()) { |
| 4592 Object* callback_value = result.GetCallbackObject(); |
| 4593 if (callback_value->IsAccessorPair()) { |
| 4594 source_accessors = AccessorPair::cast(callback_value); |
| 4595 Object* entry = source_accessors->get(component); |
| 4596 if (entry == accessor && result.GetAttributes() == attributes) { |
| 4597 return this; |
| 4598 } |
| 4599 } |
4655 } | 4600 } |
4656 | 4601 |
4657 // If the property is not a JavaScript accessor, fall back to the slow case. | 4602 // If not, lookup a transition. |
4658 if (!result.IsCallbacks()) return GetHeap()->null_value(); | 4603 map()->LookupTransition(this, name, &result); |
4659 | 4604 |
4660 Object* callback_value = result.GetCallbackObject(); | 4605 // If there is a transition, try to follow it. |
4661 if (!callback_value->IsAccessorPair()) return GetHeap()->null_value(); | 4606 if (result.IsFound()) { |
4662 AccessorPair* accessors = AccessorPair::cast(callback_value); | 4607 Map* target = result.GetTransitionTarget(); |
4663 | 4608 return TryAccessorTransition( |
4664 // Follow a callback transition, if there is a fitting one. | 4609 this, target, name, component, accessor, attributes); |
4665 Object* entry = accessors->get(component); | |
4666 if (entry->IsMap() && | |
4667 TransitionToSameAccessor(entry, name, component, accessor, attributes)) { | |
4668 set_map(Map::cast(entry)); | |
4669 return this; | |
4670 } | 4610 } |
4671 | 4611 |
4672 if (entry == accessor && result.GetAttributes() == attributes) return this; | 4612 // If there is no transition yet, add a transition to the a new accessor pair |
| 4613 // containing the accessor. |
| 4614 AccessorPair* accessors; |
| 4615 MaybeObject* maybe_accessors; |
4673 | 4616 |
4674 // Only the other accessor has been set so far, create a new transition. | 4617 // Allocate a new pair if there were no source accessors. Otherwise, copy the |
4675 if (entry->IsTheHole()) { | 4618 // pair and modify the accessor. |
4676 return NewCallbackTransition(this, | 4619 if (source_accessors != NULL) { |
4677 name, | 4620 maybe_accessors = source_accessors->Copy(); |
4678 component, | 4621 } else { |
4679 accessor, | 4622 maybe_accessors = GetHeap()->AllocateAccessorPair(); |
4680 attributes, | |
4681 accessors); | |
4682 } | 4623 } |
| 4624 if (!maybe_accessors->To(&accessors)) return maybe_accessors; |
| 4625 accessors->set(component, accessor); |
4683 | 4626 |
4684 // Nothing from the above worked, so we have to fall back to the slow case. | 4627 return NewCallbackTransition(this, |
4685 return GetHeap()->null_value(); | 4628 name, |
| 4629 component, |
| 4630 accessor, |
| 4631 attributes, |
| 4632 accessors); |
4686 } | 4633 } |
4687 | 4634 |
4688 | 4635 |
4689 MaybeObject* JSObject::DefineAccessor(AccessorInfo* info) { | 4636 MaybeObject* JSObject::DefineAccessor(AccessorInfo* info) { |
4690 Isolate* isolate = GetIsolate(); | 4637 Isolate* isolate = GetIsolate(); |
4691 String* name = String::cast(info->name()); | 4638 String* name = String::cast(info->name()); |
4692 // Check access rights if needed. | 4639 // Check access rights if needed. |
4693 if (IsAccessCheckNeeded() && | 4640 if (IsAccessCheckNeeded() && |
4694 !isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) { | 4641 !isolate->MayNamedAccess(this, name, v8::ACCESS_SET)) { |
4695 isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET); | 4642 isolate->ReportFailedAccessCheck(this, v8::ACCESS_SET); |
(...skipping 309 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5005 ASSERT(!IsIterating()); | 4952 ASSERT(!IsIterating()); |
5006 *TransitionArrayHeader() = Smi::FromInt(0); | 4953 *TransitionArrayHeader() = Smi::FromInt(0); |
5007 } | 4954 } |
5008 | 4955 |
5009 bool IsIterating() { | 4956 bool IsIterating() { |
5010 return (*TransitionArrayHeader())->IsSmi(); | 4957 return (*TransitionArrayHeader())->IsSmi(); |
5011 } | 4958 } |
5012 | 4959 |
5013 Map* Next() { | 4960 Map* Next() { |
5014 ASSERT(IsIterating()); | 4961 ASSERT(IsIterating()); |
5015 // Attention, tricky index manipulation ahead: Two consecutive indices are | 4962 int index = Smi::cast(*TransitionArrayHeader())->value(); |
5016 // assigned to each descriptor. Most descriptors directly advance to the | |
5017 // next descriptor by adding 2 to the index. The exceptions are the | |
5018 // CALLBACKS entries: An even index means we look at its getter, and an odd | |
5019 // index means we look at its setter. | |
5020 int raw_index = Smi::cast(*TransitionArrayHeader())->value(); | |
5021 int index = raw_index / 2; | |
5022 int number_of_transitions = transition_array_->number_of_transitions(); | 4963 int number_of_transitions = transition_array_->number_of_transitions(); |
5023 while (index < number_of_transitions) { | 4964 while (index < number_of_transitions) { |
5024 Object* value = transition_array_->GetValue(index); | 4965 *TransitionArrayHeader() = Smi::FromInt(index + 1); |
5025 | 4966 return transition_array_->GetTarget(index); |
5026 if (value->IsMap()) { | |
5027 *TransitionArrayHeader() = Smi::FromInt(raw_index + 2); | |
5028 return static_cast<Map*>(value); | |
5029 } | |
5030 | |
5031 ASSERT(value->IsAccessorPair()); | |
5032 | |
5033 // We might have a map transition in a getter or in a setter. | |
5034 AccessorPair* accessors = static_cast<AccessorPair*>(value); | |
5035 Object* accessor; | |
5036 if ((raw_index & 1) == 0) { | |
5037 accessor = accessors->setter(); | |
5038 } else { | |
5039 ++index; | |
5040 accessor = accessors->getter(); | |
5041 } | |
5042 ++raw_index; | |
5043 if (accessor->IsMap()) { | |
5044 *TransitionArrayHeader() = Smi::FromInt(raw_index); | |
5045 return static_cast<Map*>(accessor); | |
5046 } | |
5047 } | 4967 } |
5048 | 4968 |
5049 if (index == transition_array_->number_of_transitions() && | 4969 if (index == number_of_transitions && |
5050 transition_array_->HasElementsTransition()) { | 4970 transition_array_->HasElementsTransition()) { |
5051 Map* elements_transition = transition_array_->elements_transition(); | 4971 Map* elements_transition = transition_array_->elements_transition(); |
5052 *TransitionArrayHeader() = Smi::FromInt(raw_index + 2); | 4972 *TransitionArrayHeader() = Smi::FromInt(index + 1); |
5053 return elements_transition; | 4973 return elements_transition; |
5054 } | 4974 } |
5055 *TransitionArrayHeader() = transition_array_->GetHeap()->fixed_array_map(); | 4975 *TransitionArrayHeader() = transition_array_->GetHeap()->fixed_array_map(); |
5056 return NULL; | 4976 return NULL; |
5057 } | 4977 } |
5058 | 4978 |
5059 private: | 4979 private: |
5060 Object** TransitionArrayHeader() { | 4980 Object** TransitionArrayHeader() { |
5061 return HeapObject::RawField(transition_array_, TransitionArray::kMapOffset); | 4981 return HeapObject::RawField(transition_array_, TransitionArray::kMapOffset); |
5062 } | 4982 } |
(...skipping 716 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5779 set(kLastAddedIndex, bridge_storage); | 5699 set(kLastAddedIndex, bridge_storage); |
5780 } | 5700 } |
5781 } | 5701 } |
5782 | 5702 |
5783 | 5703 |
5784 static bool InsertionPointFound(String* key1, String* key2) { | 5704 static bool InsertionPointFound(String* key1, String* key2) { |
5785 return key1->Hash() > key2->Hash() || key1 == key2; | 5705 return key1->Hash() > key2->Hash() || key1 == key2; |
5786 } | 5706 } |
5787 | 5707 |
5788 | 5708 |
5789 void DescriptorArray::CopyFrom(Handle<DescriptorArray> dst, | 5709 void DescriptorArray::CopyFrom(int dst_index, |
5790 int dst_index, | 5710 DescriptorArray* src, |
5791 Handle<DescriptorArray> src, | |
5792 int src_index, | 5711 int src_index, |
5793 const WhitenessWitness& witness) { | 5712 const WhitenessWitness& witness) { |
5794 CALL_HEAP_FUNCTION_VOID(dst->GetIsolate(), | |
5795 dst->CopyFrom(dst_index, *src, src_index, witness)); | |
5796 } | |
5797 | |
5798 | |
5799 MaybeObject* DescriptorArray::CopyFrom(int dst_index, | |
5800 DescriptorArray* src, | |
5801 int src_index, | |
5802 const WhitenessWitness& witness) { | |
5803 Object* value = src->GetValue(src_index); | 5713 Object* value = src->GetValue(src_index); |
5804 PropertyDetails details = src->GetDetails(src_index); | 5714 PropertyDetails details = src->GetDetails(src_index); |
5805 if (details.type() == CALLBACKS && value->IsAccessorPair()) { | |
5806 MaybeObject* maybe_copy = | |
5807 AccessorPair::cast(value)->CopyWithoutTransitions(); | |
5808 if (!maybe_copy->To(&value)) return maybe_copy; | |
5809 } | |
5810 Descriptor desc(src->GetKey(src_index), value, details); | 5715 Descriptor desc(src->GetKey(src_index), value, details); |
5811 Set(dst_index, &desc, witness); | 5716 Set(dst_index, &desc, witness); |
5812 return this; | |
5813 } | 5717 } |
5814 | 5718 |
5815 MaybeObject* DescriptorArray::CopyReplace(Descriptor* descriptor, | 5719 MaybeObject* DescriptorArray::CopyReplace(Descriptor* descriptor, |
5816 int insertion_index) { | 5720 int insertion_index) { |
5817 ASSERT(0 <= insertion_index && insertion_index < number_of_descriptors()); | 5721 ASSERT(0 <= insertion_index && insertion_index < number_of_descriptors()); |
5818 | 5722 |
5819 // Ensure the key is a symbol. | 5723 // Ensure the key is a symbol. |
5820 { MaybeObject* maybe_result = descriptor->KeyToSymbol(); | 5724 { MaybeObject* maybe_result = descriptor->KeyToSymbol(); |
5821 if (maybe_result->IsFailure()) return maybe_result; | 5725 if (maybe_result->IsFailure()) return maybe_result; |
5822 } | 5726 } |
5823 | 5727 |
5824 int size = number_of_descriptors(); | 5728 int size = number_of_descriptors(); |
5825 | 5729 |
5826 DescriptorArray* new_descriptors; | 5730 DescriptorArray* new_descriptors; |
5827 { MaybeObject* maybe_result = Allocate(size, MAY_BE_SHARED); | 5731 { MaybeObject* maybe_result = Allocate(size, MAY_BE_SHARED); |
5828 if (!maybe_result->To(&new_descriptors)) return maybe_result; | 5732 if (!maybe_result->To(&new_descriptors)) return maybe_result; |
5829 } | 5733 } |
5830 | 5734 |
5831 FixedArray::WhitenessWitness witness(new_descriptors); | 5735 FixedArray::WhitenessWitness witness(new_descriptors); |
5832 | 5736 |
5833 // Copy the descriptors, replacing a descriptor. | 5737 // Copy the descriptors, replacing a descriptor. |
5834 for (int index = 0; index < size; ++index) { | 5738 for (int index = 0; index < size; ++index) { |
5835 if (index == insertion_index) continue; | 5739 if (index == insertion_index) continue; |
5836 MaybeObject* copy_result = | 5740 new_descriptors->CopyFrom(index, this, index, witness); |
5837 new_descriptors->CopyFrom(index, this, index, witness); | |
5838 if (copy_result->IsFailure()) return copy_result; | |
5839 } | 5741 } |
5840 | 5742 |
5841 descriptor->SetEnumerationIndex(GetDetails(insertion_index).index()); | 5743 descriptor->SetEnumerationIndex(GetDetails(insertion_index).index()); |
5842 new_descriptors->Set(insertion_index, descriptor, witness); | 5744 new_descriptors->Set(insertion_index, descriptor, witness); |
5843 new_descriptors->SetLastAdded(LastAdded()); | 5745 new_descriptors->SetLastAdded(LastAdded()); |
5844 | 5746 |
5845 SLOW_ASSERT(new_descriptors->IsSortedNoDuplicates()); | 5747 SLOW_ASSERT(new_descriptors->IsSortedNoDuplicates()); |
5846 | 5748 |
5847 return new_descriptors; | 5749 return new_descriptors; |
5848 } | 5750 } |
5849 | 5751 |
5850 | 5752 |
5851 MaybeObject* DescriptorArray::CopyInsert(Descriptor* descriptor) { | 5753 MaybeObject* DescriptorArray::CopyInsert(Descriptor* descriptor) { |
5852 // Ensure the key is a symbol. | 5754 // Ensure the key is a symbol. |
5853 { MaybeObject* maybe_result = descriptor->KeyToSymbol(); | 5755 MaybeObject* maybe_result = descriptor->KeyToSymbol(); |
5854 if (maybe_result->IsFailure()) return maybe_result; | 5756 if (maybe_result->IsFailure()) return maybe_result; |
5855 } | |
5856 | 5757 |
5857 // We replace the key if it is already present. | 5758 // We replace the key if it is already present. |
5858 int index = SearchWithCache(descriptor->GetKey()); | 5759 int index = SearchWithCache(descriptor->GetKey()); |
5859 if (index == kNotFound) return CopyAdd(descriptor); | 5760 if (index == kNotFound) return CopyAdd(descriptor); |
5860 return CopyReplace(descriptor, index); | 5761 return CopyReplace(descriptor, index); |
5861 } | 5762 } |
5862 | 5763 |
5863 | 5764 |
5864 MaybeObject* DescriptorArray::CopyAdd(Descriptor* descriptor) { | 5765 MaybeObject* DescriptorArray::CopyAdd(Descriptor* descriptor) { |
5865 // Ensure the key is a symbol. | 5766 // Ensure the key is a symbol. |
5866 { MaybeObject* maybe_result = descriptor->KeyToSymbol(); | 5767 MaybeObject* maybe_result = descriptor->KeyToSymbol(); |
5867 if (maybe_result->IsFailure()) return maybe_result; | 5768 if (maybe_result->IsFailure()) return maybe_result; |
5868 } | |
5869 | 5769 |
5870 String* key = descriptor->GetKey(); | 5770 String* key = descriptor->GetKey(); |
5871 ASSERT(Search(key) == kNotFound); | 5771 ASSERT(Search(key) == kNotFound); |
5872 | 5772 |
5873 int new_size = number_of_descriptors() + 1; | 5773 int new_size = number_of_descriptors() + 1; |
5874 | 5774 |
5875 DescriptorArray* new_descriptors; | 5775 DescriptorArray* new_descriptors; |
5876 { MaybeObject* maybe_result = Allocate(new_size, MAY_BE_SHARED); | 5776 MaybeObject* maybe_descriptors = Allocate(new_size, MAY_BE_SHARED); |
5877 if (!maybe_result->To(&new_descriptors)) return maybe_result; | 5777 if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors; |
5878 } | |
5879 | 5778 |
5880 FixedArray::WhitenessWitness witness(new_descriptors); | 5779 FixedArray::WhitenessWitness witness(new_descriptors); |
5881 | 5780 |
5882 // Copy the descriptors, inserting a descriptor. | 5781 // Copy the descriptors, inserting a descriptor. |
5883 int insertion_index = -1; | 5782 int insertion_index = -1; |
5884 int to = 0; | 5783 int to = 0; |
5885 for (int from = 0; from < number_of_descriptors(); ++from) { | 5784 for (int from = 0; from < number_of_descriptors(); ++from) { |
5886 if (insertion_index < 0 && InsertionPointFound(GetKey(from), key)) { | 5785 if (insertion_index < 0 && InsertionPointFound(GetKey(from), key)) { |
5887 insertion_index = to++; | 5786 insertion_index = to++; |
5888 } | 5787 } |
5889 MaybeObject* copy_result = | 5788 new_descriptors->CopyFrom(to++, this, from, witness); |
5890 new_descriptors->CopyFrom(to++, this, from, witness); | |
5891 if (copy_result->IsFailure()) return copy_result; | |
5892 } | 5789 } |
5893 if (insertion_index < 0) insertion_index = to++; | 5790 if (insertion_index < 0) insertion_index = to++; |
5894 | 5791 |
5895 ASSERT(to == new_descriptors->number_of_descriptors()); | 5792 ASSERT(to == new_descriptors->number_of_descriptors()); |
5896 | 5793 |
5897 ASSERT(new_size == NextEnumerationIndex()); | 5794 ASSERT(new_size == NextEnumerationIndex()); |
5898 descriptor->SetEnumerationIndex(new_size); | 5795 descriptor->SetEnumerationIndex(new_size); |
5899 new_descriptors->Set(insertion_index, descriptor, witness); | 5796 new_descriptors->Set(insertion_index, descriptor, witness); |
5900 new_descriptors->SetLastAdded(insertion_index); | 5797 new_descriptors->SetLastAdded(insertion_index); |
5901 | 5798 |
5902 SLOW_ASSERT(new_descriptors->IsSortedNoDuplicates()); | 5799 SLOW_ASSERT(new_descriptors->IsSortedNoDuplicates()); |
5903 | 5800 |
5904 return new_descriptors; | 5801 return new_descriptors; |
5905 } | 5802 } |
5906 | 5803 |
5907 | 5804 |
5908 MaybeObject* DescriptorArray::Copy(SharedMode shared_mode) { | 5805 MaybeObject* DescriptorArray::Copy(SharedMode shared_mode) { |
5909 // Allocate the new descriptor array. | 5806 // Allocate the new descriptor array. |
5910 int number_of_descriptors = this->number_of_descriptors(); | 5807 int number_of_descriptors = this->number_of_descriptors(); |
5911 DescriptorArray* new_descriptors; | 5808 DescriptorArray* new_descriptors; |
5912 { MaybeObject* maybe_result = Allocate(number_of_descriptors, | 5809 MaybeObject* maybe_result = Allocate(number_of_descriptors, shared_mode); |
5913 shared_mode); | 5810 if (!maybe_result->To(&new_descriptors)) return maybe_result; |
5914 if (!maybe_result->To(&new_descriptors)) return maybe_result; | |
5915 } | |
5916 | 5811 |
5917 // Copy the content. | 5812 // Copy the content. |
5918 if (number_of_descriptors > 0) { | 5813 if (number_of_descriptors > 0) { |
5919 FixedArray::WhitenessWitness witness(new_descriptors); | 5814 FixedArray::WhitenessWitness witness(new_descriptors); |
5920 for (int i = 0; i < number_of_descriptors; i++) { | 5815 for (int i = 0; i < number_of_descriptors; i++) { |
5921 MaybeObject* copy_result = | 5816 new_descriptors->CopyFrom(i, this, i, witness); |
5922 new_descriptors->CopyFrom(i, this, i, witness); | |
5923 if (copy_result->IsFailure()) return copy_result; | |
5924 } | 5817 } |
5925 new_descriptors->SetLastAdded(LastAdded()); | 5818 new_descriptors->SetLastAdded(LastAdded()); |
5926 } | 5819 } |
5927 | 5820 |
5928 return new_descriptors; | 5821 return new_descriptors; |
5929 } | 5822 } |
5930 | 5823 |
5931 // We need the whiteness witness since sort will reshuffle the entries in the | 5824 // We need the whiteness witness since sort will reshuffle the entries in the |
5932 // descriptor array. If the descriptor array were to be black, the shuffling | 5825 // descriptor array. If the descriptor array were to be black, the shuffling |
5933 // would move a slot that was already recorded as pointing into an evacuation | 5826 // would move a slot that was already recorded as pointing into an evacuation |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6013 UNREACHABLE(); | 5906 UNREACHABLE(); |
6014 } | 5907 } |
6015 | 5908 |
6016 | 5909 |
6017 void DescriptorArray::Sort(const WhitenessWitness& witness) { | 5910 void DescriptorArray::Sort(const WhitenessWitness& witness) { |
6018 SortUnchecked(witness); | 5911 SortUnchecked(witness); |
6019 SLOW_ASSERT(IsSortedNoDuplicates()); | 5912 SLOW_ASSERT(IsSortedNoDuplicates()); |
6020 } | 5913 } |
6021 | 5914 |
6022 | 5915 |
6023 MaybeObject* AccessorPair::CopyWithoutTransitions() { | 5916 MaybeObject* AccessorPair::Copy() { |
6024 Heap* heap = GetHeap(); | 5917 Heap* heap = GetHeap(); |
6025 AccessorPair* copy; | 5918 AccessorPair* copy; |
6026 { MaybeObject* maybe_copy = heap->AllocateAccessorPair(); | 5919 MaybeObject* maybe_copy = heap->AllocateAccessorPair(); |
6027 if (!maybe_copy->To(©)) return maybe_copy; | 5920 if (!maybe_copy->To(©)) return maybe_copy; |
6028 } | 5921 |
6029 copy->set_getter(getter()->IsMap() ? heap->the_hole_value() : getter()); | 5922 copy->set_getter(getter()); |
6030 copy->set_setter(setter()->IsMap() ? heap->the_hole_value() : setter()); | 5923 copy->set_setter(setter()); |
6031 return copy; | 5924 return copy; |
6032 } | 5925 } |
6033 | 5926 |
6034 | 5927 |
6035 Object* AccessorPair::GetComponent(AccessorComponent component) { | 5928 Object* AccessorPair::GetComponent(AccessorComponent component) { |
6036 Object* accessor = get(component); | 5929 Object* accessor = get(component); |
6037 return accessor->IsTheHole() ? GetHeap()->undefined_value() : accessor; | 5930 return accessor->IsTheHole() ? GetHeap()->undefined_value() : accessor; |
6038 } | 5931 } |
6039 | 5932 |
6040 | 5933 |
(...skipping 1265 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7306 // Return true in case a back pointer has been cleared and false otherwise. | 7199 // Return true in case a back pointer has been cleared and false otherwise. |
7307 static bool ClearBackPointer(Heap* heap, Object* target) { | 7200 static bool ClearBackPointer(Heap* heap, Object* target) { |
7308 ASSERT(target->IsMap()); | 7201 ASSERT(target->IsMap()); |
7309 Map* map = Map::cast(target); | 7202 Map* map = Map::cast(target); |
7310 if (Marking::MarkBitFrom(map).Get()) return false; | 7203 if (Marking::MarkBitFrom(map).Get()) return false; |
7311 map->SetBackPointer(heap->undefined_value(), SKIP_WRITE_BARRIER); | 7204 map->SetBackPointer(heap->undefined_value(), SKIP_WRITE_BARRIER); |
7312 return true; | 7205 return true; |
7313 } | 7206 } |
7314 | 7207 |
7315 | 7208 |
7316 static bool ClearAccessorComponent(Heap* heap, | |
7317 AccessorPair* accessors, | |
7318 AccessorComponent component) { | |
7319 Object* component_value = accessors->get(component); | |
7320 if (!component_value->IsMap()) return true; | |
7321 if (ClearBackPointer(heap, component_value)) { | |
7322 accessors->set(component, heap->the_hole_value()); | |
7323 return true; | |
7324 } | |
7325 return false; | |
7326 } | |
7327 | |
7328 | |
7329 static bool ClearNonLiveTransition(Heap* heap, | |
7330 TransitionArray* t, | |
7331 int transition_index) { | |
7332 // If the value is a map, check if the target is live. If not, clear the | |
7333 // transition. Also drop the back pointer for that map transition, so that | |
7334 // this map is not reached again by following a back pointer from that | |
7335 // non-live map. | |
7336 Object* value = t->GetValue(transition_index); | |
7337 if (value->IsMap()) { | |
7338 return ClearBackPointer(heap, t->GetValue(transition_index)); | |
7339 } | |
7340 | |
7341 ASSERT(value->IsAccessorPair()); | |
7342 | |
7343 AccessorPair* accessors = AccessorPair::cast(value); | |
7344 bool getter = ClearAccessorComponent(heap, accessors, ACCESSOR_GETTER); | |
7345 bool setter = ClearAccessorComponent(heap, accessors, ACCESSOR_SETTER); | |
7346 return getter && setter; | |
7347 } | |
7348 | |
7349 | |
7350 // TODO(mstarzinger): This method should be moved into MarkCompactCollector, | 7209 // TODO(mstarzinger): This method should be moved into MarkCompactCollector, |
7351 // because it cannot be called from outside the GC and we already have methods | 7210 // because it cannot be called from outside the GC and we already have methods |
7352 // depending on the transitions layout in the GC anyways. | 7211 // depending on the transitions layout in the GC anyways. |
7353 void Map::ClearNonLiveTransitions(Heap* heap) { | 7212 void Map::ClearNonLiveTransitions(Heap* heap) { |
7354 // If there are no transitions to be cleared, return. | 7213 // If there are no transitions to be cleared, return. |
7355 // TODO(verwaest) Should be an assert, otherwise back pointers are not | 7214 // TODO(verwaest) Should be an assert, otherwise back pointers are not |
7356 // properly cleared. | 7215 // properly cleared. |
7357 if (!HasTransitionArray()) return; | 7216 if (!HasTransitionArray()) return; |
7358 | 7217 |
7359 TransitionArray* t = transitions(); | 7218 TransitionArray* t = transitions(); |
7360 | 7219 |
7361 int transition_index = 0; | 7220 int transition_index = 0; |
7362 | 7221 |
7363 // Compact all live descriptors to the left. | 7222 // Compact all live descriptors to the left. |
7364 for (int i = 0; i < t->number_of_transitions(); ++i) { | 7223 for (int i = 0; i < t->number_of_transitions(); ++i) { |
7365 if (!ClearNonLiveTransition(heap, t, i)) { | 7224 if (!ClearBackPointer(heap, t->GetTarget(i))) { |
7366 if (i != transition_index) { | 7225 if (i != transition_index) { |
7367 String* key = t->GetKey(i); | 7226 String* key = t->GetKey(i); |
7368 Object* value = t->GetValue(i); | 7227 Map* target = t->GetTarget(i); |
7369 t->SetKey(transition_index, key); | 7228 t->SetKey(transition_index, key); |
7370 t->SetValue(transition_index, value); | 7229 t->SetTarget(transition_index, target); |
7371 MarkCompactCollector* collector = heap->mark_compact_collector(); | 7230 MarkCompactCollector* collector = heap->mark_compact_collector(); |
7372 Object** key_slot = t->GetKeySlot(transition_index); | 7231 Object** key_slot = t->GetKeySlot(transition_index); |
7373 collector->RecordSlot(key_slot, key_slot, key); | 7232 collector->RecordSlot(key_slot, key_slot, key); |
7374 Object** value_slot = t->GetValueSlot(transition_index); | 7233 Object** target_slot = t->GetTargetSlot(transition_index); |
7375 collector->RecordSlot(value_slot, value_slot, value); | 7234 collector->RecordSlot(target_slot, target_slot, target); |
7376 } | 7235 } |
7377 transition_index++; | 7236 transition_index++; |
7378 } | 7237 } |
7379 } | 7238 } |
7380 | 7239 |
7381 if (t->HasElementsTransition() && | 7240 if (t->HasElementsTransition() && |
7382 ClearBackPointer(heap, t->elements_transition())) { | 7241 ClearBackPointer(heap, t->elements_transition())) { |
7383 t->ClearElementsTransition(); | 7242 t->ClearElementsTransition(); |
7384 } else { | 7243 } else { |
7385 // If there are no transitions to be cleared, return. | 7244 // If there are no transitions to be cleared, return. |
(...skipping 3079 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10465 Isolate* isolate = GetIsolate(); | 10324 Isolate* isolate = GetIsolate(); |
10466 if (IsAccessCheckNeeded()) { | 10325 if (IsAccessCheckNeeded()) { |
10467 if (!isolate->MayNamedAccess(this, key, v8::ACCESS_HAS)) { | 10326 if (!isolate->MayNamedAccess(this, key, v8::ACCESS_HAS)) { |
10468 isolate->ReportFailedAccessCheck(this, v8::ACCESS_HAS); | 10327 isolate->ReportFailedAccessCheck(this, v8::ACCESS_HAS); |
10469 return false; | 10328 return false; |
10470 } | 10329 } |
10471 } | 10330 } |
10472 | 10331 |
10473 LookupResult result(isolate); | 10332 LookupResult result(isolate); |
10474 LocalLookupRealNamedProperty(key, &result); | 10333 LocalLookupRealNamedProperty(key, &result); |
10475 return result.IsCallbacks(); | 10334 return result.IsPropertyCallbacks(); |
10476 } | 10335 } |
10477 | 10336 |
10478 | 10337 |
10479 int JSObject::NumberOfLocalProperties(PropertyAttributes filter) { | 10338 int JSObject::NumberOfLocalProperties(PropertyAttributes filter) { |
10480 return HasFastProperties() ? | 10339 return HasFastProperties() ? |
10481 map()->NumberOfDescribedProperties(filter) : | 10340 map()->NumberOfDescribedProperties(filter) : |
10482 property_dictionary()->NumberOfElementsFilterAttributes(filter); | 10341 property_dictionary()->NumberOfElementsFilterAttributes(filter); |
10483 } | 10342 } |
10484 | 10343 |
10485 | 10344 |
(...skipping 2203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
12689 } | 12548 } |
12690 | 12549 |
12691 // Fill in the instance descriptor and the fields. | 12550 // Fill in the instance descriptor and the fields. |
12692 int next_descriptor = 0; | 12551 int next_descriptor = 0; |
12693 int current_offset = 0; | 12552 int current_offset = 0; |
12694 for (int i = 0; i < capacity; i++) { | 12553 for (int i = 0; i < capacity; i++) { |
12695 Object* k = KeyAt(i); | 12554 Object* k = KeyAt(i); |
12696 if (IsKey(k)) { | 12555 if (IsKey(k)) { |
12697 Object* value = ValueAt(i); | 12556 Object* value = ValueAt(i); |
12698 // Ensure the key is a symbol before writing into the instance descriptor. | 12557 // Ensure the key is a symbol before writing into the instance descriptor. |
12699 Object* key; | 12558 String* key; |
12700 { MaybeObject* maybe_key = heap->LookupSymbol(String::cast(k)); | 12559 MaybeObject* maybe_key = heap->LookupSymbol(String::cast(k)); |
12701 if (!maybe_key->ToObject(&key)) return maybe_key; | 12560 if (!maybe_key->To(&key)) return maybe_key; |
12702 } | 12561 |
12703 PropertyDetails details = DetailsAt(i); | 12562 PropertyDetails details = DetailsAt(i); |
12704 PropertyType type = details.type(); | 12563 PropertyType type = details.type(); |
12705 | 12564 |
12706 if (value->IsJSFunction() && !heap->InNewSpace(value)) { | 12565 if (value->IsJSFunction() && !heap->InNewSpace(value)) { |
12707 ConstantFunctionDescriptor d(String::cast(key), | 12566 ConstantFunctionDescriptor d(key, |
12708 JSFunction::cast(value), | 12567 JSFunction::cast(value), |
12709 details.attributes(), | 12568 details.attributes(), |
12710 details.index()); | 12569 details.index()); |
12711 descriptors->Set(next_descriptor, &d, witness); | 12570 descriptors->Set(next_descriptor, &d, witness); |
12712 } else if (type == NORMAL) { | 12571 } else if (type == NORMAL) { |
12713 if (current_offset < inobject_props) { | 12572 if (current_offset < inobject_props) { |
12714 obj->InObjectPropertyAtPut(current_offset, | 12573 obj->InObjectPropertyAtPut(current_offset, |
12715 value, | 12574 value, |
12716 UPDATE_WRITE_BARRIER); | 12575 UPDATE_WRITE_BARRIER); |
12717 } else { | 12576 } else { |
12718 int offset = current_offset - inobject_props; | 12577 int offset = current_offset - inobject_props; |
12719 FixedArray::cast(fields)->set(offset, value); | 12578 FixedArray::cast(fields)->set(offset, value); |
12720 } | 12579 } |
12721 FieldDescriptor d(String::cast(key), | 12580 FieldDescriptor d(key, |
12722 current_offset++, | 12581 current_offset++, |
12723 details.attributes(), | 12582 details.attributes(), |
12724 details.index()); | 12583 details.index()); |
12725 descriptors->Set(next_descriptor, &d, witness); | 12584 descriptors->Set(next_descriptor, &d, witness); |
12726 } else if (type == CALLBACKS) { | 12585 } else if (type == CALLBACKS) { |
12727 if (value->IsAccessorPair()) { | 12586 CallbacksDescriptor d(key, |
12728 MaybeObject* maybe_copy = | |
12729 AccessorPair::cast(value)->CopyWithoutTransitions(); | |
12730 if (!maybe_copy->To(&value)) return maybe_copy; | |
12731 } | |
12732 CallbacksDescriptor d(String::cast(key), | |
12733 value, | 12587 value, |
12734 details.attributes(), | 12588 details.attributes(), |
12735 details.index()); | 12589 details.index()); |
12736 descriptors->Set(next_descriptor, &d, witness); | 12590 descriptors->Set(next_descriptor, &d, witness); |
12737 } else { | 12591 } else { |
12738 UNREACHABLE(); | 12592 UNREACHABLE(); |
12739 } | 12593 } |
12740 ++next_descriptor; | 12594 ++next_descriptor; |
12741 } | 12595 } |
12742 } | 12596 } |
12743 ASSERT(current_offset == number_of_fields); | 12597 ASSERT(current_offset == number_of_fields); |
12744 | 12598 |
12745 descriptors->Sort(witness); | 12599 descriptors->Sort(witness); |
12746 // Allocate new map. | 12600 // Allocate new map. |
12747 Map* new_map; | 12601 Map* new_map; |
12748 { MaybeObject* maybe_new_map = | 12602 MaybeObject* maybe_new_map = obj->map()->CopyReplaceDescriptors(descriptors); |
12749 obj->map()->CopyReplaceDescriptors(descriptors); | 12603 if (!maybe_new_map->To(&new_map)) return maybe_new_map; |
12750 if (!maybe_new_map->To(&new_map)) return maybe_new_map; | |
12751 } | |
12752 | 12604 |
12753 new_map->set_unused_property_fields(unused_property_fields); | 12605 new_map->set_unused_property_fields(unused_property_fields); |
12754 | 12606 |
12755 // Transform the object. | 12607 // Transform the object. |
12756 obj->set_map(new_map); | 12608 obj->set_map(new_map); |
12757 | 12609 |
12758 obj->set_properties(FixedArray::cast(fields)); | 12610 obj->set_properties(FixedArray::cast(fields)); |
12759 ASSERT(obj->IsJSObject()); | 12611 ASSERT(obj->IsJSObject()); |
12760 | 12612 |
12761 // Check that it really works. | 12613 // Check that it really works. |
(...skipping 500 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
13262 set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER); | 13114 set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER); |
13263 set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER); | 13115 set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER); |
13264 set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER); | 13116 set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER); |
13265 set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER); | 13117 set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER); |
13266 set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER); | 13118 set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER); |
13267 set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER); | 13119 set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER); |
13268 set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER); | 13120 set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER); |
13269 } | 13121 } |
13270 | 13122 |
13271 } } // namespace v8::internal | 13123 } } // namespace v8::internal |
OLD | NEW |