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