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