Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(449)

Side by Side Diff: src/objects.cc

Issue 8050013: Move logic for hidden properties into the JSObject. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Fix typo. Created 9 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/objects.h ('k') | src/objects-inl.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
OLDNEW
« no previous file with comments | « src/objects.h ('k') | src/objects-inl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698