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#ifndef V8_HEAP_INL_H_ 29#define V8_HEAP_INL_H_ 30 31#include "heap.h" 32#include "isolate.h" 33#include "list-inl.h" 34#include "objects.h" 35#include "platform.h" 36#include "v8-counters.h" 37#include "store-buffer.h" 38#include "store-buffer-inl.h" 39 40namespace v8 { 41namespace internal { 42 43void PromotionQueue::insert(HeapObject* target, int size) { 44 if (emergency_stack_ != NULL) { 45 emergency_stack_->Add(Entry(target, size)); 46 return; 47 } 48 49 if (NewSpacePage::IsAtStart(reinterpret_cast<Address>(rear_))) { 50 NewSpacePage* rear_page = 51 NewSpacePage::FromAddress(reinterpret_cast<Address>(rear_)); 52 ASSERT(!rear_page->prev_page()->is_anchor()); 53 rear_ = reinterpret_cast<intptr_t*>(rear_page->prev_page()->area_end()); 54 ActivateGuardIfOnTheSamePage(); 55 } 56 57 if (guard_) { 58 ASSERT(GetHeadPage() == 59 Page::FromAllocationTop(reinterpret_cast<Address>(limit_))); 60 61 if ((rear_ - 2) < limit_) { 62 RelocateQueueHead(); 63 emergency_stack_->Add(Entry(target, size)); 64 return; 65 } 66 } 67 68 *(--rear_) = reinterpret_cast<intptr_t>(target); 69 *(--rear_) = size; 70 // Assert no overflow into live objects. 71#ifdef DEBUG 72 SemiSpace::AssertValidRange(HEAP->new_space()->top(), 73 reinterpret_cast<Address>(rear_)); 74#endif 75} 76 77 78void PromotionQueue::ActivateGuardIfOnTheSamePage() { 79 guard_ = guard_ || 80 heap_->new_space()->active_space()->current_page()->address() == 81 GetHeadPage()->address(); 82} 83 84 85MaybeObject* Heap::AllocateStringFromUtf8(Vector<const char> str, 86 PretenureFlag pretenure) { 87 // Check for ASCII first since this is the common case. 88 if (String::IsAscii(str.start(), str.length())) { 89 // If the string is ASCII, we do not need to convert the characters 90 // since UTF8 is backwards compatible with ASCII. 91 return AllocateStringFromAscii(str, pretenure); 92 } 93 // Non-ASCII and we need to decode. 94 return AllocateStringFromUtf8Slow(str, pretenure); 95} 96 97 98MaybeObject* Heap::AllocateSymbol(Vector<const char> str, 99 int chars, 100 uint32_t hash_field) { 101 unibrow::Utf8InputBuffer<> buffer(str.start(), 102 static_cast<unsigned>(str.length())); 103 return AllocateInternalSymbol(&buffer, chars, hash_field); 104} 105 106 107MaybeObject* Heap::AllocateAsciiSymbol(Vector<const char> str, 108 uint32_t hash_field) { 109 if (str.length() > SeqAsciiString::kMaxLength) { 110 return Failure::OutOfMemoryException(); 111 } 112 // Compute map and object size. 113 Map* map = ascii_symbol_map(); 114 int size = SeqAsciiString::SizeFor(str.length()); 115 116 // Allocate string. 117 Object* result; 118 { MaybeObject* maybe_result = (size > Page::kMaxNonCodeHeapObjectSize) 119 ? lo_space_->AllocateRaw(size, NOT_EXECUTABLE) 120 : old_data_space_->AllocateRaw(size); 121 if (!maybe_result->ToObject(&result)) return maybe_result; 122 } 123 124 // String maps are all immortal immovable objects. 125 reinterpret_cast<HeapObject*>(result)->set_map_no_write_barrier(map); 126 // Set length and hash fields of the allocated string. 127 String* answer = String::cast(result); 128 answer->set_length(str.length()); 129 answer->set_hash_field(hash_field); 130 131 ASSERT_EQ(size, answer->Size()); 132 133 // Fill in the characters. 134 memcpy(answer->address() + SeqAsciiString::kHeaderSize, 135 str.start(), str.length()); 136 137 return answer; 138} 139 140 141MaybeObject* Heap::AllocateTwoByteSymbol(Vector<const uc16> str, 142 uint32_t hash_field) { 143 if (str.length() > SeqTwoByteString::kMaxLength) { 144 return Failure::OutOfMemoryException(); 145 } 146 // Compute map and object size. 147 Map* map = symbol_map(); 148 int size = SeqTwoByteString::SizeFor(str.length()); 149 150 // Allocate string. 151 Object* result; 152 { MaybeObject* maybe_result = (size > Page::kMaxNonCodeHeapObjectSize) 153 ? lo_space_->AllocateRaw(size, NOT_EXECUTABLE) 154 : old_data_space_->AllocateRaw(size); 155 if (!maybe_result->ToObject(&result)) return maybe_result; 156 } 157 158 reinterpret_cast<HeapObject*>(result)->set_map(map); 159 // Set length and hash fields of the allocated string. 160 String* answer = String::cast(result); 161 answer->set_length(str.length()); 162 answer->set_hash_field(hash_field); 163 164 ASSERT_EQ(size, answer->Size()); 165 166 // Fill in the characters. 167 memcpy(answer->address() + SeqTwoByteString::kHeaderSize, 168 str.start(), str.length() * kUC16Size); 169 170 return answer; 171} 172 173MaybeObject* Heap::CopyFixedArray(FixedArray* src) { 174 return CopyFixedArrayWithMap(src, src->map()); 175} 176 177 178MaybeObject* Heap::CopyFixedDoubleArray(FixedDoubleArray* src) { 179 return CopyFixedDoubleArrayWithMap(src, src->map()); 180} 181 182 183MaybeObject* Heap::AllocateRaw(int size_in_bytes, 184 AllocationSpace space, 185 AllocationSpace retry_space) { 186 ASSERT(allocation_allowed_ && gc_state_ == NOT_IN_GC); 187 ASSERT(space != NEW_SPACE || 188 retry_space == OLD_POINTER_SPACE || 189 retry_space == OLD_DATA_SPACE || 190 retry_space == LO_SPACE); 191#ifdef DEBUG 192 if (FLAG_gc_interval >= 0 && 193 !disallow_allocation_failure_ && 194 Heap::allocation_timeout_-- <= 0) { 195 return Failure::RetryAfterGC(space); 196 } 197 isolate_->counters()->objs_since_last_full()->Increment(); 198 isolate_->counters()->objs_since_last_young()->Increment(); 199#endif 200 MaybeObject* result; 201 if (NEW_SPACE == space) { 202 result = new_space_.AllocateRaw(size_in_bytes); 203 if (always_allocate() && result->IsFailure()) { 204 space = retry_space; 205 } else { 206 return result; 207 } 208 } 209 210 if (OLD_POINTER_SPACE == space) { 211 result = old_pointer_space_->AllocateRaw(size_in_bytes); 212 } else if (OLD_DATA_SPACE == space) { 213 result = old_data_space_->AllocateRaw(size_in_bytes); 214 } else if (CODE_SPACE == space) { 215 result = code_space_->AllocateRaw(size_in_bytes); 216 } else if (LO_SPACE == space) { 217 result = lo_space_->AllocateRaw(size_in_bytes, NOT_EXECUTABLE); 218 } else if (CELL_SPACE == space) { 219 result = cell_space_->AllocateRaw(size_in_bytes); 220 } else { 221 ASSERT(MAP_SPACE == space); 222 result = map_space_->AllocateRaw(size_in_bytes); 223 } 224 if (result->IsFailure()) old_gen_exhausted_ = true; 225 return result; 226} 227 228 229MaybeObject* Heap::NumberFromInt32( 230 int32_t value, PretenureFlag pretenure) { 231 if (Smi::IsValid(value)) return Smi::FromInt(value); 232 // Bypass NumberFromDouble to avoid various redundant checks. 233 return AllocateHeapNumber(FastI2D(value), pretenure); 234} 235 236 237MaybeObject* Heap::NumberFromUint32( 238 uint32_t value, PretenureFlag pretenure) { 239 if ((int32_t)value >= 0 && Smi::IsValid((int32_t)value)) { 240 return Smi::FromInt((int32_t)value); 241 } 242 // Bypass NumberFromDouble to avoid various redundant checks. 243 return AllocateHeapNumber(FastUI2D(value), pretenure); 244} 245 246 247void Heap::FinalizeExternalString(String* string) { 248 ASSERT(string->IsExternalString()); 249 v8::String::ExternalStringResourceBase** resource_addr = 250 reinterpret_cast<v8::String::ExternalStringResourceBase**>( 251 reinterpret_cast<byte*>(string) + 252 ExternalString::kResourceOffset - 253 kHeapObjectTag); 254 255 // Dispose of the C++ object if it has not already been disposed. 256 if (*resource_addr != NULL) { 257 (*resource_addr)->Dispose(); 258 *resource_addr = NULL; 259 } 260} 261 262 263MaybeObject* Heap::AllocateRawMap() { 264#ifdef DEBUG 265 isolate_->counters()->objs_since_last_full()->Increment(); 266 isolate_->counters()->objs_since_last_young()->Increment(); 267#endif 268 MaybeObject* result = map_space_->AllocateRaw(Map::kSize); 269 if (result->IsFailure()) old_gen_exhausted_ = true; 270#ifdef DEBUG 271 if (!result->IsFailure()) { 272 // Maps have their own alignment. 273 CHECK((reinterpret_cast<intptr_t>(result) & kMapAlignmentMask) == 274 static_cast<intptr_t>(kHeapObjectTag)); 275 } 276#endif 277 return result; 278} 279 280 281MaybeObject* Heap::AllocateRawCell() { 282#ifdef DEBUG 283 isolate_->counters()->objs_since_last_full()->Increment(); 284 isolate_->counters()->objs_since_last_young()->Increment(); 285#endif 286 MaybeObject* result = cell_space_->AllocateRaw(JSGlobalPropertyCell::kSize); 287 if (result->IsFailure()) old_gen_exhausted_ = true; 288 return result; 289} 290 291 292bool Heap::InNewSpace(Object* object) { 293 bool result = new_space_.Contains(object); 294 ASSERT(!result || // Either not in new space 295 gc_state_ != NOT_IN_GC || // ... or in the middle of GC 296 InToSpace(object)); // ... or in to-space (where we allocate). 297 return result; 298} 299 300 301bool Heap::InNewSpace(Address addr) { 302 return new_space_.Contains(addr); 303} 304 305 306bool Heap::InFromSpace(Object* object) { 307 return new_space_.FromSpaceContains(object); 308} 309 310 311bool Heap::InToSpace(Object* object) { 312 return new_space_.ToSpaceContains(object); 313} 314 315 316bool Heap::OldGenerationAllocationLimitReached() { 317 if (!incremental_marking()->IsStopped()) return false; 318 return OldGenerationSpaceAvailable() < 0; 319} 320 321 322bool Heap::ShouldBePromoted(Address old_address, int object_size) { 323 // An object should be promoted if: 324 // - the object has survived a scavenge operation or 325 // - to space is already 25% full. 326 NewSpacePage* page = NewSpacePage::FromAddress(old_address); 327 Address age_mark = new_space_.age_mark(); 328 bool below_mark = page->IsFlagSet(MemoryChunk::NEW_SPACE_BELOW_AGE_MARK) && 329 (!page->ContainsLimit(age_mark) || old_address < age_mark); 330 return below_mark || (new_space_.Size() + object_size) >= 331 (new_space_.EffectiveCapacity() >> 2); 332} 333 334 335void Heap::RecordWrite(Address address, int offset) { 336 if (!InNewSpace(address)) store_buffer_.Mark(address + offset); 337} 338 339 340void Heap::RecordWrites(Address address, int start, int len) { 341 if (!InNewSpace(address)) { 342 for (int i = 0; i < len; i++) { 343 store_buffer_.Mark(address + start + i * kPointerSize); 344 } 345 } 346} 347 348 349OldSpace* Heap::TargetSpace(HeapObject* object) { 350 InstanceType type = object->map()->instance_type(); 351 AllocationSpace space = TargetSpaceId(type); 352 return (space == OLD_POINTER_SPACE) 353 ? old_pointer_space_ 354 : old_data_space_; 355} 356 357 358AllocationSpace Heap::TargetSpaceId(InstanceType type) { 359 // Heap numbers and sequential strings are promoted to old data space, all 360 // other object types are promoted to old pointer space. We do not use 361 // object->IsHeapNumber() and object->IsSeqString() because we already 362 // know that object has the heap object tag. 363 364 // These objects are never allocated in new space. 365 ASSERT(type != MAP_TYPE); 366 ASSERT(type != CODE_TYPE); 367 ASSERT(type != ODDBALL_TYPE); 368 ASSERT(type != JS_GLOBAL_PROPERTY_CELL_TYPE); 369 370 if (type < FIRST_NONSTRING_TYPE) { 371 // There are four string representations: sequential strings, external 372 // strings, cons strings, and sliced strings. 373 // Only the latter two contain non-map-word pointers to heap objects. 374 return ((type & kIsIndirectStringMask) == kIsIndirectStringTag) 375 ? OLD_POINTER_SPACE 376 : OLD_DATA_SPACE; 377 } else { 378 return (type <= LAST_DATA_TYPE) ? OLD_DATA_SPACE : OLD_POINTER_SPACE; 379 } 380} 381 382 383void Heap::CopyBlock(Address dst, Address src, int byte_size) { 384 CopyWords(reinterpret_cast<Object**>(dst), 385 reinterpret_cast<Object**>(src), 386 byte_size / kPointerSize); 387} 388 389 390void Heap::MoveBlock(Address dst, Address src, int byte_size) { 391 ASSERT(IsAligned(byte_size, kPointerSize)); 392 393 int size_in_words = byte_size / kPointerSize; 394 395 if ((dst < src) || (dst >= (src + byte_size))) { 396 Object** src_slot = reinterpret_cast<Object**>(src); 397 Object** dst_slot = reinterpret_cast<Object**>(dst); 398 Object** end_slot = src_slot + size_in_words; 399 400 while (src_slot != end_slot) { 401 *dst_slot++ = *src_slot++; 402 } 403 } else { 404 memmove(dst, src, byte_size); 405 } 406} 407 408 409void Heap::ScavengePointer(HeapObject** p) { 410 ScavengeObject(p, *p); 411} 412 413 414void Heap::ScavengeObject(HeapObject** p, HeapObject* object) { 415 ASSERT(HEAP->InFromSpace(object)); 416 417 // We use the first word (where the map pointer usually is) of a heap 418 // object to record the forwarding pointer. A forwarding pointer can 419 // point to an old space, the code space, or the to space of the new 420 // generation. 421 MapWord first_word = object->map_word(); 422 423 // If the first word is a forwarding address, the object has already been 424 // copied. 425 if (first_word.IsForwardingAddress()) { 426 HeapObject* dest = first_word.ToForwardingAddress(); 427 ASSERT(HEAP->InFromSpace(*p)); 428 *p = dest; 429 return; 430 } 431 432 // Call the slow part of scavenge object. 433 return ScavengeObjectSlow(p, object); 434} 435 436 437bool Heap::CollectGarbage(AllocationSpace space, const char* gc_reason) { 438 const char* collector_reason = NULL; 439 GarbageCollector collector = SelectGarbageCollector(space, &collector_reason); 440 return CollectGarbage(space, collector, gc_reason, collector_reason); 441} 442 443 444MaybeObject* Heap::PrepareForCompare(String* str) { 445 // Always flatten small strings and force flattening of long strings 446 // after we have accumulated a certain amount we failed to flatten. 447 static const int kMaxAlwaysFlattenLength = 32; 448 static const int kFlattenLongThreshold = 16*KB; 449 450 const int length = str->length(); 451 MaybeObject* obj = str->TryFlatten(); 452 if (length <= kMaxAlwaysFlattenLength || 453 unflattened_strings_length_ >= kFlattenLongThreshold) { 454 return obj; 455 } 456 if (obj->IsFailure()) { 457 unflattened_strings_length_ += length; 458 } 459 return str; 460} 461 462 463int Heap::AdjustAmountOfExternalAllocatedMemory(int change_in_bytes) { 464 ASSERT(HasBeenSetUp()); 465 int amount = amount_of_external_allocated_memory_ + change_in_bytes; 466 if (change_in_bytes >= 0) { 467 // Avoid overflow. 468 if (amount > amount_of_external_allocated_memory_) { 469 amount_of_external_allocated_memory_ = amount; 470 } 471 int amount_since_last_global_gc = 472 amount_of_external_allocated_memory_ - 473 amount_of_external_allocated_memory_at_last_global_gc_; 474 if (amount_since_last_global_gc > external_allocation_limit_) { 475 CollectAllGarbage(kNoGCFlags, "external memory allocation limit reached"); 476 } 477 } else { 478 // Avoid underflow. 479 if (amount >= 0) { 480 amount_of_external_allocated_memory_ = amount; 481 } 482 } 483 ASSERT(amount_of_external_allocated_memory_ >= 0); 484 return amount_of_external_allocated_memory_; 485} 486 487 488void Heap::SetLastScriptId(Object* last_script_id) { 489 roots_[kLastScriptIdRootIndex] = last_script_id; 490} 491 492 493Isolate* Heap::isolate() { 494 return reinterpret_cast<Isolate*>(reinterpret_cast<intptr_t>(this) - 495 reinterpret_cast<size_t>(reinterpret_cast<Isolate*>(4)->heap()) + 4); 496} 497 498 499#ifdef DEBUG 500#define GC_GREEDY_CHECK() \ 501 if (FLAG_gc_greedy) HEAP->GarbageCollectionGreedyCheck() 502#else 503#define GC_GREEDY_CHECK() { } 504#endif 505 506// Calls the FUNCTION_CALL function and retries it up to three times 507// to guarantee that any allocations performed during the call will 508// succeed if there's enough memory. 509 510// Warning: Do not use the identifiers __object__, __maybe_object__ or 511// __scope__ in a call to this macro. 512 513#define CALL_AND_RETRY(ISOLATE, FUNCTION_CALL, RETURN_VALUE, RETURN_EMPTY)\ 514 do { \ 515 GC_GREEDY_CHECK(); \ 516 MaybeObject* __maybe_object__ = FUNCTION_CALL; \ 517 Object* __object__ = NULL; \ 518 if (__maybe_object__->ToObject(&__object__)) RETURN_VALUE; \ 519 if (__maybe_object__->IsOutOfMemory()) { \ 520 v8::internal::V8::FatalProcessOutOfMemory("CALL_AND_RETRY_0", true);\ 521 } \ 522 if (!__maybe_object__->IsRetryAfterGC()) RETURN_EMPTY; \ 523 ISOLATE->heap()->CollectGarbage(Failure::cast(__maybe_object__)-> \ 524 allocation_space(), \ 525 "allocation failure"); \ 526 __maybe_object__ = FUNCTION_CALL; \ 527 if (__maybe_object__->ToObject(&__object__)) RETURN_VALUE; \ 528 if (__maybe_object__->IsOutOfMemory()) { \ 529 v8::internal::V8::FatalProcessOutOfMemory("CALL_AND_RETRY_1", true);\ 530 } \ 531 if (!__maybe_object__->IsRetryAfterGC()) RETURN_EMPTY; \ 532 ISOLATE->counters()->gc_last_resort_from_handles()->Increment(); \ 533 ISOLATE->heap()->CollectAllAvailableGarbage("last resort gc"); \ 534 { \ 535 AlwaysAllocateScope __scope__; \ 536 __maybe_object__ = FUNCTION_CALL; \ 537 } \ 538 if (__maybe_object__->ToObject(&__object__)) RETURN_VALUE; \ 539 if (__maybe_object__->IsOutOfMemory() || \ 540 __maybe_object__->IsRetryAfterGC()) { \ 541 /* TODO(1181417): Fix this. */ \ 542 v8::internal::V8::FatalProcessOutOfMemory("CALL_AND_RETRY_2", true);\ 543 } \ 544 RETURN_EMPTY; \ 545 } while (false) 546 547 548#define CALL_HEAP_FUNCTION(ISOLATE, FUNCTION_CALL, TYPE) \ 549 CALL_AND_RETRY(ISOLATE, \ 550 FUNCTION_CALL, \ 551 return Handle<TYPE>(TYPE::cast(__object__), ISOLATE), \ 552 return Handle<TYPE>()) 553 554 555#define CALL_HEAP_FUNCTION_VOID(ISOLATE, FUNCTION_CALL) \ 556 CALL_AND_RETRY(ISOLATE, FUNCTION_CALL, return, return) 557 558 559#ifdef DEBUG 560 561inline bool Heap::allow_allocation(bool new_state) { 562 bool old = allocation_allowed_; 563 allocation_allowed_ = new_state; 564 return old; 565} 566 567#endif 568 569 570void ExternalStringTable::AddString(String* string) { 571 ASSERT(string->IsExternalString()); 572 if (heap_->InNewSpace(string)) { 573 new_space_strings_.Add(string); 574 } else { 575 old_space_strings_.Add(string); 576 } 577} 578 579 580void ExternalStringTable::Iterate(ObjectVisitor* v) { 581 if (!new_space_strings_.is_empty()) { 582 Object** start = &new_space_strings_[0]; 583 v->VisitPointers(start, start + new_space_strings_.length()); 584 } 585 if (!old_space_strings_.is_empty()) { 586 Object** start = &old_space_strings_[0]; 587 v->VisitPointers(start, start + old_space_strings_.length()); 588 } 589} 590 591 592// Verify() is inline to avoid ifdef-s around its calls in release 593// mode. 594void ExternalStringTable::Verify() { 595#ifdef DEBUG 596 for (int i = 0; i < new_space_strings_.length(); ++i) { 597 ASSERT(heap_->InNewSpace(new_space_strings_[i])); 598 ASSERT(new_space_strings_[i] != HEAP->raw_unchecked_the_hole_value()); 599 } 600 for (int i = 0; i < old_space_strings_.length(); ++i) { 601 ASSERT(!heap_->InNewSpace(old_space_strings_[i])); 602 ASSERT(old_space_strings_[i] != HEAP->raw_unchecked_the_hole_value()); 603 } 604#endif 605} 606 607 608void ExternalStringTable::AddOldString(String* string) { 609 ASSERT(string->IsExternalString()); 610 ASSERT(!heap_->InNewSpace(string)); 611 old_space_strings_.Add(string); 612} 613 614 615void ExternalStringTable::ShrinkNewStrings(int position) { 616 new_space_strings_.Rewind(position); 617 if (FLAG_verify_heap) { 618 Verify(); 619 } 620} 621 622 623void Heap::ClearInstanceofCache() { 624 set_instanceof_cache_function(the_hole_value()); 625} 626 627 628Object* Heap::ToBoolean(bool condition) { 629 return condition ? true_value() : false_value(); 630} 631 632 633void Heap::CompletelyClearInstanceofCache() { 634 set_instanceof_cache_map(the_hole_value()); 635 set_instanceof_cache_function(the_hole_value()); 636} 637 638 639MaybeObject* TranscendentalCache::Get(Type type, double input) { 640 SubCache* cache = caches_[type]; 641 if (cache == NULL) { 642 caches_[type] = cache = new SubCache(type); 643 } 644 return cache->Get(input); 645} 646 647 648Address TranscendentalCache::cache_array_address() { 649 return reinterpret_cast<Address>(caches_); 650} 651 652 653double TranscendentalCache::SubCache::Calculate(double input) { 654 switch (type_) { 655 case ACOS: 656 return acos(input); 657 case ASIN: 658 return asin(input); 659 case ATAN: 660 return atan(input); 661 case COS: 662 return fast_cos(input); 663 case EXP: 664 return exp(input); 665 case LOG: 666 return fast_log(input); 667 case SIN: 668 return fast_sin(input); 669 case TAN: 670 return fast_tan(input); 671 default: 672 return 0.0; // Never happens. 673 } 674} 675 676 677MaybeObject* TranscendentalCache::SubCache::Get(double input) { 678 Converter c; 679 c.dbl = input; 680 int hash = Hash(c); 681 Element e = elements_[hash]; 682 if (e.in[0] == c.integers[0] && 683 e.in[1] == c.integers[1]) { 684 ASSERT(e.output != NULL); 685 isolate_->counters()->transcendental_cache_hit()->Increment(); 686 return e.output; 687 } 688 double answer = Calculate(input); 689 isolate_->counters()->transcendental_cache_miss()->Increment(); 690 Object* heap_number; 691 { MaybeObject* maybe_heap_number = 692 isolate_->heap()->AllocateHeapNumber(answer); 693 if (!maybe_heap_number->ToObject(&heap_number)) return maybe_heap_number; 694 } 695 elements_[hash].in[0] = c.integers[0]; 696 elements_[hash].in[1] = c.integers[1]; 697 elements_[hash].output = heap_number; 698 return heap_number; 699} 700 701 702AlwaysAllocateScope::AlwaysAllocateScope() { 703 // We shouldn't hit any nested scopes, because that requires 704 // non-handle code to call handle code. The code still works but 705 // performance will degrade, so we want to catch this situation 706 // in debug mode. 707 ASSERT(HEAP->always_allocate_scope_depth_ == 0); 708 HEAP->always_allocate_scope_depth_++; 709} 710 711 712AlwaysAllocateScope::~AlwaysAllocateScope() { 713 HEAP->always_allocate_scope_depth_--; 714 ASSERT(HEAP->always_allocate_scope_depth_ == 0); 715} 716 717 718LinearAllocationScope::LinearAllocationScope() { 719 HEAP->linear_allocation_scope_depth_++; 720} 721 722 723LinearAllocationScope::~LinearAllocationScope() { 724 HEAP->linear_allocation_scope_depth_--; 725 ASSERT(HEAP->linear_allocation_scope_depth_ >= 0); 726} 727 728 729#ifdef DEBUG 730void VerifyPointersVisitor::VisitPointers(Object** start, Object** end) { 731 for (Object** current = start; current < end; current++) { 732 if ((*current)->IsHeapObject()) { 733 HeapObject* object = HeapObject::cast(*current); 734 ASSERT(HEAP->Contains(object)); 735 ASSERT(object->map()->IsMap()); 736 } 737 } 738} 739#endif 740 741 742double GCTracer::SizeOfHeapObjects() { 743 return (static_cast<double>(HEAP->SizeOfObjects())) / MB; 744} 745 746 747#ifdef DEBUG 748DisallowAllocationFailure::DisallowAllocationFailure() { 749 old_state_ = HEAP->disallow_allocation_failure_; 750 HEAP->disallow_allocation_failure_ = true; 751} 752 753 754DisallowAllocationFailure::~DisallowAllocationFailure() { 755 HEAP->disallow_allocation_failure_ = old_state_; 756} 757#endif 758 759 760#ifdef DEBUG 761AssertNoAllocation::AssertNoAllocation() { 762 old_state_ = HEAP->allow_allocation(false); 763} 764 765 766AssertNoAllocation::~AssertNoAllocation() { 767 HEAP->allow_allocation(old_state_); 768} 769 770 771DisableAssertNoAllocation::DisableAssertNoAllocation() { 772 old_state_ = HEAP->allow_allocation(true); 773} 774 775 776DisableAssertNoAllocation::~DisableAssertNoAllocation() { 777 HEAP->allow_allocation(old_state_); 778} 779 780#else 781 782AssertNoAllocation::AssertNoAllocation() { } 783AssertNoAllocation::~AssertNoAllocation() { } 784DisableAssertNoAllocation::DisableAssertNoAllocation() { } 785DisableAssertNoAllocation::~DisableAssertNoAllocation() { } 786 787#endif 788 789 790} } // namespace v8::internal 791 792#endif // V8_HEAP_INL_H_ 793