Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(766)

Side by Side Diff: src/runtime.cc

Issue 6592007: Port revision 6934 and 6993 (plus fix from 6935) to the 3.0 branch. (Closed) Base URL: https://v8.googlecode.com/svn/branches/3.0
Patch Set: Created 9 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2010 the V8 project authors. All rights reserved. 1 // Copyright 2010 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 7873 matching lines...) Expand 10 before | Expand all | Expand 10 after
7884 * A simple visitor visits every element of Array's. 7884 * A simple visitor visits every element of Array's.
7885 * The backend storage can be a fixed array for fast elements case, 7885 * The backend storage can be a fixed array for fast elements case,
7886 * or a dictionary for sparse array. Since Dictionary is a subtype 7886 * or a dictionary for sparse array. Since Dictionary is a subtype
7887 * of FixedArray, the class can be used by both fast and slow cases. 7887 * of FixedArray, the class can be used by both fast and slow cases.
7888 * The second parameter of the constructor, fast_elements, specifies 7888 * The second parameter of the constructor, fast_elements, specifies
7889 * whether the storage is a FixedArray or Dictionary. 7889 * whether the storage is a FixedArray or Dictionary.
7890 * 7890 *
7891 * An index limit is used to deal with the situation that a result array 7891 * An index limit is used to deal with the situation that a result array
7892 * length overflows 32-bit non-negative integer. 7892 * length overflows 32-bit non-negative integer.
7893 */ 7893 */
7894 class ArrayConcatVisitor { 7894 class ArrayConcatVisitor {
Mads Ager (chromium) 2011/02/28 08:11:20 Should this BASE_EMBEDDED. This should not be allo
7895 public: 7895 public:
7896 ArrayConcatVisitor(Handle<FixedArray> storage, 7896 ArrayConcatVisitor(Handle<FixedArray> storage,
7897 uint32_t index_limit,
7898 bool fast_elements) : 7897 bool fast_elements) :
7899 storage_(storage), index_limit_(index_limit), 7898 storage_(storage),
7900 index_offset_(0), fast_elements_(fast_elements) { } 7899 index_offset_(0u),
7900 fast_elements_(fast_elements) { }
7901 7901
7902 void visit(uint32_t i, Handle<Object> elm) { 7902 void visit(uint32_t i, Handle<Object> elm) {
7903 if (i >= index_limit_ - index_offset_) return; 7903 if (i >= JSObject::kMaxElementCount - index_offset_) return;
7904 uint32_t index = index_offset_ + i; 7904 uint32_t index = index_offset_ + i;
7905 7905
7906 if (fast_elements_) { 7906 if (fast_elements_) {
7907 ASSERT(index < static_cast<uint32_t>(storage_->length())); 7907 if (index < static_cast<uint32_t>(storage_->length())) {
7908 storage_->set(index, *elm); 7908 storage_->set(index, *elm);
7909 7909 return;
7910 } else { 7910 }
7911 Handle<NumberDictionary> dict = Handle<NumberDictionary>::cast(storage_); 7911 // Our initial estimate of length was foiled, possibly by
7912 Handle<NumberDictionary> result = 7912 // getters on the arrays increasing the length of later arrays
7913 Factory::DictionaryAtNumberPut(dict, index, elm); 7913 // during iteration.
7914 if (!result.is_identical_to(dict)) 7914 // This shouldn't happen in anything but pathological cases.
7915 storage_ = result; 7915 SetDictionaryMode(index);
7916 } 7916 // Fall-through to dictionary mode.
7917 } 7917 }
7918 ASSERT(!fast_elements_);
7919 Handle<NumberDictionary> dict(storage_.cast<NumberDictionary>());
7920 Handle<NumberDictionary> result =
7921 Factory::DictionaryAtNumberPut(dict, index, elm);
7922 if (!result.is_identical_to(dict)) {
7923 storage_ = Handle<FixedArray>::cast(result);
7924 }
7925 }
7918 7926
7919 void increase_index_offset(uint32_t delta) { 7927 void increase_index_offset(uint32_t delta) {
7920 if (index_limit_ - index_offset_ < delta) { 7928 if (JSObject::kMaxElementCount - index_offset_ < delta) {
7921 index_offset_ = index_limit_; 7929 index_offset_ = JSObject::kMaxElementCount;
7922 } else { 7930 } else {
7923 index_offset_ += delta; 7931 index_offset_ += delta;
7924 } 7932 }
7925 } 7933 }
7926 7934
7927 Handle<FixedArray> storage() { return storage_; } 7935 Handle<JSArray> ToArray() {
7936 Handle<JSArray> array = Factory::NewJSArray(0);
7937 Handle<Object> length =
7938 Factory::NewNumber(static_cast<double>(index_offset_));
7939 Handle<Map> map;
7940 if (fast_elements_) {
7941 map = Factory::GetFastElementsMap(Handle<Map>(array->map()));
7942 } else {
7943 map = Factory::GetSlowElementsMap(Handle<Map>(array->map()));
7944 }
7945 array->set_map(*map);
7946 array->set_length(*length);
7947 array->set_elements(*storage_);
7948 return array;
7949 }
7928 7950
7929 private: 7951 private:
7930 Handle<FixedArray> storage_; 7952 // Convert storage to dictionary mode.
7931 // Limit on the accepted indices. Elements with indices larger than the 7953 void SetDictionaryMode(uint32_t index) {
7932 // limit are ignored by the visitor. 7954 ASSERT(fast_elements_);
7933 uint32_t index_limit_; 7955 Handle<FixedArray> current_storage(storage_.ToHandle());
7934 // Index after last seen index. Always less than or equal to index_limit_. 7956 HandleCell<NumberDictionary> slow_storage(
Mads Ager (chromium) 2011/02/28 08:11:20 Just use a normal handle and escape the handle fro
7957 Factory::NewNumberDictionary(current_storage->length()));
7958 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
7959 for (uint32_t i = 0; i < current_length; i++) {
7960 HandleScope loop_scope;
7961 Handle<Object> element(current_storage->get(i));
7962 if (!element->IsTheHole()) {
7963 slow_storage =
Mads Ager (chromium) 2011/02/28 08:11:20 slow_storage = GetNewHandle().EscapeFrom(&loop_sco
7964 Factory::DictionaryAtNumberPut(slow_storage.ToHandle(), i, element);
7965 }
7966 }
7967 storage_ = slow_storage.cast<FixedArray>();
7968 fast_elements_ = false;
7969 }
7970
7971 HandleCell<FixedArray> storage_;
7972 // Index after last seen index. Always less than or equal to
7973 // JSObject::kMaxElementCount.
7935 uint32_t index_offset_; 7974 uint32_t index_offset_;
7936 const bool fast_elements_; 7975 bool fast_elements_;
7937 }; 7976 };
7938 7977
7939 7978
7979 static uint32_t EstimateElementCount(Handle<JSArray> array) {
7980 uint32_t length = static_cast<uint32_t>(array->length()->Number());
7981 int element_count = 0;
7982 switch (array->GetElementsKind()) {
7983 case JSObject::FAST_ELEMENTS: {
7984 // Fast elements can't have lengths that are not representable by
7985 // a 32-bit signed integer.
7986 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
7987 int fast_length = static_cast<int>(length);
7988 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
7989 for (int i = 0; i < fast_length; i++) {
7990 if (!elements->get(i)->IsTheHole()) element_count++;
7991 }
7992 break;
7993 }
7994 case JSObject::DICTIONARY_ELEMENTS: {
7995 Handle<NumberDictionary> dictionary(
7996 NumberDictionary::cast(array->elements()));
7997 int capacity = dictionary->Capacity();
7998 for (int i = 0; i < capacity; i++) {
7999 Handle<Object> key(dictionary->KeyAt(i));
8000 if (dictionary->IsKey(*key)) {
8001 element_count++;
8002 }
8003 }
8004 break;
8005 }
8006 default:
8007 // External arrays are always dense.
8008 return length;
8009 }
8010 // As an estimate, we assume that the prototype doesn't contain any
8011 // inherited elements.
8012 return element_count;
8013 }
8014
8015
8016
7940 template<class ExternalArrayClass, class ElementType> 8017 template<class ExternalArrayClass, class ElementType>
7941 static uint32_t IterateExternalArrayElements(Handle<JSObject> receiver, 8018 static void IterateExternalArrayElements(Handle<JSObject> receiver,
7942 bool elements_are_ints, 8019 bool elements_are_ints,
7943 bool elements_are_guaranteed_smis, 8020 bool elements_are_guaranteed_smis,
7944 uint32_t range, 8021 ArrayConcatVisitor* visitor) {
7945 ArrayConcatVisitor* visitor) {
7946 Handle<ExternalArrayClass> array( 8022 Handle<ExternalArrayClass> array(
7947 ExternalArrayClass::cast(receiver->elements())); 8023 ExternalArrayClass::cast(receiver->elements()));
7948 uint32_t len = Min(static_cast<uint32_t>(array->length()), range); 8024 uint32_t len = static_cast<uint32_t>(array->length());
7949 8025
7950 if (visitor != NULL) { 8026 ASSERT(visitor != NULL);
7951 if (elements_are_ints) { 8027 if (elements_are_ints) {
7952 if (elements_are_guaranteed_smis) { 8028 if (elements_are_guaranteed_smis) {
7953 for (uint32_t j = 0; j < len; j++) { 8029 for (uint32_t j = 0; j < len; j++) {
7954 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j)))); 8030 HandleScope loop_scope;
7955 visitor->visit(j, e); 8031 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j))));
7956 } 8032 visitor->visit(j, e);
7957 } else {
7958 for (uint32_t j = 0; j < len; j++) {
7959 int64_t val = static_cast<int64_t>(array->get(j));
7960 if (Smi::IsValid(static_cast<intptr_t>(val))) {
7961 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
7962 visitor->visit(j, e);
7963 } else {
7964 Handle<Object> e =
7965 Factory::NewNumber(static_cast<ElementType>(val));
7966 visitor->visit(j, e);
7967 }
7968 }
7969 } 8033 }
7970 } else { 8034 } else {
7971 for (uint32_t j = 0; j < len; j++) { 8035 for (uint32_t j = 0; j < len; j++) {
7972 Handle<Object> e = Factory::NewNumber(array->get(j)); 8036 HandleScope loop_scope;
7973 visitor->visit(j, e); 8037 int64_t val = static_cast<int64_t>(array->get(j));
7974 } 8038 if (Smi::IsValid(static_cast<intptr_t>(val))) {
7975 } 8039 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
7976 } 8040 visitor->visit(j, e);
7977 8041 } else {
7978 return len; 8042 Handle<Object> e =
7979 } 8043 Factory::NewNumber(static_cast<ElementType>(val));
7980 8044 visitor->visit(j, e);
7981 /** 8045 }
7982 * A helper function that visits elements of a JSObject. Only elements 8046 }
7983 * whose index between 0 and range (exclusive) are visited. 8047 }
7984 * 8048 } else {
7985 * If the third parameter, visitor, is not NULL, the visitor is called 8049 for (uint32_t j = 0; j < len; j++) {
7986 * with parameters, 'visitor_index_offset + element index' and the element. 8050 HandleScope loop_scope;
7987 * 8051 Handle<Object> e = Factory::NewNumber(array->get(j));
7988 * It returns the number of visisted elements. 8052 visitor->visit(j, e);
7989 */ 8053 }
7990 static uint32_t IterateElements(Handle<JSObject> receiver, 8054 }
7991 uint32_t range, 8055 }
7992 ArrayConcatVisitor* visitor) { 8056
7993 uint32_t num_of_elements = 0; 8057
7994 8058 // Used for sorting indices in a List<uint32_t>.
7995 switch (receiver->GetElementsKind()) { 8059 static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
8060 uint32_t a = *ap;
8061 uint32_t b = *bp;
8062 return (a == b) ? 0 : (a < b) ? -1 : 1;
8063 }
8064
8065
8066 static void CollectElementIndices(Handle<JSObject> object,
8067 uint32_t range,
8068 List<uint32_t>* indices) {
8069 JSObject::ElementsKind kind = object->GetElementsKind();
8070 switch (kind) {
7996 case JSObject::FAST_ELEMENTS: { 8071 case JSObject::FAST_ELEMENTS: {
7997 Handle<FixedArray> elements(FixedArray::cast(receiver->elements())); 8072 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
7998 uint32_t len = elements->length(); 8073 uint32_t length = static_cast<uint32_t>(elements->length());
7999 if (range < len) { 8074 if (range < length) length = range;
8000 len = range; 8075 for (uint32_t i = 0; i < length; i++) {
8001 } 8076 if (!elements->get(i)->IsTheHole()) {
8002 8077 indices->Add(i);
8003 for (uint32_t j = 0; j < len; j++) { 8078 }
8004 Handle<Object> e(elements->get(j)); 8079 }
8005 if (!e->IsTheHole()) {
8006 num_of_elements++;
8007 if (visitor) {
8008 visitor->visit(j, e);
8009 }
8010 }
8011 }
8012 break;
8013 }
8014 case JSObject::PIXEL_ELEMENTS: {
8015 Handle<PixelArray> pixels(PixelArray::cast(receiver->elements()));
8016 uint32_t len = pixels->length();
8017 if (range < len) {
8018 len = range;
8019 }
8020
8021 for (uint32_t j = 0; j < len; j++) {
8022 num_of_elements++;
8023 if (visitor != NULL) {
8024 Handle<Smi> e(Smi::FromInt(pixels->get(j)));
8025 visitor->visit(j, e);
8026 }
8027 }
8028 break;
8029 }
8030 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
8031 num_of_elements =
8032 IterateExternalArrayElements<ExternalByteArray, int8_t>(
8033 receiver, true, true, range, visitor);
8034 break;
8035 }
8036 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
8037 num_of_elements =
8038 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
8039 receiver, true, true, range, visitor);
8040 break;
8041 }
8042 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
8043 num_of_elements =
8044 IterateExternalArrayElements<ExternalShortArray, int16_t>(
8045 receiver, true, true, range, visitor);
8046 break;
8047 }
8048 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
8049 num_of_elements =
8050 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
8051 receiver, true, true, range, visitor);
8052 break;
8053 }
8054 case JSObject::EXTERNAL_INT_ELEMENTS: {
8055 num_of_elements =
8056 IterateExternalArrayElements<ExternalIntArray, int32_t>(
8057 receiver, true, false, range, visitor);
8058 break;
8059 }
8060 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
8061 num_of_elements =
8062 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
8063 receiver, true, false, range, visitor);
8064 break;
8065 }
8066 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
8067 num_of_elements =
8068 IterateExternalArrayElements<ExternalFloatArray, float>(
8069 receiver, false, false, range, visitor);
8070 break; 8080 break;
8071 } 8081 }
8072 case JSObject::DICTIONARY_ELEMENTS: { 8082 case JSObject::DICTIONARY_ELEMENTS: {
8073 Handle<NumberDictionary> dict(receiver->element_dictionary()); 8083 Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements()));
8074 uint32_t capacity = dict->Capacity(); 8084 uint32_t capacity = dict->Capacity();
8075 for (uint32_t j = 0; j < capacity; j++) { 8085 for (uint32_t j = 0; j < capacity; j++) {
8086 HandleScope loop_scope;
8076 Handle<Object> k(dict->KeyAt(j)); 8087 Handle<Object> k(dict->KeyAt(j));
8077 if (dict->IsKey(*k)) { 8088 if (dict->IsKey(*k)) {
8078 ASSERT(k->IsNumber()); 8089 ASSERT(k->IsNumber());
8079 uint32_t index = static_cast<uint32_t>(k->Number()); 8090 uint32_t index = static_cast<uint32_t>(k->Number());
8080 if (index < range) { 8091 if (index < range) {
8081 num_of_elements++; 8092 indices->Add(index);
8082 if (visitor) {
8083 visitor->visit(index, Handle<Object>(dict->ValueAt(j)));
8084 }
8085 } 8093 }
8086 } 8094 }
8087 } 8095 }
8088 break; 8096 break;
8089 } 8097 }
8098 default: {
8099 int dense_elements_length;
8100 switch (kind) {
8101 case JSObject::PIXEL_ELEMENTS: {
8102 dense_elements_length =
8103 PixelArray::cast(object->elements())->length();
8104 break;
8105 }
8106 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
8107 dense_elements_length =
8108 ExternalByteArray::cast(object->elements())->length();
8109 break;
8110 }
8111 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
8112 dense_elements_length =
8113 ExternalUnsignedByteArray::cast(object->elements())->length();
8114 break;
8115 }
8116 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
8117 dense_elements_length =
8118 ExternalShortArray::cast(object->elements())->length();
8119 break;
8120 }
8121 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
8122 dense_elements_length =
8123 ExternalUnsignedShortArray::cast(object->elements())->length();
8124 break;
8125 }
8126 case JSObject::EXTERNAL_INT_ELEMENTS: {
8127 dense_elements_length =
8128 ExternalIntArray::cast(object->elements())->length();
8129 break;
8130 }
8131 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
8132 dense_elements_length =
8133 ExternalUnsignedIntArray::cast(object->elements())->length();
8134 break;
8135 }
8136 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
8137 dense_elements_length =
8138 ExternalFloatArray::cast(object->elements())->length();
8139 break;
8140 }
8141 default:
8142 UNREACHABLE();
8143 dense_elements_length = 0;
8144 break;
8145 }
8146 uint32_t length = static_cast<uint32_t>(dense_elements_length);
8147 if (range <= length) {
8148 length = range;
8149 // We will add all indices, so we might as well clear it first
8150 // and avoid duplicates.
8151 indices->Clear();
8152 }
8153 for (uint32_t i = 0; i < length; i++) {
8154 indices->Add(i);
8155 }
8156 if (length == range) return; // All indices accounted for already.
8157 break;
8158 }
8159 }
8160
8161 Handle<Object> prototype(object->GetPrototype());
8162 if (prototype->IsJSObject()) {
8163 // The prototype will usually have no inherited element indices,
8164 // but we have to check.
8165 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
8166 }
8167 }
8168
8169
8170 /**
8171 * A helper function that visits elements of a JSArray in numerical
8172 * order.
8173 *
8174 * The visitor argument called for each existing element in the array
8175 * with the element index and the element's value.
8176 * Afterwards it increments the base-index of the visitor by the array
8177 * length.
8178 */
8179 static void IterateElements(Handle<JSArray> receiver,
8180 ArrayConcatVisitor* visitor) {
8181 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
8182 switch (receiver->GetElementsKind()) {
8183 case JSObject::FAST_ELEMENTS: {
8184 // Run through the elements FixedArray and use HasElement and GetElement
8185 // to check the prototype for missing elements.
8186 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
8187 int fast_length = static_cast<int>(length);
8188 ASSERT(fast_length <= elements->length());
8189 for (int j = 0; j < fast_length; j++) {
8190 HandleScope loop_scope;
8191 Handle<Object> element_value(elements->get(j));
8192 if (!element_value->IsTheHole()) {
8193 visitor->visit(j, element_value);
8194 } else if (receiver->HasElement(j)) {
8195 // Call GetElement on receiver, not its prototype, or getters won't
8196 // have the correct receiver.
8197 element_value = GetElement(receiver, j);
8198 visitor->visit(j, element_value);
8199 }
8200 }
8201 break;
8202 }
8203 case JSObject::DICTIONARY_ELEMENTS: {
8204 Handle<NumberDictionary> dict(receiver->element_dictionary());
8205 List<uint32_t> indices(dict->Capacity() / 2);
8206 // Collect all indices in the object and the prototypes less
8207 // than length. This might introduce duplicates in the indices list.
8208 CollectElementIndices(receiver, length, &indices);
8209 indices.Sort(&compareUInt32);
8210 int j = 0;
8211 int n = indices.length();
8212 while (j < n) {
8213 HandleScope loop_scope;
8214 uint32_t index = indices[j];
8215 Handle<Object> element = GetElement(receiver, index);
8216 visitor->visit(index, element);
8217 // Skip to next different index (i.e., omit duplicates).
8218 do {
8219 j++;
8220 } while (j < n && indices[j] == index);
8221 }
8222 break;
8223 }
8224 case JSObject::PIXEL_ELEMENTS: {
8225 Handle<PixelArray> pixels(PixelArray::cast(receiver->elements()));
8226 for (uint32_t j = 0; j < length; j++) {
8227 Handle<Smi> e(Smi::FromInt(pixels->get(j)));
8228 visitor->visit(j, e);
8229 }
8230 break;
8231 }
8232 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
8233 IterateExternalArrayElements<ExternalByteArray, int8_t>(
8234 receiver, true, true, visitor);
8235 break;
8236 }
8237 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
8238 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
8239 receiver, true, true, visitor);
8240 break;
8241 }
8242 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
8243 IterateExternalArrayElements<ExternalShortArray, int16_t>(
8244 receiver, true, true, visitor);
8245 break;
8246 }
8247 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
8248 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
8249 receiver, true, true, visitor);
8250 break;
8251 }
8252 case JSObject::EXTERNAL_INT_ELEMENTS: {
8253 IterateExternalArrayElements<ExternalIntArray, int32_t>(
8254 receiver, true, false, visitor);
8255 break;
8256 }
8257 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
8258 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
8259 receiver, true, false, visitor);
8260 break;
8261 }
8262 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
8263 IterateExternalArrayElements<ExternalFloatArray, float>(
8264 receiver, false, false, visitor);
8265 break;
8266 }
8090 default: 8267 default:
8091 UNREACHABLE(); 8268 UNREACHABLE();
8092 break; 8269 break;
8093 } 8270 }
8094 8271 visitor->increase_index_offset(length);
8095 return num_of_elements;
8096 }
8097
8098
8099 /**
8100 * A helper function that visits elements of an Array object, and elements
8101 * on its prototypes.
8102 *
8103 * Elements on prototypes are visited first, and only elements whose indices
8104 * less than Array length are visited.
8105 *
8106 * If a ArrayConcatVisitor object is given, the visitor is called with
8107 * parameters, element's index + visitor_index_offset and the element.
8108 *
8109 * The returned number of elements is an upper bound on the actual number
8110 * of elements added. If the same element occurs in more than one object
8111 * in the array's prototype chain, it will be counted more than once, but
8112 * will only occur once in the result.
8113 */
8114 static uint32_t IterateArrayAndPrototypeElements(Handle<JSArray> array,
8115 ArrayConcatVisitor* visitor) {
8116 uint32_t range = static_cast<uint32_t>(array->length()->Number());
8117 Handle<Object> obj = array;
8118
8119 static const int kEstimatedPrototypes = 3;
8120 List< Handle<JSObject> > objects(kEstimatedPrototypes);
8121
8122 // Visit prototype first. If an element on the prototype is shadowed by
8123 // the inheritor using the same index, the ArrayConcatVisitor visits
8124 // the prototype element before the shadowing element.
8125 // The visitor can simply overwrite the old value by new value using
8126 // the same index. This follows Array::concat semantics.
8127 while (!obj->IsNull()) {
8128 objects.Add(Handle<JSObject>::cast(obj));
8129 obj = Handle<Object>(obj->GetPrototype());
8130 }
8131
8132 uint32_t nof_elements = 0;
8133 for (int i = objects.length() - 1; i >= 0; i--) {
8134 Handle<JSObject> obj = objects[i];
8135 uint32_t encountered_elements =
8136 IterateElements(Handle<JSObject>::cast(obj), range, visitor);
8137
8138 if (encountered_elements > JSObject::kMaxElementCount - nof_elements) {
8139 nof_elements = JSObject::kMaxElementCount;
8140 } else {
8141 nof_elements += encountered_elements;
8142 }
8143 }
8144
8145 return nof_elements;
8146 }
8147
8148
8149 /**
8150 * A helper function of Runtime_ArrayConcat.
8151 *
8152 * The first argument is an Array of arrays and objects. It is the
8153 * same as the arguments array of Array::concat JS function.
8154 *
8155 * If an argument is an Array object, the function visits array
8156 * elements. If an argument is not an Array object, the function
8157 * visits the object as if it is an one-element array.
8158 *
8159 * If the result array index overflows 32-bit unsigned integer, the rounded
8160 * non-negative number is used as new length. For example, if one
8161 * array length is 2^32 - 1, second array length is 1, the
8162 * concatenated array length is 0.
8163 * TODO(lrn) Change length behavior to ECMAScript 5 specification (length
8164 * is one more than the last array index to get a value assigned).
8165 */
8166 static uint32_t IterateArguments(Handle<JSArray> arguments,
8167 ArrayConcatVisitor* visitor) {
8168 uint32_t visited_elements = 0;
8169 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number());
8170
8171 for (uint32_t i = 0; i < num_of_args; i++) {
8172 Object *element;
8173 MaybeObject* maybe_element = arguments->GetElement(i);
8174 // This if() is not expected to fail, but we have the check in the
8175 // interest of hardening the runtime calls.
8176 if (maybe_element->ToObject(&element)) {
8177 Handle<Object> obj(element);
8178 if (obj->IsJSArray()) {
8179 Handle<JSArray> array = Handle<JSArray>::cast(obj);
8180 uint32_t len = static_cast<uint32_t>(array->length()->Number());
8181 uint32_t nof_elements =
8182 IterateArrayAndPrototypeElements(array, visitor);
8183 // Total elements of array and its prototype chain can be more than
8184 // the array length, but ArrayConcat can only concatenate at most
8185 // the array length number of elements. We use the length as an estimate
8186 // for the actual number of elements added.
8187 uint32_t added_elements = (nof_elements > len) ? len : nof_elements;
8188 if (JSArray::kMaxElementCount - visited_elements < added_elements) {
8189 visited_elements = JSArray::kMaxElementCount;
8190 } else {
8191 visited_elements += added_elements;
8192 }
8193 if (visitor) visitor->increase_index_offset(len);
8194 } else {
8195 if (visitor) {
8196 visitor->visit(0, obj);
8197 visitor->increase_index_offset(1);
8198 }
8199 if (visited_elements < JSArray::kMaxElementCount) {
8200 visited_elements++;
8201 }
8202 }
8203 }
8204 }
8205 return visited_elements;
8206 } 8272 }
8207 8273
8208 8274
8209 /** 8275 /**
8210 * Array::concat implementation. 8276 * Array::concat implementation.
8211 * See ECMAScript 262, 15.4.4.4. 8277 * See ECMAScript 262, 15.4.4.4.
8212 * TODO(lrn): Fix non-compliance for very large concatenations and update to 8278 * TODO(581): Fix non-compliance for very large concatenations and update to
8213 * following the ECMAScript 5 specification. 8279 * following the ECMAScript 5 specification.
8214 */ 8280 */
8215 static MaybeObject* Runtime_ArrayConcat(Arguments args) { 8281 static MaybeObject* Runtime_ArrayConcat(Arguments args) {
8216 ASSERT(args.length() == 1); 8282 ASSERT(args.length() == 1);
8217 HandleScope handle_scope; 8283 HandleScope handle_scope;
8218 8284
8219 CONVERT_CHECKED(JSArray, arg_arrays, args[0]); 8285 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
8220 Handle<JSArray> arguments(arg_arrays); 8286 int argument_count = static_cast<int>(arguments->length()->Number());
8221 8287 RUNTIME_ASSERT(arguments->HasFastElements());
8222 // Pass 1: estimate the number of elements of the result 8288 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
8223 // (it could be more than real numbers if prototype has elements). 8289
8224 uint32_t result_length = 0; 8290 // Pass 1: estimate the length and number of elements of the result.
8225 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number()); 8291 // The actual length can be larger if any of the arguments have getters
8226 8292 // that mutate other arguments (but will otherwise be precise).
8227 { AssertNoAllocation nogc; 8293 // The number of elements is precise if there are no inherited elements.
8228 for (uint32_t i = 0; i < num_of_args; i++) { 8294
8229 Object* obj; 8295 uint32_t estimate_result_length = 0;
8230 MaybeObject* maybe_object = arguments->GetElement(i); 8296 uint32_t estimate_nof_elements = 0;
8231 // This if() is not expected to fail, but we have the check in the 8297 {
8232 // interest of hardening the runtime calls. 8298 for (int i = 0; i < argument_count; i++) {
8233 if (maybe_object->ToObject(&obj)) { 8299 HandleScope loop_scope;
8234 uint32_t length_estimate; 8300 Handle<Object> obj(elements->get(i));
8235 if (obj->IsJSArray()) { 8301 uint32_t length_estimate;
8236 length_estimate = 8302 uint32_t element_estimate;
8237 static_cast<uint32_t>(JSArray::cast(obj)->length()->Number()); 8303 if (obj->IsJSArray()) {
8238 } else { 8304 Handle<JSArray> array(Handle<JSArray>::cast(obj));
8239 length_estimate = 1; 8305 length_estimate =
8240 } 8306 static_cast<uint32_t>(array->length()->Number());
8241 if (JSObject::kMaxElementCount - result_length < length_estimate) { 8307 element_estimate =
8242 result_length = JSObject::kMaxElementCount; 8308 EstimateElementCount(array);
8243 break; 8309 } else {
8244 } 8310 length_estimate = 1;
8245 result_length += length_estimate; 8311 element_estimate = 1;
8246 } 8312 }
8247 } 8313 // Avoid overflows by capping at kMaxElementCount.
8248 } 8314 if (JSObject::kMaxElementCount - estimate_result_length <
8249 8315 length_estimate) {
8250 // Allocate an empty array, will set length and content later. 8316 estimate_result_length = JSObject::kMaxElementCount;
8251 Handle<JSArray> result = Factory::NewJSArray(0); 8317 } else {
8252 8318 estimate_result_length += length_estimate;
8253 uint32_t estimate_nof_elements = IterateArguments(arguments, NULL); 8319 }
8320 if (JSObject::kMaxElementCount - estimate_nof_elements <
8321 element_estimate) {
8322 estimate_nof_elements = JSObject::kMaxElementCount;
8323 } else {
8324 estimate_nof_elements += element_estimate;
8325 }
8326 }
8327 }
8328
8254 // If estimated number of elements is more than half of length, a 8329 // If estimated number of elements is more than half of length, a
8255 // fixed array (fast case) is more time and space-efficient than a 8330 // fixed array (fast case) is more time and space-efficient than a
8256 // dictionary. 8331 // dictionary.
8257 bool fast_case = (estimate_nof_elements * 2) >= result_length; 8332 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
8258 8333
8259 Handle<FixedArray> storage; 8334 Handle<FixedArray> storage;
8260 if (fast_case) { 8335 if (fast_case) {
8261 // The backing storage array must have non-existing elements to 8336 // The backing storage array must have non-existing elements to
8262 // preserve holes across concat operations. 8337 // preserve holes across concat operations.
8263 storage = Factory::NewFixedArrayWithHoles(result_length); 8338 storage = Factory::NewFixedArrayWithHoles(estimate_result_length);
8264 Handle<Map> fast_map =
8265 Factory::GetFastElementsMap(Handle<Map>(result->map()));
8266 result->set_map(*fast_map);
8267 } else { 8339 } else {
8268 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate 8340 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
8269 uint32_t at_least_space_for = estimate_nof_elements + 8341 uint32_t at_least_space_for = estimate_nof_elements +
8270 (estimate_nof_elements >> 2); 8342 (estimate_nof_elements >> 2);
8271 storage = Handle<FixedArray>::cast( 8343 storage = Handle<FixedArray>::cast(
8272 Factory::NewNumberDictionary(at_least_space_for)); 8344 Factory::NewNumberDictionary(at_least_space_for));
8273 Handle<Map> slow_map = 8345 Handle<Map> slow_map =
8274 Factory::GetSlowElementsMap(Handle<Map>(result->map())); 8346 Factory::GetSlowElementsMap(Handle<Map>(result->map()));
8275 result->set_map(*slow_map); 8347 result->set_map(*slow_map);
8276 } 8348 }
8277 8349
8278 Handle<Object> len = Factory::NewNumber(static_cast<double>(result_length)); 8350 ArrayConcatVisitor visitor(storage, fast_case);
8279 8351
8280 ArrayConcatVisitor visitor(storage, result_length, fast_case); 8352 for (int i = 0; i < argument_count; i++) {
8353 Handle<Object> obj(elements->get(i));
8354 if (obj->IsJSArray()) {
8355 Handle<JSArray> array = Handle<JSArray>::cast(obj);
8356 IterateElements(array, &visitor);
8357 } else {
8358 visitor.visit(0, obj);
8359 visitor.increase_index_offset(1);
8360 }
8361 }
8281 8362
8282 IterateArguments(arguments, &visitor); 8363 return *visitor.ToArray();
8283
8284 result->set_length(*len);
8285 // Please note the storage might have changed in the visitor.
8286 result->set_elements(*visitor.storage());
8287
8288 return *result;
8289 } 8364 }
8290 8365
8291 8366
8292 // This will not allocate (flatten the string), but it may run 8367 // This will not allocate (flatten the string), but it may run
8293 // very slowly for very deeply nested ConsStrings. For debugging use only. 8368 // very slowly for very deeply nested ConsStrings. For debugging use only.
8294 static MaybeObject* Runtime_GlobalPrint(Arguments args) { 8369 static MaybeObject* Runtime_GlobalPrint(Arguments args) {
8295 NoHandleAllocation ha; 8370 NoHandleAllocation ha;
8296 ASSERT(args.length() == 1); 8371 ASSERT(args.length() == 1);
8297 8372
8298 CONVERT_CHECKED(String, string, args[0]); 8373 CONVERT_CHECKED(String, string, args[0]);
(...skipping 2763 matching lines...) Expand 10 before | Expand all | Expand 10 after
11062 } else { 11137 } else {
11063 // Handle last resort GC and make sure to allow future allocations 11138 // Handle last resort GC and make sure to allow future allocations
11064 // to grow the heap without causing GCs (if possible). 11139 // to grow the heap without causing GCs (if possible).
11065 Counters::gc_last_resort_from_js.Increment(); 11140 Counters::gc_last_resort_from_js.Increment();
11066 Heap::CollectAllGarbage(false); 11141 Heap::CollectAllGarbage(false);
11067 } 11142 }
11068 } 11143 }
11069 11144
11070 11145
11071 } } // namespace v8::internal 11146 } } // namespace v8::internal
OLDNEW
« src/handles.h ('K') | « src/objects-inl.h ('k') | src/version.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698