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