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 43 namespace v8 { 44 namespace internal { 45 46 47 v8::ImplementationUtilities::HandleScopeData HandleScope::current_ = 48 { -1, NULL, NULL }; 49 50 51 int 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 59 Object** 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 96 void HandleScope::DeleteExtensions() { 97 ASSERT(current_.extensions != 0); 98 HandleScopeImplementer::instance()->DeleteExtensions(current_.extensions); 99 } 100 101 102 void 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 110 Address HandleScope::current_extensions_address() { 111 return reinterpret_cast<Address>(¤t_.extensions); 112 } 113 114 115 Address HandleScope::current_next_address() { 116 return reinterpret_cast<Address>(¤t_.next); 117 } 118 119 120 Address HandleScope::current_limit_address() { 121 return reinterpret_cast<Address>(¤t_.limit); 122 } 123 124 125 Handle<FixedArray> AddKeysFromJSArray(Handle<FixedArray> content, 126 Handle<JSArray> array) { 127 CALL_HEAP_FUNCTION(content->AddKeysFromJSArray(*array), FixedArray); 128 } 129 130 131 Handle<FixedArray> UnionOfKeys(Handle<FixedArray> first, 132 Handle<FixedArray> second) { 133 CALL_HEAP_FUNCTION(first->UnionOfKeys(*second), FixedArray); 134 } 135 136 137 Handle<JSGlobalProxy> ReinitializeJSGlobalProxy( 138 Handle<JSFunction> constructor, 139 Handle<JSGlobalProxy> global) { 140 CALL_HEAP_FUNCTION(Heap::ReinitializeJSGlobalProxy(*constructor, *global), 141 JSGlobalProxy); 142 } 143 144 145 void 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 156 void SetPrototypeProperty(Handle<JSFunction> func, Handle<JSObject> value) { 157 CALL_HEAP_FUNCTION_VOID(func->SetPrototype(*value)); 158 } 159 160 161 static 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 170 void SetExpectedNofPropertiesFromEstimate(Handle<SharedFunctionInfo> shared, 171 int estimate) { 172 shared->set_expected_nof_properties( 173 ExpectedNofPropertiesFromEstimate(estimate)); 174 } 175 176 177 void SetExpectedNofPropertiesFromEstimate(Handle<JSFunction> func, 178 int estimate) { 179 SetExpectedNofProperties( 180 func, ExpectedNofPropertiesFromEstimate(estimate)); 181 } 182 183 184 void NormalizeProperties(Handle<JSObject> object, 185 PropertyNormalizationMode mode, 186 int expected_additional_properties) { 187 CALL_HEAP_FUNCTION_VOID(object->NormalizeProperties( 188 mode, 189 expected_additional_properties)); 190 } 191 192 193 void NormalizeElements(Handle<JSObject> object) { 194 CALL_HEAP_FUNCTION_VOID(object->NormalizeElements()); 195 } 196 197 198 void TransformToFastProperties(Handle<JSObject> object, 199 int unused_property_fields) { 200 CALL_HEAP_FUNCTION_VOID( 201 object->TransformToFastProperties(unused_property_fields)); 202 } 203 204 205 void FlattenString(Handle<String> string) { 206 CALL_HEAP_FUNCTION_VOID(string->TryFlattenIfNotFlat()); 207 ASSERT(string->IsFlat()); 208 } 209 210 211 Handle<Object> SetPrototype(Handle<JSFunction> function, 212 Handle<Object> prototype) { 213 CALL_HEAP_FUNCTION(Accessors::FunctionSetPrototype(*function, 214 *prototype, 215 NULL), 216 Object); 217 } 218 219 220 Handle<Object> SetProperty(Handle<JSObject> object, 221 Handle<String> key, 222 Handle<Object> value, 223 PropertyAttributes attributes) { 224 CALL_HEAP_FUNCTION(object->SetProperty(*key, *value, attributes), Object); 225 } 226 227 228 Handle<Object> SetProperty(Handle<Object> object, 229 Handle<Object> key, 230 Handle<Object> value, 231 PropertyAttributes attributes) { 232 CALL_HEAP_FUNCTION( 233 Runtime::SetObjectProperty(object, key, value, attributes), Object); 234 } 235 236 237 Handle<Object> ForceSetProperty(Handle<JSObject> object, 238 Handle<Object> key, 239 Handle<Object> value, 240 PropertyAttributes attributes) { 241 CALL_HEAP_FUNCTION( 242 Runtime::ForceSetObjectProperty(object, key, value, attributes), Object); 243 } 244 245 246 Handle<Object> SetNormalizedProperty(Handle<JSObject> object, 247 Handle<String> key, 248 Handle<Object> value, 249 PropertyDetails details) { 250 CALL_HEAP_FUNCTION(object->SetNormalizedProperty(*key, *value, details), 251 Object); 252 } 253 254 255 Handle<Object> ForceDeleteProperty(Handle<JSObject> object, 256 Handle<Object> key) { 257 CALL_HEAP_FUNCTION(Runtime::ForceDeleteObjectProperty(object, key), Object); 258 } 259 260 261 Handle<Object> IgnoreAttributesAndSetLocalProperty( 262 Handle<JSObject> object, 263 Handle<String> key, 264 Handle<Object> value, 265 PropertyAttributes attributes) { 266 CALL_HEAP_FUNCTION(object-> 267 IgnoreAttributesAndSetLocalProperty(*key, *value, attributes), Object); 268 } 269 270 271 Handle<Object> SetPropertyWithInterceptor(Handle<JSObject> object, 272 Handle<String> key, 273 Handle<Object> value, 274 PropertyAttributes attributes) { 275 CALL_HEAP_FUNCTION(object->SetPropertyWithInterceptor(*key, 276 *value, 277 attributes), 278 Object); 279 } 280 281 282 Handle<Object> GetProperty(Handle<JSObject> obj, 283 const char* name) { 284 Handle<String> str = Factory::LookupAsciiSymbol(name); 285 CALL_HEAP_FUNCTION(obj->GetProperty(*str), Object); 286 } 287 288 289 Handle<Object> GetProperty(Handle<Object> obj, 290 Handle<Object> key) { 291 CALL_HEAP_FUNCTION(Runtime::GetObjectProperty(obj, key), Object); 292 } 293 294 295 Handle<Object> GetPropertyWithInterceptor(Handle<JSObject> receiver, 296 Handle<JSObject> holder, 297 Handle<String> name, 298 PropertyAttributes* attributes) { 299 CALL_HEAP_FUNCTION(holder->GetPropertyWithInterceptor(*receiver, 300 *name, 301 attributes), 302 Object); 303 } 304 305 306 Handle<Object> GetPrototype(Handle<Object> obj) { 307 Handle<Object> result(obj->GetPrototype()); 308 return result; 309 } 310 311 312 Handle<Object> SetPrototype(Handle<JSObject> obj, Handle<Object> value) { 313 const bool skip_hidden_prototypes = false; 314 CALL_HEAP_FUNCTION(obj->SetPrototype(*value, skip_hidden_prototypes), Object); 315 } 316 317 318 Handle<Object> GetHiddenProperties(Handle<JSObject> obj, 319 bool create_if_needed) { 320 Object* holder = obj->BypassGlobalProxy(); 321 if (holder->IsUndefined()) return Factory::undefined_value(); 322 obj = Handle<JSObject>(JSObject::cast(holder)); 323 324 if (obj->HasFastProperties()) { 325 // If the object has fast properties, check whether the first slot 326 // in the descriptor array matches the hidden symbol. Since the 327 // hidden symbols hash code is zero (and no other string has hash 328 // code zero) it will always occupy the first entry if present. 329 DescriptorArray* descriptors = obj->map()->instance_descriptors(); 330 if ((descriptors->number_of_descriptors() > 0) && 331 (descriptors->GetKey(0) == Heap::hidden_symbol()) && 332 descriptors->IsProperty(0)) { 333 ASSERT(descriptors->GetType(0) == FIELD); 334 return Handle<Object>(obj->FastPropertyAt(descriptors->GetFieldIndex(0))); 335 } 336 } 337 338 // Only attempt to find the hidden properties in the local object and not 339 // in the prototype chain. Note that HasLocalProperty() can cause a GC in 340 // the general case in the presence of interceptors. 341 if (!obj->HasHiddenPropertiesObject()) { 342 // Hidden properties object not found. Allocate a new hidden properties 343 // object if requested. Otherwise return the undefined value. 344 if (create_if_needed) { 345 Handle<Object> hidden_obj = Factory::NewJSObject(Top::object_function()); 346 CALL_HEAP_FUNCTION(obj->SetHiddenPropertiesObject(*hidden_obj), Object); 347 } else { 348 return Factory::undefined_value(); 349 } 350 } 351 return Handle<Object>(obj->GetHiddenPropertiesObject()); 352 } 353 354 355 Handle<Object> DeleteElement(Handle<JSObject> obj, 356 uint32_t index) { 357 CALL_HEAP_FUNCTION(obj->DeleteElement(index, JSObject::NORMAL_DELETION), 358 Object); 359 } 360 361 362 Handle<Object> DeleteProperty(Handle<JSObject> obj, 363 Handle<String> prop) { 364 CALL_HEAP_FUNCTION(obj->DeleteProperty(*prop, JSObject::NORMAL_DELETION), 365 Object); 366 } 367 368 369 Handle<Object> LookupSingleCharacterStringFromCode(uint32_t index) { 370 CALL_HEAP_FUNCTION(Heap::LookupSingleCharacterStringFromCode(index), Object); 371 } 372 373 374 Handle<String> SubString(Handle<String> str, int start, int end) { 375 CALL_HEAP_FUNCTION(str->SubString(start, end), String); 376 } 377 378 379 Handle<Object> SetElement(Handle<JSObject> object, 380 uint32_t index, 381 Handle<Object> value) { 382 if (object->HasPixelElements() || object->HasExternalArrayElements()) { 383 if (!value->IsSmi() && !value->IsHeapNumber() && !value->IsUndefined()) { 384 bool has_exception; 385 Handle<Object> number = Execution::ToNumber(value, &has_exception); 386 if (has_exception) return Handle<Object>(); 387 value = number; 388 } 389 } 390 CALL_HEAP_FUNCTION(object->SetElement(index, *value), Object); 391 } 392 393 394 Handle<JSObject> Copy(Handle<JSObject> obj) { 395 CALL_HEAP_FUNCTION(Heap::CopyJSObject(*obj), JSObject); 396 } 397 398 399 // Wrappers for scripts are kept alive and cached in weak global 400 // handles referred from proxy objects held by the scripts as long as 401 // they are used. When they are not used anymore, the garbage 402 // collector will call the weak callback on the global handle 403 // associated with the wrapper and get rid of both the wrapper and the 404 // handle. 405 static void ClearWrapperCache(Persistent<v8::Value> handle, void*) { 406 #ifdef ENABLE_HEAP_PROTECTION 407 // Weak reference callbacks are called as if from outside V8. We 408 // need to reeenter to unprotect the heap. 409 VMState state(OTHER); 410 #endif 411 Handle<Object> cache = Utils::OpenHandle(*handle); 412 JSValue* wrapper = JSValue::cast(*cache); 413 Proxy* proxy = Script::cast(wrapper->value())->wrapper(); 414 ASSERT(proxy->proxy() == reinterpret_cast<Address>(cache.location())); 415 proxy->set_proxy(0); 416 GlobalHandles::Destroy(cache.location()); 417 Counters::script_wrappers.Decrement(); 418 } 419 420 421 Handle<JSValue> GetScriptWrapper(Handle<Script> script) { 422 if (script->wrapper()->proxy() != NULL) { 423 // Return the script wrapper directly from the cache. 424 return Handle<JSValue>( 425 reinterpret_cast<JSValue**>(script->wrapper()->proxy())); 426 } 427 428 // Construct a new script wrapper. 429 Counters::script_wrappers.Increment(); 430 Handle<JSFunction> constructor = Top::script_function(); 431 Handle<JSValue> result = 432 Handle<JSValue>::cast(Factory::NewJSObject(constructor)); 433 result->set_value(*script); 434 435 // Create a new weak global handle and use it to cache the wrapper 436 // for future use. The cache will automatically be cleared by the 437 // garbage collector when it is not used anymore. 438 Handle<Object> handle = GlobalHandles::Create(*result); 439 GlobalHandles::MakeWeak(handle.location(), NULL, &ClearWrapperCache); 440 script->wrapper()->set_proxy(reinterpret_cast<Address>(handle.location())); 441 return result; 442 } 443 444 445 // Init line_ends array with code positions of line ends inside script 446 // source. 447 void InitScriptLineEnds(Handle<Script> script) { 448 if (!script->line_ends()->IsUndefined()) return; 449 450 if (!script->source()->IsString()) { 451 ASSERT(script->source()->IsUndefined()); 452 script->set_line_ends(*(Factory::NewFixedArray(0))); 453 ASSERT(script->line_ends()->IsFixedArray()); 454 return; 455 } 456 457 Handle<String> src(String::cast(script->source())); 458 const int src_len = src->length(); 459 Handle<String> new_line = Factory::NewStringFromAscii(CStrVector("\n")); 460 461 // Pass 1: Identify line count. 462 int line_count = 0; 463 int position = 0; 464 while (position != -1 && position < src_len) { 465 position = Runtime::StringMatch(src, new_line, position); 466 if (position != -1) { 467 position++; 468 } 469 // Even if the last line misses a line end, it is counted. 470 line_count++; 471 } 472 473 // Pass 2: Fill in line ends positions 474 Handle<FixedArray> array = Factory::NewFixedArray(line_count); 475 int array_index = 0; 476 position = 0; 477 while (position != -1 && position < src_len) { 478 position = Runtime::StringMatch(src, new_line, position); 479 // If the script does not end with a line ending add the final end 480 // position as just past the last line ending. 481 array->set(array_index++, 482 Smi::FromInt(position != -1 ? position++ : src_len)); 483 } 484 ASSERT(array_index == line_count); 485 486 script->set_line_ends(*array); 487 ASSERT(script->line_ends()->IsFixedArray()); 488 } 489 490 491 // Convert code position into line number. 492 int GetScriptLineNumber(Handle<Script> script, int code_pos) { 493 InitScriptLineEnds(script); 494 AssertNoAllocation no_allocation; 495 FixedArray* line_ends_array = FixedArray::cast(script->line_ends()); 496 const int line_ends_len = line_ends_array->length(); 497 498 if (!line_ends_len) 499 return -1; 500 501 if ((Smi::cast(line_ends_array->get(0)))->value() >= code_pos) 502 return script->line_offset()->value(); 503 504 int left = 0; 505 int right = line_ends_len; 506 while (int half = (right - left) / 2) { 507 if ((Smi::cast(line_ends_array->get(left + half)))->value() > code_pos) { 508 right -= half; 509 } else { 510 left += half; 511 } 512 } 513 return right + script->line_offset()->value(); 514 } 515 516 517 void CustomArguments::IterateInstance(ObjectVisitor* v) { 518 v->VisitPointers(values_, values_ + 4); 519 } 520 521 522 // Compute the property keys from the interceptor. 523 v8::Handle<v8::Array> GetKeysForNamedInterceptor(Handle<JSObject> receiver, 524 Handle<JSObject> object) { 525 Handle<InterceptorInfo> interceptor(object->GetNamedInterceptor()); 526 CustomArguments args(interceptor->data(), *receiver, *object); 527 v8::AccessorInfo info(args.end()); 528 v8::Handle<v8::Array> result; 529 if (!interceptor->enumerator()->IsUndefined()) { 530 v8::NamedPropertyEnumerator enum_fun = 531 v8::ToCData<v8::NamedPropertyEnumerator>(interceptor->enumerator()); 532 LOG(ApiObjectAccess("interceptor-named-enum", *object)); 533 { 534 // Leaving JavaScript. 535 VMState state(EXTERNAL); 536 result = enum_fun(info); 537 } 538 } 539 return result; 540 } 541 542 543 // Compute the element keys from the interceptor. 544 v8::Handle<v8::Array> GetKeysForIndexedInterceptor(Handle<JSObject> receiver, 545 Handle<JSObject> object) { 546 Handle<InterceptorInfo> interceptor(object->GetIndexedInterceptor()); 547 CustomArguments args(interceptor->data(), *receiver, *object); 548 v8::AccessorInfo info(args.end()); 549 v8::Handle<v8::Array> result; 550 if (!interceptor->enumerator()->IsUndefined()) { 551 v8::IndexedPropertyEnumerator enum_fun = 552 v8::ToCData<v8::IndexedPropertyEnumerator>(interceptor->enumerator()); 553 LOG(ApiObjectAccess("interceptor-indexed-enum", *object)); 554 { 555 // Leaving JavaScript. 556 VMState state(EXTERNAL); 557 result = enum_fun(info); 558 } 559 } 560 return result; 561 } 562 563 564 Handle<FixedArray> GetKeysInFixedArrayFor(Handle<JSObject> object, 565 KeyCollectionType type) { 566 Handle<FixedArray> content = Factory::empty_fixed_array(); 567 Handle<JSObject> arguments_boilerplate = 568 Handle<JSObject>( 569 Top::context()->global_context()->arguments_boilerplate()); 570 Handle<JSFunction> arguments_function = 571 Handle<JSFunction>( 572 JSFunction::cast(arguments_boilerplate->map()->constructor())); 573 574 // Only collect keys if access is permitted. 575 for (Handle<Object> p = object; 576 *p != Heap::null_value(); 577 p = Handle<Object>(p->GetPrototype())) { 578 Handle<JSObject> current(JSObject::cast(*p)); 579 580 // Check access rights if required. 581 if (current->IsAccessCheckNeeded() && 582 !Top::MayNamedAccess(*current, Heap::undefined_value(), 583 v8::ACCESS_KEYS)) { 584 Top::ReportFailedAccessCheck(*current, v8::ACCESS_KEYS); 585 break; 586 } 587 588 // Compute the element keys. 589 Handle<FixedArray> element_keys = 590 Factory::NewFixedArray(current->NumberOfEnumElements()); 591 current->GetEnumElementKeys(*element_keys); 592 content = UnionOfKeys(content, element_keys); 593 594 // Add the element keys from the interceptor. 595 if (current->HasIndexedInterceptor()) { 596 v8::Handle<v8::Array> result = 597 GetKeysForIndexedInterceptor(object, current); 598 if (!result.IsEmpty()) 599 content = AddKeysFromJSArray(content, v8::Utils::OpenHandle(*result)); 600 } 601 602 // We can cache the computed property keys if access checks are 603 // not needed and no interceptors are involved. 604 // 605 // We do not use the cache if the object has elements and 606 // therefore it does not make sense to cache the property names 607 // for arguments objects. Arguments objects will always have 608 // elements. 609 bool cache_enum_keys = 610 ((current->map()->constructor() != *arguments_function) && 611 !current->IsAccessCheckNeeded() && 612 !current->HasNamedInterceptor() && 613 !current->HasIndexedInterceptor()); 614 // Compute the property keys and cache them if possible. 615 content = 616 UnionOfKeys(content, GetEnumPropertyKeys(current, cache_enum_keys)); 617 618 // Add the property keys from the interceptor. 619 if (current->HasNamedInterceptor()) { 620 v8::Handle<v8::Array> result = 621 GetKeysForNamedInterceptor(object, current); 622 if (!result.IsEmpty()) 623 content = AddKeysFromJSArray(content, v8::Utils::OpenHandle(*result)); 624 } 625 626 // If we only want local properties we bail out after the first 627 // iteration. 628 if (type == LOCAL_ONLY) 629 break; 630 } 631 return content; 632 } 633 634 635 Handle<JSArray> GetKeysFor(Handle<JSObject> object) { 636 Counters::for_in.Increment(); 637 Handle<FixedArray> elements = GetKeysInFixedArrayFor(object, 638 INCLUDE_PROTOS); 639 return Factory::NewJSArrayWithElements(elements); 640 } 641 642 643 Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object, 644 bool cache_result) { 645 int index = 0; 646 if (object->HasFastProperties()) { 647 if (object->map()->instance_descriptors()->HasEnumCache()) { 648 Counters::enum_cache_hits.Increment(); 649 DescriptorArray* desc = object->map()->instance_descriptors(); 650 return Handle<FixedArray>(FixedArray::cast(desc->GetEnumCache())); 651 } 652 Counters::enum_cache_misses.Increment(); 653 int num_enum = object->NumberOfEnumProperties(); 654 Handle<FixedArray> storage = Factory::NewFixedArray(num_enum); 655 Handle<FixedArray> sort_array = Factory::NewFixedArray(num_enum); 656 Handle<DescriptorArray> descs = 657 Handle<DescriptorArray>(object->map()->instance_descriptors()); 658 for (int i = 0; i < descs->number_of_descriptors(); i++) { 659 if (descs->IsProperty(i) && !descs->IsDontEnum(i)) { 660 (*storage)->set(index, descs->GetKey(i)); 661 PropertyDetails details(descs->GetDetails(i)); 662 (*sort_array)->set(index, Smi::FromInt(details.index())); 663 index++; 664 } 665 } 666 (*storage)->SortPairs(*sort_array, sort_array->length()); 667 if (cache_result) { 668 Handle<FixedArray> bridge_storage = 669 Factory::NewFixedArray(DescriptorArray::kEnumCacheBridgeLength); 670 DescriptorArray* desc = object->map()->instance_descriptors(); 671 desc->SetEnumCache(*bridge_storage, *storage); 672 } 673 ASSERT(storage->length() == index); 674 return storage; 675 } else { 676 int num_enum = object->NumberOfEnumProperties(); 677 Handle<FixedArray> storage = Factory::NewFixedArray(num_enum); 678 Handle<FixedArray> sort_array = Factory::NewFixedArray(num_enum); 679 object->property_dictionary()->CopyEnumKeysTo(*storage, *sort_array); 680 return storage; 681 } 682 } 683 684 685 bool EnsureCompiled(Handle<SharedFunctionInfo> shared, 686 ClearExceptionFlag flag) { 687 return shared->is_compiled() || CompileLazyShared(shared, flag); 688 } 689 690 691 static bool CompileLazyHelper(CompilationInfo* info, 692 ClearExceptionFlag flag) { 693 // Compile the source information to a code object. 694 ASSERT(!info->shared_info()->is_compiled()); 695 bool result = Compiler::CompileLazy(info); 696 ASSERT(result != Top::has_pending_exception()); 697 if (!result && flag == CLEAR_EXCEPTION) Top::clear_pending_exception(); 698 return result; 699 } 700 701 702 bool CompileLazyShared(Handle<SharedFunctionInfo> shared, 703 ClearExceptionFlag flag) { 704 CompilationInfo info(shared); 705 return CompileLazyHelper(&info, flag); 706 } 707 708 709 bool CompileLazy(Handle<JSFunction> function, 710 Handle<Object> receiver, 711 ClearExceptionFlag flag) { 712 CompilationInfo info(function, 0, receiver); 713 bool result = CompileLazyHelper(&info, flag); 714 LOG(FunctionCreateEvent(*function)); 715 return result; 716 } 717 718 719 bool CompileLazyInLoop(Handle<JSFunction> function, 720 Handle<Object> receiver, 721 ClearExceptionFlag flag) { 722 CompilationInfo info(function, 1, receiver); 723 bool result = CompileLazyHelper(&info, flag); 724 LOG(FunctionCreateEvent(*function)); 725 return result; 726 } 727 728 729 OptimizedObjectForAddingMultipleProperties:: 730 OptimizedObjectForAddingMultipleProperties(Handle<JSObject> object, 731 int expected_additional_properties, 732 bool condition) { 733 object_ = object; 734 if (condition && object_->HasFastProperties()) { 735 // Normalize the properties of object to avoid n^2 behavior 736 // when extending the object multiple properties. Indicate the number of 737 // properties to be added. 738 unused_property_fields_ = object->map()->unused_property_fields(); 739 NormalizeProperties(object_, 740 KEEP_INOBJECT_PROPERTIES, 741 expected_additional_properties); 742 has_been_transformed_ = true; 743 744 } else { 745 has_been_transformed_ = false; 746 } 747 } 748 749 750 Handle<Code> ComputeLazyCompile(int argc) { 751 CALL_HEAP_FUNCTION(StubCache::ComputeLazyCompile(argc), Code); 752 } 753 754 755 OptimizedObjectForAddingMultipleProperties:: 756 ~OptimizedObjectForAddingMultipleProperties() { 757 // Reoptimize the object to allow fast property access. 758 if (has_been_transformed_) { 759 TransformToFastProperties(object_, unused_property_fields_); 760 } 761 } 762 763 } } // namespace v8::internal 764