'gcc': {
'all': {
'LIBPATH': [abspath('.')]
- }
+ },
+ 'wordsize:64': {
+ 'CCFLAGS': ['-m32'],
+ 'LINKFLAGS': ['-m32']
+ },
},
'msvc': {
'all': {
'LIBS': ['pthread'],
'LIBPATH': ['.']
},
+ 'wordsize:64': {
+ 'CCFLAGS': ['-m32'],
+ 'LINKFLAGS': ['-m32']
+ },
},
'msvc': {
'all': {
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);
}
// 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;
}
V(ScriptType) \
V(ObjectPrototype)
-// Accessors contains all prodefined proxy accessors.
+// Accessors contains all predefined proxy accessors.
class Accessors : public AllStatic {
public:
// 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);
}
// 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);
}
}
+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);
}
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");
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.
};
+// 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;
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);
}
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;
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) \
// 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
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);
}
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);
}
// 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.
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.
}
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();
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()) {
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());
}
+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();
}
-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;
}
}
+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();
// 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 =
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.
// 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();
// 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);
// 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.
bool Equals(String* name) { return name->Equals(GetKey()); }
- void ReplaceConstantFunction(JSFunction* value) {
- descriptors_->ReplaceConstantFunction(pos_, value);
- }
-
void Get(Descriptor* desc) {
descriptors_->Get(pos_, desc);
}
}
-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
\
/* Numbers */ \
F(NumberIsFinite, 1) \
- F(NumberMaxValue, 0) \
- F(NumberMinValue, 0) \
- F(NumberNaN, 0) \
\
/* Globals */ \
F(CompileString, 2) \
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.
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));
};
// 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.
var pat = ToString(searchString);
var index = (%_ArgumentsLength() > 1)
? ToNumber(%_Arguments(1) /* position */)
- : %NumberNaN();
+ : $NaN;
var firstIndex;
if ($isNaN(index)) {
firstIndex = sub.length - pat.length;
// 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.
%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);
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);
--- /dev/null
+// 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();
# 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']
self.remaining -= 1
self.HasRun(output)
self.Done()
+ return self.failed == 0
def EscapeCommand(command):
def __init__(self, path):
super(TestRepository, self).__init__(basename(path))
- self.path = path
+ self.path = abspath(path)
self.is_loaded = False
self.config = None
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):
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())