1 // Copyright 2012 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 44 namespace v8 { 45 namespace internal { 46 47 48 int HandleScope::NumberOfHandles(Isolate* isolate) { 49 HandleScopeImplementer* impl = isolate->handle_scope_implementer(); 50 int n = impl->blocks()->length(); 51 if (n == 0) return 0; 52 return ((n - 1) * kHandleBlockSize) + static_cast<int>( 53 (isolate->handle_scope_data()->next - impl->blocks()->last())); 54 } 55 56 57 Object** HandleScope::Extend(Isolate* isolate) { 58 v8::ImplementationUtilities::HandleScopeData* current = 59 isolate->handle_scope_data(); 60 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 = isolate->handle_scope_implementer(); 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 97 void HandleScope::DeleteExtensions(Isolate* isolate) { 98 v8::ImplementationUtilities::HandleScopeData* current = 99 isolate->handle_scope_data(); 100 isolate->handle_scope_implementer()->DeleteExtensions(current->limit); 101 } 102 103 104 #ifdef ENABLE_HANDLE_ZAPPING 105 void HandleScope::ZapRange(Object** start, Object** end) { 106 ASSERT(end - start <= kHandleBlockSize); 107 for (Object** p = start; p != end; p++) { 108 *reinterpret_cast<Address*>(p) = v8::internal::kHandleZapValue; 109 } 110 } 111 #endif 112 113 114 Address HandleScope::current_level_address(Isolate* isolate) { 115 return reinterpret_cast<Address>(&isolate->handle_scope_data()->level); 116 } 117 118 119 Address HandleScope::current_next_address(Isolate* isolate) { 120 return reinterpret_cast<Address>(&isolate->handle_scope_data()->next); 121 } 122 123 124 Address HandleScope::current_limit_address(Isolate* isolate) { 125 return reinterpret_cast<Address>(&isolate->handle_scope_data()->limit); 126 } 127 128 129 Handle<FixedArray> AddKeysFromJSArray(Handle<FixedArray> content, 130 Handle<JSArray> array) { 131 CALL_HEAP_FUNCTION(content->GetIsolate(), 132 content->AddKeysFromJSArray(*array), FixedArray); 133 } 134 135 136 Handle<FixedArray> UnionOfKeys(Handle<FixedArray> first, 137 Handle<FixedArray> second) { 138 CALL_HEAP_FUNCTION(first->GetIsolate(), 139 first->UnionOfKeys(*second), FixedArray); 140 } 141 142 143 Handle<JSGlobalProxy> ReinitializeJSGlobalProxy( 144 Handle<JSFunction> constructor, 145 Handle<JSGlobalProxy> global) { 146 CALL_HEAP_FUNCTION( 147 constructor->GetIsolate(), 148 constructor->GetHeap()->ReinitializeJSGlobalProxy(*constructor, *global), 149 JSGlobalProxy); 150 } 151 152 153 void FlattenString(Handle<String> string) { 154 CALL_HEAP_FUNCTION_VOID(string->GetIsolate(), string->TryFlatten()); 155 } 156 157 158 Handle<String> FlattenGetString(Handle<String> string) { 159 CALL_HEAP_FUNCTION(string->GetIsolate(), string->TryFlatten(), String); 160 } 161 162 163 Handle<Object> ForceSetProperty(Handle<JSObject> object, 164 Handle<Object> key, 165 Handle<Object> value, 166 PropertyAttributes attributes) { 167 return Runtime::ForceSetObjectProperty(object->GetIsolate(), object, key, 168 value, attributes); 169 } 170 171 172 Handle<Object> DeleteProperty(Handle<JSObject> object, Handle<Object> key) { 173 Isolate* isolate = object->GetIsolate(); 174 CALL_HEAP_FUNCTION(isolate, 175 Runtime::DeleteObjectProperty( 176 isolate, object, key, JSReceiver::NORMAL_DELETION), 177 Object); 178 } 179 180 181 Handle<Object> ForceDeleteProperty(Handle<JSObject> object, 182 Handle<Object> key) { 183 Isolate* isolate = object->GetIsolate(); 184 CALL_HEAP_FUNCTION(isolate, 185 Runtime::DeleteObjectProperty( 186 isolate, object, key, JSReceiver::FORCE_DELETION), 187 Object); 188 } 189 190 191 Handle<Object> HasProperty(Handle<JSReceiver> obj, Handle<Object> key) { 192 Isolate* isolate = obj->GetIsolate(); 193 CALL_HEAP_FUNCTION(isolate, 194 Runtime::HasObjectProperty(isolate, obj, key), Object); 195 } 196 197 198 Handle<Object> GetProperty(Handle<JSReceiver> obj, 199 const char* name) { 200 Isolate* isolate = obj->GetIsolate(); 201 Handle<String> str = isolate->factory()->InternalizeUtf8String(name); 202 CALL_HEAP_FUNCTION(isolate, obj->GetProperty(*str), Object); 203 } 204 205 206 Handle<Object> GetProperty(Isolate* isolate, 207 Handle<Object> obj, 208 Handle<Object> key) { 209 CALL_HEAP_FUNCTION(isolate, 210 Runtime::GetObjectProperty(isolate, obj, key), Object); 211 } 212 213 214 Handle<Object> LookupSingleCharacterStringFromCode(Isolate* isolate, 215 uint32_t index) { 216 CALL_HEAP_FUNCTION( 217 isolate, 218 isolate->heap()->LookupSingleCharacterStringFromCode(index), Object); 219 } 220 221 222 // Wrappers for scripts are kept alive and cached in weak global 223 // handles referred from foreign objects held by the scripts as long as 224 // they are used. When they are not used anymore, the garbage 225 // collector will call the weak callback on the global handle 226 // associated with the wrapper and get rid of both the wrapper and the 227 // handle. 228 static void ClearWrapperCache(v8::Isolate* v8_isolate, 229 Persistent<v8::Value>* handle, 230 void*) { 231 Handle<Object> cache = Utils::OpenPersistent(handle); 232 JSValue* wrapper = JSValue::cast(*cache); 233 Foreign* foreign = Script::cast(wrapper->value())->wrapper(); 234 ASSERT(foreign->foreign_address() == 235 reinterpret_cast<Address>(cache.location())); 236 foreign->set_foreign_address(0); 237 Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate); 238 isolate->global_handles()->Destroy(cache.location()); 239 isolate->counters()->script_wrappers()->Decrement(); 240 } 241 242 243 Handle<JSValue> GetScriptWrapper(Handle<Script> script) { 244 if (script->wrapper()->foreign_address() != NULL) { 245 // Return a handle for the existing script wrapper from the cache. 246 return Handle<JSValue>( 247 *reinterpret_cast<JSValue**>(script->wrapper()->foreign_address())); 248 } 249 Isolate* isolate = script->GetIsolate(); 250 // Construct a new script wrapper. 251 isolate->counters()->script_wrappers()->Increment(); 252 Handle<JSFunction> constructor = isolate->script_function(); 253 Handle<JSValue> result = 254 Handle<JSValue>::cast(isolate->factory()->NewJSObject(constructor)); 255 256 // The allocation might have triggered a GC, which could have called this 257 // function recursively, and a wrapper has already been created and cached. 258 // In that case, simply return a handle for the cached wrapper. 259 if (script->wrapper()->foreign_address() != NULL) { 260 return Handle<JSValue>( 261 *reinterpret_cast<JSValue**>(script->wrapper()->foreign_address())); 262 } 263 264 result->set_value(*script); 265 266 // Create a new weak global handle and use it to cache the wrapper 267 // for future use. The cache will automatically be cleared by the 268 // garbage collector when it is not used anymore. 269 Handle<Object> handle = isolate->global_handles()->Create(*result); 270 isolate->global_handles()->MakeWeak(handle.location(), 271 NULL, 272 &ClearWrapperCache); 273 script->wrapper()->set_foreign_address( 274 reinterpret_cast<Address>(handle.location())); 275 return result; 276 } 277 278 279 // Init line_ends array with code positions of line ends inside script 280 // source. 281 void InitScriptLineEnds(Handle<Script> script) { 282 if (!script->line_ends()->IsUndefined()) return; 283 284 Isolate* isolate = script->GetIsolate(); 285 286 if (!script->source()->IsString()) { 287 ASSERT(script->source()->IsUndefined()); 288 Handle<FixedArray> empty = isolate->factory()->NewFixedArray(0); 289 script->set_line_ends(*empty); 290 ASSERT(script->line_ends()->IsFixedArray()); 291 return; 292 } 293 294 Handle<String> src(String::cast(script->source()), isolate); 295 296 Handle<FixedArray> array = CalculateLineEnds(src, true); 297 298 if (*array != isolate->heap()->empty_fixed_array()) { 299 array->set_map(isolate->heap()->fixed_cow_array_map()); 300 } 301 302 script->set_line_ends(*array); 303 ASSERT(script->line_ends()->IsFixedArray()); 304 } 305 306 307 template <typename SourceChar> 308 static void CalculateLineEnds(Isolate* isolate, 309 List<int>* line_ends, 310 Vector<const SourceChar> src, 311 bool with_last_line) { 312 const int src_len = src.length(); 313 StringSearch<uint8_t, SourceChar> search(isolate, STATIC_ASCII_VECTOR("\n")); 314 315 // Find and record line ends. 316 int position = 0; 317 while (position != -1 && position < src_len) { 318 position = search.Search(src, position); 319 if (position != -1) { 320 line_ends->Add(position); 321 position++; 322 } else if (with_last_line) { 323 // Even if the last line misses a line end, it is counted. 324 line_ends->Add(src_len); 325 return; 326 } 327 } 328 } 329 330 331 Handle<FixedArray> CalculateLineEnds(Handle<String> src, 332 bool with_last_line) { 333 src = FlattenGetString(src); 334 // Rough estimate of line count based on a roughly estimated average 335 // length of (unpacked) code. 336 int line_count_estimate = src->length() >> 4; 337 List<int> line_ends(line_count_estimate); 338 Isolate* isolate = src->GetIsolate(); 339 { 340 DisallowHeapAllocation no_allocation; // ensure vectors stay valid. 341 // Dispatch on type of strings. 342 String::FlatContent content = src->GetFlatContent(); 343 ASSERT(content.IsFlat()); 344 if (content.IsAscii()) { 345 CalculateLineEnds(isolate, 346 &line_ends, 347 content.ToOneByteVector(), 348 with_last_line); 349 } else { 350 CalculateLineEnds(isolate, 351 &line_ends, 352 content.ToUC16Vector(), 353 with_last_line); 354 } 355 } 356 int line_count = line_ends.length(); 357 Handle<FixedArray> array = isolate->factory()->NewFixedArray(line_count); 358 for (int i = 0; i < line_count; i++) { 359 array->set(i, Smi::FromInt(line_ends[i])); 360 } 361 return array; 362 } 363 364 365 // Convert code position into line number. 366 int GetScriptLineNumber(Handle<Script> script, int code_pos) { 367 InitScriptLineEnds(script); 368 DisallowHeapAllocation no_allocation; 369 FixedArray* line_ends_array = FixedArray::cast(script->line_ends()); 370 const int line_ends_len = line_ends_array->length(); 371 372 if (!line_ends_len) return -1; 373 374 if ((Smi::cast(line_ends_array->get(0)))->value() >= code_pos) { 375 return script->line_offset()->value(); 376 } 377 378 int left = 0; 379 int right = line_ends_len; 380 while (int half = (right - left) / 2) { 381 if ((Smi::cast(line_ends_array->get(left + half)))->value() > code_pos) { 382 right -= half; 383 } else { 384 left += half; 385 } 386 } 387 return right + script->line_offset()->value(); 388 } 389 390 391 // Convert code position into column number. 392 int GetScriptColumnNumber(Handle<Script> script, int code_pos) { 393 int line_number = GetScriptLineNumber(script, code_pos); 394 if (line_number == -1) return -1; 395 396 DisallowHeapAllocation no_allocation; 397 FixedArray* line_ends_array = FixedArray::cast(script->line_ends()); 398 line_number = line_number - script->line_offset()->value(); 399 if (line_number == 0) return code_pos + script->column_offset()->value(); 400 int prev_line_end_pos = 401 Smi::cast(line_ends_array->get(line_number - 1))->value(); 402 return code_pos - (prev_line_end_pos + 1); 403 } 404 405 406 int GetScriptLineNumberSafe(Handle<Script> script, int code_pos) { 407 DisallowHeapAllocation no_allocation; 408 if (!script->line_ends()->IsUndefined()) { 409 return GetScriptLineNumber(script, code_pos); 410 } 411 // Slow mode: we do not have line_ends. We have to iterate through source. 412 if (!script->source()->IsString()) { 413 return -1; 414 } 415 String* source = String::cast(script->source()); 416 int line = 0; 417 int len = source->length(); 418 for (int pos = 0; pos < len; pos++) { 419 if (pos == code_pos) { 420 break; 421 } 422 if (source->Get(pos) == '\n') { 423 line++; 424 } 425 } 426 return line; 427 } 428 429 430 // Compute the property keys from the interceptor. 431 // TODO(rossberg): support symbols in API, and filter here if needed. 432 v8::Handle<v8::Array> GetKeysForNamedInterceptor(Handle<JSReceiver> receiver, 433 Handle<JSObject> object) { 434 Isolate* isolate = receiver->GetIsolate(); 435 Handle<InterceptorInfo> interceptor(object->GetNamedInterceptor()); 436 PropertyCallbackArguments 437 args(isolate, interceptor->data(), *receiver, *object); 438 v8::Handle<v8::Array> result; 439 if (!interceptor->enumerator()->IsUndefined()) { 440 v8::NamedPropertyEnumeratorCallback enum_fun = 441 v8::ToCData<v8::NamedPropertyEnumeratorCallback>( 442 interceptor->enumerator()); 443 LOG(isolate, ApiObjectAccess("interceptor-named-enum", *object)); 444 result = args.Call(enum_fun); 445 } 446 #if ENABLE_EXTRA_CHECKS 447 CHECK(result.IsEmpty() || v8::Utils::OpenHandle(*result)->IsJSObject()); 448 #endif 449 return v8::Local<v8::Array>::New(reinterpret_cast<v8::Isolate*>(isolate), 450 result); 451 } 452 453 454 // Compute the element keys from the interceptor. 455 v8::Handle<v8::Array> GetKeysForIndexedInterceptor(Handle<JSReceiver> receiver, 456 Handle<JSObject> object) { 457 Isolate* isolate = receiver->GetIsolate(); 458 Handle<InterceptorInfo> interceptor(object->GetIndexedInterceptor()); 459 PropertyCallbackArguments 460 args(isolate, interceptor->data(), *receiver, *object); 461 v8::Handle<v8::Array> result; 462 if (!interceptor->enumerator()->IsUndefined()) { 463 v8::IndexedPropertyEnumeratorCallback enum_fun = 464 v8::ToCData<v8::IndexedPropertyEnumeratorCallback>( 465 interceptor->enumerator()); 466 LOG(isolate, ApiObjectAccess("interceptor-indexed-enum", *object)); 467 result = args.Call(enum_fun); 468 #if ENABLE_EXTRA_CHECKS 469 CHECK(result.IsEmpty() || v8::Utils::OpenHandle(*result)->IsJSObject()); 470 #endif 471 } 472 return v8::Local<v8::Array>::New(reinterpret_cast<v8::Isolate*>(isolate), 473 result); 474 } 475 476 477 Handle<Object> GetScriptNameOrSourceURL(Handle<Script> script) { 478 Isolate* isolate = script->GetIsolate(); 479 Handle<String> name_or_source_url_key = 480 isolate->factory()->InternalizeOneByteString( 481 STATIC_ASCII_VECTOR("nameOrSourceURL")); 482 Handle<JSValue> script_wrapper = GetScriptWrapper(script); 483 Handle<Object> property = GetProperty(isolate, 484 script_wrapper, 485 name_or_source_url_key); 486 ASSERT(property->IsJSFunction()); 487 Handle<JSFunction> method = Handle<JSFunction>::cast(property); 488 bool caught_exception; 489 Handle<Object> result = Execution::TryCall(method, script_wrapper, 0, 490 NULL, &caught_exception); 491 if (caught_exception) { 492 result = isolate->factory()->undefined_value(); 493 } 494 return result; 495 } 496 497 498 static bool ContainsOnlyValidKeys(Handle<FixedArray> array) { 499 int len = array->length(); 500 for (int i = 0; i < len; i++) { 501 Object* e = array->get(i); 502 if (!(e->IsString() || e->IsNumber())) return false; 503 } 504 return true; 505 } 506 507 508 Handle<FixedArray> GetKeysInFixedArrayFor(Handle<JSReceiver> object, 509 KeyCollectionType type, 510 bool* threw) { 511 USE(ContainsOnlyValidKeys); 512 Isolate* isolate = object->GetIsolate(); 513 Handle<FixedArray> content = isolate->factory()->empty_fixed_array(); 514 Handle<JSObject> arguments_boilerplate = Handle<JSObject>( 515 isolate->context()->native_context()->arguments_boilerplate(), 516 isolate); 517 Handle<JSFunction> arguments_function = Handle<JSFunction>( 518 JSFunction::cast(arguments_boilerplate->map()->constructor()), 519 isolate); 520 521 // Only collect keys if access is permitted. 522 for (Handle<Object> p = object; 523 *p != isolate->heap()->null_value(); 524 p = Handle<Object>(p->GetPrototype(isolate), isolate)) { 525 if (p->IsJSProxy()) { 526 Handle<JSProxy> proxy(JSProxy::cast(*p), isolate); 527 Handle<Object> args[] = { proxy }; 528 Handle<Object> names = Execution::Call(isolate, 529 isolate->proxy_enumerate(), 530 object, 531 ARRAY_SIZE(args), 532 args, 533 threw); 534 if (*threw) return content; 535 content = AddKeysFromJSArray(content, Handle<JSArray>::cast(names)); 536 break; 537 } 538 539 Handle<JSObject> current(JSObject::cast(*p), isolate); 540 541 // Check access rights if required. 542 if (current->IsAccessCheckNeeded() && 543 !isolate->MayNamedAccess(*current, 544 isolate->heap()->undefined_value(), 545 v8::ACCESS_KEYS)) { 546 isolate->ReportFailedAccessCheck(*current, v8::ACCESS_KEYS); 547 if (isolate->has_scheduled_exception()) { 548 isolate->PromoteScheduledException(); 549 *threw = true; 550 } 551 break; 552 } 553 554 // Compute the element keys. 555 Handle<FixedArray> element_keys = 556 isolate->factory()->NewFixedArray(current->NumberOfEnumElements()); 557 current->GetEnumElementKeys(*element_keys); 558 content = UnionOfKeys(content, element_keys); 559 ASSERT(ContainsOnlyValidKeys(content)); 560 561 // Add the element keys from the interceptor. 562 if (current->HasIndexedInterceptor()) { 563 v8::Handle<v8::Array> result = 564 GetKeysForIndexedInterceptor(object, current); 565 if (!result.IsEmpty()) 566 content = AddKeysFromJSArray(content, v8::Utils::OpenHandle(*result)); 567 ASSERT(ContainsOnlyValidKeys(content)); 568 } 569 570 // We can cache the computed property keys if access checks are 571 // not needed and no interceptors are involved. 572 // 573 // We do not use the cache if the object has elements and 574 // therefore it does not make sense to cache the property names 575 // for arguments objects. Arguments objects will always have 576 // elements. 577 // Wrapped strings have elements, but don't have an elements 578 // array or dictionary. So the fast inline test for whether to 579 // use the cache says yes, so we should not create a cache. 580 bool cache_enum_keys = 581 ((current->map()->constructor() != *arguments_function) && 582 !current->IsJSValue() && 583 !current->IsAccessCheckNeeded() && 584 !current->HasNamedInterceptor() && 585 !current->HasIndexedInterceptor()); 586 // Compute the property keys and cache them if possible. 587 content = 588 UnionOfKeys(content, GetEnumPropertyKeys(current, cache_enum_keys)); 589 ASSERT(ContainsOnlyValidKeys(content)); 590 591 // Add the property keys from the interceptor. 592 if (current->HasNamedInterceptor()) { 593 v8::Handle<v8::Array> result = 594 GetKeysForNamedInterceptor(object, current); 595 if (!result.IsEmpty()) 596 content = AddKeysFromJSArray(content, v8::Utils::OpenHandle(*result)); 597 ASSERT(ContainsOnlyValidKeys(content)); 598 } 599 600 // If we only want local properties we bail out after the first 601 // iteration. 602 if (type == LOCAL_ONLY) 603 break; 604 } 605 return content; 606 } 607 608 609 Handle<JSArray> GetKeysFor(Handle<JSReceiver> object, bool* threw) { 610 Isolate* isolate = object->GetIsolate(); 611 isolate->counters()->for_in()->Increment(); 612 Handle<FixedArray> elements = 613 GetKeysInFixedArrayFor(object, INCLUDE_PROTOS, threw); 614 return isolate->factory()->NewJSArrayWithElements(elements); 615 } 616 617 618 Handle<FixedArray> ReduceFixedArrayTo(Handle<FixedArray> array, int length) { 619 ASSERT(array->length() >= length); 620 if (array->length() == length) return array; 621 622 Handle<FixedArray> new_array = 623 array->GetIsolate()->factory()->NewFixedArray(length); 624 for (int i = 0; i < length; ++i) new_array->set(i, array->get(i)); 625 return new_array; 626 } 627 628 629 Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object, 630 bool cache_result) { 631 Isolate* isolate = object->GetIsolate(); 632 if (object->HasFastProperties()) { 633 if (object->map()->instance_descriptors()->HasEnumCache()) { 634 int own_property_count = object->map()->EnumLength(); 635 // If we have an enum cache, but the enum length of the given map is set 636 // to kInvalidEnumCache, this means that the map itself has never used the 637 // present enum cache. The first step to using the cache is to set the 638 // enum length of the map by counting the number of own descriptors that 639 // are not DONT_ENUM or SYMBOLIC. 640 if (own_property_count == kInvalidEnumCacheSentinel) { 641 own_property_count = object->map()->NumberOfDescribedProperties( 642 OWN_DESCRIPTORS, DONT_SHOW); 643 644 if (cache_result) object->map()->SetEnumLength(own_property_count); 645 } 646 647 DescriptorArray* desc = object->map()->instance_descriptors(); 648 Handle<FixedArray> keys(desc->GetEnumCache(), isolate); 649 650 // In case the number of properties required in the enum are actually 651 // present, we can reuse the enum cache. Otherwise, this means that the 652 // enum cache was generated for a previous (smaller) version of the 653 // Descriptor Array. In that case we regenerate the enum cache. 654 if (own_property_count <= keys->length()) { 655 isolate->counters()->enum_cache_hits()->Increment(); 656 return ReduceFixedArrayTo(keys, own_property_count); 657 } 658 } 659 660 Handle<Map> map(object->map()); 661 662 if (map->instance_descriptors()->IsEmpty()) { 663 isolate->counters()->enum_cache_hits()->Increment(); 664 if (cache_result) map->SetEnumLength(0); 665 return isolate->factory()->empty_fixed_array(); 666 } 667 668 isolate->counters()->enum_cache_misses()->Increment(); 669 int num_enum = map->NumberOfDescribedProperties(ALL_DESCRIPTORS, DONT_SHOW); 670 671 Handle<FixedArray> storage = isolate->factory()->NewFixedArray(num_enum); 672 Handle<FixedArray> indices = isolate->factory()->NewFixedArray(num_enum); 673 674 Handle<DescriptorArray> descs = 675 Handle<DescriptorArray>(object->map()->instance_descriptors(), isolate); 676 677 int real_size = map->NumberOfOwnDescriptors(); 678 int enum_size = 0; 679 int index = 0; 680 681 for (int i = 0; i < descs->number_of_descriptors(); i++) { 682 PropertyDetails details = descs->GetDetails(i); 683 Object* key = descs->GetKey(i); 684 if (!(details.IsDontEnum() || key->IsSymbol())) { 685 if (i < real_size) ++enum_size; 686 storage->set(index, key); 687 if (!indices.is_null()) { 688 if (details.type() != FIELD) { 689 indices = Handle<FixedArray>(); 690 } else { 691 int field_index = descs->GetFieldIndex(i); 692 if (field_index >= map->inobject_properties()) { 693 field_index = -(field_index - map->inobject_properties() + 1); 694 } 695 indices->set(index, Smi::FromInt(field_index)); 696 } 697 } 698 index++; 699 } 700 } 701 ASSERT(index == storage->length()); 702 703 Handle<FixedArray> bridge_storage = 704 isolate->factory()->NewFixedArray( 705 DescriptorArray::kEnumCacheBridgeLength); 706 DescriptorArray* desc = object->map()->instance_descriptors(); 707 desc->SetEnumCache(*bridge_storage, 708 *storage, 709 indices.is_null() ? Object::cast(Smi::FromInt(0)) 710 : Object::cast(*indices)); 711 if (cache_result) { 712 object->map()->SetEnumLength(enum_size); 713 } 714 715 return ReduceFixedArrayTo(storage, enum_size); 716 } else { 717 Handle<NameDictionary> dictionary(object->property_dictionary()); 718 719 int length = dictionary->NumberOfElements(); 720 if (length == 0) { 721 return Handle<FixedArray>(isolate->heap()->empty_fixed_array()); 722 } 723 724 // The enumeration array is generated by allocating an array big enough to 725 // hold all properties that have been seen, whether they are are deleted or 726 // not. Subsequently all visible properties are added to the array. If some 727 // properties were not visible, the array is trimmed so it only contains 728 // visible properties. This improves over adding elements and sorting by 729 // index by having linear complexity rather than n*log(n). 730 731 // By comparing the monotonous NextEnumerationIndex to the NumberOfElements, 732 // we can predict the number of holes in the final array. If there will be 733 // more than 50% holes, regenerate the enumeration indices to reduce the 734 // number of holes to a minimum. This avoids allocating a large array if 735 // many properties were added but subsequently deleted. 736 int next_enumeration = dictionary->NextEnumerationIndex(); 737 if (!object->IsGlobalObject() && next_enumeration > (length * 3) / 2) { 738 NameDictionary::DoGenerateNewEnumerationIndices(dictionary); 739 next_enumeration = dictionary->NextEnumerationIndex(); 740 } 741 742 Handle<FixedArray> storage = 743 isolate->factory()->NewFixedArray(next_enumeration); 744 745 storage = Handle<FixedArray>(dictionary->CopyEnumKeysTo(*storage)); 746 ASSERT(storage->length() == object->NumberOfLocalProperties(DONT_SHOW)); 747 return storage; 748 } 749 } 750 751 752 DeferredHandleScope::DeferredHandleScope(Isolate* isolate) 753 : impl_(isolate->handle_scope_implementer()) { 754 impl_->BeginDeferredScope(); 755 v8::ImplementationUtilities::HandleScopeData* data = 756 impl_->isolate()->handle_scope_data(); 757 Object** new_next = impl_->GetSpareOrNewBlock(); 758 Object** new_limit = &new_next[kHandleBlockSize]; 759 ASSERT(data->limit == &impl_->blocks()->last()[kHandleBlockSize]); 760 impl_->blocks()->Add(new_next); 761 762 #ifdef DEBUG 763 prev_level_ = data->level; 764 #endif 765 data->level++; 766 prev_limit_ = data->limit; 767 prev_next_ = data->next; 768 data->next = new_next; 769 data->limit = new_limit; 770 } 771 772 773 DeferredHandleScope::~DeferredHandleScope() { 774 impl_->isolate()->handle_scope_data()->level--; 775 ASSERT(handles_detached_); 776 ASSERT(impl_->isolate()->handle_scope_data()->level == prev_level_); 777 } 778 779 780 DeferredHandles* DeferredHandleScope::Detach() { 781 DeferredHandles* deferred = impl_->Detach(prev_limit_); 782 v8::ImplementationUtilities::HandleScopeData* data = 783 impl_->isolate()->handle_scope_data(); 784 data->next = prev_next_; 785 data->limit = prev_limit_; 786 #ifdef DEBUG 787 handles_detached_ = true; 788 #endif 789 return deferred; 790 } 791 792 793 void AddWeakObjectToCodeDependency(Heap* heap, 794 Handle<Object> object, 795 Handle<Code> code) { 796 heap->EnsureWeakObjectToCodeTable(); 797 Handle<DependentCode> dep(heap->LookupWeakObjectToCodeDependency(*object)); 798 dep = DependentCode::Insert(dep, DependentCode::kWeaklyEmbeddedGroup, code); 799 CALL_HEAP_FUNCTION_VOID(heap->isolate(), 800 heap->AddWeakObjectToCodeDependency(*object, *dep)); 801 } 802 803 804 } } // namespace v8::internal 805