handles.cc revision 3ce2e2076e8e3e60cf1810eec160ea2d8557e9e7
1// Copyright 2009 the V8 project authors. All rights reserved. 2// Redistribution and use in source and binary forms, with or without 3// modification, are permitted provided that the following conditions are 4// met: 5// 6// * Redistributions of source code must retain the above copyright 7// notice, this list of conditions and the following disclaimer. 8// * Redistributions in binary form must reproduce the above 9// copyright notice, this list of conditions and the following 10// disclaimer in the documentation and/or other materials provided 11// with the distribution. 12// * Neither the name of Google Inc. nor the names of its 13// contributors may be used to endorse or promote products derived 14// from this software without specific prior written permission. 15// 16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28#include "v8.h" 29 30#include "accessors.h" 31#include "api.h" 32#include "arguments.h" 33#include "bootstrapper.h" 34#include "compiler.h" 35#include "debug.h" 36#include "execution.h" 37#include "global-handles.h" 38#include "natives.h" 39#include "runtime.h" 40 41namespace v8 { 42namespace internal { 43 44 45v8::ImplementationUtilities::HandleScopeData HandleScope::current_ = 46 { -1, NULL, NULL }; 47 48 49int HandleScope::NumberOfHandles() { 50 int n = HandleScopeImplementer::instance()->blocks()->length(); 51 if (n == 0) return 0; 52 return ((n - 1) * kHandleBlockSize) + 53 (current_.next - HandleScopeImplementer::instance()->blocks()->last()); 54} 55 56 57Object** HandleScope::Extend() { 58 Object** result = current_.next; 59 60 ASSERT(result == current_.limit); 61 // Make sure there's at least one scope on the stack and that the 62 // top of the scope stack isn't a barrier. 63 if (current_.extensions < 0) { 64 Utils::ReportApiFailure("v8::HandleScope::CreateHandle()", 65 "Cannot create a handle without a HandleScope"); 66 return NULL; 67 } 68 HandleScopeImplementer* impl = HandleScopeImplementer::instance(); 69 // If there's more room in the last block, we use that. This is used 70 // for fast creation of scopes after scope barriers. 71 if (!impl->blocks()->is_empty()) { 72 Object** limit = &impl->blocks()->last()[kHandleBlockSize]; 73 if (current_.limit != limit) { 74 current_.limit = limit; 75 } 76 } 77 78 // If we still haven't found a slot for the handle, we extend the 79 // current handle scope by allocating a new handle block. 80 if (result == current_.limit) { 81 // If there's a spare block, use it for growing the current scope. 82 result = impl->GetSpareOrNewBlock(); 83 // Add the extension to the global list of blocks, but count the 84 // extension as part of the current scope. 85 impl->blocks()->Add(result); 86 current_.extensions++; 87 current_.limit = &result[kHandleBlockSize]; 88 } 89 90 return result; 91} 92 93 94void HandleScope::DeleteExtensions() { 95 ASSERT(current_.extensions != 0); 96 HandleScopeImplementer::instance()->DeleteExtensions(current_.extensions); 97} 98 99 100void HandleScope::ZapRange(Object** start, Object** end) { 101 if (start == NULL) return; 102 for (Object** p = start; p < end; p++) { 103 *reinterpret_cast<Address*>(p) = v8::internal::kHandleZapValue; 104 } 105} 106 107 108Handle<FixedArray> AddKeysFromJSArray(Handle<FixedArray> content, 109 Handle<JSArray> array) { 110 CALL_HEAP_FUNCTION(content->AddKeysFromJSArray(*array), FixedArray); 111} 112 113 114Handle<FixedArray> UnionOfKeys(Handle<FixedArray> first, 115 Handle<FixedArray> second) { 116 CALL_HEAP_FUNCTION(first->UnionOfKeys(*second), FixedArray); 117} 118 119 120Handle<JSGlobalProxy> ReinitializeJSGlobalProxy( 121 Handle<JSFunction> constructor, 122 Handle<JSGlobalProxy> global) { 123 CALL_HEAP_FUNCTION(Heap::ReinitializeJSGlobalProxy(*constructor, *global), 124 JSGlobalProxy); 125} 126 127 128void SetExpectedNofProperties(Handle<JSFunction> func, int nof) { 129 func->shared()->set_expected_nof_properties(nof); 130 if (func->has_initial_map()) { 131 Handle<Map> new_initial_map = 132 Factory::CopyMapDropTransitions(Handle<Map>(func->initial_map())); 133 new_initial_map->set_unused_property_fields(nof); 134 func->set_initial_map(*new_initial_map); 135 } 136} 137 138 139void SetPrototypeProperty(Handle<JSFunction> func, Handle<JSObject> value) { 140 CALL_HEAP_FUNCTION_VOID(func->SetPrototype(*value)); 141} 142 143 144static int ExpectedNofPropertiesFromEstimate(int estimate) { 145 // TODO(1231235): We need dynamic feedback to estimate the number 146 // of expected properties in an object. The static hack below 147 // is barely a solution. 148 if (estimate == 0) return 4; 149 return estimate + 2; 150} 151 152 153void SetExpectedNofPropertiesFromEstimate(Handle<SharedFunctionInfo> shared, 154 int estimate) { 155 shared->set_expected_nof_properties( 156 ExpectedNofPropertiesFromEstimate(estimate)); 157} 158 159 160void SetExpectedNofPropertiesFromEstimate(Handle<JSFunction> func, 161 int estimate) { 162 SetExpectedNofProperties( 163 func, ExpectedNofPropertiesFromEstimate(estimate)); 164} 165 166 167void NormalizeProperties(Handle<JSObject> object, 168 PropertyNormalizationMode mode, 169 int expected_additional_properties) { 170 CALL_HEAP_FUNCTION_VOID(object->NormalizeProperties( 171 mode, 172 expected_additional_properties)); 173} 174 175 176void NormalizeElements(Handle<JSObject> object) { 177 CALL_HEAP_FUNCTION_VOID(object->NormalizeElements()); 178} 179 180 181void TransformToFastProperties(Handle<JSObject> object, 182 int unused_property_fields) { 183 CALL_HEAP_FUNCTION_VOID( 184 object->TransformToFastProperties(unused_property_fields)); 185} 186 187 188void FlattenString(Handle<String> string) { 189 CALL_HEAP_FUNCTION_VOID(string->TryFlattenIfNotFlat()); 190 ASSERT(string->IsFlat()); 191} 192 193 194Handle<Object> SetPrototype(Handle<JSFunction> function, 195 Handle<Object> prototype) { 196 CALL_HEAP_FUNCTION(Accessors::FunctionSetPrototype(*function, 197 *prototype, 198 NULL), 199 Object); 200} 201 202 203Handle<Object> SetProperty(Handle<JSObject> object, 204 Handle<String> key, 205 Handle<Object> value, 206 PropertyAttributes attributes) { 207 CALL_HEAP_FUNCTION(object->SetProperty(*key, *value, attributes), Object); 208} 209 210 211Handle<Object> SetProperty(Handle<Object> object, 212 Handle<Object> key, 213 Handle<Object> value, 214 PropertyAttributes attributes) { 215 CALL_HEAP_FUNCTION( 216 Runtime::SetObjectProperty(object, key, value, attributes), Object); 217} 218 219 220Handle<Object> ForceSetProperty(Handle<JSObject> object, 221 Handle<Object> key, 222 Handle<Object> value, 223 PropertyAttributes attributes) { 224 CALL_HEAP_FUNCTION( 225 Runtime::ForceSetObjectProperty(object, key, value, attributes), Object); 226} 227 228 229Handle<Object> ForceDeleteProperty(Handle<JSObject> object, 230 Handle<Object> key) { 231 CALL_HEAP_FUNCTION(Runtime::ForceDeleteObjectProperty(object, key), Object); 232} 233 234 235Handle<Object> IgnoreAttributesAndSetLocalProperty( 236 Handle<JSObject> object, 237 Handle<String> key, 238 Handle<Object> value, 239 PropertyAttributes attributes) { 240 CALL_HEAP_FUNCTION(object-> 241 IgnoreAttributesAndSetLocalProperty(*key, *value, attributes), Object); 242} 243 244 245Handle<Object> SetPropertyWithInterceptor(Handle<JSObject> object, 246 Handle<String> key, 247 Handle<Object> value, 248 PropertyAttributes attributes) { 249 CALL_HEAP_FUNCTION(object->SetPropertyWithInterceptor(*key, 250 *value, 251 attributes), 252 Object); 253} 254 255 256Handle<Object> GetProperty(Handle<JSObject> obj, 257 const char* name) { 258 Handle<String> str = Factory::LookupAsciiSymbol(name); 259 CALL_HEAP_FUNCTION(obj->GetProperty(*str), Object); 260} 261 262 263Handle<Object> GetProperty(Handle<Object> obj, 264 Handle<Object> key) { 265 CALL_HEAP_FUNCTION(Runtime::GetObjectProperty(obj, key), Object); 266} 267 268 269Handle<Object> GetPropertyWithInterceptor(Handle<JSObject> receiver, 270 Handle<JSObject> holder, 271 Handle<String> name, 272 PropertyAttributes* attributes) { 273 CALL_HEAP_FUNCTION(holder->GetPropertyWithInterceptor(*receiver, 274 *name, 275 attributes), 276 Object); 277} 278 279 280Handle<Object> GetPrototype(Handle<Object> obj) { 281 Handle<Object> result(obj->GetPrototype()); 282 return result; 283} 284 285 286Handle<Object> GetHiddenProperties(Handle<JSObject> obj, 287 bool create_if_needed) { 288 Handle<String> key = Factory::hidden_symbol(); 289 290 if (obj->HasFastProperties()) { 291 // If the object has fast properties, check whether the first slot 292 // in the descriptor array matches the hidden symbol. Since the 293 // hidden symbols hash code is zero (and no other string has hash 294 // code zero) it will always occupy the first entry if present. 295 DescriptorArray* descriptors = obj->map()->instance_descriptors(); 296 if ((descriptors->number_of_descriptors() > 0) && 297 (descriptors->GetKey(0) == *key) && 298 descriptors->IsProperty(0)) { 299 ASSERT(descriptors->GetType(0) == FIELD); 300 return Handle<Object>(obj->FastPropertyAt(descriptors->GetFieldIndex(0))); 301 } 302 } 303 304 // Only attempt to find the hidden properties in the local object and not 305 // in the prototype chain. Note that HasLocalProperty() can cause a GC in 306 // the general case in the presence of interceptors. 307 if (!obj->HasLocalProperty(*key)) { 308 // Hidden properties object not found. Allocate a new hidden properties 309 // object if requested. Otherwise return the undefined value. 310 if (create_if_needed) { 311 Handle<Object> hidden_obj = Factory::NewJSObject(Top::object_function()); 312 return SetProperty(obj, key, hidden_obj, DONT_ENUM); 313 } else { 314 return Factory::undefined_value(); 315 } 316 } 317 return GetProperty(obj, key); 318} 319 320 321Handle<Object> DeleteElement(Handle<JSObject> obj, 322 uint32_t index) { 323 CALL_HEAP_FUNCTION(obj->DeleteElement(index, JSObject::NORMAL_DELETION), 324 Object); 325} 326 327 328Handle<Object> DeleteProperty(Handle<JSObject> obj, 329 Handle<String> prop) { 330 CALL_HEAP_FUNCTION(obj->DeleteProperty(*prop, JSObject::NORMAL_DELETION), 331 Object); 332} 333 334 335Handle<Object> LookupSingleCharacterStringFromCode(uint32_t index) { 336 CALL_HEAP_FUNCTION(Heap::LookupSingleCharacterStringFromCode(index), Object); 337} 338 339 340Handle<String> SubString(Handle<String> str, int start, int end) { 341 CALL_HEAP_FUNCTION(str->Slice(start, end), String); 342} 343 344 345Handle<Object> SetElement(Handle<JSObject> object, 346 uint32_t index, 347 Handle<Object> value) { 348 if (object->HasPixelElements() || object->HasExternalArrayElements()) { 349 if (!value->IsSmi() && !value->IsHeapNumber() && !value->IsUndefined()) { 350 bool has_exception; 351 Handle<Object> number = Execution::ToNumber(value, &has_exception); 352 if (has_exception) return Handle<Object>(); 353 value = number; 354 } 355 } 356 CALL_HEAP_FUNCTION(object->SetElement(index, *value), Object); 357} 358 359 360Handle<JSObject> Copy(Handle<JSObject> obj) { 361 CALL_HEAP_FUNCTION(Heap::CopyJSObject(*obj), JSObject); 362} 363 364 365// Wrappers for scripts are kept alive and cached in weak global 366// handles referred from proxy objects held by the scripts as long as 367// they are used. When they are not used anymore, the garbage 368// collector will call the weak callback on the global handle 369// associated with the wrapper and get rid of both the wrapper and the 370// handle. 371static void ClearWrapperCache(Persistent<v8::Value> handle, void*) { 372#ifdef ENABLE_HEAP_PROTECTION 373 // Weak reference callbacks are called as if from outside V8. We 374 // need to reeenter to unprotect the heap. 375 VMState state(OTHER); 376#endif 377 Handle<Object> cache = Utils::OpenHandle(*handle); 378 JSValue* wrapper = JSValue::cast(*cache); 379 Proxy* proxy = Script::cast(wrapper->value())->wrapper(); 380 ASSERT(proxy->proxy() == reinterpret_cast<Address>(cache.location())); 381 proxy->set_proxy(0); 382 GlobalHandles::Destroy(cache.location()); 383 Counters::script_wrappers.Decrement(); 384} 385 386 387Handle<JSValue> GetScriptWrapper(Handle<Script> script) { 388 if (script->wrapper()->proxy() != NULL) { 389 // Return the script wrapper directly from the cache. 390 return Handle<JSValue>( 391 reinterpret_cast<JSValue**>(script->wrapper()->proxy())); 392 } 393 394 // Construct a new script wrapper. 395 Counters::script_wrappers.Increment(); 396 Handle<JSFunction> constructor = Top::script_function(); 397 Handle<JSValue> result = 398 Handle<JSValue>::cast(Factory::NewJSObject(constructor)); 399 result->set_value(*script); 400 401 // Create a new weak global handle and use it to cache the wrapper 402 // for future use. The cache will automatically be cleared by the 403 // garbage collector when it is not used anymore. 404 Handle<Object> handle = GlobalHandles::Create(*result); 405 GlobalHandles::MakeWeak(handle.location(), NULL, &ClearWrapperCache); 406 script->wrapper()->set_proxy(reinterpret_cast<Address>(handle.location())); 407 return result; 408} 409 410 411// Init line_ends array with code positions of line ends inside script 412// source. 413void InitScriptLineEnds(Handle<Script> script) { 414 if (!script->line_ends()->IsUndefined()) return; 415 416 if (!script->source()->IsString()) { 417 ASSERT(script->source()->IsUndefined()); 418 script->set_line_ends(*(Factory::NewJSArray(0))); 419 ASSERT(script->line_ends()->IsJSArray()); 420 return; 421 } 422 423 Handle<String> src(String::cast(script->source())); 424 const int src_len = src->length(); 425 Handle<String> new_line = Factory::NewStringFromAscii(CStrVector("\n")); 426 427 // Pass 1: Identify line count. 428 int line_count = 0; 429 int position = 0; 430 while (position != -1 && position < src_len) { 431 position = Runtime::StringMatch(src, new_line, position); 432 if (position != -1) { 433 position++; 434 } 435 // Even if the last line misses a line end, it is counted. 436 line_count++; 437 } 438 439 // Pass 2: Fill in line ends positions 440 Handle<FixedArray> array = Factory::NewFixedArray(line_count); 441 int array_index = 0; 442 position = 0; 443 while (position != -1 && position < src_len) { 444 position = Runtime::StringMatch(src, new_line, position); 445 // If the script does not end with a line ending add the final end 446 // position as just past the last line ending. 447 array->set(array_index++, 448 Smi::FromInt(position != -1 ? position++ : src_len)); 449 } 450 ASSERT(array_index == line_count); 451 452 Handle<JSArray> object = Factory::NewJSArrayWithElements(array); 453 script->set_line_ends(*object); 454 ASSERT(script->line_ends()->IsJSArray()); 455} 456 457 458// Convert code position into line number. 459int GetScriptLineNumber(Handle<Script> script, int code_pos) { 460 InitScriptLineEnds(script); 461 AssertNoAllocation no_allocation; 462 JSArray* line_ends_array = JSArray::cast(script->line_ends()); 463 const int line_ends_len = (Smi::cast(line_ends_array->length()))->value(); 464 465 int line = -1; 466 if (line_ends_len > 0 && 467 code_pos <= (Smi::cast(line_ends_array->GetElement(0)))->value()) { 468 line = 0; 469 } else { 470 for (int i = 1; i < line_ends_len; ++i) { 471 if ((Smi::cast(line_ends_array->GetElement(i - 1)))->value() < code_pos && 472 code_pos <= (Smi::cast(line_ends_array->GetElement(i)))->value()) { 473 line = i; 474 break; 475 } 476 } 477 } 478 479 return line != -1 ? line + script->line_offset()->value() : line; 480} 481 482 483void CustomArguments::IterateInstance(ObjectVisitor* v) { 484 v->VisitPointers(values_, values_ + 4); 485} 486 487 488// Compute the property keys from the interceptor. 489v8::Handle<v8::Array> GetKeysForNamedInterceptor(Handle<JSObject> receiver, 490 Handle<JSObject> object) { 491 Handle<InterceptorInfo> interceptor(object->GetNamedInterceptor()); 492 CustomArguments args(interceptor->data(), *receiver, *object); 493 v8::AccessorInfo info(args.end()); 494 v8::Handle<v8::Array> result; 495 if (!interceptor->enumerator()->IsUndefined()) { 496 v8::NamedPropertyEnumerator enum_fun = 497 v8::ToCData<v8::NamedPropertyEnumerator>(interceptor->enumerator()); 498 LOG(ApiObjectAccess("interceptor-named-enum", *object)); 499 { 500 // Leaving JavaScript. 501 VMState state(EXTERNAL); 502 result = enum_fun(info); 503 } 504 } 505 return result; 506} 507 508 509// Compute the element keys from the interceptor. 510v8::Handle<v8::Array> GetKeysForIndexedInterceptor(Handle<JSObject> receiver, 511 Handle<JSObject> object) { 512 Handle<InterceptorInfo> interceptor(object->GetIndexedInterceptor()); 513 CustomArguments args(interceptor->data(), *receiver, *object); 514 v8::AccessorInfo info(args.end()); 515 v8::Handle<v8::Array> result; 516 if (!interceptor->enumerator()->IsUndefined()) { 517 v8::IndexedPropertyEnumerator enum_fun = 518 v8::ToCData<v8::IndexedPropertyEnumerator>(interceptor->enumerator()); 519 LOG(ApiObjectAccess("interceptor-indexed-enum", *object)); 520 { 521 // Leaving JavaScript. 522 VMState state(EXTERNAL); 523 result = enum_fun(info); 524 } 525 } 526 return result; 527} 528 529 530Handle<FixedArray> GetKeysInFixedArrayFor(Handle<JSObject> object, 531 KeyCollectionType type) { 532 Handle<FixedArray> content = Factory::empty_fixed_array(); 533 534 // Only collect keys if access is permitted. 535 for (Handle<Object> p = object; 536 *p != Heap::null_value(); 537 p = Handle<Object>(p->GetPrototype())) { 538 Handle<JSObject> current(JSObject::cast(*p)); 539 540 // Check access rights if required. 541 if (current->IsAccessCheckNeeded() && 542 !Top::MayNamedAccess(*current, Heap::undefined_value(), 543 v8::ACCESS_KEYS)) { 544 Top::ReportFailedAccessCheck(*current, v8::ACCESS_KEYS); 545 break; 546 } 547 548 // Compute the element keys. 549 Handle<FixedArray> element_keys = 550 Factory::NewFixedArray(current->NumberOfEnumElements()); 551 current->GetEnumElementKeys(*element_keys); 552 content = UnionOfKeys(content, element_keys); 553 554 // Add the element keys from the interceptor. 555 if (current->HasIndexedInterceptor()) { 556 v8::Handle<v8::Array> result = 557 GetKeysForIndexedInterceptor(object, current); 558 if (!result.IsEmpty()) 559 content = AddKeysFromJSArray(content, v8::Utils::OpenHandle(*result)); 560 } 561 562 // Compute the property keys. 563 content = UnionOfKeys(content, GetEnumPropertyKeys(current)); 564 565 // Add the property keys from the interceptor. 566 if (current->HasNamedInterceptor()) { 567 v8::Handle<v8::Array> result = 568 GetKeysForNamedInterceptor(object, current); 569 if (!result.IsEmpty()) 570 content = AddKeysFromJSArray(content, v8::Utils::OpenHandle(*result)); 571 } 572 573 // If we only want local properties we bail out after the first 574 // iteration. 575 if (type == LOCAL_ONLY) 576 break; 577 } 578 return content; 579} 580 581 582Handle<JSArray> GetKeysFor(Handle<JSObject> object) { 583 Counters::for_in.Increment(); 584 Handle<FixedArray> elements = GetKeysInFixedArrayFor(object, 585 INCLUDE_PROTOS); 586 return Factory::NewJSArrayWithElements(elements); 587} 588 589 590Handle<FixedArray> GetEnumPropertyKeys(Handle<JSObject> object) { 591 int index = 0; 592 if (object->HasFastProperties()) { 593 if (object->map()->instance_descriptors()->HasEnumCache()) { 594 Counters::enum_cache_hits.Increment(); 595 DescriptorArray* desc = object->map()->instance_descriptors(); 596 return Handle<FixedArray>(FixedArray::cast(desc->GetEnumCache())); 597 } 598 Counters::enum_cache_misses.Increment(); 599 int num_enum = object->NumberOfEnumProperties(); 600 Handle<FixedArray> storage = Factory::NewFixedArray(num_enum); 601 Handle<FixedArray> sort_array = Factory::NewFixedArray(num_enum); 602 Handle<DescriptorArray> descs = 603 Handle<DescriptorArray>(object->map()->instance_descriptors()); 604 for (int i = 0; i < descs->number_of_descriptors(); i++) { 605 if (descs->IsProperty(i) && !descs->IsDontEnum(i)) { 606 (*storage)->set(index, descs->GetKey(i)); 607 PropertyDetails details(descs->GetDetails(i)); 608 (*sort_array)->set(index, Smi::FromInt(details.index())); 609 index++; 610 } 611 } 612 (*storage)->SortPairs(*sort_array, sort_array->length()); 613 Handle<FixedArray> bridge_storage = 614 Factory::NewFixedArray(DescriptorArray::kEnumCacheBridgeLength); 615 DescriptorArray* desc = object->map()->instance_descriptors(); 616 desc->SetEnumCache(*bridge_storage, *storage); 617 ASSERT(storage->length() == index); 618 return storage; 619 } else { 620 int num_enum = object->NumberOfEnumProperties(); 621 Handle<FixedArray> storage = Factory::NewFixedArray(num_enum); 622 Handle<FixedArray> sort_array = Factory::NewFixedArray(num_enum); 623 object->property_dictionary()->CopyEnumKeysTo(*storage, *sort_array); 624 return storage; 625 } 626} 627 628 629bool CompileLazyShared(Handle<SharedFunctionInfo> shared, 630 ClearExceptionFlag flag, 631 int loop_nesting) { 632 // Compile the source information to a code object. 633 ASSERT(!shared->is_compiled()); 634 bool result = Compiler::CompileLazy(shared, loop_nesting); 635 ASSERT(result != Top::has_pending_exception()); 636 if (!result && flag == CLEAR_EXCEPTION) Top::clear_pending_exception(); 637 return result; 638} 639 640 641bool CompileLazy(Handle<JSFunction> function, ClearExceptionFlag flag) { 642 // Compile the source information to a code object. 643 Handle<SharedFunctionInfo> shared(function->shared()); 644 return CompileLazyShared(shared, flag, 0); 645} 646 647 648bool CompileLazyInLoop(Handle<JSFunction> function, ClearExceptionFlag flag) { 649 // Compile the source information to a code object. 650 Handle<SharedFunctionInfo> shared(function->shared()); 651 return CompileLazyShared(shared, flag, 1); 652} 653 654OptimizedObjectForAddingMultipleProperties:: 655OptimizedObjectForAddingMultipleProperties(Handle<JSObject> object, 656 int expected_additional_properties, 657 bool condition) { 658 object_ = object; 659 if (condition && object_->HasFastProperties()) { 660 // Normalize the properties of object to avoid n^2 behavior 661 // when extending the object multiple properties. Indicate the number of 662 // properties to be added. 663 unused_property_fields_ = object->map()->unused_property_fields(); 664 NormalizeProperties(object_, 665 KEEP_INOBJECT_PROPERTIES, 666 expected_additional_properties); 667 has_been_transformed_ = true; 668 669 } else { 670 has_been_transformed_ = false; 671 } 672} 673 674 675OptimizedObjectForAddingMultipleProperties:: 676~OptimizedObjectForAddingMultipleProperties() { 677 // Reoptimize the object to allow fast property access. 678 if (has_been_transformed_) { 679 TransformToFastProperties(object_, unused_property_fields_); 680 } 681} 682 683 684void LoadLazy(Handle<JSObject> obj, bool* pending_exception) { 685 HandleScope scope; 686 Handle<FixedArray> info(FixedArray::cast(obj->map()->constructor())); 687 int index = Smi::cast(info->get(0))->value(); 688 ASSERT(index >= 0); 689 Handle<Context> compile_context(Context::cast(info->get(1))); 690 Handle<Context> function_context(Context::cast(info->get(2))); 691 Handle<Object> receiver(compile_context->global()->builtins()); 692 693 Vector<const char> name = Natives::GetScriptName(index); 694 695 Handle<JSFunction> boilerplate; 696 697 if (!Bootstrapper::NativesCacheLookup(name, &boilerplate)) { 698 Handle<String> source_code = Bootstrapper::NativesSourceLookup(index); 699 Handle<String> script_name = Factory::NewStringFromAscii(name); 700 bool allow_natives_syntax = FLAG_allow_natives_syntax; 701 FLAG_allow_natives_syntax = true; 702 boilerplate = Compiler::Compile(source_code, script_name, 0, 0, NULL, NULL); 703 FLAG_allow_natives_syntax = allow_natives_syntax; 704 // If the compilation failed (possibly due to stack overflows), we 705 // should never enter the result in the natives cache. Instead we 706 // return from the function without marking the function as having 707 // been lazily loaded. 708 if (boilerplate.is_null()) { 709 *pending_exception = true; 710 return; 711 } 712 Bootstrapper::NativesCacheAdd(name, boilerplate); 713 } 714 715 // We shouldn't get here if compiling the script failed. 716 ASSERT(!boilerplate.is_null()); 717 718#ifdef ENABLE_DEBUGGER_SUPPORT 719 // When the debugger running in its own context touches lazy loaded 720 // functions loading can be triggered. In that case ensure that the 721 // execution of the boilerplate is in the correct context. 722 SaveContext save; 723 if (!Debug::debug_context().is_null() && 724 Top::context() == *Debug::debug_context()) { 725 Top::set_context(*compile_context); 726 } 727#endif 728 729 // Reset the lazy load data before running the script to make sure 730 // not to get recursive lazy loading. 731 obj->map()->set_needs_loading(false); 732 obj->map()->set_constructor(info->get(3)); 733 734 // Run the script. 735 Handle<JSFunction> script_fun( 736 Factory::NewFunctionFromBoilerplate(boilerplate, function_context)); 737 Execution::Call(script_fun, receiver, 0, NULL, pending_exception); 738 739 // If lazy loading failed, restore the unloaded state of obj. 740 if (*pending_exception) { 741 obj->map()->set_needs_loading(true); 742 obj->map()->set_constructor(*info); 743 } 744} 745 746 747void SetupLazy(Handle<JSObject> obj, 748 int index, 749 Handle<Context> compile_context, 750 Handle<Context> function_context) { 751 Handle<FixedArray> arr = Factory::NewFixedArray(4); 752 arr->set(0, Smi::FromInt(index)); 753 arr->set(1, *compile_context); // Compile in this context 754 arr->set(2, *function_context); // Set function context to this 755 arr->set(3, obj->map()->constructor()); // Remember the constructor 756 Handle<Map> old_map(obj->map()); 757 Handle<Map> new_map = Factory::CopyMapDropTransitions(old_map); 758 obj->set_map(*new_map); 759 new_map->set_needs_loading(true); 760 // Store the lazy loading info in the constructor field. We'll 761 // reestablish the constructor from the fixed array after loading. 762 new_map->set_constructor(*arr); 763 ASSERT(!obj->IsLoaded()); 764} 765 766} } // namespace v8::internal 767