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

Side by Side Diff: src/runtime.cc

Issue 6588047: Version 3.1.7... (Closed) Base URL: http://v8.googlecode.com/svn/trunk/
Patch Set: 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/spaces.h » ('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 7002 matching lines...) Expand 10 before | Expand all | Expand 10 after
7013 if (FLAG_trace_opt) { 7013 if (FLAG_trace_opt) {
7014 PrintF("[failed to optimize "); 7014 PrintF("[failed to optimize ");
7015 function->PrintName(); 7015 function->PrintName();
7016 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n", 7016 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
7017 function->shared()->code()->optimizable() ? "T" : "F", 7017 function->shared()->code()->optimizable() ? "T" : "F",
7018 Debug::has_break_points() ? "T" : "F"); 7018 Debug::has_break_points() ? "T" : "F");
7019 } 7019 }
7020 function->ReplaceCode(function->shared()->code()); 7020 function->ReplaceCode(function->shared()->code());
7021 return function->code(); 7021 return function->code();
7022 } 7022 }
7023 if (CompileOptimized(function, AstNode::kNoNumber)) { 7023 if (CompileOptimized(function, AstNode::kNoNumber, CLEAR_EXCEPTION)) {
7024 return function->code(); 7024 return function->code();
7025 } 7025 }
7026 if (FLAG_trace_opt) { 7026 if (FLAG_trace_opt) {
7027 PrintF("[failed to optimize "); 7027 PrintF("[failed to optimize ");
7028 function->PrintName(); 7028 function->PrintName();
7029 PrintF(": optimized compilation failed]\n"); 7029 PrintF(": optimized compilation failed]\n");
7030 } 7030 }
7031 function->ReplaceCode(function->shared()->code()); 7031 function->ReplaceCode(function->shared()->code());
7032 return Failure::Exception(); 7032 return function->code();
7033 } 7033 }
7034 7034
7035 7035
7036 static MaybeObject* Runtime_NotifyDeoptimized(Arguments args) { 7036 static MaybeObject* Runtime_NotifyDeoptimized(Arguments args) {
7037 HandleScope scope; 7037 HandleScope scope;
7038 ASSERT(args.length() == 1); 7038 ASSERT(args.length() == 1);
7039 RUNTIME_ASSERT(args[0]->IsSmi()); 7039 RUNTIME_ASSERT(args[0]->IsSmi());
7040 Deoptimizer::BailoutType type = 7040 Deoptimizer::BailoutType type =
7041 static_cast<Deoptimizer::BailoutType>(Smi::cast(args[0])->value()); 7041 static_cast<Deoptimizer::BailoutType>(Smi::cast(args[0])->value());
7042 Deoptimizer* deoptimizer = Deoptimizer::Grab(); 7042 Deoptimizer* deoptimizer = Deoptimizer::Grab();
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after
7182 ASSERT(ast_id != AstNode::kNoNumber); 7182 ASSERT(ast_id != AstNode::kNoNumber);
7183 if (FLAG_trace_osr) { 7183 if (FLAG_trace_osr) {
7184 PrintF("[replacing on-stack at AST id %d in ", ast_id); 7184 PrintF("[replacing on-stack at AST id %d in ", ast_id);
7185 function->PrintName(); 7185 function->PrintName();
7186 PrintF("]\n"); 7186 PrintF("]\n");
7187 } 7187 }
7188 7188
7189 // Try to compile the optimized code. A true return value from 7189 // Try to compile the optimized code. A true return value from
7190 // CompileOptimized means that compilation succeeded, not necessarily 7190 // CompileOptimized means that compilation succeeded, not necessarily
7191 // that optimization succeeded. 7191 // that optimization succeeded.
7192 if (CompileOptimized(function, ast_id) && function->IsOptimized()) { 7192 if (CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
7193 function->IsOptimized()) {
7193 DeoptimizationInputData* data = DeoptimizationInputData::cast( 7194 DeoptimizationInputData* data = DeoptimizationInputData::cast(
7194 function->code()->deoptimization_data()); 7195 function->code()->deoptimization_data());
7195 if (data->OsrPcOffset()->value() >= 0) { 7196 if (data->OsrPcOffset()->value() >= 0) {
7196 if (FLAG_trace_osr) { 7197 if (FLAG_trace_osr) {
7197 PrintF("[on-stack replacement offset %d in optimized code]\n", 7198 PrintF("[on-stack replacement offset %d in optimized code]\n",
7198 data->OsrPcOffset()->value()); 7199 data->OsrPcOffset()->value());
7199 } 7200 }
7200 ASSERT(data->OsrAstId()->value() == ast_id); 7201 ASSERT(data->OsrAstId()->value() == ast_id);
7201 } else { 7202 } else {
7202 // We may never generate the desired OSR entry if we emit an 7203 // We may never generate the desired OSR entry if we emit an
(...skipping 22 matching lines...) Expand all
7225 // Allow OSR only at nesting level zero again. 7226 // Allow OSR only at nesting level zero again.
7226 unoptimized->set_allow_osr_at_loop_nesting_level(0); 7227 unoptimized->set_allow_osr_at_loop_nesting_level(0);
7227 7228
7228 // If the optimization attempt succeeded, return the AST id tagged as a 7229 // If the optimization attempt succeeded, return the AST id tagged as a
7229 // smi. This tells the builtin that we need to translate the unoptimized 7230 // smi. This tells the builtin that we need to translate the unoptimized
7230 // frame to an optimized one. 7231 // frame to an optimized one.
7231 if (succeeded) { 7232 if (succeeded) {
7232 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION); 7233 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
7233 return Smi::FromInt(ast_id); 7234 return Smi::FromInt(ast_id);
7234 } else { 7235 } else {
7236 if (function->IsMarkedForLazyRecompilation()) {
7237 function->ReplaceCode(function->shared()->code());
7238 }
7235 return Smi::FromInt(-1); 7239 return Smi::FromInt(-1);
7236 } 7240 }
7237 } 7241 }
7238 7242
7239 7243
7240 static MaybeObject* Runtime_GetFunctionDelegate(Arguments args) { 7244 static MaybeObject* Runtime_GetFunctionDelegate(Arguments args) {
7241 HandleScope scope; 7245 HandleScope scope;
7242 ASSERT(args.length() == 1); 7246 ASSERT(args.length() == 1);
7243 RUNTIME_ASSERT(!args[0]->IsJSFunction()); 7247 RUNTIME_ASSERT(!args[0]->IsJSFunction());
7244 return *Execution::GetFunctionDelegate(args.at<Object>(0)); 7248 return *Execution::GetFunctionDelegate(args.at<Object>(0));
(...skipping 776 matching lines...) Expand 10 before | Expand all | Expand 10 after
8021 * of FixedArray, the class can be used by both fast and slow cases. 8025 * of FixedArray, the class can be used by both fast and slow cases.
8022 * The second parameter of the constructor, fast_elements, specifies 8026 * The second parameter of the constructor, fast_elements, specifies
8023 * whether the storage is a FixedArray or Dictionary. 8027 * whether the storage is a FixedArray or Dictionary.
8024 * 8028 *
8025 * An index limit is used to deal with the situation that a result array 8029 * An index limit is used to deal with the situation that a result array
8026 * length overflows 32-bit non-negative integer. 8030 * length overflows 32-bit non-negative integer.
8027 */ 8031 */
8028 class ArrayConcatVisitor { 8032 class ArrayConcatVisitor {
8029 public: 8033 public:
8030 ArrayConcatVisitor(Handle<FixedArray> storage, 8034 ArrayConcatVisitor(Handle<FixedArray> storage,
8031 uint32_t index_limit,
8032 bool fast_elements) : 8035 bool fast_elements) :
8033 storage_(storage), index_limit_(index_limit), 8036 storage_(storage),
8034 index_offset_(0), fast_elements_(fast_elements) { } 8037 index_offset_(0u),
8038 fast_elements_(fast_elements) { }
8035 8039
8036 void visit(uint32_t i, Handle<Object> elm) { 8040 void visit(uint32_t i, Handle<Object> elm) {
8037 if (i >= index_limit_ - index_offset_) return; 8041 if (i >= JSObject::kMaxElementCount - index_offset_) return;
8038 uint32_t index = index_offset_ + i; 8042 uint32_t index = index_offset_ + i;
8039 8043
8040 if (fast_elements_) { 8044 if (fast_elements_) {
8041 ASSERT(index < static_cast<uint32_t>(storage_->length())); 8045 if (index < static_cast<uint32_t>(storage_->length())) {
8042 storage_->set(index, *elm); 8046 storage_->set(index, *elm);
8043 8047 return;
8044 } else { 8048 }
8045 Handle<NumberDictionary> dict = Handle<NumberDictionary>::cast(storage_); 8049 // Our initial estimate of length was foiled, possibly by
8046 Handle<NumberDictionary> result = 8050 // getters on the arrays increasing the length of later arrays
8047 Factory::DictionaryAtNumberPut(dict, index, elm); 8051 // during iteration.
8048 if (!result.is_identical_to(dict)) 8052 // This shouldn't happen in anything but pathological cases.
8049 storage_ = result; 8053 SetDictionaryMode(index);
8050 } 8054 // Fall-through to dictionary mode.
8051 } 8055 }
8056 ASSERT(!fast_elements_);
8057 Handle<NumberDictionary> dict(storage_.cast<NumberDictionary>());
8058 Handle<NumberDictionary> result =
8059 Factory::DictionaryAtNumberPut(dict, index, elm);
8060 if (!result.is_identical_to(dict)) {
8061 storage_ = Handle<FixedArray>::cast(result);
8062 }
8063 }
8052 8064
8053 void increase_index_offset(uint32_t delta) { 8065 void increase_index_offset(uint32_t delta) {
8054 if (index_limit_ - index_offset_ < delta) { 8066 if (JSObject::kMaxElementCount - index_offset_ < delta) {
8055 index_offset_ = index_limit_; 8067 index_offset_ = JSObject::kMaxElementCount;
8056 } else { 8068 } else {
8057 index_offset_ += delta; 8069 index_offset_ += delta;
8058 } 8070 }
8059 } 8071 }
8060 8072
8061 Handle<FixedArray> storage() { return storage_; } 8073 Handle<JSArray> ToArray() {
8074 Handle<JSArray> array = Factory::NewJSArray(0);
8075 Handle<Object> length =
8076 Factory::NewNumber(static_cast<double>(index_offset_));
8077 Handle<Map> map;
8078 if (fast_elements_) {
8079 map = Factory::GetFastElementsMap(Handle<Map>(array->map()));
8080 } else {
8081 map = Factory::GetSlowElementsMap(Handle<Map>(array->map()));
8082 }
8083 array->set_map(*map);
8084 array->set_length(*length);
8085 array->set_elements(*storage_);
8086 return array;
8087 }
8062 8088
8063 private: 8089 private:
8064 Handle<FixedArray> storage_; 8090 // Convert storage to dictionary mode.
8065 // Limit on the accepted indices. Elements with indices larger than the 8091 void SetDictionaryMode(uint32_t index) {
8066 // limit are ignored by the visitor. 8092 ASSERT(fast_elements_);
8067 uint32_t index_limit_; 8093 Handle<FixedArray> current_storage(storage_.ToHandle());
8068 // Index after last seen index. Always less than or equal to index_limit_. 8094 HandleCell<NumberDictionary> slow_storage(
8095 Factory::NewNumberDictionary(current_storage->length()));
8096 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
8097 for (uint32_t i = 0; i < current_length; i++) {
8098 HandleScope loop_scope;
8099 Handle<Object> element(current_storage->get(i));
8100 if (!element->IsTheHole()) {
8101 slow_storage =
8102 Factory::DictionaryAtNumberPut(slow_storage.ToHandle(), i, element);
8103 }
8104 }
8105 storage_ = slow_storage.cast<FixedArray>();
8106 fast_elements_ = false;
8107 }
8108
8109 HandleCell<FixedArray> storage_;
8110 // Index after last seen index. Always less than or equal to
8111 // JSObject::kMaxElementCount.
8069 uint32_t index_offset_; 8112 uint32_t index_offset_;
8070 const bool fast_elements_; 8113 bool fast_elements_;
8071 }; 8114 };
8072 8115
8073 8116
8117 static uint32_t EstimateElementCount(Handle<JSArray> array) {
8118 uint32_t length = static_cast<uint32_t>(array->length()->Number());
8119 int element_count = 0;
8120 switch (array->GetElementsKind()) {
8121 case JSObject::FAST_ELEMENTS: {
8122 // Fast elements can't have lengths that are not representable by
8123 // a 32-bit signed integer.
8124 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
8125 int fast_length = static_cast<int>(length);
8126 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
8127 for (int i = 0; i < fast_length; i++) {
8128 if (!elements->get(i)->IsTheHole()) element_count++;
8129 }
8130 break;
8131 }
8132 case JSObject::DICTIONARY_ELEMENTS: {
8133 Handle<NumberDictionary> dictionary(
8134 NumberDictionary::cast(array->elements()));
8135 int capacity = dictionary->Capacity();
8136 for (int i = 0; i < capacity; i++) {
8137 Handle<Object> key(dictionary->KeyAt(i));
8138 if (dictionary->IsKey(*key)) {
8139 element_count++;
8140 }
8141 }
8142 break;
8143 }
8144 default:
8145 // External arrays are always dense.
8146 return length;
8147 }
8148 // As an estimate, we assume that the prototype doesn't contain any
8149 // inherited elements.
8150 return element_count;
8151 }
8152
8153
8154
8074 template<class ExternalArrayClass, class ElementType> 8155 template<class ExternalArrayClass, class ElementType>
8075 static uint32_t IterateExternalArrayElements(Handle<JSObject> receiver, 8156 static void IterateExternalArrayElements(Handle<JSObject> receiver,
8076 bool elements_are_ints, 8157 bool elements_are_ints,
8077 bool elements_are_guaranteed_smis, 8158 bool elements_are_guaranteed_smis,
8078 uint32_t range, 8159 ArrayConcatVisitor* visitor) {
8079 ArrayConcatVisitor* visitor) {
8080 Handle<ExternalArrayClass> array( 8160 Handle<ExternalArrayClass> array(
8081 ExternalArrayClass::cast(receiver->elements())); 8161 ExternalArrayClass::cast(receiver->elements()));
8082 uint32_t len = Min(static_cast<uint32_t>(array->length()), range); 8162 uint32_t len = static_cast<uint32_t>(array->length());
8083 8163
8084 if (visitor != NULL) { 8164 ASSERT(visitor != NULL);
8085 if (elements_are_ints) { 8165 if (elements_are_ints) {
8086 if (elements_are_guaranteed_smis) { 8166 if (elements_are_guaranteed_smis) {
8087 for (uint32_t j = 0; j < len; j++) { 8167 for (uint32_t j = 0; j < len; j++) {
8088 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j)))); 8168 HandleScope loop_scope;
8089 visitor->visit(j, e); 8169 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j))));
8090 } 8170 visitor->visit(j, e);
8091 } else {
8092 for (uint32_t j = 0; j < len; j++) {
8093 int64_t val = static_cast<int64_t>(array->get(j));
8094 if (Smi::IsValid(static_cast<intptr_t>(val))) {
8095 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
8096 visitor->visit(j, e);
8097 } else {
8098 Handle<Object> e =
8099 Factory::NewNumber(static_cast<ElementType>(val));
8100 visitor->visit(j, e);
8101 }
8102 }
8103 } 8171 }
8104 } else { 8172 } else {
8105 for (uint32_t j = 0; j < len; j++) { 8173 for (uint32_t j = 0; j < len; j++) {
8106 Handle<Object> e = Factory::NewNumber(array->get(j)); 8174 HandleScope loop_scope;
8107 visitor->visit(j, e); 8175 int64_t val = static_cast<int64_t>(array->get(j));
8108 } 8176 if (Smi::IsValid(static_cast<intptr_t>(val))) {
8109 } 8177 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
8110 } 8178 visitor->visit(j, e);
8111 8179 } else {
8112 return len; 8180 Handle<Object> e =
8113 } 8181 Factory::NewNumber(static_cast<ElementType>(val));
8114 8182 visitor->visit(j, e);
8115 /** 8183 }
8116 * A helper function that visits elements of a JSObject. Only elements 8184 }
8117 * whose index between 0 and range (exclusive) are visited. 8185 }
8118 * 8186 } else {
8119 * If the third parameter, visitor, is not NULL, the visitor is called 8187 for (uint32_t j = 0; j < len; j++) {
8120 * with parameters, 'visitor_index_offset + element index' and the element. 8188 HandleScope loop_scope;
8121 * 8189 Handle<Object> e = Factory::NewNumber(array->get(j));
8122 * It returns the number of visisted elements. 8190 visitor->visit(j, e);
8123 */ 8191 }
8124 static uint32_t IterateElements(Handle<JSObject> receiver, 8192 }
8125 uint32_t range, 8193 }
8126 ArrayConcatVisitor* visitor) { 8194
8127 uint32_t num_of_elements = 0; 8195
8128 8196 // Used for sorting indices in a List<uint32_t>.
8129 switch (receiver->GetElementsKind()) { 8197 static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
8198 uint32_t a = *ap;
8199 uint32_t b = *bp;
8200 return (a == b) ? 0 : (a < b) ? -1 : 1;
8201 }
8202
8203
8204 static void CollectElementIndices(Handle<JSObject> object,
8205 uint32_t range,
8206 List<uint32_t>* indices) {
8207 JSObject::ElementsKind kind = object->GetElementsKind();
8208 switch (kind) {
8130 case JSObject::FAST_ELEMENTS: { 8209 case JSObject::FAST_ELEMENTS: {
8131 Handle<FixedArray> elements(FixedArray::cast(receiver->elements())); 8210 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
8132 uint32_t len = elements->length(); 8211 uint32_t length = static_cast<uint32_t>(elements->length());
8133 if (range < len) { 8212 if (range < length) length = range;
8134 len = range; 8213 for (uint32_t i = 0; i < length; i++) {
8135 } 8214 if (!elements->get(i)->IsTheHole()) {
8136 8215 indices->Add(i);
8137 for (uint32_t j = 0; j < len; j++) { 8216 }
8138 Handle<Object> e(elements->get(j)); 8217 }
8139 if (!e->IsTheHole()) {
8140 num_of_elements++;
8141 if (visitor) {
8142 visitor->visit(j, e);
8143 }
8144 }
8145 }
8146 break;
8147 }
8148 case JSObject::PIXEL_ELEMENTS: {
8149 Handle<PixelArray> pixels(PixelArray::cast(receiver->elements()));
8150 uint32_t len = pixels->length();
8151 if (range < len) {
8152 len = range;
8153 }
8154
8155 for (uint32_t j = 0; j < len; j++) {
8156 num_of_elements++;
8157 if (visitor != NULL) {
8158 Handle<Smi> e(Smi::FromInt(pixels->get(j)));
8159 visitor->visit(j, e);
8160 }
8161 }
8162 break;
8163 }
8164 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
8165 num_of_elements =
8166 IterateExternalArrayElements<ExternalByteArray, int8_t>(
8167 receiver, true, true, range, visitor);
8168 break;
8169 }
8170 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
8171 num_of_elements =
8172 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
8173 receiver, true, true, range, visitor);
8174 break;
8175 }
8176 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
8177 num_of_elements =
8178 IterateExternalArrayElements<ExternalShortArray, int16_t>(
8179 receiver, true, true, range, visitor);
8180 break;
8181 }
8182 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
8183 num_of_elements =
8184 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
8185 receiver, true, true, range, visitor);
8186 break;
8187 }
8188 case JSObject::EXTERNAL_INT_ELEMENTS: {
8189 num_of_elements =
8190 IterateExternalArrayElements<ExternalIntArray, int32_t>(
8191 receiver, true, false, range, visitor);
8192 break;
8193 }
8194 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
8195 num_of_elements =
8196 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
8197 receiver, true, false, range, visitor);
8198 break;
8199 }
8200 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
8201 num_of_elements =
8202 IterateExternalArrayElements<ExternalFloatArray, float>(
8203 receiver, false, false, range, visitor);
8204 break; 8218 break;
8205 } 8219 }
8206 case JSObject::DICTIONARY_ELEMENTS: { 8220 case JSObject::DICTIONARY_ELEMENTS: {
8207 Handle<NumberDictionary> dict(receiver->element_dictionary()); 8221 Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements()));
8208 uint32_t capacity = dict->Capacity(); 8222 uint32_t capacity = dict->Capacity();
8209 for (uint32_t j = 0; j < capacity; j++) { 8223 for (uint32_t j = 0; j < capacity; j++) {
8224 HandleScope loop_scope;
8210 Handle<Object> k(dict->KeyAt(j)); 8225 Handle<Object> k(dict->KeyAt(j));
8211 if (dict->IsKey(*k)) { 8226 if (dict->IsKey(*k)) {
8212 ASSERT(k->IsNumber()); 8227 ASSERT(k->IsNumber());
8213 uint32_t index = static_cast<uint32_t>(k->Number()); 8228 uint32_t index = static_cast<uint32_t>(k->Number());
8214 if (index < range) { 8229 if (index < range) {
8215 num_of_elements++; 8230 indices->Add(index);
8216 if (visitor) {
8217 visitor->visit(index, Handle<Object>(dict->ValueAt(j)));
8218 }
8219 } 8231 }
8220 } 8232 }
8221 } 8233 }
8222 break; 8234 break;
8223 } 8235 }
8236 default: {
8237 int dense_elements_length;
8238 switch (kind) {
8239 case JSObject::PIXEL_ELEMENTS: {
8240 dense_elements_length =
8241 PixelArray::cast(object->elements())->length();
8242 break;
8243 }
8244 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
8245 dense_elements_length =
8246 ExternalByteArray::cast(object->elements())->length();
8247 break;
8248 }
8249 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
8250 dense_elements_length =
8251 ExternalUnsignedByteArray::cast(object->elements())->length();
8252 break;
8253 }
8254 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
8255 dense_elements_length =
8256 ExternalShortArray::cast(object->elements())->length();
8257 break;
8258 }
8259 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
8260 dense_elements_length =
8261 ExternalUnsignedShortArray::cast(object->elements())->length();
8262 break;
8263 }
8264 case JSObject::EXTERNAL_INT_ELEMENTS: {
8265 dense_elements_length =
8266 ExternalIntArray::cast(object->elements())->length();
8267 break;
8268 }
8269 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
8270 dense_elements_length =
8271 ExternalUnsignedIntArray::cast(object->elements())->length();
8272 break;
8273 }
8274 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
8275 dense_elements_length =
8276 ExternalFloatArray::cast(object->elements())->length();
8277 break;
8278 }
8279 default:
8280 UNREACHABLE();
8281 dense_elements_length = 0;
8282 break;
8283 }
8284 uint32_t length = static_cast<uint32_t>(dense_elements_length);
8285 if (range <= length) {
8286 length = range;
8287 // We will add all indices, so we might as well clear it first
8288 // and avoid duplicates.
8289 indices->Clear();
8290 }
8291 for (uint32_t i = 0; i < length; i++) {
8292 indices->Add(i);
8293 }
8294 if (length == range) return; // All indices accounted for already.
8295 break;
8296 }
8297 }
8298
8299 Handle<Object> prototype(object->GetPrototype());
8300 if (prototype->IsJSObject()) {
8301 // The prototype will usually have no inherited element indices,
8302 // but we have to check.
8303 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
8304 }
8305 }
8306
8307
8308 /**
8309 * A helper function that visits elements of a JSArray in numerical
8310 * order.
8311 *
8312 * The visitor argument called for each existing element in the array
8313 * with the element index and the element's value.
8314 * Afterwards it increments the base-index of the visitor by the array
8315 * length.
8316 */
8317 static void IterateElements(Handle<JSArray> receiver,
8318 ArrayConcatVisitor* visitor) {
8319 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
8320 switch (receiver->GetElementsKind()) {
8321 case JSObject::FAST_ELEMENTS: {
8322 // Run through the elements FixedArray and use HasElement and GetElement
8323 // to check the prototype for missing elements.
8324 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
8325 int fast_length = static_cast<int>(length);
8326 ASSERT(fast_length <= elements->length());
8327 for (int j = 0; j < fast_length; j++) {
8328 HandleScope loop_scope;
8329 Handle<Object> element_value(elements->get(j));
8330 if (!element_value->IsTheHole()) {
8331 visitor->visit(j, element_value);
8332 } else if (receiver->HasElement(j)) {
8333 // Call GetElement on receiver, not its prototype, or getters won't
8334 // have the correct receiver.
8335 element_value = GetElement(receiver, j);
8336 visitor->visit(j, element_value);
8337 }
8338 }
8339 break;
8340 }
8341 case JSObject::DICTIONARY_ELEMENTS: {
8342 Handle<NumberDictionary> dict(receiver->element_dictionary());
8343 List<uint32_t> indices(dict->Capacity() / 2);
8344 // Collect all indices in the object and the prototypes less
8345 // than length. This might introduce duplicates in the indices list.
8346 CollectElementIndices(receiver, length, &indices);
8347 indices.Sort(&compareUInt32);
8348 int j = 0;
8349 int n = indices.length();
8350 while (j < n) {
8351 HandleScope loop_scope;
8352 uint32_t index = indices[j];
8353 Handle<Object> element = GetElement(receiver, index);
8354 visitor->visit(index, element);
8355 // Skip to next different index (i.e., omit duplicates).
8356 do {
8357 j++;
8358 } while (j < n && indices[j] == index);
8359 }
8360 break;
8361 }
8362 case JSObject::PIXEL_ELEMENTS: {
8363 Handle<PixelArray> pixels(PixelArray::cast(receiver->elements()));
8364 for (uint32_t j = 0; j < length; j++) {
8365 Handle<Smi> e(Smi::FromInt(pixels->get(j)));
8366 visitor->visit(j, e);
8367 }
8368 break;
8369 }
8370 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
8371 IterateExternalArrayElements<ExternalByteArray, int8_t>(
8372 receiver, true, true, visitor);
8373 break;
8374 }
8375 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
8376 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
8377 receiver, true, true, visitor);
8378 break;
8379 }
8380 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
8381 IterateExternalArrayElements<ExternalShortArray, int16_t>(
8382 receiver, true, true, visitor);
8383 break;
8384 }
8385 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
8386 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
8387 receiver, true, true, visitor);
8388 break;
8389 }
8390 case JSObject::EXTERNAL_INT_ELEMENTS: {
8391 IterateExternalArrayElements<ExternalIntArray, int32_t>(
8392 receiver, true, false, visitor);
8393 break;
8394 }
8395 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
8396 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
8397 receiver, true, false, visitor);
8398 break;
8399 }
8400 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
8401 IterateExternalArrayElements<ExternalFloatArray, float>(
8402 receiver, false, false, visitor);
8403 break;
8404 }
8224 default: 8405 default:
8225 UNREACHABLE(); 8406 UNREACHABLE();
8226 break; 8407 break;
8227 } 8408 }
8228 8409 visitor->increase_index_offset(length);
8229 return num_of_elements;
8230 }
8231
8232
8233 /**
8234 * A helper function that visits elements of an Array object, and elements
8235 * on its prototypes.
8236 *
8237 * Elements on prototypes are visited first, and only elements whose indices
8238 * less than Array length are visited.
8239 *
8240 * If a ArrayConcatVisitor object is given, the visitor is called with
8241 * parameters, element's index + visitor_index_offset and the element.
8242 *
8243 * The returned number of elements is an upper bound on the actual number
8244 * of elements added. If the same element occurs in more than one object
8245 * in the array's prototype chain, it will be counted more than once, but
8246 * will only occur once in the result.
8247 */
8248 static uint32_t IterateArrayAndPrototypeElements(Handle<JSArray> array,
8249 ArrayConcatVisitor* visitor) {
8250 uint32_t range = static_cast<uint32_t>(array->length()->Number());
8251 Handle<Object> obj = array;
8252
8253 static const int kEstimatedPrototypes = 3;
8254 List< Handle<JSObject> > objects(kEstimatedPrototypes);
8255
8256 // Visit prototype first. If an element on the prototype is shadowed by
8257 // the inheritor using the same index, the ArrayConcatVisitor visits
8258 // the prototype element before the shadowing element.
8259 // The visitor can simply overwrite the old value by new value using
8260 // the same index. This follows Array::concat semantics.
8261 while (!obj->IsNull()) {
8262 objects.Add(Handle<JSObject>::cast(obj));
8263 obj = Handle<Object>(obj->GetPrototype());
8264 }
8265
8266 uint32_t nof_elements = 0;
8267 for (int i = objects.length() - 1; i >= 0; i--) {
8268 Handle<JSObject> obj = objects[i];
8269 uint32_t encountered_elements =
8270 IterateElements(Handle<JSObject>::cast(obj), range, visitor);
8271
8272 if (encountered_elements > JSObject::kMaxElementCount - nof_elements) {
8273 nof_elements = JSObject::kMaxElementCount;
8274 } else {
8275 nof_elements += encountered_elements;
8276 }
8277 }
8278
8279 return nof_elements;
8280 }
8281
8282
8283 /**
8284 * A helper function of Runtime_ArrayConcat.
8285 *
8286 * The first argument is an Array of arrays and objects. It is the
8287 * same as the arguments array of Array::concat JS function.
8288 *
8289 * If an argument is an Array object, the function visits array
8290 * elements. If an argument is not an Array object, the function
8291 * visits the object as if it is an one-element array.
8292 *
8293 * If the result array index overflows 32-bit unsigned integer, the rounded
8294 * non-negative number is used as new length. For example, if one
8295 * array length is 2^32 - 1, second array length is 1, the
8296 * concatenated array length is 0.
8297 * TODO(lrn) Change length behavior to ECMAScript 5 specification (length
8298 * is one more than the last array index to get a value assigned).
8299 */
8300 static uint32_t IterateArguments(Handle<JSArray> arguments,
8301 ArrayConcatVisitor* visitor) {
8302 uint32_t visited_elements = 0;
8303 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number());
8304
8305 for (uint32_t i = 0; i < num_of_args; i++) {
8306 Object *element;
8307 MaybeObject* maybe_element = arguments->GetElement(i);
8308 // This if() is not expected to fail, but we have the check in the
8309 // interest of hardening the runtime calls.
8310 if (maybe_element->ToObject(&element)) {
8311 Handle<Object> obj(element);
8312 if (obj->IsJSArray()) {
8313 Handle<JSArray> array = Handle<JSArray>::cast(obj);
8314 uint32_t len = static_cast<uint32_t>(array->length()->Number());
8315 uint32_t nof_elements =
8316 IterateArrayAndPrototypeElements(array, visitor);
8317 // Total elements of array and its prototype chain can be more than
8318 // the array length, but ArrayConcat can only concatenate at most
8319 // the array length number of elements. We use the length as an estimate
8320 // for the actual number of elements added.
8321 uint32_t added_elements = (nof_elements > len) ? len : nof_elements;
8322 if (JSArray::kMaxElementCount - visited_elements < added_elements) {
8323 visited_elements = JSArray::kMaxElementCount;
8324 } else {
8325 visited_elements += added_elements;
8326 }
8327 if (visitor) visitor->increase_index_offset(len);
8328 } else {
8329 if (visitor) {
8330 visitor->visit(0, obj);
8331 visitor->increase_index_offset(1);
8332 }
8333 if (visited_elements < JSArray::kMaxElementCount) {
8334 visited_elements++;
8335 }
8336 }
8337 }
8338 }
8339 return visited_elements;
8340 } 8410 }
8341 8411
8342 8412
8343 /** 8413 /**
8344 * Array::concat implementation. 8414 * Array::concat implementation.
8345 * See ECMAScript 262, 15.4.4.4. 8415 * See ECMAScript 262, 15.4.4.4.
8346 * TODO(lrn): Fix non-compliance for very large concatenations and update to 8416 * TODO(581): Fix non-compliance for very large concatenations and update to
8347 * following the ECMAScript 5 specification. 8417 * following the ECMAScript 5 specification.
8348 */ 8418 */
8349 static MaybeObject* Runtime_ArrayConcat(Arguments args) { 8419 static MaybeObject* Runtime_ArrayConcat(Arguments args) {
8350 ASSERT(args.length() == 1); 8420 ASSERT(args.length() == 1);
8351 HandleScope handle_scope; 8421 HandleScope handle_scope;
8352 8422
8353 CONVERT_CHECKED(JSArray, arg_arrays, args[0]); 8423 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
8354 Handle<JSArray> arguments(arg_arrays); 8424 int argument_count = static_cast<int>(arguments->length()->Number());
8355 8425 RUNTIME_ASSERT(arguments->HasFastElements());
8356 // Pass 1: estimate the number of elements of the result 8426 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
8357 // (it could be more than real numbers if prototype has elements). 8427
8358 uint32_t result_length = 0; 8428 // Pass 1: estimate the length and number of elements of the result.
8359 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number()); 8429 // The actual length can be larger if any of the arguments have getters
8360 8430 // that mutate other arguments (but will otherwise be precise).
8361 { AssertNoAllocation nogc; 8431 // The number of elements is precise if there are no inherited elements.
8362 for (uint32_t i = 0; i < num_of_args; i++) { 8432
8363 Object* obj; 8433 uint32_t estimate_result_length = 0;
8364 MaybeObject* maybe_object = arguments->GetElement(i); 8434 uint32_t estimate_nof_elements = 0;
8365 // This if() is not expected to fail, but we have the check in the 8435 {
8366 // interest of hardening the runtime calls. 8436 for (int i = 0; i < argument_count; i++) {
8367 if (maybe_object->ToObject(&obj)) { 8437 HandleScope loop_scope;
8368 uint32_t length_estimate; 8438 Handle<Object> obj(elements->get(i));
8369 if (obj->IsJSArray()) { 8439 uint32_t length_estimate;
8370 length_estimate = 8440 uint32_t element_estimate;
8371 static_cast<uint32_t>(JSArray::cast(obj)->length()->Number()); 8441 if (obj->IsJSArray()) {
8372 } else { 8442 Handle<JSArray> array(Handle<JSArray>::cast(obj));
8373 length_estimate = 1; 8443 length_estimate =
8374 } 8444 static_cast<uint32_t>(array->length()->Number());
8375 if (JSObject::kMaxElementCount - result_length < length_estimate) { 8445 element_estimate =
8376 result_length = JSObject::kMaxElementCount; 8446 EstimateElementCount(array);
8377 break; 8447 } else {
8378 } 8448 length_estimate = 1;
8379 result_length += length_estimate; 8449 element_estimate = 1;
8380 } 8450 }
8381 } 8451 // Avoid overflows by capping at kMaxElementCount.
8382 } 8452 if (JSObject::kMaxElementCount - estimate_result_length <
8383 8453 length_estimate) {
8384 // Allocate an empty array, will set map, length, and content later. 8454 estimate_result_length = JSObject::kMaxElementCount;
8385 Handle<JSArray> result = Factory::NewJSArray(0); 8455 } else {
8386 8456 estimate_result_length += length_estimate;
8387 uint32_t estimate_nof_elements = IterateArguments(arguments, NULL); 8457 }
8458 if (JSObject::kMaxElementCount - estimate_nof_elements <
8459 element_estimate) {
8460 estimate_nof_elements = JSObject::kMaxElementCount;
8461 } else {
8462 estimate_nof_elements += element_estimate;
8463 }
8464 }
8465 }
8466
8388 // If estimated number of elements is more than half of length, a 8467 // If estimated number of elements is more than half of length, a
8389 // fixed array (fast case) is more time and space-efficient than a 8468 // fixed array (fast case) is more time and space-efficient than a
8390 // dictionary. 8469 // dictionary.
8391 bool fast_case = (estimate_nof_elements * 2) >= result_length; 8470 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
8392 8471
8393 Handle<Map> map;
8394 Handle<FixedArray> storage; 8472 Handle<FixedArray> storage;
8395 if (fast_case) { 8473 if (fast_case) {
8396 // The backing storage array must have non-existing elements to 8474 // The backing storage array must have non-existing elements to
8397 // preserve holes across concat operations. 8475 // preserve holes across concat operations.
8398 map = Factory::GetFastElementsMap(Handle<Map>(result->map())); 8476 storage = Factory::NewFixedArrayWithHoles(estimate_result_length);
8399 storage = Factory::NewFixedArrayWithHoles(result_length);
8400 } else { 8477 } else {
8401 map = Factory::GetSlowElementsMap(Handle<Map>(result->map()));
8402 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate 8478 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
8403 uint32_t at_least_space_for = estimate_nof_elements + 8479 uint32_t at_least_space_for = estimate_nof_elements +
8404 (estimate_nof_elements >> 2); 8480 (estimate_nof_elements >> 2);
8405 storage = Handle<FixedArray>::cast( 8481 storage = Handle<FixedArray>::cast(
8406 Factory::NewNumberDictionary(at_least_space_for)); 8482 Factory::NewNumberDictionary(at_least_space_for));
8407 } 8483 }
8408 8484
8409 Handle<Object> len = Factory::NewNumber(static_cast<double>(result_length)); 8485 ArrayConcatVisitor visitor(storage, fast_case);
8410 8486
8411 ArrayConcatVisitor visitor(storage, result_length, fast_case); 8487 for (int i = 0; i < argument_count; i++) {
8488 Handle<Object> obj(elements->get(i));
8489 if (obj->IsJSArray()) {
8490 Handle<JSArray> array = Handle<JSArray>::cast(obj);
8491 IterateElements(array, &visitor);
8492 } else {
8493 visitor.visit(0, obj);
8494 visitor.increase_index_offset(1);
8495 }
8496 }
8412 8497
8413 IterateArguments(arguments, &visitor); 8498 return *visitor.ToArray();
8414
8415 // Please note:
8416 // - the storage might have been changed in the visitor;
8417 // - the map and the storage must be set together to avoid breaking
8418 // the invariant that the map describes the array's elements.
8419 result->set_map(*map);
8420 result->set_length(*len);
8421 result->set_elements(*visitor.storage());
8422
8423 return *result;
8424 } 8499 }
8425 8500
8426 8501
8427 // This will not allocate (flatten the string), but it may run 8502 // This will not allocate (flatten the string), but it may run
8428 // very slowly for very deeply nested ConsStrings. For debugging use only. 8503 // very slowly for very deeply nested ConsStrings. For debugging use only.
8429 static MaybeObject* Runtime_GlobalPrint(Arguments args) { 8504 static MaybeObject* Runtime_GlobalPrint(Arguments args) {
8430 NoHandleAllocation ha; 8505 NoHandleAllocation ha;
8431 ASSERT(args.length() == 1); 8506 ASSERT(args.length() == 1);
8432 8507
8433 CONVERT_CHECKED(String, string, args[0]); 8508 CONVERT_CHECKED(String, string, args[0]);
(...skipping 2787 matching lines...) Expand 10 before | Expand all | Expand 10 after
11221 } else { 11296 } else {
11222 // Handle last resort GC and make sure to allow future allocations 11297 // Handle last resort GC and make sure to allow future allocations
11223 // to grow the heap without causing GCs (if possible). 11298 // to grow the heap without causing GCs (if possible).
11224 Counters::gc_last_resort_from_js.Increment(); 11299 Counters::gc_last_resort_from_js.Increment();
11225 Heap::CollectAllGarbage(false); 11300 Heap::CollectAllGarbage(false);
11226 } 11301 }
11227 } 11302 }
11228 11303
11229 11304
11230 } } // namespace v8::internal 11305 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/objects-inl.h ('k') | src/spaces.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698