Handlify number-related allocators.

R=mstarzinger@chromium.org

Review URL: https://codereview.chromium.org/240293002

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@20811 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
yangguo@chromium.org 2014-04-16 14:04:54 +00:00
parent a947aeb315
commit 3abbb03c0a
5 changed files with 102 additions and 199 deletions

View File

@ -6,6 +6,7 @@
#include "macro-assembler.h"
#include "isolate-inl.h"
#include "v8conversions.h"
namespace v8 {
namespace internal {
@ -722,10 +723,11 @@ Handle<Struct> Factory::NewStruct(InstanceType type) {
Handle<CodeCache> Factory::NewCodeCache() {
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->AllocateCodeCache(),
CodeCache);
Handle<CodeCache> code_cache =
Handle<CodeCache>::cast(NewStruct(CODE_CACHE_TYPE));
code_cache->set_default_cache(*empty_fixed_array(), SKIP_WRITE_BARRIER);
code_cache->set_normal_type_cache(*undefined_value(), SKIP_WRITE_BARRIER);
return code_cache;
}
@ -1017,17 +1019,26 @@ Handle<JSFunction> Factory::NewFunctionFromSharedFunctionInfo(
Handle<Object> Factory::NewNumber(double value,
PretenureFlag pretenure) {
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->NumberFromDouble(value, pretenure), Object);
// We need to distinguish the minus zero value and this cannot be
// done after conversion to int. Doing this by comparing bit
// patterns is faster than using fpclassify() et al.
if (IsMinusZero(value)) return NewHeapNumber(-0.0, pretenure);
int int_value = FastD2I(value);
if (value == int_value && Smi::IsValid(int_value)) {
return handle(Smi::FromInt(int_value), isolate());
}
// Materialize the value in the heap.
return NewHeapNumber(value, pretenure);
}
Handle<Object> Factory::NewNumberFromInt(int32_t value,
PretenureFlag pretenure) {
CALL_HEAP_FUNCTION(
isolate(),
isolate()->heap()->NumberFromInt32(value, pretenure), Object);
if (Smi::IsValid(value)) return handle(Smi::FromInt(value), isolate());
// Bypass NumberFromDouble to avoid various redundant checks.
return NewHeapNumber(FastI2D(value), pretenure);
}
@ -1854,18 +1865,78 @@ Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfo(Handle<String> name) {
}
Handle<String> Factory::NumberToString(Handle<Object> number,
bool check_number_string_cache) {
CALL_HEAP_FUNCTION(isolate(),
isolate()->heap()->NumberToString(
*number, check_number_string_cache),
String);
static inline int NumberCacheHash(Handle<FixedArray> cache,
Handle<Object> number) {
int mask = (cache->length() >> 1) - 1;
if (number->IsSmi()) {
return Handle<Smi>::cast(number)->value() & mask;
} else {
DoubleRepresentation rep(number->Number());
return
(static_cast<int>(rep.bits) ^ static_cast<int>(rep.bits >> 32)) & mask;
}
}
Handle<String> Factory::Uint32ToString(uint32_t value) {
CALL_HEAP_FUNCTION(isolate(),
isolate()->heap()->Uint32ToString(value), String);
Handle<Object> Factory::GetNumberStringCache(Handle<Object> number) {
DisallowHeapAllocation no_gc;
int hash = NumberCacheHash(number_string_cache(), number);
Object* key = number_string_cache()->get(hash * 2);
if (key == *number || (key->IsHeapNumber() && number->IsHeapNumber() &&
key->Number() == number->Number())) {
return Handle<String>(
String::cast(number_string_cache()->get(hash * 2 + 1)), isolate());
}
return undefined_value();
}
void Factory::SetNumberStringCache(Handle<Object> number,
Handle<String> string) {
int hash = NumberCacheHash(number_string_cache(), number);
if (number_string_cache()->get(hash * 2) != *undefined_value()) {
int full_size = isolate()->heap()->FullSizeNumberStringCacheLength();
if (number_string_cache()->length() != full_size) {
// The first time we have a hash collision, we move to the full sized
// number string cache. The idea is to have a small number string
// cache in the snapshot to keep boot-time memory usage down.
// If we expand the number string cache already while creating
// the snapshot then that didn't work out.
ASSERT(!Serializer::enabled() || FLAG_extra_code != NULL);
Handle<FixedArray> new_cache = NewFixedArray(full_size, TENURED);
isolate()->heap()->set_number_string_cache(*new_cache);
return;
}
}
number_string_cache()->set(hash * 2, *number);
number_string_cache()->set(hash * 2 + 1, *string);
}
Handle<String> Factory::NumberToString(Handle<Object> number,
bool check_number_string_cache) {
isolate()->counters()->number_to_string_runtime()->Increment();
if (check_number_string_cache) {
Handle<Object> cached = GetNumberStringCache(number);
if (!cached->IsUndefined()) return Handle<String>::cast(cached);
}
char arr[100];
Vector<char> buffer(arr, ARRAY_SIZE(arr));
const char* str;
if (number->IsSmi()) {
int num = Handle<Smi>::cast(number)->value();
str = IntToCString(num, buffer);
} else {
double num = Handle<HeapNumber>::cast(number)->value();
str = DoubleToCString(num, buffer);
}
// We tenure the allocated string since it is referenced from the
// number-string cache which lives in the old space.
Handle<String> js_string = NewStringFromOneByte(OneByteVector(str), TENURED);
SetNumberStringCache(number, js_string);
return js_string;
}

View File

@ -283,6 +283,7 @@ class Factory V8_FINAL {
Handle<ConstantPoolArray> array);
// Numbers (e.g. literals) are pretenured by the parser.
// The return value may be a smi or a heap number.
Handle<Object> NewNumber(double value,
PretenureFlag pretenure = NOT_TENURED);
@ -500,7 +501,10 @@ class Factory V8_FINAL {
Handle<String> NumberToString(Handle<Object> number,
bool check_number_string_cache = true);
Handle<String> Uint32ToString(uint32_t value);
Handle<String> Uint32ToString(uint32_t value) {
return NumberToString(NewNumberFromUint(value));
}
enum ApiInstanceType {
JavaScriptObject,
@ -645,6 +649,13 @@ class Factory V8_FINAL {
Handle<MapCache> AddToMapCache(Handle<Context> context,
Handle<FixedArray> keys,
Handle<Map> map);
// Attempt to find the number in a small cache. If we finds it, return
// the string representation of the number. Otherwise return undefined.
Handle<Object> GetNumberStringCache(Handle<Object> number);
// Update the cache with a new number-string pair.
void SetNumberStringCache(Handle<Object> number, Handle<String> string);
};
} } // namespace v8::internal

View File

@ -269,14 +269,6 @@ MaybeObject* Heap::AllocateRaw(int size_in_bytes,
}
MaybeObject* Heap::NumberFromInt32(
int32_t value, PretenureFlag pretenure) {
if (Smi::IsValid(value)) return Smi::FromInt(value);
// Bypass NumberFromDouble to avoid various redundant checks.
return AllocateHeapNumber(FastI2D(value), pretenure);
}
MaybeObject* Heap::NumberFromUint32(
uint32_t value, PretenureFlag pretenure) {
if (static_cast<int32_t>(value) >= 0 &&

View File

@ -2408,17 +2408,6 @@ MaybeObject* Heap::AllocateMap(InstanceType instance_type,
}
MaybeObject* Heap::AllocateCodeCache() {
CodeCache* code_cache;
{ MaybeObject* maybe_code_cache = AllocateStruct(CODE_CACHE_TYPE);
if (!maybe_code_cache->To(&code_cache)) return maybe_code_cache;
}
code_cache->set_default_cache(empty_fixed_array(), SKIP_WRITE_BARRIER);
code_cache->set_normal_type_cache(undefined_value(), SKIP_WRITE_BARRIER);
return code_cache;
}
MaybeObject* Heap::AllocatePolymorphicCodeCache() {
return AllocateStruct(POLYMORPHIC_CODE_CACHE_TYPE);
}
@ -3255,24 +3244,6 @@ int Heap::FullSizeNumberStringCacheLength() {
}
void Heap::AllocateFullSizeNumberStringCache() {
// The idea is to have a small number string cache in the snapshot to keep
// boot-time memory usage down. If we expand the number string cache already
// while creating the snapshot then that didn't work out.
ASSERT(!Serializer::enabled() || FLAG_extra_code != NULL);
MaybeObject* maybe_obj =
AllocateFixedArray(FullSizeNumberStringCacheLength(), TENURED);
Object* new_cache;
if (maybe_obj->ToObject(&new_cache)) {
// We don't bother to repopulate the cache with entries from the old cache.
// It will be repopulated soon enough with new strings.
set_number_string_cache(FixedArray::cast(new_cache));
}
// If allocation fails then we just return without doing anything. It is only
// a cache, so best effort is OK here.
}
void Heap::FlushNumberStringCache() {
// Flush the number to string cache.
int len = number_string_cache()->length();
@ -3282,100 +3253,6 @@ void Heap::FlushNumberStringCache() {
}
static inline int double_get_hash(double d) {
DoubleRepresentation rep(d);
return static_cast<int>(rep.bits) ^ static_cast<int>(rep.bits >> 32);
}
static inline int smi_get_hash(Smi* smi) {
return smi->value();
}
Object* Heap::GetNumberStringCache(Object* number) {
int hash;
int mask = (number_string_cache()->length() >> 1) - 1;
if (number->IsSmi()) {
hash = smi_get_hash(Smi::cast(number)) & mask;
} else {
hash = double_get_hash(number->Number()) & mask;
}
Object* key = number_string_cache()->get(hash * 2);
if (key == number) {
return String::cast(number_string_cache()->get(hash * 2 + 1));
} else if (key->IsHeapNumber() &&
number->IsHeapNumber() &&
key->Number() == number->Number()) {
return String::cast(number_string_cache()->get(hash * 2 + 1));
}
return undefined_value();
}
void Heap::SetNumberStringCache(Object* number, String* string) {
int hash;
int mask = (number_string_cache()->length() >> 1) - 1;
if (number->IsSmi()) {
hash = smi_get_hash(Smi::cast(number)) & mask;
} else {
hash = double_get_hash(number->Number()) & mask;
}
if (number_string_cache()->get(hash * 2) != undefined_value() &&
number_string_cache()->length() != FullSizeNumberStringCacheLength()) {
// The first time we have a hash collision, we move to the full sized
// number string cache.
AllocateFullSizeNumberStringCache();
return;
}
number_string_cache()->set(hash * 2, number);
number_string_cache()->set(hash * 2 + 1, string);
}
MaybeObject* Heap::NumberToString(Object* number,
bool check_number_string_cache) {
isolate_->counters()->number_to_string_runtime()->Increment();
if (check_number_string_cache) {
Object* cached = GetNumberStringCache(number);
if (cached != undefined_value()) {
return cached;
}
}
char arr[100];
Vector<char> buffer(arr, ARRAY_SIZE(arr));
const char* str;
if (number->IsSmi()) {
int num = Smi::cast(number)->value();
str = IntToCString(num, buffer);
} else {
double num = HeapNumber::cast(number)->value();
str = DoubleToCString(num, buffer);
}
Object* js_string;
// We tenure the allocated string since it is referenced from the
// number-string cache which lives in the old space.
MaybeObject* maybe_js_string =
AllocateStringFromOneByte(CStrVector(str), TENURED);
if (maybe_js_string->ToObject(&js_string)) {
SetNumberStringCache(number, String::cast(js_string));
}
return maybe_js_string;
}
MaybeObject* Heap::Uint32ToString(uint32_t value,
bool check_number_string_cache) {
Object* number;
MaybeObject* maybe = NumberFromUint32(value);
if (!maybe->To<Object>(&number)) return maybe;
return NumberToString(number, check_number_string_cache);
}
MaybeObject* Heap::AllocateAllocationSitesScratchpad() {
MaybeObject* maybe_obj =
AllocateFixedArray(kAllocationSiteScratchpadSize, TENURED);
@ -3513,24 +3390,6 @@ FixedTypedArrayBase* Heap::EmptyFixedTypedArrayForMap(Map* map) {
}
MaybeObject* Heap::NumberFromDouble(double value, PretenureFlag pretenure) {
// We need to distinguish the minus zero value and this cannot be
// done after conversion to int. Doing this by comparing bit
// patterns is faster than using fpclassify() et al.
if (IsMinusZero(value)) {
return AllocateHeapNumber(-0.0, pretenure);
}
int int_value = FastD2I(value);
if (value == int_value && Smi::IsValid(int_value)) {
return Smi::FromInt(int_value);
}
// Materialize the value in the heap.
return AllocateHeapNumber(value, pretenure);
}
MaybeObject* Heap::AllocateForeign(Address address, PretenureFlag pretenure) {
// Statically ensure that it is safe to allocate foreigns in paged spaces.
STATIC_ASSERT(Foreign::kSize <= Page::kMaxRegularHeapObjectSize);

View File

@ -755,9 +755,6 @@ class Heap {
MUST_USE_RESULT MaybeObject* AllocatePartialMap(InstanceType instance_type,
int instance_size);
// Allocates an empty code cache.
MUST_USE_RESULT MaybeObject* AllocateCodeCache();
// Allocates an empty PolymorphicCodeCache.
MUST_USE_RESULT MaybeObject* AllocatePolymorphicCodeCache();
@ -982,22 +979,10 @@ class Heap {
MUST_USE_RESULT MaybeObject* AllocateArgumentsObject(
Object* callee, int length);
// Same as NewNumberFromDouble, but may return a preallocated/immutable
// number object (e.g., minus_zero_value_, nan_value_)
MUST_USE_RESULT MaybeObject* NumberFromDouble(
double value, PretenureFlag pretenure = NOT_TENURED);
// Allocated a HeapNumber from value.
MUST_USE_RESULT MaybeObject* AllocateHeapNumber(
double value, PretenureFlag pretenure = NOT_TENURED);
// Converts an int into either a Smi or a HeapNumber object.
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed.
// Please note this does not perform a garbage collection.
MUST_USE_RESULT inline MaybeObject* NumberFromInt32(
int32_t value, PretenureFlag pretenure = NOT_TENURED);
// Converts an int into either a Smi or a HeapNumber object.
// Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
// failed.
@ -1367,13 +1352,6 @@ class Heap {
bool CreateApiObjects();
// Attempt to find the number in a small cache. If we finds it, return
// the string representation of the number. Otherwise return undefined.
Object* GetNumberStringCache(Object* number);
// Update the cache with a new number-string pair.
void SetNumberStringCache(Object* number, String* str);
// Adjusts the amount of registered external memory.
// Returns the adjusted value.
inline int64_t AdjustAmountOfExternalAllocatedMemory(
@ -1470,11 +1448,6 @@ class Heap {
// Generated code can treat direct references to this root as constant.
bool RootCanBeTreatedAsConstant(RootListIndex root_index);
MUST_USE_RESULT MaybeObject* NumberToString(
Object* number, bool check_number_string_cache = true);
MUST_USE_RESULT MaybeObject* Uint32ToString(
uint32_t value, bool check_number_string_cache = true);
Map* MapForFixedTypedArray(ExternalArrayType array_type);
RootListIndex RootIndexForFixedTypedArray(
ExternalArrayType array_type);
@ -2119,9 +2092,6 @@ class Heap {
// Allocates a small number to string cache.
MUST_USE_RESULT MaybeObject* AllocateInitialNumberStringCache();
// Creates and installs the full-sized number string cache.
void AllocateFullSizeNumberStringCache();
// Get the length of the number to string cache based on the max semispace
// size.
int FullSizeNumberStringCacheLength();
// Flush the number to string cache.
void FlushNumberStringCache();