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:
parent
a947aeb315
commit
3abbb03c0a
109
src/factory.cc
109
src/factory.cc
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 &&
|
||||
|
141
src/heap.cc
141
src/heap.cc
@ -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);
|
||||
|
30
src/heap.h
30
src/heap.h
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user