| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |