handles.cc revision b0fe1620dcb4135ac3ab2d66ff93072373911299
1// Copyright 2009 the V8 project authors. All rights reserved. 2// Redistribution and use in source and binary forms, with or without 3// modification, are permitted provided that the following conditions are 4// met: 5// 6// * Redistributions of source code must retain the above copyright 7// notice, this list of conditions and the following disclaimer. 8// * Redistributions in binary form must reproduce the above 9// copyright notice, this list of conditions and the following 10// disclaimer in the documentation and/or other materials provided 11// with the distribution. 12// * Neither the name of Google Inc. nor the names of its 13// contributors may be used to endorse or promote products derived 14// from this software without specific prior written permission. 15// 16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28#include "v8.h" 29 30#include "accessors.h" 31#include "api.h" 32#include "arguments.h" 33#include "bootstrapper.h" 34#include "compiler.h" 35#include "debug.h" 36#include "execution.h" 37#include "global-handles.h" 38#include "natives.h" 39#include "runtime.h" 40#include "string-search.h" 41#include "stub-cache.h" 42#include "vm-state-inl.h" 43 44namespace v8 { 45namespace internal { 46 47 48v8::ImplementationUtilities::HandleScopeData HandleScope::current_ = 49 { NULL, NULL, 0 }; 50 51 52int HandleScope::NumberOfHandles() { 53 int n = HandleScopeImplementer::instance()->blocks()->length(); 54 if (n == 0) return 0; 55 return ((n - 1) * kHandleBlockSize) + static_cast<int>( 56 (current_.next - HandleScopeImplementer::instance()->blocks()->last())); 57} 58 59 60Object** HandleScope::Extend() { 61 Object** result = current_.next; 62 63 ASSERT(result == current_.limit); 64 // Make sure there's at least one scope on the stack and that the 65 // top of the scope stack isn't a barrier. 66 if (current_.level == 0) { 67 Utils::ReportApiFailure("v8::HandleScope::CreateHandle()", 68 "Cannot create a handle without a HandleScope"); 69 return NULL; 70 } 71 HandleScopeImplementer* impl = HandleScopeImplementer::instance(); 72 // If there's more room in the last block, we use that. This is used 73 // for fast creation of scopes after scope barriers. 74 if (!impl->blocks()->is_empty()) { 75 Object** limit = &impl->blocks()->last()[kHandleBlockSize]; 76 if (current_.limit != limit) { 77 current_.limit = limit; 78 ASSERT(limit - current_.next < kHandleBlockSize); 79 } 80 } 81 82 // If we still haven't found a slot for the handle, we extend the 83 // current handle scope by allocating a new handle block. 84 if (result == current_.limit) { 85 // If there's a spare block, use it for growing the current scope. 86 result = impl->GetSpareOrNewBlock(); 87 // Add the extension to the global list of blocks, but count the 88 // extension as part of the current scope. 89 impl->blocks()->Add(result); 90 current_.limit = &result[kHandleBlockSize]; 91 } 92 93 return result; 94} 95 96 97void HandleScope::DeleteExtensions() { 98 HandleScopeImplementer::instance()->DeleteExtensions(current_.limit); 99} 100 101 102void HandleScope::ZapRange(Object** start, Object** end) { 103 ASSERT(end - start <= kHandleBlockSize); 104 for (Object** p = start; p != end; p++) { 105 *reinterpret_cast<Address*>(p) = v8::internal::kHandleZapValue; 106 } 107} 108 109 110Address HandleScope::current_level_address() { 111 return reinterpret_cast<Address>(¤t_.level); 112} 113 114 115Address HandleScope::current_next_address() { 116 return reinterpret_cast<Address>(¤t_.next); 117} 118 119 120Address HandleScope::current_limit_address() { 121 return reinterpret_cast<Address>(¤t_.limit); 122} 123 124 125Handle<FixedArray> AddKeysFromJSArray(Handle<FixedArray> content, 126 Handle<JSArray> array) { 127 CALL_HEAP_FUNCTION(content->AddKeysFromJSArray(*array), FixedArray); 128} 129 130 131Handle<FixedArray> UnionOfKeys(Handle<FixedArray> first, 132 Handle<FixedArray> second) { 133 CALL_HEAP_FUNCTION(first->UnionOfKeys(*second), FixedArray); 134} 135 136 137Handle<JSGlobalProxy> ReinitializeJSGlobalProxy( 138 Handle<JSFunction> constructor, 139 Handle<JSGlobalProxy> global) { 140 CALL_HEAP_FUNCTION(Heap::ReinitializeJSGlobalProxy(*constructor, *global), 141 JSGlobalProxy); 142} 143 144 145void SetExpectedNofProperties(Handle<JSFunction> func, int nof) { 146 // If objects constructed from this function exist then changing 147 // 'estimated_nof_properties' is dangerous since the previous value might 148 // have been compiled into the fast construct stub. More over, the inobject 149 // slack tracking logic might have adjusted the previous value, so even 150 // passing the same value is risky. 151 if (func->shared()->live_objects_may_exist()) return; 152 153 func->shared()->set_expected_nof_properties(nof); 154 if (func->has_initial_map()) { 155 Handle<Map> new_initial_map = 156 Factory::CopyMapDropTransitions(Handle<Map>(func->initial_map())); 157 new_initial_map->set_unused_property_fields(nof); 158 func->set_initial_map(*new_initial_map); 159 } 160} 161 162 163void SetPrototypeProperty(Handle<JSFunction> func, Handle<JSObject> value) { 164 CALL_HEAP_FUNCTION_VOID(func->SetPrototype(*value)); 165} 166 167 168static int ExpectedNofPropertiesFromEstimate(int estimate) { 169 // If no properties are added in the constructor, they are more likely 170 // to be added later. 171 if (estimate == 0) estimate = 2; 172 173 // We do not shrink objects that go into a snapshot (yet), so we adjust 174 // the estimate conservatively. 175 if (Serializer::enabled()) return estimate + 2; 176 177 // Inobject slack tracking will reclaim redundant inobject space later, 178 // so we can afford to adjust the estimate generously. 179 return estimate + 8; 180} 181 182 183void SetExpectedNofPropertiesFromEstimate(Handle<SharedFunctionInfo> shared, 184 int estimate) { 185 // See the comment in SetExpectedNofProperties. 186 if (shared->live_objects_may_exist()) return; 187 188 shared->set_expected_nof_properties( 189 ExpectedNofPropertiesFromEstimate(estimate)); 190} 191 192 193void NormalizeProperties(Handle<JSObject> object, 194 PropertyNormalizationMode mode, 195 int expected_additional_properties) { 196 CALL_HEAP_FUNCTION_VOID(object->NormalizeProperties( 197 mode, 198 expected_additional_properties)); 199} 200 201 202void NormalizeElements(Handle<JSObject> object) { 203 CALL_HEAP_FUNCTION_VOID(object->NormalizeElements()); 204} 205 206 207void TransformToFastProperties(Handle<JSObject> object, 208 int unused_property_fields) { 209 CALL_HEAP_FUNCTION_VOID( 210 object->TransformToFastProperties(unused_property_fields)); 211} 212 213 214void NumberDictionarySet(Handle<NumberDictionary> dictionary, 215 uint32_t index, 216 Handle<Object> value, 217 PropertyDetails details) { 218 CALL_HEAP_FUNCTION_VOID(dictionary->Set(index, *value, details)); 219} 220 221 222void FlattenString(Handle<String> string) { 223 CALL_HEAP_FUNCTION_VOID(string->TryFlatten()); 224} 225 226 227Handle<String> FlattenGetString(Handle<String> string) { 228 CALL_HEAP_FUNCTION(string->TryFlatten(), String); 229} 230 231 232Handle<Object> SetPrototype(Handle<JSFunction> function, 233 Handle<Object> prototype) { 234 ASSERT(function->should_have_prototype()); 235 CALL_HEAP_FUNCTION(Accessors::FunctionSetPrototype(*function, 236 *prototype, 237 NULL), 238 Object); 239} 240 241 242Handle<Object> SetProperty(Handle<JSObject> object, 243 Handle<String> key, 244 Handle<Object> value, 245 PropertyAttributes attributes) { 246 CALL_HEAP_FUNCTION(object->SetProperty(*key, *value, attributes), Object); 247} 248 249 250Handle<Object> SetProperty(Handle<Object> object, 251 Handle<Object> key, 252 Handle<Object> value, 253 PropertyAttributes attributes) { 254 CALL_HEAP_FUNCTION( 255 Runtime::SetObjectProperty(object, key, value, attributes), Object); 256} 257 258 259Handle<Object> ForceSetProperty(Handle<JSObject> object, 260 Handle<Object> key, 261 Handle<Object> value, 262 PropertyAttributes attributes) { 263 CALL_HEAP_FUNCTION( 264 Runtime::ForceSetObjectProperty(object, key, value, attributes), Object); 265} 266 267 268Handle<Object> SetNormalizedProperty(Handle<JSObject> object, 269 Handle<String> key, 270 Handle<Object> value, 271 PropertyDetails details) { 272 CALL_HEAP_FUNCTION(object->SetNormalizedProperty(*key, *value, details), 273 Object); 274} 275 276 277Handle<Object> ForceDeleteProperty(Handle<JSObject> object, 278 Handle<Object> key) { 279 CALL_HEAP_FUNCTION(Runtime::ForceDeleteObjectProperty(object, key), Object); 280} 281 282 283Handle<Object> IgnoreAttributesAndSetLocalProperty( 284 Handle<JSObject> object, 285 Handle<String> key, 286 Handle<Object> value, 287 PropertyAttributes attributes) { 288 CALL_HEAP_FUNCTION(object-> 289 IgnoreAttributesAndSetLocalProperty(*key, *value, attributes), Object); 290} 291 292 293Handle<Object> SetPropertyWithInterceptor(Handle<JSObject> object, 294 Handle<String> key, 295 Handle<Object> value, 296 PropertyAttributes attributes) { 297 CALL_HEAP_FUNCTION(object->SetPropertyWithInterceptor(*key, 298 *value, 299 attributes), 300 Object); 301} 302 303 304Handle<Object> GetProperty(Handle<JSObject> obj, 305 const char* name) { 306 Handle<String> str = Factory::LookupAsciiSymbol(name); 307 CALL_HEAP_FUNCTION(obj->GetProperty(*str), Object); 308} 309 310 311Handle<Object> GetProperty(Handle<Object> obj, 312 Handle<Object> key) { 313 CALL_HEAP_FUNCTION(Runtime::GetObjectProperty(obj, key), Object); 314} 315 316 317Handle<Object> GetElement(Handle<Object> obj, 318 uint32_t index) { 319 CALL_HEAP_FUNCTION(Runtime::GetElement(obj, index), Object); 320} 321 322 323Handle<Object> GetPropertyWithInterceptor(Handle<JSObject> receiver, 324 Handle<JSObject> holder, 325 Handle<String> name, 326 PropertyAttributes* attributes) { 327 CALL_HEAP_FUNCTION(holder->GetPropertyWithInterceptor(*receiver, 328 *name, 329 attributes), 330 Object); 331} 332 333 334Handle<Object> GetPrototype(Handle<Object> obj) { 335 Handle<Object> result(obj->GetPrototype()); 336 return result; 337} 338 339 340Handle<Object> SetPrototype(Handle<JSObject> obj, Handle<Object> value) { 341 const bool skip_hidden_prototypes = false; 342 CALL_HEAP_FUNCTION(obj->SetPrototype(*value, skip_hidden_prototypes), Object); 343} 344 345 346Handle<Object> GetHiddenProperties(Handle<JSObject> obj, 347 bool create_if_needed) { 348 Object* holder = obj->BypassGlobalProxy(); 349 if (holder->IsUndefined()) return Factory::undefined_value(); 350 obj = Handle<JSObject>(JSObject::cast(holder)); 351 352 if (obj->HasFastProperties()) { 353 // If the object has fast properties, check whether the first slot 354 // in the descriptor array matches the hidden symbol. Since the 355 // hidden symbols hash code is zero (and no other string has hash 356 // code zero) it will always occupy the first entry if present. 357 DescriptorArray* descriptors = obj->map()->instance_descriptors(); 358 if ((descriptors->number_of_descriptors() > 0) && 359 (descriptors->GetKey(0) == Heap::hidden_symbol()) && 360 descriptors->IsProperty(0)) { 361 ASSERT(descriptors->GetType(0) == FIELD); 362 return Handle<Object>(obj->FastPropertyAt(descriptors->GetFieldIndex(0))); 363 } 364 } 365 366 // Only attempt to find the hidden properties in the local object and not 367 // in the prototype chain. Note that HasLocalProperty() can cause a GC in 368 // the general case in the presence of interceptors. 369 if (!obj->HasHiddenPropertiesObject()) { 370 // Hidden properties object not found. Allocate a new hidden properties 371 // object if requested. Otherwise return the undefined value. 372 if (create_if_needed) { 373 Handle<Object> hidden_obj = Factory::NewJSObject(Top::object_function()); 374 CALL_HEAP_FUNCTION(obj->SetHiddenPropertiesObject(*hidden_obj), Object); 375 } else { 376 return Factory::undefined_value(); 377 } 378 } 379 return Handle<Object>(obj->GetHiddenPropertiesObject()); 380} 381 382 383Handle<Object> DeleteElement(Handle<JSObject> obj, 384 uint32_t index) { 385 CALL_HEAP_FUNCTION(obj->DeleteElement(index, JSObject::NORMAL_DELETION), 386 Object); 387} 388 389 390Handle<Object> DeleteProperty(Handle<JSObject> obj, 391 Handle<String> prop) { 392 CALL_HEAP_FUNCTION(obj->DeleteProperty(*prop, JSObject::NORMAL_DELETION), 393 Object); 394} 395 396 397Handle<Object> LookupSingleCharacterStringFromCode(uint32_t index) { 398 CALL_HEAP_FUNCTION(Heap::LookupSingleCharacterStringFromCode(index), Object); 399} 400 401 402Handle<String> SubString(Handle<String> str, 403 int start, 404 int end, 405 PretenureFlag pretenure) { 406 CALL_HEAP_FUNCTION(str->SubString(start, end, pretenure), String); 407} 408 409 410Handle<Object> SetElement(Handle<JSObject> object, 411 uint32_t index, 412 Handle<Object> value) { 413 if (object->HasPixelElements() || object->HasExternalArrayElements()) { 414 if (!value->IsSmi() && !value->IsHeapNumber() && !value->IsUndefined()) { 415 bool has_exception; 416 Handle<Object> number = Execution::ToNumber(value, &has_exception); 417 if (has_exception) return Handle<Object>(); 418 value = number; 419 } 420 } 421 CALL_HEAP_FUNCTION(object->SetElement(index, *value), Object); 422} 423 424 425Handle<JSObject> Copy(Handle<JSObject> obj) { 426 CALL_HEAP_FUNCTION(Heap::CopyJSObject(*obj), JSObject); 427} 428 429 430Handle<Object> SetAccessor(Handle<JSObject> obj, Handle<AccessorInfo> info) { 431 CALL_HEAP_FUNCTION(obj->DefineAccessor(*info), Object); 432} 433 434 435// Wrappers for scripts are kept alive and cached in weak global 436// handles referred from proxy objects held by the scripts as long as 437// they are used. When they are not used anymore, the garbage 438// collector will call the weak callback on the global handle 439// associated with the wrapper and get rid of both the wrapper and the 440// handle. 441static void ClearWrapperCache(Persistent<v8::Value> handle, void*) { 442#ifdef ENABLE_HEAP_PROTECTION 443 // Weak reference callbacks are called as if from outside V8. We 444 // need to reeenter to unprotect the heap. 445 VMState state(OTHER); 446#endif 447 Handle<Object> cache = Utils::OpenHandle(*handle); 448 JSValue* wrapper = JSValue::cast(*cache); 449 Proxy* proxy = Script::cast(wrapper->value())->wrapper(); 450 ASSERT(proxy->proxy() == reinterpret_cast<Address>(cache.location())); 451 proxy->set_proxy(0); 452 GlobalHandles::Destroy(cache.location()); 453 Counters::script_wrappers.Decrement(); 454} 455 456 457Handle<JSValue> GetScriptWrapper(Handle<Script> script) { 458 if (script->wrapper()->proxy() != NULL) { 459 // Return the script wrapper directly from the cache. 460 return Handle<JSValue>( 461 reinterpret_cast<JSValue**>(script->wrapper()->proxy())); 462 } 463 464 // Construct a new script wrapper. 465 Counters::script_wrappers.Increment(); 466 Handle<JSFunction> constructor = Top::script_function(); 467 Handle<JSValue> result = 468 Handle<JSValue>::cast(Factory::NewJSObject(constructor)); 469 result->set_value(*script); 470 471 // Create a new weak global handle and use it to cache the wrapper 472 // for future use. The cache will automatically be cleared by the 473 // garbage collector when it is not used anymore. 474 Handle<Object> handle = GlobalHandles::Create(*result); 475 GlobalHandles::MakeWeak(handle.location(), NULL, &ClearWrapperCache); 476 script->wrapper()->set_proxy(reinterpret_cast<Address>(handle.location())); 477 return result; 478} 479 480 481// Init line_ends array with code positions of line ends inside script 482// source. 483void InitScriptLineEnds(Handle<Script> script) { 484 if (!script->line_ends()->IsUndefined()) return; 485 486 if (!script->source()->IsString()) { 487 ASSERT(script->source()->IsUndefined()); 488 Handle<FixedArray> empty = Factory::NewFixedArray(0); 489 script->set_line_ends(*empty); 490 ASSERT(script->line_ends()->IsFixedArray()); 491 return; 492 } 493 494 Handle<String> src(String::cast(script->source())); 495 496 Handle<FixedArray> array = CalculateLineEnds(src, true); 497 498 if (*array != Heap::empty_fixed_array()) { 499 array->set_map(Heap::fixed_cow_array_map()); 500 } 501 502 script->set_line_ends(*array); 503 ASSERT(script->line_ends()->IsFixedArray()); 504} 505 506 507template <typename SourceChar> 508static void CalculateLineEnds(List<int>* line_ends, 509 Vector<const SourceChar> src, 510 bool with_last_line) { 511 const int src_len = src.length(); 512 StringSearch<char, SourceChar> search(CStrVector("\n")); 513 514 // Find and record line ends. 515 int position = 0; 516 while (position != -1 && position < src_len) { 517 position = search.Search(src, position); 518 if (position != -1) { 519 line_ends->Add(position); 520 position++; 521 } else if (with_last_line) { 522 // Even if the last line misses a line end, it is counted. 523 line_ends->Add(src_len); 524 return; 525 } 526 } 527} 528 529 530Handle<FixedArray> CalculateLineEnds(Handle<String> src, 531 bool with_last_line) { 532 src = FlattenGetString(src); 533 // Rough estimate of line count based on a roughly estimated average 534 // length of (unpacked) code. 535 int line_count_estimate = src->length() >> 4; 536 List<int> line_ends(line_count_estimate); 537 { 538 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid. 539 // Dispatch on type of strings. 540 if (src->IsAsciiRepresentation()) { 541 CalculateLineEnds(&line_ends, src->ToAsciiVector(), with_last_line); 542 } else { 543 CalculateLineEnds(&line_ends, src->ToUC16Vector(), with_last_line); 544 } 545 } 546 int line_count = line_ends.length(); 547 Handle<FixedArray> array = Factory::NewFixedArray(line_count); 548 for (int i = 0; i < line_count; i++) { 549 array->set(i, Smi::FromInt(line_ends[i])); 550 } 551 return array; 552} 553 554 555// Convert code position into line number. 556int GetScriptLineNumber(Handle<Script> script, int code_pos) { 557 InitScriptLineEnds(script); 558 AssertNoAllocation no_allocation; 559 FixedArray* line_ends_array = FixedArray::cast(script->line_ends()); 560 const int line_ends_len = line_ends_array->length(); 561 562 if (!line_ends_len) return -1; 563 564 if ((Smi::cast(line_ends_array->get(0)))->value() >= code_pos) { 565 return script->line_offset()->value(); 566 } 567 568 int left = 0; 569 int right = line_ends_len; 570 while (int half = (right - left) / 2) { 571 if ((Smi::cast(line_ends_array->get(left + half)))->value() > code_pos) { 572 right -= half; 573 } else { 574 left += half; 575 } 576 } 577 return right + script->line_offset()->value(); 578} 579 580 581int GetScriptLineNumberSafe(Handle<Script> script, int code_pos) { 582 AssertNoAllocation no_allocation; 583 if (!script->line_ends()->IsUndefined()) { 584 return GetScriptLineNumber(script, code_pos); 585 } 586 // Slow mode: we do not have line_ends. We have to iterate through source. 587 if (!script->source()->IsString()) { 588 return -1; 589 } 590 String* source = String::cast(script->source()); 591 int line = 0; 592 int len = source->length(); 593 for (int pos = 0; pos < len; pos++) { 594 if (pos == code_pos) { 595 break; 596 } 597 if (source->Get(pos) == '\n') { 598 line++; 599 } 600 } 601 return line; 602} 603 604 605void CustomArguments::IterateInstance(ObjectVisitor* v) { 606 v->VisitPointers(values_, values_ + ARRAY_SIZE(values_)); 607} 608 609 610// Compute the property keys from the interceptor. 611v8::Handle<v8::Array> GetKeysForNamedInterceptor(Handle<JSObject> receiver, 612 Handle<JSObject> object) { 613 Handle<InterceptorInfo> interceptor(object->GetNamedInterceptor()); 614 CustomArguments args(interceptor->data(), *receiver, *object); 615 v8::AccessorInfo info(args.end()); 616 v8::Handle<v8::Array> result; 617 if (!interceptor->enumerator()->IsUndefined()) { 618 v8::NamedPropertyEnumerator enum_fun = 619 v8::ToCData<v8::NamedPropertyEnumerator>(interceptor->enumerator()); 620 LOG(ApiObjectAccess("interceptor-named-enum", *object)); 621 { 622 // Leaving JavaScript. 623 VMState state(EXTERNAL); 624 result = enum_fun(info); 625 } 626 } 627 return result; 628} 629 630 631// Compute the element keys from the interceptor. 632v8::Handle<v8::Array> GetKeysForIndexedInterceptor(Handle<JSObject> receiver, 633 Handle<JSObject> object) { 634 Handle<InterceptorInfo> interceptor(object->GetIndexedInterceptor()); 635 CustomArguments args(interceptor->data(), *receiver, *object); 636 v8::AccessorInfo info(args.end()); 637 v8::Handle<v8::Array> result; 638 if (!interceptor->enumerator()->IsUndefined()) { 639 v8::IndexedPropertyEnumerator enum_fun = 640 v8::ToCData<v8::IndexedPropertyEnumerator>(interceptor->enumerator()); 641 LOG(ApiObjectAccess("interceptor-indexed-enum", *object)); 642 { 643 // Leaving JavaScript. 644 VMState state(EXTERNAL); 645 result = enum_fun(info); 646 } 647 } 648 return result; 649} 650 651 652static bool ContainsOnlyValidKeys(Handle<FixedArray> array) { 653 int len = array->length(); 654 for (int i = 0; i < len; i++) { 655 Object* e = array->get(i); 656 if (!(e->IsString() || e->IsNumber())) return false; 657 } 658 return true; 659} 660 661 662Handle<FixedArray> GetKeysInFixedArrayFor(Handle<JSObject> object, 663 KeyCollectionType type) { 664 USE(ContainsOnlyValidKeys); 665 Handle<FixedArray> content = Factory::empty_fixed_array(); 666 Handle<JSObject> arguments_boilerplate = 667 Handle<JSObject>( 668 Top::context()->global_context()->arguments_boilerplate()); 669 Handle<JSFunction> arguments_function = 670 Handle<JSFunction>( 671 JSFunction::cast(arguments_boilerplate->map()->constructor())); 672 673 // Only collect keys if access is permitted. 674 for (Handle<Object> p = object; 675 *p != Heap::null_value(); 676 p = Handle<Object>(p->GetPrototype())) { 677 Handle<JSObject> current(JSObject::cast(*p)); 678 679 // Check access rights if required. 680 if (current->IsAccessCheckNeeded() && 681 !Top::MayNamedAccess(*current, Heap::undefined_value(), 682 v8::ACCESS_KEYS)) { 683 Top::ReportFailedAccessCheck(*current, v8::ACCESS_KEYS); 684 break; 685 } 686 687 // Compute the element keys. 688 Handle<FixedArray> element_keys = 689 Factory::NewFixedArray(current->NumberOfEnumElements()); 690 current->GetEnumElementKeys(*element_keys); 691 content = UnionOfKeys(content, element_keys); 692 ASSERT(ContainsOnlyValidKeys(content)); 693 694 // Add the element keys from the interceptor. 695 if (current->HasIndexedInterceptor()) { 696 v8::Handle<v8::Array> result = 697 GetKeysForIndexedInterceptor(object, current); 698 if (!result.IsEmpty()) 699 content = AddKeysFromJSArray(content, v8::Utils::OpenHandle(*result)); 700 ASSERT(ContainsOnlyValidKeys(content)); 701 } 702 703 // We can cache the computed property keys if access checks are 704 // not needed and no interceptors are involved. 705 // 706 // We do not use the cache if the object has elements and 707 // therefore it does not make sense to cache the property names 708 // for arguments objects. Arguments objects will always have 709 // elements. 710 // Wrapped strings have elements, but don't have an elements 711 // array or dictionary. So the fast inline test for whether to 712 // use the cache says yes, so we should not create a cache. 713 bool cache_enum_keys = 714 ((current->map()->constructor() != *arguments_function) && 715 !current->IsJSValue() && 716 !current->IsAccessCheckNeeded() && 717 !current->HasNamedInterceptor() && 718 !current->HasIndexedInterceptor()); 719 // Compute the property keys and cache them if possible. 720 content = 721 UnionOfKeys(content, GetEnumPropertyKeys(current, cache_enum_keys)); 722 ASSERT(ContainsOnlyValidKeys(content)); 723 724 // Add the property keys from the interceptor. 725 if (current->HasNamedInterceptor()) { 726 v8::Handle<v8::Array> result = 727 GetKeysForNamedInterceptor(object, current); 728 if (!result.IsEmpty()) 729 content = AddKeysFromJSArray(content, v8::Utils::OpenHandle(*result)); 730 ASSERT(ContainsOnlyValidKeys(content)); 731 } 732 733 // If we only want local properties we bail out after the first 734 // iteration. 735 if (type == LOCAL_ONLY) 736 break; 737 } 738 return content; 739} 740 741 742Handle<JSArray> GetKeysFor(Handle<JSObject> object) { 743 Counters::for_in.Increment(); 744 Handle<FixedArray> elements = GetKeysInFixedArrayFor(object, 745 INCLUDE_PROTOS); 746 return Factory::NewJSArrayWithElements(elements); 747} 748 749 750Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object, 751 bool cache_result) { 752 int index = 0; 753 if (object->HasFastProperties()) { 754 if (object->map()->instance_descriptors()->HasEnumCache()) { 755 Counters::enum_cache_hits.Increment(); 756 DescriptorArray* desc = object->map()->instance_descriptors(); 757 return Handle<FixedArray>(FixedArray::cast(desc->GetEnumCache())); 758 } 759 Counters::enum_cache_misses.Increment(); 760 int num_enum = object->NumberOfEnumProperties(); 761 Handle<FixedArray> storage = Factory::NewFixedArray(num_enum); 762 Handle<FixedArray> sort_array = Factory::NewFixedArray(num_enum); 763 Handle<DescriptorArray> descs = 764 Handle<DescriptorArray>(object->map()->instance_descriptors()); 765 for (int i = 0; i < descs->number_of_descriptors(); i++) { 766 if (descs->IsProperty(i) && !descs->IsDontEnum(i)) { 767 (*storage)->set(index, descs->GetKey(i)); 768 PropertyDetails details(descs->GetDetails(i)); 769 (*sort_array)->set(index, Smi::FromInt(details.index())); 770 index++; 771 } 772 } 773 (*storage)->SortPairs(*sort_array, sort_array->length()); 774 if (cache_result) { 775 Handle<FixedArray> bridge_storage = 776 Factory::NewFixedArray(DescriptorArray::kEnumCacheBridgeLength); 777 DescriptorArray* desc = object->map()->instance_descriptors(); 778 desc->SetEnumCache(*bridge_storage, *storage); 779 } 780 ASSERT(storage->length() == index); 781 return storage; 782 } else { 783 int num_enum = object->NumberOfEnumProperties(); 784 Handle<FixedArray> storage = Factory::NewFixedArray(num_enum); 785 Handle<FixedArray> sort_array = Factory::NewFixedArray(num_enum); 786 object->property_dictionary()->CopyEnumKeysTo(*storage, *sort_array); 787 return storage; 788 } 789} 790 791 792bool EnsureCompiled(Handle<SharedFunctionInfo> shared, 793 ClearExceptionFlag flag) { 794 return shared->is_compiled() || CompileLazyShared(shared, flag); 795} 796 797 798static bool CompileLazyHelper(CompilationInfo* info, 799 ClearExceptionFlag flag) { 800 // Compile the source information to a code object. 801 ASSERT(info->IsOptimizing() || !info->shared_info()->is_compiled()); 802 bool result = Compiler::CompileLazy(info); 803 ASSERT(result != Top::has_pending_exception()); 804 if (!result && flag == CLEAR_EXCEPTION) Top::clear_pending_exception(); 805 return result; 806} 807 808 809bool CompileLazyShared(Handle<SharedFunctionInfo> shared, 810 ClearExceptionFlag flag) { 811 CompilationInfo info(shared); 812 return CompileLazyHelper(&info, flag); 813} 814 815 816bool CompileLazy(Handle<JSFunction> function, 817 ClearExceptionFlag flag) { 818 bool result = true; 819 if (function->shared()->is_compiled()) { 820 function->ReplaceCode(function->shared()->code()); 821 function->shared()->set_code_age(0); 822 } else { 823 CompilationInfo info(function); 824 result = CompileLazyHelper(&info, flag); 825 ASSERT(!result || function->is_compiled()); 826 } 827 if (result && function->is_compiled()) { 828 PROFILE(FunctionCreateEvent(*function)); 829 } 830 return result; 831} 832 833 834bool CompileLazyInLoop(Handle<JSFunction> function, 835 ClearExceptionFlag flag) { 836 bool result = true; 837 if (function->shared()->is_compiled()) { 838 function->ReplaceCode(function->shared()->code()); 839 function->shared()->set_code_age(0); 840 } else { 841 CompilationInfo info(function); 842 info.MarkAsInLoop(); 843 result = CompileLazyHelper(&info, flag); 844 ASSERT(!result || function->is_compiled()); 845 } 846 if (result && function->is_compiled()) { 847 PROFILE(FunctionCreateEvent(*function)); 848 } 849 return result; 850} 851 852 853bool CompileOptimized(Handle<JSFunction> function, int osr_ast_id) { 854 CompilationInfo info(function); 855 info.SetOptimizing(osr_ast_id); 856 bool result = CompileLazyHelper(&info, KEEP_EXCEPTION); 857 if (result) PROFILE(FunctionCreateEvent(*function)); 858 return result; 859} 860 861 862OptimizedObjectForAddingMultipleProperties:: 863OptimizedObjectForAddingMultipleProperties(Handle<JSObject> object, 864 int expected_additional_properties, 865 bool condition) { 866 object_ = object; 867 if (condition && object_->HasFastProperties()) { 868 // Normalize the properties of object to avoid n^2 behavior 869 // when extending the object multiple properties. Indicate the number of 870 // properties to be added. 871 unused_property_fields_ = object->map()->unused_property_fields(); 872 NormalizeProperties(object_, 873 KEEP_INOBJECT_PROPERTIES, 874 expected_additional_properties); 875 has_been_transformed_ = true; 876 877 } else { 878 has_been_transformed_ = false; 879 } 880} 881 882 883OptimizedObjectForAddingMultipleProperties:: 884~OptimizedObjectForAddingMultipleProperties() { 885 // Reoptimize the object to allow fast property access. 886 if (has_been_transformed_) { 887 TransformToFastProperties(object_, unused_property_fields_); 888 } 889} 890 891} } // namespace v8::internal 892