OLD | NEW |
---|---|
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 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 3261 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3272 PrintF("Object elements have been normalized:\n"); | 3272 PrintF("Object elements have been normalized:\n"); |
3273 Print(); | 3273 Print(); |
3274 } | 3274 } |
3275 #endif | 3275 #endif |
3276 | 3276 |
3277 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements()); | 3277 ASSERT(HasDictionaryElements() || HasDictionaryArgumentsElements()); |
3278 return dictionary; | 3278 return dictionary; |
3279 } | 3279 } |
3280 | 3280 |
3281 | 3281 |
3282 MaybeObject* JSObject::GetHiddenProperties(CreationFlag flag) { | |
3283 Isolate* isolate = GetIsolate(); | |
3284 Heap* heap = isolate->heap(); | |
3285 Object* holder = BypassGlobalProxy(); | |
3286 if (holder->IsUndefined()) return heap->undefined_value(); | |
3287 JSObject* obj = JSObject::cast(holder); | |
3288 if (obj->HasFastProperties()) { | |
3289 // If the object has fast properties, check whether the first slot | |
3290 // in the descriptor array matches the hidden symbol. Since the | |
3291 // hidden symbols hash code is zero (and no other string has hash | |
3292 // code zero) it will always occupy the first entry if present. | |
3293 DescriptorArray* descriptors = obj->map()->instance_descriptors(); | |
3294 if ((descriptors->number_of_descriptors() > 0) && | |
3295 (descriptors->GetKey(0) == heap->hidden_symbol()) && | |
3296 descriptors->IsProperty(0)) { | |
3297 ASSERT(descriptors->GetType(0) == FIELD); | |
3298 return obj->FastPropertyAt(descriptors->GetFieldIndex(0)); | |
3299 } | |
3300 } | |
3301 | |
3302 // Only attempt to find the hidden properties in the local object and not | |
3303 // in the prototype chain. | |
3304 if (!obj->HasHiddenPropertiesObject()) { | |
3305 // Hidden properties object not found. Allocate a new hidden properties | |
3306 // object if requested. Otherwise return the undefined value. | |
3307 if (flag == ALLOW_CREATION) { | |
3308 Object* hidden_obj; | |
3309 { MaybeObject* maybe_obj = heap->AllocateJSObject( | |
3310 isolate->context()->global_context()->object_function()); | |
3311 if (!maybe_obj->ToObject(&hidden_obj)) return maybe_obj; | |
3312 } | |
3313 // Don't allow leakage of the hidden object through accessors | |
3314 // on Object.prototype. | |
3315 { | |
3316 MaybeObject* maybe_obj = | |
3317 JSObject::cast(hidden_obj)->SetPrototype(heap->null_value(), false); | |
3318 if (maybe_obj->IsFailure()) return maybe_obj; | |
3319 } | |
3320 return obj->SetHiddenPropertiesObject(hidden_obj); | |
3321 } else { | |
3322 return heap->undefined_value(); | |
3323 } | |
3324 } | |
3325 return obj->GetHiddenPropertiesObject(); | |
3326 } | |
3327 | |
3328 | |
3329 Smi* JSReceiver::GenerateIdentityHash() { | 3282 Smi* JSReceiver::GenerateIdentityHash() { |
3330 Isolate* isolate = GetIsolate(); | 3283 Isolate* isolate = GetIsolate(); |
3331 | 3284 |
3332 int hash_value; | 3285 int hash_value; |
3333 int attempts = 0; | 3286 int attempts = 0; |
3334 do { | 3287 do { |
3335 // Generate a random 32-bit hash value but limit range to fit | 3288 // Generate a random 32-bit hash value but limit range to fit |
3336 // within a smi. | 3289 // within a smi. |
3337 hash_value = V8::Random(isolate) & Smi::kMaxValue; | 3290 hash_value = V8::Random(isolate) & Smi::kMaxValue; |
3338 attempts++; | 3291 attempts++; |
3339 } while (hash_value == 0 && attempts < 30); | 3292 } while (hash_value == 0 && attempts < 30); |
3340 hash_value = hash_value != 0 ? hash_value : 1; // never return 0 | 3293 hash_value = hash_value != 0 ? hash_value : 1; // never return 0 |
3341 | 3294 |
3342 return Smi::FromInt(hash_value); | 3295 return Smi::FromInt(hash_value); |
3343 } | 3296 } |
3344 | 3297 |
3345 | 3298 |
3346 MaybeObject* JSObject::SetIdentityHash(Object* hash, CreationFlag flag) { | 3299 MaybeObject* JSObject::SetIdentityHash(Object* hash, CreationFlag flag) { |
3347 JSObject* hidden_props; | 3300 MaybeObject* maybe = SetHiddenProperty(GetHeap()->identity_hash_symbol(), |
3348 MaybeObject* maybe = GetHiddenProperties(flag); | 3301 hash); |
3349 if (!maybe->To<JSObject>(&hidden_props)) return maybe; | |
3350 maybe = hidden_props->SetLocalPropertyIgnoreAttributes( | |
3351 GetHeap()->identity_hash_symbol(), hash, NONE); | |
3352 if (maybe->IsFailure()) return maybe; | 3302 if (maybe->IsFailure()) return maybe; |
3353 return this; | 3303 return this; |
3354 } | 3304 } |
3355 | 3305 |
3356 | 3306 |
3357 MaybeObject* JSObject::GetIdentityHash(CreationFlag flag) { | 3307 MaybeObject* JSObject::GetIdentityHash(CreationFlag flag) { |
3358 Isolate* isolate = GetIsolate(); | 3308 Object* stored_value = GetHiddenProperty(GetHeap()->identity_hash_symbol()); |
3359 Object* hidden_props_obj; | 3309 if (stored_value->IsSmi()) return stored_value; |
3360 { MaybeObject* maybe_obj = GetHiddenProperties(flag); | |
3361 if (!maybe_obj->ToObject(&hidden_props_obj)) return maybe_obj; | |
3362 } | |
3363 if (!hidden_props_obj->IsJSObject()) { | |
3364 // We failed to create hidden properties. That's a detached | |
3365 // global proxy. | |
3366 ASSERT(hidden_props_obj->IsUndefined()); | |
3367 return Smi::FromInt(0); | |
3368 } | |
3369 JSObject* hidden_props = JSObject::cast(hidden_props_obj); | |
3370 String* hash_symbol = isolate->heap()->identity_hash_symbol(); | |
3371 { | |
3372 // Note that HasLocalProperty() can cause a GC in the general case in the | |
3373 // presence of interceptors. | |
3374 AssertNoAllocation no_alloc; | |
3375 if (hidden_props->HasLocalProperty(hash_symbol)) { | |
3376 MaybeObject* hash = hidden_props->GetProperty(hash_symbol); | |
3377 return Smi::cast(hash->ToObjectChecked()); | |
3378 } | |
3379 } | |
3380 | 3310 |
3381 Smi* hash = GenerateIdentityHash(); | 3311 Smi* hash = GenerateIdentityHash(); |
3382 { MaybeObject* result = hidden_props->SetLocalPropertyIgnoreAttributes( | 3312 MaybeObject* result = SetHiddenProperty(GetHeap()->identity_hash_symbol(), |
3383 hash_symbol, | 3313 hash); |
3384 hash, | 3314 if (result->IsFailure()) return result; |
3385 static_cast<PropertyAttributes>(None)); | 3315 if (result->ToObjectUnchecked()->IsUndefined()) { |
3386 if (result->IsFailure()) return result; | 3316 // Trying to get hash of detached proxy. |
3317 return Smi::FromInt(0); | |
3387 } | 3318 } |
3388 return hash; | 3319 return hash; |
3389 } | 3320 } |
3390 | 3321 |
3391 | 3322 |
3392 MaybeObject* JSProxy::GetIdentityHash(CreationFlag flag) { | 3323 MaybeObject* JSProxy::GetIdentityHash(CreationFlag flag) { |
3393 Object* hash = this->hash(); | 3324 Object* hash = this->hash(); |
3394 if (!hash->IsSmi() && flag == ALLOW_CREATION) { | 3325 if (!hash->IsSmi() && flag == ALLOW_CREATION) { |
3395 hash = GenerateIdentityHash(); | 3326 hash = GenerateIdentityHash(); |
3396 set_hash(hash); | 3327 set_hash(hash); |
3397 } | 3328 } |
3398 return hash; | 3329 return hash; |
3399 } | 3330 } |
3400 | 3331 |
3401 | 3332 |
3333 Object* JSObject::GetHiddenProperty(String* key) { | |
3334 if (IsJSGlobalProxy()) { | |
3335 // For a proxy, use the prototype as target object. | |
3336 Object* proxy_parent = GetPrototype(); | |
3337 // If the proxy is detached, return undefined. | |
3338 if (proxy_parent->IsNull()) return GetHeap()->undefined_value(); | |
3339 ASSERT(proxy_parent->IsJSGlobalObject()); | |
3340 return JSObject::cast(proxy_parent)->GetHiddenProperty(key); | |
3341 } | |
3342 ASSERT(!IsJSGlobalProxy()); | |
3343 MaybeObject* hidden_lookup = GetHiddenPropertiesDictionary(false); | |
3344 ASSERT(!hidden_lookup->IsFailure()); // No failure when passing false as arg. | |
3345 if (hidden_lookup->ToObjectUnchecked()->IsUndefined()) { | |
3346 return GetHeap()->undefined_value(); | |
3347 } | |
3348 StringDictionary* dictionary = | |
3349 StringDictionary::cast(hidden_lookup->ToObjectUnchecked()); | |
3350 int entry = dictionary->FindEntry(key); | |
3351 if (entry == StringDictionary::kNotFound) return GetHeap()->undefined_value(); | |
3352 return dictionary->ValueAt(entry); | |
3353 } | |
3354 | |
3355 | |
3356 MaybeObject* JSObject::SetHiddenProperty(String* key, Object* value) { | |
3357 if (IsJSGlobalProxy()) { | |
3358 // For a proxy, use the prototype as target object. | |
3359 Object* proxy_parent = GetPrototype(); | |
3360 // If the proxy is detached, return undefined. | |
3361 if (proxy_parent->IsNull()) return GetHeap()->undefined_value(); | |
3362 ASSERT(proxy_parent->IsJSGlobalObject()); | |
3363 return JSObject::cast(proxy_parent)->SetHiddenProperty(key, value); | |
3364 } | |
3365 ASSERT(!IsJSGlobalProxy()); | |
3366 MaybeObject* hidden_lookup = GetHiddenPropertiesDictionary(true); | |
3367 StringDictionary* dictionary; | |
3368 if (!hidden_lookup->To<StringDictionary>(&dictionary)) return hidden_lookup; | |
3369 | |
3370 // If it was found, check if the key is already in the dictionary. | |
3371 int entry = dictionary->FindEntry(key); | |
3372 if (entry != StringDictionary::kNotFound) { | |
3373 // If key was found, just update the value. | |
3374 dictionary->ValueAtPut(entry, value); | |
3375 return this; | |
3376 } | |
3377 // Key was not already in the dictionary, so add the entry. | |
3378 MaybeObject* insert_result = dictionary->Add(key, | |
3379 value, | |
3380 PropertyDetails(NONE, NORMAL)); | |
3381 StringDictionary* new_dict; | |
3382 if (!insert_result->To<StringDictionary>(&new_dict)) return insert_result; | |
3383 if (new_dict != dictionary) { | |
3384 // If adding the key expanded the dictionary (i.e., Add returned a new | |
3385 // dictionary), store it back to the object. | |
3386 MaybeObject* store_result = SetHiddenPropertiesDictionary(new_dict); | |
3387 if (store_result->IsFailure()) return store_result; | |
3388 } | |
3389 // Return this to mark success. | |
3390 return this; | |
3391 } | |
3392 | |
3393 | |
3394 void JSObject::DeleteHiddenProperty(String* key) { | |
3395 if (IsJSGlobalProxy()) { | |
3396 // For a proxy, use the prototype as target object. | |
3397 Object* proxy_parent = GetPrototype(); | |
3398 // If the proxy is detached, return immediately. | |
3399 if (proxy_parent->IsNull()) return; | |
3400 ASSERT(proxy_parent->IsJSGlobalObject()); | |
3401 JSObject::cast(proxy_parent)->DeleteHiddenProperty(key); | |
3402 return; | |
3403 } | |
3404 MaybeObject* hidden_lookup = GetHiddenPropertiesDictionary(false); | |
3405 ASSERT(!hidden_lookup->IsFailure()); // No failure when passing false as arg. | |
3406 if (hidden_lookup->ToObjectUnchecked()->IsUndefined()) return; | |
3407 StringDictionary* dictionary = | |
3408 StringDictionary::cast(hidden_lookup->ToObjectUnchecked()); | |
3409 int entry = dictionary->FindEntry(key); | |
3410 if (entry == StringDictionary::kNotFound) { | |
3411 // Key wasn't in dictionary. Deletion is a success. | |
3412 return; | |
3413 } | |
3414 // Key was in the dictionary. Remove it. | |
3415 dictionary->DeleteProperty(entry, JSReceiver::FORCE_DELETION); | |
3416 } | |
3417 | |
3418 | |
3419 bool JSObject::HasHiddenProperties() { | |
3420 LookupResult lookup; | |
3421 LocalLookupRealNamedProperty(GetHeap()->hidden_symbol(), &lookup); | |
3422 return lookup.IsFound(); | |
3423 } | |
3424 | |
3425 | |
3426 MaybeObject* JSObject::GetHiddenPropertiesDictionary(bool create_if_absent) { | |
3427 ASSERT(!IsJSGlobalProxy()); | |
3428 if (HasFastProperties()) { | |
3429 // If the object has fast properties, check whether the first slot | |
3430 // in the descriptor array matches the hidden symbol. Since the | |
3431 // hidden symbols hash code is zero (and no other string has hash | |
3432 // code zero) it will always occupy the first entry if present. | |
3433 DescriptorArray* descriptors = this->map()->instance_descriptors(); | |
3434 if ((descriptors->number_of_descriptors() > 0) && | |
3435 (descriptors->GetKey(0) == GetHeap()->hidden_symbol()) && | |
3436 descriptors->IsProperty(0)) { | |
3437 ASSERT(descriptors->GetType(0) == FIELD); | |
3438 Object* hidden_store = | |
3439 this->FastPropertyAt(descriptors->GetFieldIndex(0)); | |
3440 return StringDictionary::cast(hidden_store); | |
3441 } | |
3442 } else { | |
3443 PropertyAttributes attributes; | |
3444 // You can't install a getter on a property indexed by the hidden symbol, | |
3445 // so we can be sure that GetLocalPropertyPostInterceptor returns a real | |
3446 // object. | |
3447 Object* lookup = | |
3448 GetLocalPropertyPostInterceptor(this, | |
3449 GetHeap()->hidden_symbol(), | |
3450 &attributes)->ToObjectUnchecked(); | |
3451 if (!lookup->IsUndefined()) { | |
3452 return StringDictionary::cast(lookup); | |
3453 } | |
3454 } | |
3455 if (!create_if_absent) return GetHeap()->undefined_value(); | |
3456 const int kInitialSize = 5; | |
3457 MaybeObject* dict_alloc = StringDictionary::Allocate(kInitialSize); | |
3458 StringDictionary* dictionary; | |
3459 if (!dict_alloc->To<StringDictionary>(&dictionary)) return dict_alloc; | |
3460 MaybeObject* store_result = | |
Rico
2011/09/28 08:59:56
If we have fast properties shouldn't we set this o
Lasse Reichstein
2011/09/28 10:21:42
The SetPropertyPostInterceptor will put the new pr
| |
3461 SetPropertyPostInterceptor(GetHeap()->hidden_symbol(), | |
3462 dictionary, | |
3463 DONT_ENUM, | |
3464 kNonStrictMode); | |
3465 if (store_result->IsFailure()) return store_result; | |
3466 return dictionary; | |
3467 } | |
3468 | |
3469 | |
3470 MaybeObject* JSObject::SetHiddenPropertiesDictionary( | |
3471 StringDictionary* dictionary) { | |
3472 ASSERT(!IsJSGlobalProxy()); | |
3473 ASSERT(HasHiddenProperties()); | |
3474 if (HasFastProperties()) { | |
3475 // If the object has fast properties, check whether the first slot | |
3476 // in the descriptor array matches the hidden symbol. Since the | |
3477 // hidden symbols hash code is zero (and no other string has hash | |
3478 // code zero) it will always occupy the first entry if present. | |
3479 DescriptorArray* descriptors = this->map()->instance_descriptors(); | |
3480 if ((descriptors->number_of_descriptors() > 0) && | |
3481 (descriptors->GetKey(0) == GetHeap()->hidden_symbol()) && | |
3482 descriptors->IsProperty(0)) { | |
3483 ASSERT(descriptors->GetType(0) == FIELD); | |
3484 this->FastPropertyAtPut(descriptors->GetFieldIndex(0), dictionary); | |
3485 return this; | |
3486 } | |
3487 } | |
3488 MaybeObject* store_result = | |
3489 SetPropertyPostInterceptor(GetHeap()->hidden_symbol(), | |
3490 dictionary, | |
3491 DONT_ENUM, | |
3492 kNonStrictMode); | |
3493 if (store_result->IsFailure()) return store_result; | |
3494 return this; | |
3495 } | |
3496 | |
3497 | |
3402 MaybeObject* JSObject::DeletePropertyPostInterceptor(String* name, | 3498 MaybeObject* JSObject::DeletePropertyPostInterceptor(String* name, |
3403 DeleteMode mode) { | 3499 DeleteMode mode) { |
3404 // Check local property, ignore interceptor. | 3500 // Check local property, ignore interceptor. |
3405 LookupResult result; | 3501 LookupResult result; |
3406 LocalLookupRealNamedProperty(name, &result); | 3502 LocalLookupRealNamedProperty(name, &result); |
3407 if (!result.IsProperty()) return GetHeap()->true_value(); | 3503 if (!result.IsProperty()) return GetHeap()->true_value(); |
3408 | 3504 |
3409 // Normalize object if needed. | 3505 // Normalize object if needed. |
3410 Object* obj; | 3506 Object* obj; |
3411 { MaybeObject* maybe_obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); | 3507 { MaybeObject* maybe_obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); |
(...skipping 8656 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
12068 if (break_point_objects()->IsUndefined()) return 0; | 12164 if (break_point_objects()->IsUndefined()) return 0; |
12069 // Single break point. | 12165 // Single break point. |
12070 if (!break_point_objects()->IsFixedArray()) return 1; | 12166 if (!break_point_objects()->IsFixedArray()) return 1; |
12071 // Multiple break points. | 12167 // Multiple break points. |
12072 return FixedArray::cast(break_point_objects())->length(); | 12168 return FixedArray::cast(break_point_objects())->length(); |
12073 } | 12169 } |
12074 #endif | 12170 #endif |
12075 | 12171 |
12076 | 12172 |
12077 } } // namespace v8::internal | 12173 } } // namespace v8::internal |
OLD | NEW |