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

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: Include refactoring of HandleCell. Created 9 years, 9 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
« no previous file with comments | « src/objects-inl.h ('k') | src/version.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 22 matching lines...) Expand all
33 #include "api.h" 33 #include "api.h"
34 #include "arguments.h" 34 #include "arguments.h"
35 #include "codegen.h" 35 #include "codegen.h"
36 #include "compilation-cache.h" 36 #include "compilation-cache.h"
37 #include "compiler.h" 37 #include "compiler.h"
38 #include "cpu.h" 38 #include "cpu.h"
39 #include "dateparser-inl.h" 39 #include "dateparser-inl.h"
40 #include "debug.h" 40 #include "debug.h"
41 #include "deoptimizer.h" 41 #include "deoptimizer.h"
42 #include "execution.h" 42 #include "execution.h"
43 #include "global-handles.h"
43 #include "jsregexp.h" 44 #include "jsregexp.h"
44 #include "liveedit.h" 45 #include "liveedit.h"
45 #include "parser.h" 46 #include "parser.h"
46 #include "platform.h" 47 #include "platform.h"
47 #include "runtime.h" 48 #include "runtime.h"
48 #include "runtime-profiler.h" 49 #include "runtime-profiler.h"
49 #include "scopeinfo.h" 50 #include "scopeinfo.h"
50 #include "smart-pointer.h" 51 #include "smart-pointer.h"
51 #include "stub-cache.h" 52 #include "stub-cache.h"
52 #include "v8threads.h" 53 #include "v8threads.h"
(...skipping 7834 matching lines...) Expand 10 before | Expand all | Expand 10 after
7887 * of FixedArray, the class can be used by both fast and slow cases. 7888 * of FixedArray, the class can be used by both fast and slow cases.
7888 * The second parameter of the constructor, fast_elements, specifies 7889 * The second parameter of the constructor, fast_elements, specifies
7889 * whether the storage is a FixedArray or Dictionary. 7890 * whether the storage is a FixedArray or Dictionary.
7890 * 7891 *
7891 * An index limit is used to deal with the situation that a result array 7892 * An index limit is used to deal with the situation that a result array
7892 * length overflows 32-bit non-negative integer. 7893 * length overflows 32-bit non-negative integer.
7893 */ 7894 */
7894 class ArrayConcatVisitor { 7895 class ArrayConcatVisitor {
7895 public: 7896 public:
7896 ArrayConcatVisitor(Handle<FixedArray> storage, 7897 ArrayConcatVisitor(Handle<FixedArray> storage,
7897 uint32_t index_limit,
7898 bool fast_elements) : 7898 bool fast_elements) :
7899 storage_(storage), index_limit_(index_limit), 7899 storage_(Handle<FixedArray>::cast(GlobalHandles::Create(*storage))),
7900 index_offset_(0), fast_elements_(fast_elements) { } 7900 index_offset_(0u),
7901 fast_elements_(fast_elements) { }
7902
7903 ~ArrayConcatVisitor() {
7904 clear_storage();
7905 }
7901 7906
7902 void visit(uint32_t i, Handle<Object> elm) { 7907 void visit(uint32_t i, Handle<Object> elm) {
7903 if (i >= index_limit_ - index_offset_) return; 7908 if (i >= JSObject::kMaxElementCount - index_offset_) return;
7904 uint32_t index = index_offset_ + i; 7909 uint32_t index = index_offset_ + i;
7905 7910
7906 if (fast_elements_) { 7911 if (fast_elements_) {
7907 ASSERT(index < static_cast<uint32_t>(storage_->length())); 7912 if (index < static_cast<uint32_t>(storage_->length())) {
7908 storage_->set(index, *elm); 7913 storage_->set(index, *elm);
7909 7914 return;
7910 } else { 7915 }
7911 Handle<NumberDictionary> dict = Handle<NumberDictionary>::cast(storage_); 7916 // Our initial estimate of length was foiled, possibly by
7912 Handle<NumberDictionary> result = 7917 // getters on the arrays increasing the length of later arrays
7913 Factory::DictionaryAtNumberPut(dict, index, elm); 7918 // during iteration.
7914 if (!result.is_identical_to(dict)) 7919 // This shouldn't happen in anything but pathological cases.
7915 storage_ = result; 7920 SetDictionaryMode(index);
7916 } 7921 // Fall-through to dictionary mode.
7917 } 7922 }
7923 ASSERT(!fast_elements_);
7924 Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_));
7925 Handle<NumberDictionary> result =
7926 Factory::DictionaryAtNumberPut(dict, index, elm);
7927 if (!result.is_identical_to(dict)) {
7928 // Dictionary needed to grow.
7929 clear_storage();
7930 set_storage(*result);
7931 }
7932 }
7918 7933
7919 void increase_index_offset(uint32_t delta) { 7934 void increase_index_offset(uint32_t delta) {
7920 if (index_limit_ - index_offset_ < delta) { 7935 if (JSObject::kMaxElementCount - index_offset_ < delta) {
7921 index_offset_ = index_limit_; 7936 index_offset_ = JSObject::kMaxElementCount;
7922 } else { 7937 } else {
7923 index_offset_ += delta; 7938 index_offset_ += delta;
7924 } 7939 }
7925 } 7940 }
7926 7941
7927 Handle<FixedArray> storage() { return storage_; } 7942 Handle<JSArray> ToArray() {
7943 Handle<JSArray> array = Factory::NewJSArray(0);
7944 Handle<Object> length =
7945 Factory::NewNumber(static_cast<double>(index_offset_));
7946 Handle<Map> map;
7947 if (fast_elements_) {
7948 map = Factory::GetFastElementsMap(Handle<Map>(array->map()));
7949 } else {
7950 map = Factory::GetSlowElementsMap(Handle<Map>(array->map()));
7951 }
7952 array->set_map(*map);
7953 array->set_length(*length);
7954 array->set_elements(*storage_);
7955 return array;
7956 }
7928 7957
7929 private: 7958 private:
7930 Handle<FixedArray> storage_; 7959 // Convert storage to dictionary mode.
7931 // Limit on the accepted indices. Elements with indices larger than the 7960 void SetDictionaryMode(uint32_t index) {
7932 // limit are ignored by the visitor. 7961 ASSERT(fast_elements_);
7933 uint32_t index_limit_; 7962 Handle<FixedArray> current_storage(*storage_);
7934 // Index after last seen index. Always less than or equal to index_limit_. 7963 Handle<NumberDictionary> slow_storage(
7964 Factory::NewNumberDictionary(current_storage->length()));
7965 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
7966 for (uint32_t i = 0; i < current_length; i++) {
7967 HandleScope loop_scope;
7968 Handle<Object> element(current_storage->get(i));
7969 if (!element->IsTheHole()) {
7970 Handle<NumberDictionary> new_storage =
7971 Factory::DictionaryAtNumberPut(slow_storage, i, element);
7972 if (!new_storage.is_identical_to(slow_storage)) {
7973 slow_storage = loop_scope.CloseAndEscape(new_storage);
7974 }
7975 }
7976 }
7977 clear_storage();
7978 set_storage(*slow_storage);
7979 fast_elements_ = false;
7980 }
7981
7982 inline void clear_storage() {
7983 GlobalHandles::Destroy(Handle<Object>::cast(storage_).location());
7984 }
7985
7986 inline void set_storage(FixedArray* storage) {
7987 storage_ = Handle<FixedArray>::cast(GlobalHandles::Create(storage));
7988 }
7989
7990 Handle<FixedArray> storage_; // Always a global handle.
7991 // Index after last seen index. Always less than or equal to
7992 // JSObject::kMaxElementCount.
7935 uint32_t index_offset_; 7993 uint32_t index_offset_;
7936 const bool fast_elements_; 7994 bool fast_elements_;
7937 }; 7995 };
7938 7996
7939 7997
7998 static uint32_t EstimateElementCount(Handle<JSArray> array) {
7999 uint32_t length = static_cast<uint32_t>(array->length()->Number());
8000 int element_count = 0;
8001 switch (array->GetElementsKind()) {
8002 case JSObject::FAST_ELEMENTS: {
8003 // Fast elements can't have lengths that are not representable by
8004 // a 32-bit signed integer.
8005 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
8006 int fast_length = static_cast<int>(length);
8007 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
8008 for (int i = 0; i < fast_length; i++) {
8009 if (!elements->get(i)->IsTheHole()) element_count++;
8010 }
8011 break;
8012 }
8013 case JSObject::DICTIONARY_ELEMENTS: {
8014 Handle<NumberDictionary> dictionary(
8015 NumberDictionary::cast(array->elements()));
8016 int capacity = dictionary->Capacity();
8017 for (int i = 0; i < capacity; i++) {
8018 Handle<Object> key(dictionary->KeyAt(i));
8019 if (dictionary->IsKey(*key)) {
8020 element_count++;
8021 }
8022 }
8023 break;
8024 }
8025 default:
8026 // External arrays are always dense.
8027 return length;
8028 }
8029 // As an estimate, we assume that the prototype doesn't contain any
8030 // inherited elements.
8031 return element_count;
8032 }
8033
8034
8035
7940 template<class ExternalArrayClass, class ElementType> 8036 template<class ExternalArrayClass, class ElementType>
7941 static uint32_t IterateExternalArrayElements(Handle<JSObject> receiver, 8037 static void IterateExternalArrayElements(Handle<JSObject> receiver,
7942 bool elements_are_ints, 8038 bool elements_are_ints,
7943 bool elements_are_guaranteed_smis, 8039 bool elements_are_guaranteed_smis,
7944 uint32_t range, 8040 ArrayConcatVisitor* visitor) {
7945 ArrayConcatVisitor* visitor) {
7946 Handle<ExternalArrayClass> array( 8041 Handle<ExternalArrayClass> array(
7947 ExternalArrayClass::cast(receiver->elements())); 8042 ExternalArrayClass::cast(receiver->elements()));
7948 uint32_t len = Min(static_cast<uint32_t>(array->length()), range); 8043 uint32_t len = static_cast<uint32_t>(array->length());
7949 8044
7950 if (visitor != NULL) { 8045 ASSERT(visitor != NULL);
7951 if (elements_are_ints) { 8046 if (elements_are_ints) {
7952 if (elements_are_guaranteed_smis) { 8047 if (elements_are_guaranteed_smis) {
7953 for (uint32_t j = 0; j < len; j++) { 8048 for (uint32_t j = 0; j < len; j++) {
7954 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j)))); 8049 HandleScope loop_scope;
7955 visitor->visit(j, e); 8050 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j))));
7956 } 8051 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 } 8052 }
7970 } else { 8053 } else {
7971 for (uint32_t j = 0; j < len; j++) { 8054 for (uint32_t j = 0; j < len; j++) {
7972 Handle<Object> e = Factory::NewNumber(array->get(j)); 8055 HandleScope loop_scope;
7973 visitor->visit(j, e); 8056 int64_t val = static_cast<int64_t>(array->get(j));
7974 } 8057 if (Smi::IsValid(static_cast<intptr_t>(val))) {
7975 } 8058 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
7976 } 8059 visitor->visit(j, e);
7977 8060 } else {
7978 return len; 8061 Handle<Object> e =
7979 } 8062 Factory::NewNumber(static_cast<ElementType>(val));
7980 8063 visitor->visit(j, e);
7981 /** 8064 }
7982 * A helper function that visits elements of a JSObject. Only elements 8065 }
7983 * whose index between 0 and range (exclusive) are visited. 8066 }
7984 * 8067 } else {
7985 * If the third parameter, visitor, is not NULL, the visitor is called 8068 for (uint32_t j = 0; j < len; j++) {
7986 * with parameters, 'visitor_index_offset + element index' and the element. 8069 HandleScope loop_scope;
7987 * 8070 Handle<Object> e = Factory::NewNumber(array->get(j));
7988 * It returns the number of visisted elements. 8071 visitor->visit(j, e);
7989 */ 8072 }
7990 static uint32_t IterateElements(Handle<JSObject> receiver, 8073 }
7991 uint32_t range, 8074 }
7992 ArrayConcatVisitor* visitor) { 8075
7993 uint32_t num_of_elements = 0; 8076
7994 8077 // Used for sorting indices in a List<uint32_t>.
7995 switch (receiver->GetElementsKind()) { 8078 static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
8079 uint32_t a = *ap;
8080 uint32_t b = *bp;
8081 return (a == b) ? 0 : (a < b) ? -1 : 1;
8082 }
8083
8084
8085 static void CollectElementIndices(Handle<JSObject> object,
8086 uint32_t range,
8087 List<uint32_t>* indices) {
8088 JSObject::ElementsKind kind = object->GetElementsKind();
8089 switch (kind) {
7996 case JSObject::FAST_ELEMENTS: { 8090 case JSObject::FAST_ELEMENTS: {
7997 Handle<FixedArray> elements(FixedArray::cast(receiver->elements())); 8091 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
7998 uint32_t len = elements->length(); 8092 uint32_t length = static_cast<uint32_t>(elements->length());
7999 if (range < len) { 8093 if (range < length) length = range;
8000 len = range; 8094 for (uint32_t i = 0; i < length; i++) {
8001 } 8095 if (!elements->get(i)->IsTheHole()) {
8002 8096 indices->Add(i);
8003 for (uint32_t j = 0; j < len; j++) { 8097 }
8004 Handle<Object> e(elements->get(j)); 8098 }
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; 8099 break;
8071 } 8100 }
8072 case JSObject::DICTIONARY_ELEMENTS: { 8101 case JSObject::DICTIONARY_ELEMENTS: {
8073 Handle<NumberDictionary> dict(receiver->element_dictionary()); 8102 Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements()));
8074 uint32_t capacity = dict->Capacity(); 8103 uint32_t capacity = dict->Capacity();
8075 for (uint32_t j = 0; j < capacity; j++) { 8104 for (uint32_t j = 0; j < capacity; j++) {
8105 HandleScope loop_scope;
8076 Handle<Object> k(dict->KeyAt(j)); 8106 Handle<Object> k(dict->KeyAt(j));
8077 if (dict->IsKey(*k)) { 8107 if (dict->IsKey(*k)) {
8078 ASSERT(k->IsNumber()); 8108 ASSERT(k->IsNumber());
8079 uint32_t index = static_cast<uint32_t>(k->Number()); 8109 uint32_t index = static_cast<uint32_t>(k->Number());
8080 if (index < range) { 8110 if (index < range) {
8081 num_of_elements++; 8111 indices->Add(index);
8082 if (visitor) {
8083 visitor->visit(index, Handle<Object>(dict->ValueAt(j)));
8084 }
8085 } 8112 }
8086 } 8113 }
8087 } 8114 }
8088 break; 8115 break;
8089 } 8116 }
8117 default: {
8118 int dense_elements_length;
8119 switch (kind) {
8120 case JSObject::PIXEL_ELEMENTS: {
8121 dense_elements_length =
8122 PixelArray::cast(object->elements())->length();
8123 break;
8124 }
8125 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
8126 dense_elements_length =
8127 ExternalByteArray::cast(object->elements())->length();
8128 break;
8129 }
8130 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
8131 dense_elements_length =
8132 ExternalUnsignedByteArray::cast(object->elements())->length();
8133 break;
8134 }
8135 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
8136 dense_elements_length =
8137 ExternalShortArray::cast(object->elements())->length();
8138 break;
8139 }
8140 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
8141 dense_elements_length =
8142 ExternalUnsignedShortArray::cast(object->elements())->length();
8143 break;
8144 }
8145 case JSObject::EXTERNAL_INT_ELEMENTS: {
8146 dense_elements_length =
8147 ExternalIntArray::cast(object->elements())->length();
8148 break;
8149 }
8150 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
8151 dense_elements_length =
8152 ExternalUnsignedIntArray::cast(object->elements())->length();
8153 break;
8154 }
8155 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
8156 dense_elements_length =
8157 ExternalFloatArray::cast(object->elements())->length();
8158 break;
8159 }
8160 default:
8161 UNREACHABLE();
8162 dense_elements_length = 0;
8163 break;
8164 }
8165 uint32_t length = static_cast<uint32_t>(dense_elements_length);
8166 if (range <= length) {
8167 length = range;
8168 // We will add all indices, so we might as well clear it first
8169 // and avoid duplicates.
8170 indices->Clear();
8171 }
8172 for (uint32_t i = 0; i < length; i++) {
8173 indices->Add(i);
8174 }
8175 if (length == range) return; // All indices accounted for already.
8176 break;
8177 }
8178 }
8179
8180 Handle<Object> prototype(object->GetPrototype());
8181 if (prototype->IsJSObject()) {
8182 // The prototype will usually have no inherited element indices,
8183 // but we have to check.
8184 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
8185 }
8186 }
8187
8188
8189 /**
8190 * A helper function that visits elements of a JSArray in numerical
8191 * order.
8192 *
8193 * The visitor argument called for each existing element in the array
8194 * with the element index and the element's value.
8195 * Afterwards it increments the base-index of the visitor by the array
8196 * length.
8197 */
8198 static void IterateElements(Handle<JSArray> receiver,
8199 ArrayConcatVisitor* visitor) {
8200 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
8201 switch (receiver->GetElementsKind()) {
8202 case JSObject::FAST_ELEMENTS: {
8203 // Run through the elements FixedArray and use HasElement and GetElement
8204 // to check the prototype for missing elements.
8205 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
8206 int fast_length = static_cast<int>(length);
8207 ASSERT(fast_length <= elements->length());
8208 for (int j = 0; j < fast_length; j++) {
8209 HandleScope loop_scope;
8210 Handle<Object> element_value(elements->get(j));
8211 if (!element_value->IsTheHole()) {
8212 visitor->visit(j, element_value);
8213 } else if (receiver->HasElement(j)) {
8214 // Call GetElement on receiver, not its prototype, or getters won't
8215 // have the correct receiver.
8216 element_value = GetElement(receiver, j);
8217 visitor->visit(j, element_value);
8218 }
8219 }
8220 break;
8221 }
8222 case JSObject::DICTIONARY_ELEMENTS: {
8223 Handle<NumberDictionary> dict(receiver->element_dictionary());
8224 List<uint32_t> indices(dict->Capacity() / 2);
8225 // Collect all indices in the object and the prototypes less
8226 // than length. This might introduce duplicates in the indices list.
8227 CollectElementIndices(receiver, length, &indices);
8228 indices.Sort(&compareUInt32);
8229 int j = 0;
8230 int n = indices.length();
8231 while (j < n) {
8232 HandleScope loop_scope;
8233 uint32_t index = indices[j];
8234 Handle<Object> element = GetElement(receiver, index);
8235 visitor->visit(index, element);
8236 // Skip to next different index (i.e., omit duplicates).
8237 do {
8238 j++;
8239 } while (j < n && indices[j] == index);
8240 }
8241 break;
8242 }
8243 case JSObject::PIXEL_ELEMENTS: {
8244 Handle<PixelArray> pixels(PixelArray::cast(receiver->elements()));
8245 for (uint32_t j = 0; j < length; j++) {
8246 Handle<Smi> e(Smi::FromInt(pixels->get(j)));
8247 visitor->visit(j, e);
8248 }
8249 break;
8250 }
8251 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
8252 IterateExternalArrayElements<ExternalByteArray, int8_t>(
8253 receiver, true, true, visitor);
8254 break;
8255 }
8256 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
8257 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
8258 receiver, true, true, visitor);
8259 break;
8260 }
8261 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
8262 IterateExternalArrayElements<ExternalShortArray, int16_t>(
8263 receiver, true, true, visitor);
8264 break;
8265 }
8266 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
8267 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
8268 receiver, true, true, visitor);
8269 break;
8270 }
8271 case JSObject::EXTERNAL_INT_ELEMENTS: {
8272 IterateExternalArrayElements<ExternalIntArray, int32_t>(
8273 receiver, true, false, visitor);
8274 break;
8275 }
8276 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
8277 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
8278 receiver, true, false, visitor);
8279 break;
8280 }
8281 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
8282 IterateExternalArrayElements<ExternalFloatArray, float>(
8283 receiver, false, false, visitor);
8284 break;
8285 }
8090 default: 8286 default:
8091 UNREACHABLE(); 8287 UNREACHABLE();
8092 break; 8288 break;
8093 } 8289 }
8094 8290 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 } 8291 }
8207 8292
8208 8293
8209 /** 8294 /**
8210 * Array::concat implementation. 8295 * Array::concat implementation.
8211 * See ECMAScript 262, 15.4.4.4. 8296 * See ECMAScript 262, 15.4.4.4.
8212 * TODO(lrn): Fix non-compliance for very large concatenations and update to 8297 * TODO(581): Fix non-compliance for very large concatenations and update to
8213 * following the ECMAScript 5 specification. 8298 * following the ECMAScript 5 specification.
8214 */ 8299 */
8215 static MaybeObject* Runtime_ArrayConcat(Arguments args) { 8300 static MaybeObject* Runtime_ArrayConcat(Arguments args) {
8216 ASSERT(args.length() == 1); 8301 ASSERT(args.length() == 1);
8217 HandleScope handle_scope; 8302 HandleScope handle_scope;
8218 8303
8219 CONVERT_CHECKED(JSArray, arg_arrays, args[0]); 8304 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
8220 Handle<JSArray> arguments(arg_arrays); 8305 int argument_count = static_cast<int>(arguments->length()->Number());
8221 8306 RUNTIME_ASSERT(arguments->HasFastElements());
8222 // Pass 1: estimate the number of elements of the result 8307 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
8223 // (it could be more than real numbers if prototype has elements). 8308
8224 uint32_t result_length = 0; 8309 // 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()); 8310 // The actual length can be larger if any of the arguments have getters
8226 8311 // that mutate other arguments (but will otherwise be precise).
8227 { AssertNoAllocation nogc; 8312 // The number of elements is precise if there are no inherited elements.
8228 for (uint32_t i = 0; i < num_of_args; i++) { 8313
8229 Object* obj; 8314 uint32_t estimate_result_length = 0;
8230 MaybeObject* maybe_object = arguments->GetElement(i); 8315 uint32_t estimate_nof_elements = 0;
8231 // This if() is not expected to fail, but we have the check in the 8316 {
8232 // interest of hardening the runtime calls. 8317 for (int i = 0; i < argument_count; i++) {
8233 if (maybe_object->ToObject(&obj)) { 8318 HandleScope loop_scope;
8234 uint32_t length_estimate; 8319 Handle<Object> obj(elements->get(i));
8235 if (obj->IsJSArray()) { 8320 uint32_t length_estimate;
8236 length_estimate = 8321 uint32_t element_estimate;
8237 static_cast<uint32_t>(JSArray::cast(obj)->length()->Number()); 8322 if (obj->IsJSArray()) {
8238 } else { 8323 Handle<JSArray> array(Handle<JSArray>::cast(obj));
8239 length_estimate = 1; 8324 length_estimate =
8240 } 8325 static_cast<uint32_t>(array->length()->Number());
8241 if (JSObject::kMaxElementCount - result_length < length_estimate) { 8326 element_estimate =
8242 result_length = JSObject::kMaxElementCount; 8327 EstimateElementCount(array);
8243 break; 8328 } else {
8244 } 8329 length_estimate = 1;
8245 result_length += length_estimate; 8330 element_estimate = 1;
8246 } 8331 }
8247 } 8332 // Avoid overflows by capping at kMaxElementCount.
8248 } 8333 if (JSObject::kMaxElementCount - estimate_result_length <
8249 8334 length_estimate) {
8250 // Allocate an empty array, will set length and content later. 8335 estimate_result_length = JSObject::kMaxElementCount;
8251 Handle<JSArray> result = Factory::NewJSArray(0); 8336 } else {
8252 8337 estimate_result_length += length_estimate;
8253 uint32_t estimate_nof_elements = IterateArguments(arguments, NULL); 8338 }
8339 if (JSObject::kMaxElementCount - estimate_nof_elements <
8340 element_estimate) {
8341 estimate_nof_elements = JSObject::kMaxElementCount;
8342 } else {
8343 estimate_nof_elements += element_estimate;
8344 }
8345 }
8346 }
8347
8254 // If estimated number of elements is more than half of length, a 8348 // 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 8349 // fixed array (fast case) is more time and space-efficient than a
8256 // dictionary. 8350 // dictionary.
8257 bool fast_case = (estimate_nof_elements * 2) >= result_length; 8351 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
8258 8352
8259 Handle<FixedArray> storage; 8353 Handle<FixedArray> storage;
8260 if (fast_case) { 8354 if (fast_case) {
8261 // The backing storage array must have non-existing elements to 8355 // The backing storage array must have non-existing elements to
8262 // preserve holes across concat operations. 8356 // preserve holes across concat operations.
8263 storage = Factory::NewFixedArrayWithHoles(result_length); 8357 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 { 8358 } else {
8268 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate 8359 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
8269 uint32_t at_least_space_for = estimate_nof_elements + 8360 uint32_t at_least_space_for = estimate_nof_elements +
8270 (estimate_nof_elements >> 2); 8361 (estimate_nof_elements >> 2);
8271 storage = Handle<FixedArray>::cast( 8362 storage = Handle<FixedArray>::cast(
8272 Factory::NewNumberDictionary(at_least_space_for)); 8363 Factory::NewNumberDictionary(at_least_space_for));
8273 Handle<Map> slow_map = 8364 }
8274 Factory::GetSlowElementsMap(Handle<Map>(result->map())); 8365
8275 result->set_map(*slow_map); 8366 ArrayConcatVisitor visitor(storage, fast_case);
8276 } 8367
8277 8368 for (int i = 0; i < argument_count; i++) {
8278 Handle<Object> len = Factory::NewNumber(static_cast<double>(result_length)); 8369 Handle<Object> obj(elements->get(i));
8279 8370 if (obj->IsJSArray()) {
8280 ArrayConcatVisitor visitor(storage, result_length, fast_case); 8371 Handle<JSArray> array = Handle<JSArray>::cast(obj);
8281 8372 IterateElements(array, &visitor);
8282 IterateArguments(arguments, &visitor); 8373 } else {
8283 8374 visitor.visit(0, obj);
8284 result->set_length(*len); 8375 visitor.increase_index_offset(1);
8285 // Please note the storage might have changed in the visitor. 8376 }
8286 result->set_elements(*visitor.storage()); 8377 }
8287 8378
8288 return *result; 8379 return *visitor.ToArray();
8289 } 8380 }
8290 8381
8291 8382
8292 // This will not allocate (flatten the string), but it may run 8383 // This will not allocate (flatten the string), but it may run
8293 // very slowly for very deeply nested ConsStrings. For debugging use only. 8384 // very slowly for very deeply nested ConsStrings. For debugging use only.
8294 static MaybeObject* Runtime_GlobalPrint(Arguments args) { 8385 static MaybeObject* Runtime_GlobalPrint(Arguments args) {
8295 NoHandleAllocation ha; 8386 NoHandleAllocation ha;
8296 ASSERT(args.length() == 1); 8387 ASSERT(args.length() == 1);
8297 8388
8298 CONVERT_CHECKED(String, string, args[0]); 8389 CONVERT_CHECKED(String, string, args[0]);
8299 StringInputBuffer buffer(string); 8390 StringInputBuffer buffer(string);
8300 while (buffer.has_more()) { 8391 while (buffer.has_more()) {
8301 uint16_t character = buffer.GetNext(); 8392 uint16_t character = buffer.GetNext();
(...skipping 2760 matching lines...) Expand 10 before | Expand all | Expand 10 after
11062 } else { 11153 } else {
11063 // Handle last resort GC and make sure to allow future allocations 11154 // Handle last resort GC and make sure to allow future allocations
11064 // to grow the heap without causing GCs (if possible). 11155 // to grow the heap without causing GCs (if possible).
11065 Counters::gc_last_resort_from_js.Increment(); 11156 Counters::gc_last_resort_from_js.Increment();
11066 Heap::CollectAllGarbage(false); 11157 Heap::CollectAllGarbage(false);
11067 } 11158 }
11068 } 11159 }
11069 11160
11070 11161
11071 } } // namespace v8::internal 11162 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/objects-inl.h ('k') | src/version.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698