- Fixed issue when building samples and cctests on 64-bit machines.
- Fixed mozilla test breakage caused by python's obscure module loading rules. - Made sure test.py propagates test failures out as the exit code of the script. - Remove runtime calls to get number constants. Remove Heap roots for some special numbers. - Fix typo in accessors.h. - Changes CopyMap to not copy descriptors. Adds CopyMapRemoveTransitions that copies non-transition descriptors. Changes interface of DescriptorArray::Copy operations to simplify them. git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@21 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
05bbf90b3a
commit
968facb9ff
10
SConstruct
10
SConstruct
@ -151,7 +151,11 @@ CCTEST_EXTRA_FLAGS = {
|
||||
'gcc': {
|
||||
'all': {
|
||||
'LIBPATH': [abspath('.')]
|
||||
}
|
||||
},
|
||||
'wordsize:64': {
|
||||
'CCFLAGS': ['-m32'],
|
||||
'LINKFLAGS': ['-m32']
|
||||
},
|
||||
},
|
||||
'msvc': {
|
||||
'all': {
|
||||
@ -174,6 +178,10 @@ SAMPLE_FLAGS = {
|
||||
'LIBS': ['pthread'],
|
||||
'LIBPATH': ['.']
|
||||
},
|
||||
'wordsize:64': {
|
||||
'CCFLAGS': ['-m32'],
|
||||
'LINKFLAGS': ['-m32']
|
||||
},
|
||||
},
|
||||
'msvc': {
|
||||
'all': {
|
||||
|
@ -278,10 +278,8 @@ Object* Accessors::FunctionSetPrototype(JSObject* object,
|
||||
if (function->has_initial_map()) {
|
||||
// If the function has allocated the initial map
|
||||
// replace it with a copy containing the new prototype.
|
||||
Object* new_map = function->initial_map()->Copy();
|
||||
Object* new_map = function->initial_map()->CopyDropTransitions();
|
||||
if (new_map->IsFailure()) return new_map;
|
||||
Object* result = Map::cast(new_map)->EnsureNoMapTransitions();
|
||||
if (result->IsFailure()) return result;
|
||||
function->set_initial_map(Map::cast(new_map));
|
||||
}
|
||||
Object* prototype = function->SetPrototype(value);
|
||||
@ -490,14 +488,12 @@ Object* Accessors::ObjectSetPrototype(JSObject* receiver,
|
||||
}
|
||||
|
||||
// Set the new prototype of the object.
|
||||
Object* new_map = current->map()->Copy();
|
||||
Object* new_map = current->map()->CopyDropTransitions();
|
||||
if (new_map->IsFailure()) return new_map;
|
||||
Object* result = Map::cast(new_map)->EnsureNoMapTransitions();
|
||||
if (result->IsFailure()) return result;
|
||||
Map::cast(new_map)->set_prototype(value);
|
||||
current->set_map(Map::cast(new_map));
|
||||
|
||||
// To be consistant with other Set functions, return the value.
|
||||
// To be consistent with other Set functions, return the value.
|
||||
return value;
|
||||
}
|
||||
|
||||
|
@ -47,7 +47,7 @@ namespace v8 { namespace internal {
|
||||
V(ScriptType) \
|
||||
V(ObjectPrototype)
|
||||
|
||||
// Accessors contains all prodefined proxy accessors.
|
||||
// Accessors contains all predefined proxy accessors.
|
||||
|
||||
class Accessors : public AllStatic {
|
||||
public:
|
||||
|
@ -505,6 +505,7 @@ void Genesis::CreateRoots(v8::Handle<v8::ObjectTemplate> global_template,
|
||||
|
||||
// Allocate the function map first and then patch the prototype later
|
||||
Handle<Map> empty_fm = Factory::CopyMap(fm);
|
||||
empty_fm->set_instance_descriptors(*function_map_descriptors);
|
||||
empty_fm->set_prototype(global_context()->object_function()->prototype());
|
||||
empty_function->set_map(*empty_fm);
|
||||
}
|
||||
@ -1247,7 +1248,7 @@ void Genesis::TransferObject(Handle<JSObject> from, Handle<JSObject> to) {
|
||||
|
||||
// Transfer the prototype (new map is needed).
|
||||
Handle<Map> old_to_map = Handle<Map>(to->map());
|
||||
Handle<Map> new_to_map = Factory::CopyMap(old_to_map);
|
||||
Handle<Map> new_to_map = Factory::CopyMapDropTransitions(old_to_map);
|
||||
new_to_map->set_prototype(from->map()->prototype());
|
||||
to->set_map(*new_to_map);
|
||||
}
|
||||
|
@ -172,6 +172,11 @@ Handle<Map> Factory::CopyMap(Handle<Map> src) {
|
||||
}
|
||||
|
||||
|
||||
Handle<Map> Factory::CopyMapDropTransitions(Handle<Map> src) {
|
||||
CALL_HEAP_FUNCTION(src->CopyDropTransitions(), Map);
|
||||
}
|
||||
|
||||
|
||||
Handle<FixedArray> Factory::CopyFixedArray(Handle<FixedArray> array) {
|
||||
CALL_HEAP_FUNCTION(array->Copy(), FixedArray);
|
||||
}
|
||||
@ -464,11 +469,11 @@ Handle<DescriptorArray> Factory::CopyAppendProxyDescriptor(
|
||||
PropertyAttributes attributes) {
|
||||
GC_GREEDY_CHECK();
|
||||
CallbacksDescriptor desc(*key, *value, attributes);
|
||||
Object* obj = array->CopyInsert(&desc);
|
||||
Object* obj = array->CopyInsert(&desc, REMOVE_TRANSITIONS);
|
||||
if (obj->IsRetryAfterGC()) {
|
||||
CALL_GC(obj);
|
||||
CallbacksDescriptor desc(*key, *value, attributes);
|
||||
obj = array->CopyInsert(&desc);
|
||||
obj = array->CopyInsert(&desc, REMOVE_TRANSITIONS);
|
||||
if (obj->IsFailure()) {
|
||||
// TODO(1181417): Fix this.
|
||||
V8::FatalProcessOutOfMemory("CopyAppendProxyDescriptor");
|
||||
|
@ -146,6 +146,8 @@ class Factory : public AllStatic {
|
||||
|
||||
static Handle<Map> CopyMap(Handle<Map> map);
|
||||
|
||||
static Handle<Map> CopyMapDropTransitions(Handle<Map> map);
|
||||
|
||||
static Handle<FixedArray> CopyFixedArray(Handle<FixedArray> array);
|
||||
|
||||
// Numbers (eg, literals) are pretenured by the parser.
|
||||
|
@ -309,6 +309,14 @@ enum PropertyType {
|
||||
};
|
||||
|
||||
|
||||
// Whether to remove map transitions and constant transitions from a
|
||||
// DescriptorArray.
|
||||
enum TransitionFlag {
|
||||
REMOVE_TRANSITIONS,
|
||||
KEEP_TRANSITIONS
|
||||
};
|
||||
|
||||
|
||||
// Union used for fast testing of specific double values.
|
||||
union DoubleRepresentation {
|
||||
double value;
|
||||
|
@ -108,7 +108,7 @@ void SetExpectedNofProperties(Handle<JSFunction> func, int nof) {
|
||||
func->shared()->set_expected_nof_properties(nof);
|
||||
if (func->has_initial_map()) {
|
||||
Handle<Map> new_initial_map =
|
||||
Factory::CopyMap(Handle<Map>(func->initial_map()));
|
||||
Factory::CopyMapDropTransitions(Handle<Map>(func->initial_map()));
|
||||
new_initial_map->set_unused_property_fields(nof);
|
||||
func->set_initial_map(*new_initial_map);
|
||||
}
|
||||
|
22
src/heap.cc
22
src/heap.cc
@ -1112,28 +1112,6 @@ bool Heap::CreateInitialObjects() {
|
||||
if (obj->IsFailure()) return false;
|
||||
nan_value_ = obj;
|
||||
|
||||
obj = NumberFromDouble(INFINITY, TENURED);
|
||||
if (obj->IsFailure()) return false;
|
||||
infinity_value_ = obj;
|
||||
|
||||
obj = NumberFromDouble(-INFINITY, TENURED);
|
||||
if (obj->IsFailure()) return false;
|
||||
negative_infinity_value_ = obj;
|
||||
|
||||
obj = NumberFromDouble(DBL_MAX, TENURED);
|
||||
if (obj->IsFailure()) return false;
|
||||
number_max_value_ = obj;
|
||||
|
||||
// C++ doesn't provide a constant for the smallest denormalized
|
||||
// double (approx. 5e-324) but only the smallest normalized one
|
||||
// which is somewhat bigger (approx. 2e-308). So we have to do
|
||||
// this raw conversion hack.
|
||||
uint64_t min_value_bits = 1L;
|
||||
double min_value = *reinterpret_cast<double*>(&min_value_bits);
|
||||
obj = NumberFromDouble(min_value, TENURED);
|
||||
if (obj->IsFailure()) return false;
|
||||
number_min_value_ = obj;
|
||||
|
||||
obj = Allocate(oddball_map(), CODE_SPACE);
|
||||
if (obj->IsFailure()) return false;
|
||||
undefined_value_ = obj;
|
||||
|
@ -101,10 +101,6 @@ namespace v8 { namespace internal {
|
||||
V(Map, one_word_filler_map) \
|
||||
V(Map, two_word_filler_map) \
|
||||
V(Object, nan_value) \
|
||||
V(Object, infinity_value) \
|
||||
V(Object, negative_infinity_value) \
|
||||
V(Object, number_max_value) \
|
||||
V(Object, number_min_value) \
|
||||
V(Object, undefined_value) \
|
||||
V(Object, minus_zero_value) \
|
||||
V(Object, null_value) \
|
||||
|
222
src/objects.cc
222
src/objects.cc
@ -997,7 +997,7 @@ Object* JSObject::AddFastProperty(String* name,
|
||||
// Allocate new instance descriptors with (name, index) added
|
||||
FieldDescriptor new_field(name, index, attributes);
|
||||
Object* new_descriptors =
|
||||
old_descriptors->CopyInsert(&new_field, true);
|
||||
old_descriptors->CopyInsert(&new_field, REMOVE_TRANSITIONS);
|
||||
if (new_descriptors->IsFailure()) return new_descriptors;
|
||||
|
||||
// Only allow map transition if the object's map is NOT equal to the
|
||||
@ -1016,7 +1016,7 @@ Object* JSObject::AddFastProperty(String* name,
|
||||
if (allow_map_transition) {
|
||||
// Allocate new instance descriptors for the old map with map transition.
|
||||
MapTransitionDescriptor d(name, Map::cast(new_map), attributes);
|
||||
Object* r = old_descriptors->CopyInsert(&d);
|
||||
Object* r = old_descriptors->CopyInsert(&d, KEEP_TRANSITIONS);
|
||||
if (r->IsFailure()) return r;
|
||||
old_descriptors = DescriptorArray::cast(r);
|
||||
}
|
||||
@ -1051,7 +1051,7 @@ Object* JSObject::AddFastProperty(String* name,
|
||||
if (allow_map_transition) {
|
||||
MapTransitionDescriptor d(name, Map::cast(new_map), attributes);
|
||||
// Allocate new instance descriptors for the old map with map transition.
|
||||
Object* r = old_descriptors->CopyInsert(&d);
|
||||
Object* r = old_descriptors->CopyInsert(&d, KEEP_TRANSITIONS);
|
||||
if (r->IsFailure()) return r;
|
||||
old_descriptors = DescriptorArray::cast(r);
|
||||
}
|
||||
@ -1074,7 +1074,7 @@ Object* JSObject::AddConstantFunctionProperty(String* name,
|
||||
// Allocate new instance descriptors with (name, function) added
|
||||
ConstantFunctionDescriptor d(name, function, attributes);
|
||||
Object* new_descriptors =
|
||||
map()->instance_descriptors()->CopyInsert(&d, true);
|
||||
map()->instance_descriptors()->CopyInsert(&d, REMOVE_TRANSITIONS);
|
||||
if (new_descriptors->IsFailure()) return new_descriptors;
|
||||
|
||||
// Allocate a new map for the object.
|
||||
@ -1105,7 +1105,8 @@ Object* JSObject::AddConstantFunctionProperty(String* name,
|
||||
return function;
|
||||
}
|
||||
ConstTransitionDescriptor mark(name);
|
||||
new_descriptors = old_map->instance_descriptors()->CopyInsert(&mark, false);
|
||||
new_descriptors =
|
||||
old_map->instance_descriptors()->CopyInsert(&mark, KEEP_TRANSITIONS);
|
||||
if (new_descriptors->IsFailure()) {
|
||||
return function; // We have accomplished the main goal, so return success.
|
||||
}
|
||||
@ -1123,23 +1124,15 @@ Object* JSObject::ReplaceConstantFunctionProperty(String* name,
|
||||
if (value->IsJSFunction()) {
|
||||
JSFunction* function = JSFunction::cast(value);
|
||||
|
||||
// Allocate new instance descriptors with (name, function) added
|
||||
Object* new_descriptors = map()->instance_descriptors()->Copy();
|
||||
if (new_descriptors->IsFailure()) return new_descriptors;
|
||||
Object* new_map =
|
||||
map()->CopyDropTransitions();
|
||||
if (new_map->IsFailure()) return new_map;
|
||||
set_map(Map::cast(new_map));
|
||||
|
||||
// Replace the function entry
|
||||
DescriptorArray* p = DescriptorArray::cast(new_descriptors);
|
||||
for (DescriptorReader r(p); !r.eos(); r.advance()) {
|
||||
if (r.Equals(name)) r.ReplaceConstantFunction(function);
|
||||
}
|
||||
|
||||
// Allocate a new map for the object.
|
||||
Object* new_map = map()->Copy();
|
||||
if (new_map->IsFailure()) return new_map;
|
||||
|
||||
Map::cast(new_map)->
|
||||
set_instance_descriptors(DescriptorArray::cast(new_descriptors));
|
||||
set_map(Map::cast(new_map));
|
||||
int index = map()->instance_descriptors()->Search(name);
|
||||
ASSERT(index != DescriptorArray::kNotFound);
|
||||
map()->instance_descriptors()->ReplaceConstantFunction(index, function);
|
||||
} else {
|
||||
// Allocate new instance descriptors with updated property index.
|
||||
int index = map()->NextFreePropertyIndex();
|
||||
@ -2186,34 +2179,6 @@ int Map::NextFreePropertyIndex() {
|
||||
return index+1;
|
||||
}
|
||||
|
||||
Object* Map::EnsureNoMapTransitions() {
|
||||
// Remove all map transitions.
|
||||
|
||||
// Compute the size of the map transition entries to be removed.
|
||||
int nof = 0;
|
||||
for (DescriptorReader r(instance_descriptors()); !r.eos(); r.advance()) {
|
||||
if (r.IsTransition()) nof++;
|
||||
}
|
||||
|
||||
if (nof == 0) return this;
|
||||
|
||||
// Allocate the new descriptor array.
|
||||
Object* result = DescriptorArray::Allocate(
|
||||
instance_descriptors()->number_of_descriptors() - nof);
|
||||
if (result->IsFailure()) return result;
|
||||
|
||||
// Copy the content.
|
||||
DescriptorWriter w(DescriptorArray::cast(result));
|
||||
for (DescriptorReader r(instance_descriptors()); !r.eos(); r.advance()) {
|
||||
if (!r.IsTransition()) w.WriteFrom(&r);
|
||||
}
|
||||
ASSERT(w.eos());
|
||||
|
||||
set_instance_descriptors(DescriptorArray::cast(result));
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
AccessorDescriptor* Map::FindAccessor(String* name) {
|
||||
for (DescriptorReader r(instance_descriptors()); !r.eos(); r.advance()) {
|
||||
@ -2387,7 +2352,8 @@ Object* Map::Copy() {
|
||||
if (result->IsFailure()) return result;
|
||||
Map::cast(result)->set_prototype(prototype());
|
||||
Map::cast(result)->set_constructor(constructor());
|
||||
Map::cast(result)->set_instance_descriptors(instance_descriptors());
|
||||
// Don't copy descriptors, so map transitions always remain a forest.
|
||||
Map::cast(result)->set_instance_descriptors(Heap::empty_descriptor_array());
|
||||
// Please note instance_type and instance_size are set when allocated.
|
||||
Map::cast(result)->set_unused_property_fields(unused_property_fields());
|
||||
Map::cast(result)->set_bit_field(bit_field());
|
||||
@ -2396,6 +2362,16 @@ Object* Map::Copy() {
|
||||
}
|
||||
|
||||
|
||||
Object* Map::CopyDropTransitions() {
|
||||
Object *new_map = Copy();
|
||||
if (new_map->IsFailure()) return new_map;
|
||||
Object* descriptors = instance_descriptors()->RemoveTransitions();
|
||||
if (descriptors->IsFailure()) return descriptors;
|
||||
cast(new_map)->set_instance_descriptors(DescriptorArray::cast(descriptors));
|
||||
return cast(new_map);
|
||||
}
|
||||
|
||||
|
||||
Object* Map::UpdateCodeCache(String* name, Code* code) {
|
||||
ASSERT(code->ic_state() == MONOMORPHIC);
|
||||
FixedArray* cache = code_cache();
|
||||
@ -2638,48 +2614,103 @@ void DescriptorArray::ReplaceConstantFunction(int descriptor_number,
|
||||
}
|
||||
|
||||
|
||||
Object* DescriptorArray::CopyInsert(Descriptor* desc,
|
||||
bool remove_map_transitions) {
|
||||
int transitions = 0;
|
||||
if (remove_map_transitions) {
|
||||
// Compute space from map transitions.
|
||||
for (DescriptorReader r(this); !r.eos(); r.advance()) {
|
||||
if (r.IsTransition()) transitions++;
|
||||
}
|
||||
}
|
||||
Object* DescriptorArray::CopyInsert(Descriptor* descriptor,
|
||||
TransitionFlag transition_flag) {
|
||||
// Transitions are only kept when inserting another transition.
|
||||
// This precondition is not required by this function's implementation, but
|
||||
// is currently required by the semantics of maps, so we check it.
|
||||
// Conversely, we filter after replacing, so replacing a transition and
|
||||
// removing all other transitions is not supported.
|
||||
bool remove_transitions = transition_flag == REMOVE_TRANSITIONS;
|
||||
ASSERT(remove_transitions == !descriptor->GetDetails().IsTransition());
|
||||
ASSERT(descriptor->GetDetails().type() != NULL_DESCRIPTOR);
|
||||
|
||||
// Ensure the key is a symbol.
|
||||
Object* result = desc->KeyToSymbol();
|
||||
Object* result = descriptor->KeyToSymbol();
|
||||
if (result->IsFailure()) return result;
|
||||
|
||||
result = Allocate(number_of_descriptors() - transitions + 1);
|
||||
if (result->IsFailure()) return result;
|
||||
int transitions = 0;
|
||||
int null_descriptors = 0;
|
||||
if (remove_transitions) {
|
||||
for (DescriptorReader r(this); !r.eos(); r.advance()) {
|
||||
if (r.IsTransition()) transitions++;
|
||||
if (r.IsNullDescriptor()) null_descriptors++;
|
||||
}
|
||||
} else {
|
||||
for (DescriptorReader r(this); !r.eos(); r.advance()) {
|
||||
if (r.IsNullDescriptor()) null_descriptors++;
|
||||
}
|
||||
}
|
||||
int new_size = number_of_descriptors() - transitions - null_descriptors;
|
||||
|
||||
// If key is in descriptor, we replace it in-place when filtering.
|
||||
int index = Search(descriptor->key());
|
||||
const bool inserting = (index == kNotFound);
|
||||
const bool replacing = !inserting;
|
||||
bool keep_enumeration_index = false;
|
||||
if (inserting) {
|
||||
++new_size;
|
||||
}
|
||||
if (replacing) {
|
||||
// We are replacing an existing descriptor. We keep the enumeration
|
||||
// index of a visible property.
|
||||
PropertyType t = PropertyDetails(GetDetails(index)).type();
|
||||
if (t == CONSTANT_FUNCTION ||
|
||||
t == FIELD ||
|
||||
t == CALLBACKS ||
|
||||
t == INTERCEPTOR) {
|
||||
keep_enumeration_index = true;
|
||||
} else if (t == NULL_DESCRIPTOR || remove_transitions) {
|
||||
// Replaced descriptor has been counted as removed if it is null
|
||||
// or a transition that will be replaced. Adjust count in this case.
|
||||
++new_size;
|
||||
}
|
||||
}
|
||||
result = Allocate(new_size);
|
||||
if (result->IsFailure()) return result;
|
||||
DescriptorArray* new_descriptors = DescriptorArray::cast(result);
|
||||
// Set the enumeration index in the descriptors and set the enumeration index
|
||||
// in the result.
|
||||
int index = NextEnumerationIndex();
|
||||
desc->SetEnumerationIndex(index);
|
||||
DescriptorArray::cast(result)->SetNextEnumerationIndex(index + 1);
|
||||
|
||||
// Write the old content and the descriptor information
|
||||
DescriptorWriter w(DescriptorArray::cast(result));
|
||||
DescriptorReader r(this);
|
||||
while (!r.eos() && r.GetKey()->Hash() <= desc->key()->Hash()) {
|
||||
if (!r.IsTransition() || !remove_map_transitions) {
|
||||
w.WriteFrom(&r);
|
||||
int enumeration_index = NextEnumerationIndex();
|
||||
if (!descriptor->GetDetails().IsTransition()) {
|
||||
if (keep_enumeration_index) {
|
||||
descriptor->SetEnumerationIndex(
|
||||
PropertyDetails(GetDetails(index)).index());
|
||||
} else {
|
||||
descriptor->SetEnumerationIndex(enumeration_index);
|
||||
++enumeration_index;
|
||||
}
|
||||
r.advance();
|
||||
}
|
||||
w.Write(desc);
|
||||
while (!r.eos()) {
|
||||
if (!r.IsTransition() || !remove_map_transitions) {
|
||||
w.WriteFrom(&r);
|
||||
}
|
||||
new_descriptors->SetNextEnumerationIndex(enumeration_index);
|
||||
|
||||
// Copy the descriptors, filtering out transitions and null descriptors,
|
||||
// and inserting or replacing a descriptor.
|
||||
DescriptorWriter w(new_descriptors);
|
||||
DescriptorReader r(this);
|
||||
uint32_t descriptor_hash = descriptor->key()->Hash();
|
||||
|
||||
for (; !r.eos(); r.advance()) {
|
||||
if (r.GetKey()->Hash() > descriptor_hash ||
|
||||
r.GetKey() == descriptor->GetKey()) break;
|
||||
if (r.IsNullDescriptor()) continue;
|
||||
if (remove_transitions && r.IsTransition()) continue;
|
||||
w.WriteFrom(&r);
|
||||
}
|
||||
w.Write(descriptor);
|
||||
if (replacing) {
|
||||
ASSERT(r.GetKey() == descriptor->GetKey());
|
||||
r.advance();
|
||||
} else {
|
||||
ASSERT(r.eos() || r.GetKey()->Hash() > descriptor_hash);
|
||||
}
|
||||
for (; !r.eos(); r.advance()) {
|
||||
if (r.IsNullDescriptor()) continue;
|
||||
if (remove_transitions && r.IsTransition()) continue;
|
||||
w.WriteFrom(&r);
|
||||
}
|
||||
ASSERT(w.eos());
|
||||
|
||||
return result;
|
||||
return new_descriptors;
|
||||
}
|
||||
|
||||
|
||||
@ -2746,6 +2777,32 @@ Object* DescriptorArray::CopyRemove(String* name) {
|
||||
}
|
||||
|
||||
|
||||
Object* DescriptorArray::RemoveTransitions() {
|
||||
// Remove all transitions. Return a copy of the array with all transitions
|
||||
// removed, or a Failure object if the new array could not be allocated.
|
||||
|
||||
// Compute the size of the map transition entries to be removed.
|
||||
int count_transitions = 0;
|
||||
for (DescriptorReader r(this); !r.eos(); r.advance()) {
|
||||
if (r.IsTransition()) count_transitions++;
|
||||
}
|
||||
|
||||
// Allocate the new descriptor array.
|
||||
Object* result = Allocate(number_of_descriptors() - count_transitions);
|
||||
if (result->IsFailure()) return result;
|
||||
DescriptorArray* new_descriptors = DescriptorArray::cast(result);
|
||||
|
||||
// Copy the content.
|
||||
DescriptorWriter w(new_descriptors);
|
||||
for (DescriptorReader r(this); !r.eos(); r.advance()) {
|
||||
if (!r.IsTransition()) w.WriteFrom(&r);
|
||||
}
|
||||
ASSERT(w.eos());
|
||||
|
||||
return new_descriptors;
|
||||
}
|
||||
|
||||
|
||||
void DescriptorArray::Sort() {
|
||||
// In-place heap sort.
|
||||
int len = number_of_descriptors();
|
||||
@ -3802,14 +3859,11 @@ Object* JSFunction::SetPrototype(Object* value) {
|
||||
// See ECMA-262 13.2.2.
|
||||
if (!value->IsJSObject()) {
|
||||
// Copy the map so this does not affect unrelated functions.
|
||||
// Remove map transitions so we do not lose the prototype
|
||||
// information on map transitions.
|
||||
Object* copy = map()->Copy();
|
||||
if (copy->IsFailure()) return copy;
|
||||
Object* new_map = Map::cast(copy)->EnsureNoMapTransitions();
|
||||
// Remove map transitions because they point to maps with a
|
||||
// different prototype.
|
||||
Object* new_map = map()->CopyDropTransitions();
|
||||
if (new_map->IsFailure()) return new_map;
|
||||
set_map(Map::cast(new_map));
|
||||
|
||||
map()->set_constructor(value);
|
||||
map()->set_non_instance_prototype(true);
|
||||
construct_prototype =
|
||||
|
@ -1555,8 +1555,18 @@ class DescriptorArray: public FixedArray {
|
||||
void ReplaceConstantFunction(int descriptor_number, JSFunction* value);
|
||||
|
||||
// Copy the descriptor array, insert a new descriptor and optionally
|
||||
// remove map transitions.
|
||||
Object* CopyInsert(Descriptor* desc, bool remove_map_transitions = false);
|
||||
// remove map transitions. If the descriptor is already present, it is
|
||||
// replaced. If a replaced descriptor is a real property (not a transition
|
||||
// or null), its enumeration index is kept as is.
|
||||
// If adding a real property, map transitions must be removed. If adding
|
||||
// a transition, they must not be removed. All null descriptors are removed.
|
||||
Object* CopyInsert(Descriptor* descriptor, TransitionFlag transition_flag);
|
||||
|
||||
// Makes a copy of the descriptor array with the descriptor with key name
|
||||
// removed. If name is the empty string, the descriptor array is copied.
|
||||
// Transitions are removed if TransitionFlag is REMOVE_TRANSITIONS.
|
||||
// All null descriptors are removed.
|
||||
Object* CopyRemove(TransitionFlag remove_transitions, String* name);
|
||||
|
||||
// Copy the descriptor array, replace the property index and attributes
|
||||
// of the named property, but preserve its enumeration index.
|
||||
@ -1566,6 +1576,10 @@ class DescriptorArray: public FixedArray {
|
||||
// of the named property.
|
||||
Object* CopyRemove(String* name);
|
||||
|
||||
// Remove all transitions. Return a copy of the array with all transitions
|
||||
// removed, or a Failure object if the new array could not be allocated.
|
||||
Object* RemoveTransitions();
|
||||
|
||||
// Sort the instance descriptors by the hash codes of their keys.
|
||||
void Sort();
|
||||
|
||||
@ -2288,6 +2302,10 @@ class Map: public HeapObject {
|
||||
// Returns a copy of the map.
|
||||
Object* Copy();
|
||||
|
||||
// Returns a copy of the map, with all transitions dropped from the
|
||||
// instance descriptors.
|
||||
Object* CopyDropTransitions();
|
||||
|
||||
// Returns the property index for name (only valid for FAST MODE).
|
||||
int PropertyIndexFor(String* name);
|
||||
|
||||
@ -2303,9 +2321,6 @@ class Map: public HeapObject {
|
||||
// Locate an accessor in the instance descriptor.
|
||||
AccessorDescriptor* FindAccessor(String* name);
|
||||
|
||||
// Make sure the instance descriptor has no map transitions
|
||||
Object* EnsureNoMapTransitions();
|
||||
|
||||
// Code cache operations.
|
||||
|
||||
// Clears the code cache.
|
||||
|
@ -370,10 +370,6 @@ class DescriptorReader: public DescriptorStream {
|
||||
|
||||
bool Equals(String* name) { return name->Equals(GetKey()); }
|
||||
|
||||
void ReplaceConstantFunction(JSFunction* value) {
|
||||
descriptors_->ReplaceConstantFunction(pos_, value);
|
||||
}
|
||||
|
||||
void Get(Descriptor* desc) {
|
||||
descriptors_->Get(pos_, desc);
|
||||
}
|
||||
|
@ -3262,30 +3262,6 @@ static Object* Runtime_NumberIsFinite(Arguments args) {
|
||||
}
|
||||
|
||||
|
||||
static Object* Runtime_NumberMaxValue(Arguments args) {
|
||||
NoHandleAllocation ha;
|
||||
ASSERT(args.length() == 0);
|
||||
|
||||
return Heap::number_max_value();
|
||||
}
|
||||
|
||||
|
||||
static Object* Runtime_NumberMinValue(Arguments args) {
|
||||
NoHandleAllocation ha;
|
||||
ASSERT(args.length() == 0);
|
||||
|
||||
return Heap::number_min_value();
|
||||
}
|
||||
|
||||
|
||||
static Object* Runtime_NumberNaN(Arguments args) {
|
||||
NoHandleAllocation ha;
|
||||
ASSERT(args.length() == 0);
|
||||
|
||||
return Heap::nan_value();
|
||||
}
|
||||
|
||||
|
||||
static Object* EvalContext() {
|
||||
// The topmost JS frame belongs to the eval function which called
|
||||
// the CompileString runtime function. We need to unwind one level
|
||||
|
@ -175,9 +175,6 @@ namespace v8 { namespace internal {
|
||||
\
|
||||
/* Numbers */ \
|
||||
F(NumberIsFinite, 1) \
|
||||
F(NumberMaxValue, 0) \
|
||||
F(NumberMinValue, 0) \
|
||||
F(NumberNaN, 0) \
|
||||
\
|
||||
/* Globals */ \
|
||||
F(CompileString, 2) \
|
||||
|
@ -47,7 +47,7 @@ const $String = global.String;
|
||||
const $Number = global.Number;
|
||||
const $Function = global.Function;
|
||||
const $Boolean = global.Boolean;
|
||||
const $NaN = %NumberNaN();
|
||||
const $NaN = 0/0;
|
||||
|
||||
|
||||
// ECMA-262, section 11.9.1, page 55.
|
||||
@ -403,7 +403,7 @@ function ToNumber(x) {
|
||||
if (IS_NUMBER(x)) return x;
|
||||
if (IS_STRING(x)) return %StringToNumber(x);
|
||||
if (IS_BOOLEAN(x)) return x ? 1 : 0;
|
||||
if (IS_UNDEFINED(x)) return %NumberNaN();
|
||||
if (IS_UNDEFINED(x)) return $NaN;
|
||||
return (IS_NULL(x)) ? 0 : ToNumber(%DefaultNumber(x));
|
||||
};
|
||||
|
||||
|
@ -29,6 +29,7 @@
|
||||
// This file relies on the fact that the following declaration has been made
|
||||
// in runtime.js:
|
||||
// const $String = global.String;
|
||||
// const $NaN = 0/0;
|
||||
|
||||
|
||||
// Set the String function and constructor.
|
||||
@ -349,7 +350,7 @@ function ApplyReplacementFunction(replace, captures, subject) {
|
||||
var pat = ToString(searchString);
|
||||
var index = (%_ArgumentsLength() > 1)
|
||||
? ToNumber(%_Arguments(1) /* position */)
|
||||
: %NumberNaN();
|
||||
: $NaN;
|
||||
var firstIndex;
|
||||
if ($isNaN(index)) {
|
||||
firstIndex = sub.length - pat.length;
|
||||
|
@ -33,7 +33,7 @@
|
||||
// const $Number = global.Number;
|
||||
// const $Function = global.Function;
|
||||
// const $Array = global.Array;
|
||||
// const $NaN = %NumberNaN();
|
||||
// const $NaN = 0/0;
|
||||
|
||||
|
||||
// ECMA 262 - 15.1.1.1.
|
||||
@ -258,10 +258,10 @@ $Object.prototype.constructor = $Object;
|
||||
%AddProperty($Number.prototype, "constructor", $Number, DONT_ENUM);
|
||||
|
||||
// ECMA-262 section 15.7.3.1.
|
||||
%AddProperty($Number, "MAX_VALUE", %NumberMaxValue(), DONT_ENUM | DONT_DELETE | READ_ONLY);
|
||||
%AddProperty($Number, "MAX_VALUE", 1.7976931348623157e+308, DONT_ENUM | DONT_DELETE | READ_ONLY);
|
||||
|
||||
// ECMA-262 section 15.7.3.2.
|
||||
%AddProperty($Number, "MIN_VALUE", %NumberMinValue(), DONT_ENUM | DONT_DELETE | READ_ONLY);
|
||||
%AddProperty($Number, "MIN_VALUE", 5e-324, DONT_ENUM | DONT_DELETE | READ_ONLY);
|
||||
|
||||
// ECMA-262 section 15.7.3.3.
|
||||
%AddProperty($Number, "NaN", $NaN, DONT_ENUM | DONT_DELETE | READ_ONLY);
|
||||
|
@ -140,10 +140,6 @@ TEST(HeapObjects) {
|
||||
CHECK(Heap::nan_value()->IsNumber());
|
||||
CHECK(isnan(Heap::nan_value()->Number()));
|
||||
|
||||
// infinit oddball checks
|
||||
CHECK(Heap::infinity_value()->IsNumber());
|
||||
CHECK(!isfinite(Heap::infinity_value()->Number()));
|
||||
|
||||
Object* str = Heap::AllocateStringFromAscii(CStrVector("fisk hest "));
|
||||
if (!str->IsFailure()) {
|
||||
String* s = String::cast(str);
|
||||
|
43
test/mjsunit/number-limits.js
Normal file
43
test/mjsunit/number-limits.js
Normal file
@ -0,0 +1,43 @@
|
||||
// Copyright 2008 Google Inc. All Rights Reserved.
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following
|
||||
// disclaimer in the documentation and/or other materials provided
|
||||
// with the distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Ensure that Number.MAX_VALUE and Number.MIN_VALUE are extreme.
|
||||
function testLimits() {
|
||||
var i; var eps;
|
||||
for (i = 0, eps = 1; i < 1100; i++, eps /= 2) {
|
||||
var mulAboveMax = Number.MAX_VALUE * (1 + eps);
|
||||
var addAboveMax = Number.MAX_VALUE + 1/eps;
|
||||
var mulBelowMin = Number.MIN_VALUE * (1 - eps);
|
||||
var addBelowMin = Number.MIN_VALUE - eps;
|
||||
assertTrue(mulAboveMax == Number.MAX_VALUE || mulAboveMax == Infinity);
|
||||
assertTrue(addAboveMax == Number.MAX_VALUE || addAboveMax == Infinity);
|
||||
assertTrue(mulBelowMin == Number.MIN_VALUE || mulBelowMin <= 0);
|
||||
assertTrue(addBelowMin == Number.MIN_VALUE || addBelowMin <= 0);
|
||||
}
|
||||
}
|
||||
|
||||
testLimits();
|
@ -26,9 +26,9 @@
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
|
||||
import test
|
||||
import os
|
||||
from os.path import join, exists
|
||||
import test
|
||||
|
||||
|
||||
EXCLUDED = ['CVS']
|
||||
|
@ -70,6 +70,7 @@ class ProgressIndicator(object):
|
||||
self.remaining -= 1
|
||||
self.HasRun(output)
|
||||
self.Done()
|
||||
return self.failed == 0
|
||||
|
||||
|
||||
def EscapeCommand(command):
|
||||
@ -366,7 +367,7 @@ class TestRepository(TestSuite):
|
||||
|
||||
def __init__(self, path):
|
||||
super(TestRepository, self).__init__(basename(path))
|
||||
self.path = path
|
||||
self.path = abspath(path)
|
||||
self.is_loaded = False
|
||||
self.config = None
|
||||
|
||||
@ -440,7 +441,7 @@ def RunTestCases(all_cases, progress):
|
||||
return SKIP in c.outcomes or SLOW in c.outcomes
|
||||
cases_to_run = [ c for c in all_cases if not DoSkip(c) ]
|
||||
progress = PROGRESS_INDICATORS[progress](cases_to_run)
|
||||
progress.Run()
|
||||
return progress.Run()
|
||||
|
||||
|
||||
def BuildRequirements(context, requirements, mode):
|
||||
@ -1018,15 +1019,17 @@ def Main():
|
||||
|
||||
if len(all_cases) == 0:
|
||||
print "No tests to run."
|
||||
return 0
|
||||
else:
|
||||
try:
|
||||
RunTestCases(all_cases, options.progress)
|
||||
if RunTestCases(all_cases, options.progress):
|
||||
return 0
|
||||
else:
|
||||
return 1
|
||||
except KeyboardInterrupt:
|
||||
print "Interrupted"
|
||||
return 1
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(Main())
|
||||
|
Loading…
Reference in New Issue
Block a user