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