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