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