diff options
Diffstat (limited to 'V8Binding/v8/src/objects.cc')
-rw-r--r-- | V8Binding/v8/src/objects.cc | 1023 |
1 files changed, 590 insertions, 433 deletions
diff --git a/V8Binding/v8/src/objects.cc b/V8Binding/v8/src/objects.cc index 72412c1..c3051b8 100644 --- a/V8Binding/v8/src/objects.cc +++ b/V8Binding/v8/src/objects.cc @@ -50,24 +50,6 @@ namespace internal { const int kGetterIndex = 0; const int kSetterIndex = 1; -bool Object::IsInstanceOf(FunctionTemplateInfo* expected) { - // There is a constraint on the object; check - if (!this->IsJSObject()) return false; - // Fetch the constructor function of the object - Object* cons_obj = JSObject::cast(this)->map()->constructor(); - if (!cons_obj->IsJSFunction()) return false; - JSFunction* fun = JSFunction::cast(cons_obj); - // Iterate through the chain of inheriting function templates to - // see if the required one occurs. - for (Object* type = fun->shared()->function_data(); - type->IsFunctionTemplateInfo(); - type = FunctionTemplateInfo::cast(type)->parent_template()) { - if (type == expected) return true; - } - // Didn't find the required type in the inheritance chain. - return false; -} - static Object* CreateJSValue(JSFunction* constructor, Object* value) { Object* result = Heap::AllocateJSObject(constructor); @@ -1006,6 +988,9 @@ void HeapObject::HeapObjectShortPrint(StringStream* accumulator) { case BYTE_ARRAY_TYPE: accumulator->Add("<ByteArray[%u]>", ByteArray::cast(this)->length()); break; + case PIXEL_ARRAY_TYPE: + accumulator->Add("<PixelArray[%u]>", PixelArray::cast(this)->length()); + break; case SHARED_FUNCTION_INFO_TYPE: accumulator->Add("<SharedFunctionInfo>"); break; @@ -1147,6 +1132,7 @@ void HeapObject::IterateBody(InstanceType type, int object_size, case HEAP_NUMBER_TYPE: case FILLER_TYPE: case BYTE_ARRAY_TYPE: + case PIXEL_ARRAY_TYPE: break; case SHARED_FUNCTION_INFO_TYPE: { SharedFunctionInfo* shared = reinterpret_cast<SharedFunctionInfo*>(this); @@ -1240,7 +1226,7 @@ Object* JSObject::AddFastProperty(String* name, // hidden symbols) and is not a real identifier. StringInputBuffer buffer(name); if (!Scanner::IsIdentifier(&buffer) && name != Heap::hidden_symbol()) { - Object* obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES); + Object* obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); if (obj->IsFailure()) return obj; return AddSlowProperty(name, value, attributes); } @@ -1278,7 +1264,7 @@ Object* JSObject::AddFastProperty(String* name, if (map()->unused_property_fields() == 0) { if (properties()->length() > kMaxFastProperties) { - Object* obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES); + Object* obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); if (obj->IsFailure()) return obj; return AddSlowProperty(name, value, attributes); } @@ -1399,7 +1385,7 @@ Object* JSObject::AddProperty(String* name, } else { // Normalize the object to prevent very large instance descriptors. // This eliminates unwanted N^2 allocation and lookup behavior. - Object* obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES); + Object* obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); if (obj->IsFailure()) return obj; } } @@ -1469,7 +1455,7 @@ Object* JSObject::ConvertDescriptorToField(String* name, PropertyAttributes attributes) { if (map()->unused_property_fields() == 0 && properties()->length() > kMaxFastProperties) { - Object* obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES); + Object* obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); if (obj->IsFailure()) return obj; return ReplaceSlowProperty(name, new_value, attributes); } @@ -1669,7 +1655,9 @@ Object* JSObject::LookupCallbackSetterInPrototypes(uint32_t index) { for (Object* pt = GetPrototype(); pt != Heap::null_value(); pt = pt->GetPrototype()) { - if (JSObject::cast(pt)->HasFastElements()) continue; + if (!JSObject::cast(pt)->HasDictionaryElements()) { + continue; + } NumberDictionary* dictionary = JSObject::cast(pt)->element_dictionary(); int entry = dictionary->FindEntry(index); if (entry != NumberDictionary::kNotFound) { @@ -2118,12 +2106,22 @@ PropertyAttributes JSObject::GetLocalPropertyAttribute(String* name) { } -Object* JSObject::NormalizeProperties(PropertyNormalizationMode mode) { +Object* JSObject::NormalizeProperties(PropertyNormalizationMode mode, + int expected_additional_properties) { if (!HasFastProperties()) return this; - // Allocate new content + // The global object is always normalized. + ASSERT(!IsGlobalObject()); + + // Allocate new content. + int property_count = map()->NumberOfDescribedProperties(); + if (expected_additional_properties > 0) { + property_count += expected_additional_properties; + } else { + property_count += 2; // Make space for two more properties. + } Object* obj = - StringDictionary::Allocate(map()->NumberOfDescribedProperties() * 2 + 4); + StringDictionary::Allocate(property_count * 2); if (obj->IsFailure()) return obj; StringDictionary* dictionary = StringDictionary::cast(obj); @@ -2135,10 +2133,6 @@ Object* JSObject::NormalizeProperties(PropertyNormalizationMode mode) { PropertyDetails d = PropertyDetails(details.attributes(), NORMAL, details.index()); Object* value = descs->GetConstantFunction(i); - if (IsGlobalObject()) { - value = Heap::AllocateJSGlobalPropertyCell(value); - if (value->IsFailure()) return value; - } Object* result = dictionary->Add(descs->GetKey(i), value, d); if (result->IsFailure()) return result; dictionary = StringDictionary::cast(result); @@ -2148,10 +2142,6 @@ Object* JSObject::NormalizeProperties(PropertyNormalizationMode mode) { PropertyDetails d = PropertyDetails(details.attributes(), NORMAL, details.index()); Object* value = FastPropertyAt(descs->GetFieldIndex(i)); - if (IsGlobalObject()) { - value = Heap::AllocateJSGlobalPropertyCell(value); - if (value->IsFailure()) return value; - } Object* result = dictionary->Add(descs->GetKey(i), value, d); if (result->IsFailure()) return result; dictionary = StringDictionary::cast(result); @@ -2161,10 +2151,6 @@ Object* JSObject::NormalizeProperties(PropertyNormalizationMode mode) { PropertyDetails d = PropertyDetails(details.attributes(), CALLBACKS, details.index()); Object* value = descs->GetCallbacksObject(i); - if (IsGlobalObject()) { - value = Heap::AllocateJSGlobalPropertyCell(value); - if (value->IsFailure()) return value; - } Object* result = dictionary->Add(descs->GetKey(i), value, d); if (result->IsFailure()) return result; dictionary = StringDictionary::cast(result); @@ -2176,9 +2162,7 @@ Object* JSObject::NormalizeProperties(PropertyNormalizationMode mode) { case INTERCEPTOR: break; default: - case NORMAL: UNREACHABLE(); - break; } } @@ -2231,7 +2215,8 @@ Object* JSObject::TransformToFastProperties(int unused_property_fields) { Object* JSObject::NormalizeElements() { - if (!HasFastElements()) return this; + ASSERT(!HasPixelElements()); + if (HasDictionaryElements()) return this; // Get number of entries. FixedArray* array = FixedArray::cast(elements()); @@ -2276,7 +2261,7 @@ Object* JSObject::DeletePropertyPostInterceptor(String* name, DeleteMode mode) { if (!result.IsValid()) return Heap::true_value(); // Normalize object if needed. - Object* obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES); + Object* obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); if (obj->IsFailure()) return obj; return DeleteNormalizedProperty(name, mode); @@ -2317,20 +2302,28 @@ Object* JSObject::DeletePropertyWithInterceptor(String* name) { Object* JSObject::DeleteElementPostInterceptor(uint32_t index, DeleteMode mode) { - if (HasFastElements()) { - uint32_t length = IsJSArray() ? + ASSERT(!HasPixelElements()); + switch (GetElementsKind()) { + case FAST_ELEMENTS: { + uint32_t length = IsJSArray() ? static_cast<uint32_t>(Smi::cast(JSArray::cast(this)->length())->value()) : static_cast<uint32_t>(FixedArray::cast(elements())->length()); - if (index < length) { - FixedArray::cast(elements())->set_the_hole(index); + if (index < length) { + FixedArray::cast(elements())->set_the_hole(index); + } + break; } - return Heap::true_value(); - } - ASSERT(!HasFastElements()); - NumberDictionary* dictionary = element_dictionary(); - int entry = dictionary->FindEntry(index); - if (entry != NumberDictionary::kNotFound) { - return dictionary->DeleteProperty(entry, mode); + case DICTIONARY_ELEMENTS: { + NumberDictionary* dictionary = element_dictionary(); + int entry = dictionary->FindEntry(index); + if (entry != NumberDictionary::kNotFound) { + return dictionary->DeleteProperty(entry, mode); + } + break; + } + default: + UNREACHABLE(); + break; } return Heap::true_value(); } @@ -2392,20 +2385,31 @@ Object* JSObject::DeleteElement(uint32_t index, DeleteMode mode) { return DeleteElementWithInterceptor(index); } - if (HasFastElements()) { - uint32_t length = IsJSArray() ? + switch (GetElementsKind()) { + case FAST_ELEMENTS: { + uint32_t length = IsJSArray() ? static_cast<uint32_t>(Smi::cast(JSArray::cast(this)->length())->value()) : static_cast<uint32_t>(FixedArray::cast(elements())->length()); - if (index < length) { - FixedArray::cast(elements())->set_the_hole(index); + if (index < length) { + FixedArray::cast(elements())->set_the_hole(index); + } + break; } - return Heap::true_value(); - } else { - NumberDictionary* dictionary = element_dictionary(); - int entry = dictionary->FindEntry(index); - if (entry != NumberDictionary::kNotFound) { - return dictionary->DeleteProperty(entry, mode); + case PIXEL_ELEMENTS: { + // Pixel elements cannot be deleted. Just silently ignore here. + break; } + case DICTIONARY_ELEMENTS: { + NumberDictionary* dictionary = element_dictionary(); + int entry = dictionary->FindEntry(index); + if (entry != NumberDictionary::kNotFound) { + return dictionary->DeleteProperty(entry, mode); + } + break; + } + default: + UNREACHABLE(); + break; } return Heap::true_value(); } @@ -2454,7 +2458,7 @@ Object* JSObject::DeleteProperty(String* name, DeleteMode mode) { mode); } // Normalize object if needed. - Object* obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES); + Object* obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); if (obj->IsFailure()) return obj; // Make sure the properties are normalized before removing the entry. return DeleteNormalizedProperty(name, mode); @@ -2483,21 +2487,32 @@ bool JSObject::ReferencesObject(Object* obj) { } // Check if the object is among the indexed properties. - if (HasFastElements()) { - int length = IsJSArray() - ? Smi::cast(JSArray::cast(this)->length())->value() - : FixedArray::cast(elements())->length(); - for (int i = 0; i < length; i++) { - Object* element = FixedArray::cast(elements())->get(i); - if (!element->IsTheHole() && element == obj) { - return true; + switch (GetElementsKind()) { + case PIXEL_ELEMENTS: + // Raw pixels do not reference other objects. + break; + case FAST_ELEMENTS: { + int length = IsJSArray() ? + Smi::cast(JSArray::cast(this)->length())->value() : + FixedArray::cast(elements())->length(); + for (int i = 0; i < length; i++) { + Object* element = FixedArray::cast(elements())->get(i); + if (!element->IsTheHole() && element == obj) { + return true; + } } + break; } - } else { - key = element_dictionary()->SlowReverseLookup(obj); - if (key != Heap::undefined_value()) { - return true; + case DICTIONARY_ELEMENTS: { + key = element_dictionary()->SlowReverseLookup(obj); + if (key != Heap::undefined_value()) { + return true; + } + break; } + default: + UNREACHABLE(); + break; } // For functions check the context. Boilerplate functions do @@ -2715,20 +2730,31 @@ Object* JSObject::DefineGetterSetter(String* name, if (is_element && IsJSArray()) return Heap::undefined_value(); if (is_element) { - // Lookup the index. - if (!HasFastElements()) { - NumberDictionary* dictionary = element_dictionary(); - int entry = dictionary->FindEntry(index); - if (entry != NumberDictionary::kNotFound) { - Object* result = dictionary->ValueAt(entry); - PropertyDetails details = dictionary->DetailsAt(entry); - if (details.IsReadOnly()) return Heap::undefined_value(); - if (details.type() == CALLBACKS) { - // Only accessors allowed as elements. - ASSERT(result->IsFixedArray()); - return result; + switch (GetElementsKind()) { + case FAST_ELEMENTS: + break; + case PIXEL_ELEMENTS: + // Ignore getters and setters on pixel elements. + return Heap::undefined_value(); + case DICTIONARY_ELEMENTS: { + // Lookup the index. + NumberDictionary* dictionary = element_dictionary(); + int entry = dictionary->FindEntry(index); + if (entry != NumberDictionary::kNotFound) { + Object* result = dictionary->ValueAt(entry); + PropertyDetails details = dictionary->DetailsAt(entry); + if (details.IsReadOnly()) return Heap::undefined_value(); + if (details.type() == CALLBACKS) { + // Only accessors allowed as elements. + ASSERT(result->IsFixedArray()); + return result; + } } + break; } + default: + UNREACHABLE(); + break; } } else { // Lookup the name. @@ -2765,7 +2791,7 @@ Object* JSObject::DefineGetterSetter(String* name, set_elements(NumberDictionary::cast(dict)); } else { // Normalize object to make this operation simple. - Object* ok = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES); + Object* ok = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); if (ok->IsFailure()) return ok; // For the global object allocate a new map to invalidate the global inline @@ -2827,9 +2853,9 @@ Object* JSObject::LookupAccessor(String* name, bool is_getter) { for (Object* obj = this; obj != Heap::null_value(); obj = JSObject::cast(obj)->GetPrototype()) { - JSObject* jsObject = JSObject::cast(obj); - if (!jsObject->HasFastElements()) { - NumberDictionary* dictionary = jsObject->element_dictionary(); + JSObject* js_object = JSObject::cast(obj); + if (js_object->HasDictionaryElements()) { + NumberDictionary* dictionary = js_object->element_dictionary(); int entry = dictionary->FindEntry(index); if (entry != NumberDictionary::kNotFound) { Object* element = dictionary->ValueAt(entry); @@ -3029,28 +3055,35 @@ static bool HasKey(FixedArray* array, Object* key) { Object* FixedArray::AddKeysFromJSArray(JSArray* array) { - if (array->HasFastElements()) { - return UnionOfKeys(array->elements()); - } - ASSERT(!array->HasFastElements()); - NumberDictionary* dict = array->element_dictionary(); - int size = dict->NumberOfElements(); - - // Allocate a temporary fixed array. - Object* object = Heap::AllocateFixedArray(size); - if (object->IsFailure()) return object; - FixedArray* key_array = FixedArray::cast(object); - - int capacity = dict->Capacity(); - int pos = 0; - // Copy the elements from the JSArray to the temporary fixed array. - for (int i = 0; i < capacity; i++) { - if (dict->IsKey(dict->KeyAt(i))) { - key_array->set(pos++, dict->ValueAt(i)); + ASSERT(!array->HasPixelElements()); + switch (array->GetElementsKind()) { + case JSObject::FAST_ELEMENTS: + return UnionOfKeys(FixedArray::cast(array->elements())); + case JSObject::DICTIONARY_ELEMENTS: { + NumberDictionary* dict = array->element_dictionary(); + int size = dict->NumberOfElements(); + + // Allocate a temporary fixed array. + Object* object = Heap::AllocateFixedArray(size); + if (object->IsFailure()) return object; + FixedArray* key_array = FixedArray::cast(object); + + int capacity = dict->Capacity(); + int pos = 0; + // Copy the elements from the JSArray to the temporary fixed array. + for (int i = 0; i < capacity; i++) { + if (dict->IsKey(dict->KeyAt(i))) { + key_array->set(pos++, dict->ValueAt(i)); + } + } + // Compute the union of this and the temporary fixed array. + return UnionOfKeys(key_array); } + default: + UNREACHABLE(); } - // Compute the union of this and the temporary fixed array. - return UnionOfKeys(key_array); + UNREACHABLE(); + return Heap::null_value(); // Failure case needs to "return" a value. } @@ -5089,54 +5122,74 @@ void Code::Disassemble(const char* name) { void JSObject::SetFastElements(FixedArray* elems) { + // We should never end in here with a pixel array. + ASSERT(!HasPixelElements()); #ifdef DEBUG // Check the provided array is filled with the_hole. uint32_t len = static_cast<uint32_t>(elems->length()); for (uint32_t i = 0; i < len; i++) ASSERT(elems->get(i)->IsTheHole()); #endif WriteBarrierMode mode = elems->GetWriteBarrierMode(); - if (HasFastElements()) { - FixedArray* old_elements = FixedArray::cast(elements()); - uint32_t old_length = static_cast<uint32_t>(old_elements->length()); - // Fill out the new array with this content and array holes. - for (uint32_t i = 0; i < old_length; i++) { - elems->set(i, old_elements->get(i), mode); + switch (GetElementsKind()) { + case FAST_ELEMENTS: { + FixedArray* old_elements = FixedArray::cast(elements()); + uint32_t old_length = static_cast<uint32_t>(old_elements->length()); + // Fill out the new array with this content and array holes. + for (uint32_t i = 0; i < old_length; i++) { + elems->set(i, old_elements->get(i), mode); + } + break; } - } else { - NumberDictionary* dictionary = NumberDictionary::cast(elements()); - for (int i = 0; i < dictionary->Capacity(); i++) { - Object* key = dictionary->KeyAt(i); - if (key->IsNumber()) { - uint32_t entry = static_cast<uint32_t>(key->Number()); - elems->set(entry, dictionary->ValueAt(i), mode); + case DICTIONARY_ELEMENTS: { + NumberDictionary* dictionary = NumberDictionary::cast(elements()); + for (int i = 0; i < dictionary->Capacity(); i++) { + Object* key = dictionary->KeyAt(i); + if (key->IsNumber()) { + uint32_t entry = static_cast<uint32_t>(key->Number()); + elems->set(entry, dictionary->ValueAt(i), mode); + } } + break; } + default: + UNREACHABLE(); + break; } set_elements(elems); } Object* JSObject::SetSlowElements(Object* len) { + // We should never end in here with a pixel array. + ASSERT(!HasPixelElements()); + uint32_t new_length = static_cast<uint32_t>(len->Number()); - if (!HasFastElements()) { - if (IsJSArray()) { - uint32_t old_length = - static_cast<uint32_t>(JSArray::cast(this)->length()->Number()); - element_dictionary()->RemoveNumberEntries(new_length, old_length), - JSArray::cast(this)->set_length(len); + switch (GetElementsKind()) { + case FAST_ELEMENTS: { + // Make sure we never try to shrink dense arrays into sparse arrays. + ASSERT(static_cast<uint32_t>(FixedArray::cast(elements())->length()) <= + new_length); + Object* obj = NormalizeElements(); + if (obj->IsFailure()) return obj; + + // Update length for JSArrays. + if (IsJSArray()) JSArray::cast(this)->set_length(len); + break; } - return this; + case DICTIONARY_ELEMENTS: { + if (IsJSArray()) { + uint32_t old_length = + static_cast<uint32_t>(JSArray::cast(this)->length()->Number()); + element_dictionary()->RemoveNumberEntries(new_length, old_length), + JSArray::cast(this)->set_length(len); + } + break; + } + default: + UNREACHABLE(); + break; } - - // Make sure we never try to shrink dense arrays into sparse arrays. - ASSERT(static_cast<uint32_t>(FixedArray::cast(elements())->length()) <= - new_length); - Object* obj = NormalizeElements(); - if (obj->IsFailure()) return obj; - - // Update length for JSArrays. - if (IsJSArray()) JSArray::cast(this)->set_length(len); return this; } @@ -5159,7 +5212,7 @@ Object* JSArray::Initialize(int capacity) { void JSArray::Expand(int required_size) { Handle<JSArray> self(this); - Handle<FixedArray> old_backing(elements()); + Handle<FixedArray> old_backing(FixedArray::cast(elements())); int old_size = old_backing->length(); // Doubling in size would be overkill, but leave some slack to avoid // constantly growing. @@ -5186,52 +5239,62 @@ static Object* ArrayLengthRangeError() { Object* JSObject::SetElementsLength(Object* len) { + // We should never end in here with a pixel array. + ASSERT(!HasPixelElements()); + Object* smi_length = len->ToSmi(); if (smi_length->IsSmi()) { int value = Smi::cast(smi_length)->value(); if (value < 0) return ArrayLengthRangeError(); - if (HasFastElements()) { - int old_capacity = FixedArray::cast(elements())->length(); - if (value <= old_capacity) { + switch (GetElementsKind()) { + case FAST_ELEMENTS: { + int old_capacity = FixedArray::cast(elements())->length(); + if (value <= old_capacity) { + if (IsJSArray()) { + int old_length = FastD2I(JSArray::cast(this)->length()->Number()); + // NOTE: We may be able to optimize this by removing the + // last part of the elements backing storage array and + // setting the capacity to the new size. + for (int i = value; i < old_length; i++) { + FixedArray::cast(elements())->set_the_hole(i); + } + JSArray::cast(this)->set_length(smi_length, SKIP_WRITE_BARRIER); + } + return this; + } + int min = NewElementsCapacity(old_capacity); + int new_capacity = value > min ? value : min; + if (new_capacity <= kMaxFastElementsLength || + !ShouldConvertToSlowElements(new_capacity)) { + Object* obj = Heap::AllocateFixedArrayWithHoles(new_capacity); + if (obj->IsFailure()) return obj; + if (IsJSArray()) JSArray::cast(this)->set_length(smi_length, + SKIP_WRITE_BARRIER); + SetFastElements(FixedArray::cast(obj)); + return this; + } + break; + } + case DICTIONARY_ELEMENTS: { if (IsJSArray()) { - int old_length = FastD2I(JSArray::cast(this)->length()->Number()); - // NOTE: We may be able to optimize this by removing the - // last part of the elements backing storage array and - // setting the capacity to the new size. - for (int i = value; i < old_length; i++) { - FixedArray::cast(elements())->set_the_hole(i); + if (value == 0) { + // If the length of a slow array is reset to zero, we clear + // the array and flush backing storage. This has the added + // benefit that the array returns to fast mode. + initialize_elements(); + } else { + // Remove deleted elements. + uint32_t old_length = + static_cast<uint32_t>(JSArray::cast(this)->length()->Number()); + element_dictionary()->RemoveNumberEntries(value, old_length); } JSArray::cast(this)->set_length(smi_length, SKIP_WRITE_BARRIER); } return this; } - int min = NewElementsCapacity(old_capacity); - int new_capacity = value > min ? value : min; - if (new_capacity <= kMaxFastElementsLength || - !ShouldConvertToSlowElements(new_capacity)) { - Object* obj = Heap::AllocateFixedArrayWithHoles(new_capacity); - if (obj->IsFailure()) return obj; - if (IsJSArray()) JSArray::cast(this)->set_length(smi_length, - SKIP_WRITE_BARRIER); - SetFastElements(FixedArray::cast(obj)); - return this; - } - } else { - if (IsJSArray()) { - if (value == 0) { - // If the length of a slow array is reset to zero, we clear - // the array and flush backing storage. This has the added - // benefit that the array returns to fast mode. - initialize_elements(); - } else { - // Remove deleted elements. - uint32_t old_length = - static_cast<uint32_t>(JSArray::cast(this)->length()->Number()); - element_dictionary()->RemoveNumberEntries(value, old_length); - } - JSArray::cast(this)->set_length(smi_length, SKIP_WRITE_BARRIER); - } - return this; + default: + UNREACHABLE(); + break; } } @@ -5258,20 +5321,36 @@ Object* JSObject::SetElementsLength(Object* len) { bool JSObject::HasElementPostInterceptor(JSObject* receiver, uint32_t index) { - if (HasFastElements()) { - uint32_t length = IsJSArray() ? - static_cast<uint32_t>( - Smi::cast(JSArray::cast(this)->length())->value()) : - static_cast<uint32_t>(FixedArray::cast(elements())->length()); - if ((index < length) && - !FixedArray::cast(elements())->get(index)->IsTheHole()) { - return true; + switch (GetElementsKind()) { + case FAST_ELEMENTS: { + uint32_t length = IsJSArray() ? + static_cast<uint32_t> + (Smi::cast(JSArray::cast(this)->length())->value()) : + static_cast<uint32_t>(FixedArray::cast(elements())->length()); + if ((index < length) && + !FixedArray::cast(elements())->get(index)->IsTheHole()) { + return true; + } + break; } - } else { - if (element_dictionary()->FindEntry(index) - != NumberDictionary::kNotFound) { - return true; + case PIXEL_ELEMENTS: { + // TODO(iposva): Add testcase. + PixelArray* pixels = PixelArray::cast(elements()); + if (index < static_cast<uint32_t>(pixels->length())) { + return true; + } + break; + } + case DICTIONARY_ELEMENTS: { + if (element_dictionary()->FindEntry(index) + != NumberDictionary::kNotFound) { + return true; + } + break; } + default: + UNREACHABLE(); + break; } // Handle [] on String objects. @@ -5338,17 +5417,29 @@ bool JSObject::HasLocalElement(uint32_t index) { // Handle [] on String objects. if (this->IsStringObjectWithCharacterAt(index)) return true; - if (HasFastElements()) { - uint32_t length = IsJSArray() ? - static_cast<uint32_t>( - Smi::cast(JSArray::cast(this)->length())->value()) : - static_cast<uint32_t>(FixedArray::cast(elements())->length()); - return (index < length) && - !FixedArray::cast(elements())->get(index)->IsTheHole(); - } else { - return element_dictionary()->FindEntry(index) - != NumberDictionary::kNotFound; + switch (GetElementsKind()) { + case FAST_ELEMENTS: { + uint32_t length = IsJSArray() ? + static_cast<uint32_t> + (Smi::cast(JSArray::cast(this)->length())->value()) : + static_cast<uint32_t>(FixedArray::cast(elements())->length()); + return (index < length) && + !FixedArray::cast(elements())->get(index)->IsTheHole(); + } + case PIXEL_ELEMENTS: { + PixelArray* pixels = PixelArray::cast(elements()); + return (index < static_cast<uint32_t>(pixels->length())); + } + case DICTIONARY_ELEMENTS: { + return element_dictionary()->FindEntry(index) + != NumberDictionary::kNotFound; + } + default: + UNREACHABLE(); + break; } + UNREACHABLE(); + return Heap::null_value(); } @@ -5365,18 +5456,33 @@ bool JSObject::HasElementWithReceiver(JSObject* receiver, uint32_t index) { return HasElementWithInterceptor(receiver, index); } - if (HasFastElements()) { - uint32_t length = IsJSArray() ? - static_cast<uint32_t>( - Smi::cast(JSArray::cast(this)->length())->value()) : - static_cast<uint32_t>(FixedArray::cast(elements())->length()); - if ((index < length) && - !FixedArray::cast(elements())->get(index)->IsTheHole()) return true; - } else { - if (element_dictionary()->FindEntry(index) - != NumberDictionary::kNotFound) { - return true; + switch (GetElementsKind()) { + case FAST_ELEMENTS: { + uint32_t length = IsJSArray() ? + static_cast<uint32_t> + (Smi::cast(JSArray::cast(this)->length())->value()) : + static_cast<uint32_t>(FixedArray::cast(elements())->length()); + if ((index < length) && + !FixedArray::cast(elements())->get(index)->IsTheHole()) return true; + break; + } + case PIXEL_ELEMENTS: { + PixelArray* pixels = PixelArray::cast(elements()); + if (index < static_cast<uint32_t>(pixels->length())) { + return true; + } + break; + } + case DICTIONARY_ELEMENTS: { + if (element_dictionary()->FindEntry(index) + != NumberDictionary::kNotFound) { + return true; + } + break; } + default: + UNREACHABLE(); + break; } // Handle [] on String objects. @@ -5472,7 +5578,7 @@ Object* JSObject::SetFastElement(uint32_t index, Object* value) { // Otherwise default to slow case. Object* obj = NormalizeElements(); if (obj->IsFailure()) return obj; - ASSERT(!HasFastElements()); + ASSERT(HasDictionaryElements()); return SetElement(index, value); } @@ -5501,80 +5607,95 @@ Object* JSObject::SetElement(uint32_t index, Object* value) { Object* JSObject::SetElementWithoutInterceptor(uint32_t index, Object* value) { - // Fast case. - if (HasFastElements()) return SetFastElement(index, value); + switch (GetElementsKind()) { + case FAST_ELEMENTS: + // Fast case. + return SetFastElement(index, value); + case PIXEL_ELEMENTS: { + PixelArray* pixels = PixelArray::cast(elements()); + return pixels->SetValue(index, value); + } + case DICTIONARY_ELEMENTS: { + // Insert element in the dictionary. + FixedArray* elms = FixedArray::cast(elements()); + NumberDictionary* dictionary = NumberDictionary::cast(elms); - // Dictionary case. - ASSERT(!HasFastElements()); - - // Insert element in the dictionary. - FixedArray* elms = FixedArray::cast(elements()); - NumberDictionary* dictionary = NumberDictionary::cast(elms); - - int entry = dictionary->FindEntry(index); - if (entry != NumberDictionary::kNotFound) { - Object* element = dictionary->ValueAt(entry); - PropertyDetails details = dictionary->DetailsAt(entry); - if (details.type() == CALLBACKS) { - // Only accessors allowed as elements. - FixedArray* structure = FixedArray::cast(element); - if (structure->get(kSetterIndex)->IsJSFunction()) { - JSFunction* setter = JSFunction::cast(structure->get(kSetterIndex)); - return SetPropertyWithDefinedSetter(setter, value); + int entry = dictionary->FindEntry(index); + if (entry != NumberDictionary::kNotFound) { + Object* element = dictionary->ValueAt(entry); + PropertyDetails details = dictionary->DetailsAt(entry); + if (details.type() == CALLBACKS) { + // Only accessors allowed as elements. + FixedArray* structure = FixedArray::cast(element); + if (structure->get(kSetterIndex)->IsJSFunction()) { + JSFunction* setter = JSFunction::cast(structure->get(kSetterIndex)); + return SetPropertyWithDefinedSetter(setter, value); + } else { + Handle<Object> self(this); + Handle<Object> key(Factory::NewNumberFromUint(index)); + Handle<Object> args[2] = { key, self }; + return Top::Throw(*Factory::NewTypeError("no_setter_in_callback", + HandleVector(args, 2))); + } + } else { + dictionary->UpdateMaxNumberKey(index); + dictionary->ValueAtPut(entry, value); + } } else { - Handle<Object> self(this); - Handle<Object> key(Factory::NewNumberFromUint(index)); - Handle<Object> args[2] = { key, self }; - return Top::Throw(*Factory::NewTypeError("no_setter_in_callback", - HandleVector(args, 2))); - } - } else { - dictionary->UpdateMaxNumberKey(index); - dictionary->ValueAtPut(entry, value); - } - } else { - // Index not already used. Look for an accessor in the prototype chain. - if (!IsJSArray()) { - Object* setter = LookupCallbackSetterInPrototypes(index); - if (setter->IsJSFunction()) { - return SetPropertyWithDefinedSetter(JSFunction::cast(setter), value); + // Index not already used. Look for an accessor in the prototype chain. + if (!IsJSArray()) { + Object* setter = LookupCallbackSetterInPrototypes(index); + if (setter->IsJSFunction()) { + return SetPropertyWithDefinedSetter(JSFunction::cast(setter), + value); + } + } + Object* result = dictionary->AtNumberPut(index, value); + if (result->IsFailure()) return result; + if (elms != FixedArray::cast(result)) { + set_elements(FixedArray::cast(result)); + } } - } - Object* result = dictionary->AtNumberPut(index, value); - if (result->IsFailure()) return result; - if (elms != FixedArray::cast(result)) { - set_elements(FixedArray::cast(result)); - } - } - // Update the array length if this JSObject is an array. - if (IsJSArray()) { - JSArray* array = JSArray::cast(this); - Object* return_value = array->JSArrayUpdateLengthFromIndex(index, value); - if (return_value->IsFailure()) return return_value; - } + // Update the array length if this JSObject is an array. + if (IsJSArray()) { + JSArray* array = JSArray::cast(this); + Object* return_value = array->JSArrayUpdateLengthFromIndex(index, + value); + if (return_value->IsFailure()) return return_value; + } - // Attempt to put this object back in fast case. - if (ShouldConvertToFastElements()) { - uint32_t new_length = 0; - if (IsJSArray()) { - CHECK(Array::IndexFromObject(JSArray::cast(this)->length(), &new_length)); - JSArray::cast(this)->set_length(Smi::FromInt(new_length)); - } else { - new_length = NumberDictionary::cast(elements())->max_number_key() + 1; - } - Object* obj = Heap::AllocateFixedArrayWithHoles(new_length); - if (obj->IsFailure()) return obj; - SetFastElements(FixedArray::cast(obj)); + // Attempt to put this object back in fast case. + if (ShouldConvertToFastElements()) { + uint32_t new_length = 0; + if (IsJSArray()) { + CHECK(Array::IndexFromObject(JSArray::cast(this)->length(), + &new_length)); + JSArray::cast(this)->set_length(Smi::FromInt(new_length)); + } else { + new_length = NumberDictionary::cast(elements())->max_number_key() + 1; + } + Object* obj = Heap::AllocateFixedArrayWithHoles(new_length); + if (obj->IsFailure()) return obj; + SetFastElements(FixedArray::cast(obj)); #ifdef DEBUG - if (FLAG_trace_normalization) { - PrintF("Object elements are fast case again:\n"); - Print(); - } + if (FLAG_trace_normalization) { + PrintF("Object elements are fast case again:\n"); + Print(); + } #endif - } + } - return value; + return value; + } + default: + UNREACHABLE(); + break; + } + // All possible cases have been handled above. Add a return to avoid the + // complaints from the compiler. + UNREACHABLE(); + return Heap::null_value(); } @@ -5597,32 +5718,45 @@ Object* JSObject::GetElementPostInterceptor(JSObject* receiver, uint32_t index) { // Get element works for both JSObject and JSArray since // JSArray::length cannot change. - if (HasFastElements()) { - FixedArray* elms = FixedArray::cast(elements()); - if (index < static_cast<uint32_t>(elms->length())) { - Object* value = elms->get(index); - if (!value->IsTheHole()) return value; + switch (GetElementsKind()) { + case FAST_ELEMENTS: { + FixedArray* elms = FixedArray::cast(elements()); + if (index < static_cast<uint32_t>(elms->length())) { + Object* value = elms->get(index); + if (!value->IsTheHole()) return value; + } + break; } - } else { - NumberDictionary* dictionary = element_dictionary(); - int entry = dictionary->FindEntry(index); - if (entry != NumberDictionary::kNotFound) { - Object* element = dictionary->ValueAt(entry); - PropertyDetails details = dictionary->DetailsAt(entry); - if (details.type() == CALLBACKS) { - // Only accessors allowed as elements. - FixedArray* structure = FixedArray::cast(element); - Object* getter = structure->get(kGetterIndex); - if (getter->IsJSFunction()) { - return GetPropertyWithDefinedGetter(receiver, - JSFunction::cast(getter)); - } else { - // Getter is not a function. - return Heap::undefined_value(); + case PIXEL_ELEMENTS: { + // TODO(iposva): Add testcase and implement. + UNIMPLEMENTED(); + break; + } + case DICTIONARY_ELEMENTS: { + NumberDictionary* dictionary = element_dictionary(); + int entry = dictionary->FindEntry(index); + if (entry != NumberDictionary::kNotFound) { + Object* element = dictionary->ValueAt(entry); + PropertyDetails details = dictionary->DetailsAt(entry); + if (details.type() == CALLBACKS) { + // Only accessors allowed as elements. + FixedArray* structure = FixedArray::cast(element); + Object* getter = structure->get(kGetterIndex); + if (getter->IsJSFunction()) { + return GetPropertyWithDefinedGetter(receiver, + JSFunction::cast(getter)); + } else { + // Getter is not a function. + return Heap::undefined_value(); + } } + return element; } - return element; + break; } + default: + UNREACHABLE(); + break; } // Continue searching via the prototype chain. @@ -5681,31 +5815,44 @@ Object* JSObject::GetElementWithReceiver(JSObject* receiver, uint32_t index) { // Get element works for both JSObject and JSArray since // JSArray::length cannot change. - if (HasFastElements()) { - FixedArray* elms = FixedArray::cast(elements()); - if (index < static_cast<uint32_t>(elms->length())) { - Object* value = elms->get(index); - if (!value->IsTheHole()) return value; + switch (GetElementsKind()) { + case FAST_ELEMENTS: { + FixedArray* elms = FixedArray::cast(elements()); + if (index < static_cast<uint32_t>(elms->length())) { + Object* value = elms->get(index); + if (!value->IsTheHole()) return value; + } + break; } - } else { - NumberDictionary* dictionary = element_dictionary(); - int entry = dictionary->FindEntry(index); - if (entry != NumberDictionary::kNotFound) { - Object* element = dictionary->ValueAt(entry); - PropertyDetails details = dictionary->DetailsAt(entry); - if (details.type() == CALLBACKS) { - // Only accessors allowed as elements. - FixedArray* structure = FixedArray::cast(element); - Object* getter = structure->get(kGetterIndex); - if (getter->IsJSFunction()) { - return GetPropertyWithDefinedGetter(receiver, - JSFunction::cast(getter)); - } else { - // Getter is not a function. - return Heap::undefined_value(); + case PIXEL_ELEMENTS: { + PixelArray* pixels = PixelArray::cast(elements()); + if (index < static_cast<uint32_t>(pixels->length())) { + uint8_t value = pixels->get(index); + return Smi::FromInt(value); + } + break; + } + case DICTIONARY_ELEMENTS: { + NumberDictionary* dictionary = element_dictionary(); + int entry = dictionary->FindEntry(index); + if (entry != NumberDictionary::kNotFound) { + Object* element = dictionary->ValueAt(entry); + PropertyDetails details = dictionary->DetailsAt(entry); + if (details.type() == CALLBACKS) { + // Only accessors allowed as elements. + FixedArray* structure = FixedArray::cast(element); + Object* getter = structure->get(kGetterIndex); + if (getter->IsJSFunction()) { + return GetPropertyWithDefinedGetter(receiver, + JSFunction::cast(getter)); + } else { + // Getter is not a function. + return Heap::undefined_value(); + } } + return element; } - return element; + break; } } @@ -5719,16 +5866,27 @@ bool JSObject::HasDenseElements() { int capacity = 0; int number_of_elements = 0; - if (HasFastElements()) { - FixedArray* elms = FixedArray::cast(elements()); - capacity = elms->length(); - for (int i = 0; i < capacity; i++) { - if (!elms->get(i)->IsTheHole()) number_of_elements++; + switch (GetElementsKind()) { + case FAST_ELEMENTS: { + FixedArray* elms = FixedArray::cast(elements()); + capacity = elms->length(); + for (int i = 0; i < capacity; i++) { + if (!elms->get(i)->IsTheHole()) number_of_elements++; + } + break; } - } else { - NumberDictionary* dictionary = NumberDictionary::cast(elements()); - capacity = dictionary->Capacity(); - number_of_elements = dictionary->NumberOfElements(); + case PIXEL_ELEMENTS: { + return true; + } + case DICTIONARY_ELEMENTS: { + NumberDictionary* dictionary = NumberDictionary::cast(elements()); + capacity = dictionary->Capacity(); + number_of_elements = dictionary->NumberOfElements(); + break; + } + default: + UNREACHABLE(); + break; } if (capacity == 0) return true; @@ -5747,7 +5905,7 @@ bool JSObject::ShouldConvertToSlowElements(int new_capacity) { bool JSObject::ShouldConvertToFastElements() { - ASSERT(!HasFastElements()); + ASSERT(HasDictionaryElements()); NumberDictionary* dictionary = NumberDictionary::cast(elements()); // If the elements are sparse, we should not go back to fast case. if (!HasDenseElements()) return false; @@ -5848,12 +6006,12 @@ Object* JSObject::GetPropertyPostInterceptor(JSObject* receiver, } -Object* JSObject::GetPropertyWithInterceptorProper( +Object* JSObject::GetPropertyWithInterceptor( JSObject* receiver, String* name, PropertyAttributes* attributes) { + InterceptorInfo* interceptor = GetNamedInterceptor(); HandleScope scope; - Handle<InterceptorInfo> interceptor(GetNamedInterceptor()); Handle<JSObject> receiver_handle(receiver); Handle<JSObject> holder_handle(this); Handle<String> name_handle(name); @@ -5872,85 +6030,14 @@ Object* JSObject::GetPropertyWithInterceptorProper( VMState state(EXTERNAL); result = getter(v8::Utils::ToLocal(name_handle), info); } - if (!Top::has_scheduled_exception() && !result.IsEmpty()) { + RETURN_IF_SCHEDULED_EXCEPTION(); + if (!result.IsEmpty()) { *attributes = NONE; return *v8::Utils::OpenHandle(*result); } } - *attributes = ABSENT; - return Heap::undefined_value(); -} - - -Object* JSObject::GetInterceptorPropertyWithLookupHint( - JSObject* receiver, - Smi* lookup_hint, - String* name, - PropertyAttributes* attributes) { - HandleScope scope; - Handle<JSObject> receiver_handle(receiver); - Handle<JSObject> holder_handle(this); - Handle<String> name_handle(name); - - Object* result = GetPropertyWithInterceptorProper(receiver, - name, - attributes); - if (*attributes != ABSENT) { - return result; - } - RETURN_IF_SCHEDULED_EXCEPTION(); - - int property_index = lookup_hint->value(); - if (property_index >= 0) { - result = holder_handle->FastPropertyAt(property_index); - } else { - switch (property_index) { - case kLookupInPrototype: { - Object* pt = holder_handle->GetPrototype(); - *attributes = ABSENT; - if (pt == Heap::null_value()) return Heap::undefined_value(); - result = pt->GetPropertyWithReceiver( - *receiver_handle, - *name_handle, - attributes); - RETURN_IF_SCHEDULED_EXCEPTION(); - } - break; - - case kLookupInHolder: - result = holder_handle->GetPropertyPostInterceptor( - *receiver_handle, - *name_handle, - attributes); - RETURN_IF_SCHEDULED_EXCEPTION(); - break; - - default: - UNREACHABLE(); - } - } - - return result; -} - - -Object* JSObject::GetPropertyWithInterceptor( - JSObject* receiver, - String* name, - PropertyAttributes* attributes) { - HandleScope scope; - Handle<JSObject> receiver_handle(receiver); - Handle<JSObject> holder_handle(this); - Handle<String> name_handle(name); - - Object* result = GetPropertyWithInterceptorProper(receiver, name, attributes); - if (*attributes != ABSENT) { - return result; - } - RETURN_IF_SCHEDULED_EXCEPTION(); - - result = holder_handle->GetPropertyPostInterceptor( + Object* result = holder_handle->GetPropertyPostInterceptor( *receiver_handle, *name_handle, attributes); @@ -6001,16 +6088,30 @@ bool JSObject::HasRealElementProperty(uint32_t index) { // Handle [] on String objects. if (this->IsStringObjectWithCharacterAt(index)) return true; - if (HasFastElements()) { - uint32_t length = IsJSArray() ? - static_cast<uint32_t>( - Smi::cast(JSArray::cast(this)->length())->value()) : - static_cast<uint32_t>(FixedArray::cast(elements())->length()); - return (index < length) && - !FixedArray::cast(elements())->get(index)->IsTheHole(); + switch (GetElementsKind()) { + case FAST_ELEMENTS: { + uint32_t length = IsJSArray() ? + static_cast<uint32_t>( + Smi::cast(JSArray::cast(this)->length())->value()) : + static_cast<uint32_t>(FixedArray::cast(elements())->length()); + return (index < length) && + !FixedArray::cast(elements())->get(index)->IsTheHole(); + } + case PIXEL_ELEMENTS: { + PixelArray* pixels = PixelArray::cast(elements()); + return index < static_cast<uint32_t>(pixels->length()); + } + case DICTIONARY_ELEMENTS: { + return element_dictionary()->FindEntry(index) + != NumberDictionary::kNotFound; + } + default: + UNREACHABLE(); + break; } - return element_dictionary()->FindEntry(index) - != NumberDictionary::kNotFound; + // All possibilities have been handled above already. + UNREACHABLE(); + return Heap::null_value(); } @@ -6193,24 +6294,43 @@ int JSObject::NumberOfEnumElements() { int JSObject::GetLocalElementKeys(FixedArray* storage, PropertyAttributes filter) { int counter = 0; - if (HasFastElements()) { - int length = IsJSArray() - ? Smi::cast(JSArray::cast(this)->length())->value() - : FixedArray::cast(elements())->length(); - for (int i = 0; i < length; i++) { - if (!FixedArray::cast(elements())->get(i)->IsTheHole()) { - if (storage) { - storage->set(counter, Smi::FromInt(i), SKIP_WRITE_BARRIER); + switch (GetElementsKind()) { + case FAST_ELEMENTS: { + int length = IsJSArray() ? + Smi::cast(JSArray::cast(this)->length())->value() : + FixedArray::cast(elements())->length(); + for (int i = 0; i < length; i++) { + if (!FixedArray::cast(elements())->get(i)->IsTheHole()) { + if (storage != NULL) { + storage->set(counter, Smi::FromInt(i), SKIP_WRITE_BARRIER); + } + counter++; + } + } + ASSERT(!storage || storage->length() >= counter); + break; + } + case PIXEL_ELEMENTS: { + int length = PixelArray::cast(elements())->length(); + while (counter < length) { + if (storage != NULL) { + storage->set(counter, Smi::FromInt(counter), SKIP_WRITE_BARRIER); } counter++; } + ASSERT(!storage || storage->length() >= counter); + break; } - ASSERT(!storage || storage->length() >= counter); - } else { - if (storage) { - element_dictionary()->CopyKeysTo(storage, filter); + case DICTIONARY_ELEMENTS: { + if (storage != NULL) { + element_dictionary()->CopyKeysTo(storage, filter); + } + counter = element_dictionary()->NumberOfElementsFilterAttributes(filter); + break; } - counter = element_dictionary()->NumberOfElementsFilterAttributes(filter); + default: + UNREACHABLE(); + break; } if (this->IsJSValue()) { @@ -6669,7 +6789,7 @@ int Dictionary<StringDictionaryShape, String*>::NumberOfEnumElements(); // Collates undefined and unexisting elements below limit from position // zero of the elements. The object stays in Dictionary mode. Object* JSObject::PrepareSlowElementsForSort(uint32_t limit) { - ASSERT(!HasFastElements()); + ASSERT(HasDictionaryElements()); // Must stay in dictionary mode, either because of requires_slow_elements, // or because we are not going to sort (and therefore compact) all of the // elements. @@ -6743,7 +6863,9 @@ Object* JSObject::PrepareSlowElementsForSort(uint32_t limit) { // If the object is in dictionary mode, it is converted to fast elements // mode. Object* JSObject::PrepareElementsForSort(uint32_t limit) { - if (!HasFastElements()) { + ASSERT(!HasPixelElements()); + + if (HasDictionaryElements()) { // Convert to fast elements containing only the existing properties. // Ordering is irrelevant, since we are going to sort anyway. NumberDictionary* dict = element_dictionary(); @@ -6768,7 +6890,7 @@ Object* JSObject::PrepareElementsForSort(uint32_t limit) { // Collect holes at the end, undefined before that and the rest at the // start, and return the number of non-hole, non-undefined values. - FixedArray* elements = this->elements(); + FixedArray* elements = FixedArray::cast(this->elements()); uint32_t elements_length = static_cast<uint32_t>(elements->length()); if (limit > elements_length) { limit = elements_length ; @@ -6838,6 +6960,41 @@ Object* JSObject::PrepareElementsForSort(uint32_t limit) { } +Object* PixelArray::SetValue(uint32_t index, Object* value) { + uint8_t clamped_value = 0; + if (index < static_cast<uint32_t>(length())) { + if (value->IsSmi()) { + int int_value = Smi::cast(value)->value(); + if (int_value < 0) { + clamped_value = 0; + } else if (int_value > 255) { + clamped_value = 255; + } else { + clamped_value = static_cast<uint8_t>(int_value); + } + } else if (value->IsHeapNumber()) { + double double_value = HeapNumber::cast(value)->value(); + if (!(double_value > 0)) { + // NaN and less than zero clamp to zero. + clamped_value = 0; + } else if (double_value > 255) { + // Greater than 255 clamp to 255. + clamped_value = 255; + } else { + // Other doubles are rounded to the nearest integer. + clamped_value = static_cast<uint8_t>(double_value + 0.5); + } + } else { + // Clamp undefined to zero (default). All other types have been + // converted to a number type further up in the call chain. + ASSERT(value->IsUndefined()); + } + set(index, clamped_value); + } + return Smi::FromInt(clamped_value); +} + + Object* GlobalObject::GetPropertyCell(LookupResult* result) { ASSERT(!HasFastProperties()); Object* value = property_dictionary()->ValueAt(result->GetDictionaryEntry()); |