- Fixed issue when building samples and cctests on 64-bit machines.
authorchristian.plesner.hansen <christian.plesner.hansen@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 27 Aug 2008 13:47:52 +0000 (13:47 +0000)
committerchristian.plesner.hansen <christian.plesner.hansen@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 27 Aug 2008 13:47:52 +0000 (13:47 +0000)
- 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

22 files changed:
SConstruct
src/accessors.cc
src/accessors.h
src/bootstrapper.cc
src/factory.cc
src/factory.h
src/globals.h
src/handles.cc
src/heap.cc
src/heap.h
src/objects.cc
src/objects.h
src/property.h
src/runtime.cc
src/runtime.h
src/runtime.js
src/string.js
src/v8natives.js
test/cctest/test-heap.cc
test/mjsunit/number-limits.js [new file with mode: 0644]
test/mozilla/testcfg.py
tools/test.py

index 199afc4de59a4738eddc38f27868daa1795f59e7..d827852bbf2261acc3b18aeb5b5ee61a8047117f 100644 (file)
@@ -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': {
index 8c5bf89678efa22baffbcfd73cd48bd0b07a9c61..7c16dad6c45d725007e42fdcd8a66a65fdfbb153 100644 (file)
@@ -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;
 }
 
index d81a0bdc0064541b5ef47fc7cf252d412c34f3e0..da1a03750f9ee25bb31b103258e7439070a80060 100644 (file)
@@ -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:
index 0cb688eb8a7d89ea68f3431aa7f2db519cb8896b..5e5e3d8c06cc7cd390c703dfaa1f99cb0ac25170 100644 (file)
@@ -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);
 }
index 78c56cae91a3f9bcc61398569b0b499954d84ce9..8016965010083c7ce5b33b200d32664db9d61f85 100644 (file)
@@ -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");
index 432f9ca0721e9ad51a2ae820c923d89ee0addf5d..a0cd93660a91bd940574d5034a076625004bd792 100644 (file)
@@ -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.
index 5f7d557fc42c4173640ac42e2f7ee466facc4045..5bccfa79c065d67b527ab6089183c319951f6564 100644 (file)
@@ -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;
index 027b1f63433a8c7420d3d0b6f7aa8e8765566d21..b7b5380c47603450badca8e98c657ee11155d432 100644 (file)
@@ -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);
   }
index d81c6129ab99c524dd5c0d61a33045d2676d398f..b04b4c1c40a510702bef4d82bebdabedfd94db53 100644 (file)
@@ -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;
index 24d08f59b0726bb5c45b3dc377837501b0b4182f..a40780cc580849854c2212d8c03f396aeb12ffe7 100644 (file)
@@ -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)                                 \
index a1624a5c868bfb72a26f2f6e08e0e705e87f8caf..29d3144cbd59fa381ad20ea18bfc33deade34fcf 100644 (file)
@@ -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;
-
-    // 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();
+    Object* new_map =
+      map()->CopyDropTransitions();
     if (new_map->IsFailure()) return new_map;
-
-    Map::cast(new_map)->
-      set_instance_descriptors(DescriptorArray::cast(new_descriptors));
     set_map(Map::cast(new_map));
+
+    // Replace the function entry
+    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);
+  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);
+  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;
+    }
+  }
+  new_descriptors->SetNextEnumerationIndex(enumeration_index);
 
-  // Write the old content and the descriptor information
-  DescriptorWriter w(DescriptorArray::cast(result));
+  // Copy the descriptors, filtering out transitions and null descriptors,
+  // and inserting or replacing a descriptor.
+  DescriptorWriter w(new_descriptors);
   DescriptorReader r(this);
-  while (!r.eos() && r.GetKey()->Hash() <= desc->key()->Hash()) {
-    if (!r.IsTransition() || !remove_map_transitions) {
-      w.WriteFrom(&r);
-    }
+  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);
   }
-  w.Write(desc);
-  while (!r.eos()) {
-    if (!r.IsTransition() || !remove_map_transitions) {
-      w.WriteFrom(&r);
-    }
-    r.advance();
+  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 =
index e61a4f9ea10da82d03c71b786feb86da09eb8498..82c6faff2ed4fd8879136b1aa6c35635c267009c 100644 (file)
@@ -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.
index 5fd2323cc5c65897790c261c953a729f79e55c4c..02e255cfe45a0b2db187ccac1c9578b13a1f6a69 100644 (file)
@@ -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);
   }
index b4a8b3b304d43db7cf15824402987157bde45909..263d86e2a8b9dd197ec10efc955831243622653e 100644 (file)
@@ -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
index 9c0ec60bf68742e53c51348935a4ec880252cc66..3353b5e8778721e2c677c72555418c14ab4bfee1 100644 (file)
@@ -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) \
index 936d192c4892de394b6357e9059e60d7144de2f8..aa624a764da62153bbf0f9ed521221b596fd13c6 100644 (file)
@@ -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));
 };
 
index 59025954823e702ff56d17978d495472e115aa62..7e5cf6e3d38b41e73501950617360cf0ae7e65dd 100644 (file)
@@ -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;
index d97345efe9ef63787e0b7ff82a9a8af3797cb49c..5ead3adc46811694c2c6f3c9e611e2e5b4a9c2ed 100644 (file)
@@ -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);
index ba9ecaede99eb1aeb1ae40f5ba7ef7efe1bf4034..269e3e9b30f22e9e604099c2edb895354572a701 100644 (file)
@@ -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);
diff --git a/test/mjsunit/number-limits.js b/test/mjsunit/number-limits.js
new file mode 100644 (file)
index 0000000..7b9d0c8
--- /dev/null
@@ -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();
index a43ee0c412c62de6c6c6e70875861d8b1d1d9f39..ea638b83da6a3f24310534aad307d6a273ebb225 100644 (file)
@@ -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']
index 43d780432c735bbfb9809321f79a4ba06934e305..ed64dade21439c75e3cd7fcbbc887593d8819c8f 100644 (file)
@@ -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())