| OLD | NEW |
| 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 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 302 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 313 ASSERT(args.length() == 1); | 313 ASSERT(args.length() == 1); |
| 314 Object* arg = args[0]; | 314 Object* arg = args[0]; |
| 315 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo(); | 315 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo(); |
| 316 return Heap::ToBoolean(result); | 316 return Heap::ToBoolean(result); |
| 317 } | 317 } |
| 318 | 318 |
| 319 | 319 |
| 320 static Object* Runtime_GetTemplateField(Arguments args) { | 320 static Object* Runtime_GetTemplateField(Arguments args) { |
| 321 ASSERT(args.length() == 2); | 321 ASSERT(args.length() == 2); |
| 322 CONVERT_CHECKED(HeapObject, templ, args[0]); | 322 CONVERT_CHECKED(HeapObject, templ, args[0]); |
| 323 RUNTIME_ASSERT(templ->IsStruct()); | |
| 324 CONVERT_CHECKED(Smi, field, args[1]); | 323 CONVERT_CHECKED(Smi, field, args[1]); |
| 325 return HeapObject::GetHeapObjectField(templ, field->value()); | 324 int index = field->value(); |
| 325 int offset = index * kPointerSize + HeapObject::kHeaderSize; |
| 326 InstanceType type = templ->map()->instance_type(); |
| 327 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE || |
| 328 type == OBJECT_TEMPLATE_INFO_TYPE); |
| 329 RUNTIME_ASSERT(offset > 0); |
| 330 if (type == FUNCTION_TEMPLATE_INFO_TYPE) { |
| 331 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize); |
| 332 } else { |
| 333 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize); |
| 334 } |
| 335 return *HeapObject::RawField(templ, offset); |
| 326 } | 336 } |
| 327 | 337 |
| 328 | 338 |
| 329 static Object* ThrowRedeclarationError(const char* type, Handle<String> name) { | 339 static Object* ThrowRedeclarationError(const char* type, Handle<String> name) { |
| 330 HandleScope scope; | 340 HandleScope scope; |
| 331 Handle<Object> type_handle = Factory::NewStringFromAscii(CStrVector(type)); | 341 Handle<Object> type_handle = Factory::NewStringFromAscii(CStrVector(type)); |
| 332 Handle<Object> args[2] = { type_handle, name }; | 342 Handle<Object> args[2] = { type_handle, name }; |
| 333 Handle<Object> error = | 343 Handle<Object> error = |
| 334 Factory::NewTypeError("redeclaration", HandleVector(args, 2)); | 344 Factory::NewTypeError("redeclaration", HandleVector(args, 2)); |
| 335 return Top::Throw(*error); | 345 return Top::Throw(*error); |
| (...skipping 3644 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3980 FixedArray* elements = FixedArray::cast(array->elements()); | 3990 FixedArray* elements = FixedArray::cast(array->elements()); |
| 3981 for (int i = 0; i < length; i++) { | 3991 for (int i = 0; i < length; i++) { |
| 3982 if (elements->get(i) == element) return Heap::false_value(); | 3992 if (elements->get(i) == element) return Heap::false_value(); |
| 3983 } | 3993 } |
| 3984 Object* obj = array->SetFastElement(length, element); | 3994 Object* obj = array->SetFastElement(length, element); |
| 3985 if (obj->IsFailure()) return obj; | 3995 if (obj->IsFailure()) return obj; |
| 3986 return Heap::true_value(); | 3996 return Heap::true_value(); |
| 3987 } | 3997 } |
| 3988 | 3998 |
| 3989 | 3999 |
| 4000 /** |
| 4001 * A simple visitor visits every element of Array's. |
| 4002 * The backend storage can be a fixed array for fast elements case, |
| 4003 * or a dictionary for sparse array. Since Dictionary is a subtype |
| 4004 * of FixedArray, the class can be used by both fast and slow cases. |
| 4005 * The second parameter of the constructor, fast_elements, specifies |
| 4006 * whether the storage is a FixedArray or Dictionary. |
| 4007 * |
| 4008 * An index limit is used to deal with the situation that a result array |
| 4009 * length overflows 32-bit non-negative integer. |
| 4010 */ |
| 4011 class ArrayConcatVisitor { |
| 4012 public: |
| 4013 ArrayConcatVisitor(Handle<FixedArray> storage, |
| 4014 uint32_t index_limit, |
| 4015 bool fast_elements) : |
| 4016 storage_(storage), index_limit_(index_limit), |
| 4017 fast_elements_(fast_elements), index_offset_(0) { } |
| 4018 |
| 4019 void visit(uint32_t i, Handle<Object> elm) { |
| 4020 uint32_t index = i + index_offset_; |
| 4021 if (index >= index_limit_) return; |
| 4022 |
| 4023 if (fast_elements_) { |
| 4024 ASSERT(index < static_cast<uint32_t>(storage_->length())); |
| 4025 storage_->set(index, *elm); |
| 4026 |
| 4027 } else { |
| 4028 Handle<Dictionary> dict = Handle<Dictionary>::cast(storage_); |
| 4029 Handle<Dictionary> result = |
| 4030 Factory::DictionaryAtNumberPut(dict, index, elm); |
| 4031 if (!result.is_identical_to(dict)) |
| 4032 storage_ = result; |
| 4033 } |
| 4034 } |
| 4035 |
| 4036 void increase_index_offset(uint32_t delta) { |
| 4037 index_offset_ += delta; |
| 4038 } |
| 4039 |
| 4040 private: |
| 4041 Handle<FixedArray> storage_; |
| 4042 uint32_t index_limit_; |
| 4043 bool fast_elements_; |
| 4044 uint32_t index_offset_; |
| 4045 }; |
| 4046 |
| 4047 |
| 4048 /** |
| 4049 * A helper function that visits elements of a JSObject. Only elements |
| 4050 * whose index between 0 and range (exclusive) are visited. |
| 4051 * |
| 4052 * If the third parameter, visitor, is not NULL, the visitor is called |
| 4053 * with parameters, 'visitor_index_offset + element index' and the element. |
| 4054 * |
| 4055 * It returns the number of visisted elements. |
| 4056 */ |
| 4057 static uint32_t IterateElements(Handle<JSObject> receiver, |
| 4058 uint32_t range, |
| 4059 ArrayConcatVisitor* visitor) { |
| 4060 uint32_t num_of_elements = 0; |
| 4061 |
| 4062 if (receiver->HasFastElements()) { |
| 4063 Handle<FixedArray> elements(FixedArray::cast(receiver->elements())); |
| 4064 uint32_t len = elements->length(); |
| 4065 if (range < len) len = range; |
| 4066 |
| 4067 for (uint32_t j = 0; j < len; j++) { |
| 4068 Handle<Object> e(elements->get(j)); |
| 4069 if (!e->IsTheHole()) { |
| 4070 num_of_elements++; |
| 4071 if (visitor) |
| 4072 visitor->visit(j, e); |
| 4073 } |
| 4074 } |
| 4075 |
| 4076 } else { |
| 4077 Handle<Dictionary> dict(receiver->element_dictionary()); |
| 4078 uint32_t capacity = dict->Capacity(); |
| 4079 for (uint32_t j = 0; j < capacity; j++) { |
| 4080 Handle<Object> k(dict->KeyAt(j)); |
| 4081 if (dict->IsKey(*k)) { |
| 4082 ASSERT(k->IsNumber()); |
| 4083 uint32_t index = static_cast<uint32_t>(k->Number()); |
| 4084 if (index < range) { |
| 4085 num_of_elements++; |
| 4086 if (visitor) { |
| 4087 visitor->visit(index, |
| 4088 Handle<Object>(dict->ValueAt(j))); |
| 4089 } |
| 4090 } |
| 4091 } |
| 4092 } |
| 4093 } |
| 4094 |
| 4095 return num_of_elements; |
| 4096 } |
| 4097 |
| 4098 |
| 4099 /** |
| 4100 * A helper function that visits elements of an Array object, and elements |
| 4101 * on its prototypes. |
| 4102 * |
| 4103 * Elements on prototypes are visited first, and only elements whose indices |
| 4104 * less than Array length are visited. |
| 4105 * |
| 4106 * If a ArrayConcatVisitor object is given, the visitor is called with |
| 4107 * parameters, element's index + visitor_index_offset and the element. |
| 4108 */ |
| 4109 static uint32_t IterateArrayAndPrototypeElements(Handle<JSArray> array, |
| 4110 ArrayConcatVisitor* visitor) { |
| 4111 uint32_t range = static_cast<uint32_t>(array->length()->Number()); |
| 4112 Handle<Object> obj = array; |
| 4113 |
| 4114 static const int kEstimatedPrototypes = 3; |
| 4115 List< Handle<JSObject> > objects(kEstimatedPrototypes); |
| 4116 |
| 4117 // Visit prototype first. If an element on the prototype is shadowed by |
| 4118 // the inheritor using the same index, the ArrayConcatVisitor visits |
| 4119 // the prototype element before the shadowing element. |
| 4120 // The visitor can simply overwrite the old value by new value using |
| 4121 // the same index. This follows Array::concat semantics. |
| 4122 while (!obj->IsNull()) { |
| 4123 objects.Add(Handle<JSObject>::cast(obj)); |
| 4124 obj = Handle<Object>(obj->GetPrototype()); |
| 4125 } |
| 4126 |
| 4127 uint32_t nof_elements = 0; |
| 4128 for (int i = objects.length() - 1; i >= 0; i--) { |
| 4129 Handle<JSObject> obj = objects[i]; |
| 4130 nof_elements += |
| 4131 IterateElements(Handle<JSObject>::cast(obj), range, visitor); |
| 4132 } |
| 4133 |
| 4134 return nof_elements; |
| 4135 } |
| 4136 |
| 4137 |
| 4138 /** |
| 4139 * A helper function of Runtime_ArrayConcat. |
| 4140 * |
| 4141 * The first argument is an Array of arrays and objects. It is the |
| 4142 * same as the arguments array of Array::concat JS function. |
| 4143 * |
| 4144 * If an argument is an Array object, the function visits array |
| 4145 * elements. If an argument is not an Array object, the function |
| 4146 * visits the object as if it is an one-element array. |
| 4147 * |
| 4148 * If the result array index overflows 32-bit integer, the rounded |
| 4149 * non-negative number is used as new length. For example, if one |
| 4150 * array length is 2^32 - 1, second array length is 1, the |
| 4151 * concatenated array length is 0. |
| 4152 */ |
| 4153 static uint32_t IterateArguments(Handle<JSArray> arguments, |
| 4154 ArrayConcatVisitor* visitor) { |
| 4155 uint32_t visited_elements = 0; |
| 4156 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number()); |
| 4157 |
| 4158 for (uint32_t i = 0; i < num_of_args; i++) { |
| 4159 Handle<Object> obj(arguments->GetElement(i)); |
| 4160 if (obj->IsJSArray()) { |
| 4161 Handle<JSArray> array = Handle<JSArray>::cast(obj); |
| 4162 uint32_t len = static_cast<uint32_t>(array->length()->Number()); |
| 4163 uint32_t nof_elements = |
| 4164 IterateArrayAndPrototypeElements(array, visitor); |
| 4165 // Total elements of array and its prototype chain can be more than |
| 4166 // the array length, but ArrayConcat can only concatenate at most |
| 4167 // the array length number of elements. |
| 4168 visited_elements += (nof_elements > len) ? len : nof_elements; |
| 4169 if (visitor) visitor->increase_index_offset(len); |
| 4170 |
| 4171 } else { |
| 4172 if (visitor) { |
| 4173 visitor->visit(0, obj); |
| 4174 visitor->increase_index_offset(1); |
| 4175 } |
| 4176 visited_elements++; |
| 4177 } |
| 4178 } |
| 4179 return visited_elements; |
| 4180 } |
| 4181 |
| 4182 |
| 4183 /** |
| 4184 * Array::concat implementation. |
| 4185 * See ECMAScript 262, 15.4.4.4. |
| 4186 */ |
| 4187 static Object* Runtime_ArrayConcat(Arguments args) { |
| 4188 ASSERT(args.length() == 1); |
| 4189 HandleScope handle_scope; |
| 4190 |
| 4191 CONVERT_CHECKED(JSArray, arg_arrays, args[0]); |
| 4192 Handle<JSArray> arguments(arg_arrays); |
| 4193 |
| 4194 // Pass 1: estimate the number of elements of the result |
| 4195 // (it could be more than real numbers if prototype has elements). |
| 4196 uint32_t result_length = 0; |
| 4197 uint32_t num_of_args = static_cast<uint32_t>(arguments->length()->Number()); |
| 4198 |
| 4199 { AssertNoAllocation nogc; |
| 4200 for (uint32_t i = 0; i < num_of_args; i++) { |
| 4201 Object* obj = arguments->GetElement(i); |
| 4202 if (obj->IsJSArray()) { |
| 4203 result_length += |
| 4204 static_cast<uint32_t>(JSArray::cast(obj)->length()->Number()); |
| 4205 } else { |
| 4206 result_length++; |
| 4207 } |
| 4208 } |
| 4209 } |
| 4210 |
| 4211 // Allocate an empty array, will set length and content later. |
| 4212 Handle<JSArray> result = Factory::NewJSArray(0); |
| 4213 |
| 4214 uint32_t estimate_nof_elements = IterateArguments(arguments, NULL); |
| 4215 // If estimated number of elements is more than half of length, a |
| 4216 // fixed array (fast case) is more time and space-efficient than a |
| 4217 // dictionary. |
| 4218 bool fast_case = (estimate_nof_elements * 2) >= result_length; |
| 4219 |
| 4220 Handle<FixedArray> storage; |
| 4221 if (fast_case) { |
| 4222 // The backing storage array must have non-existing elements to |
| 4223 // preserve holes across concat operations. |
| 4224 storage = Factory::NewFixedArrayWithHoles(result_length); |
| 4225 |
| 4226 } else { |
| 4227 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate |
| 4228 uint32_t at_least_space_for = estimate_nof_elements + |
| 4229 (estimate_nof_elements >> 2); |
| 4230 storage = Handle<FixedArray>::cast( |
| 4231 Factory::NewDictionary(at_least_space_for)); |
| 4232 } |
| 4233 |
| 4234 Handle<Object> len = Factory::NewNumber(static_cast<double>(result_length)); |
| 4235 |
| 4236 ArrayConcatVisitor visitor(storage, result_length, fast_case); |
| 4237 |
| 4238 IterateArguments(arguments, &visitor); |
| 4239 |
| 4240 result->set_length(*len); |
| 4241 result->set_elements(*storage); |
| 4242 |
| 4243 return *result; |
| 4244 } |
| 4245 |
| 4246 |
| 3990 // This will not allocate (flatten the string), but it may run | 4247 // This will not allocate (flatten the string), but it may run |
| 3991 // very slowly for very deeply nested ConsStrings. For debugging use only. | 4248 // very slowly for very deeply nested ConsStrings. For debugging use only. |
| 3992 static Object* Runtime_GlobalPrint(Arguments args) { | 4249 static Object* Runtime_GlobalPrint(Arguments args) { |
| 3993 NoHandleAllocation ha; | 4250 NoHandleAllocation ha; |
| 3994 ASSERT(args.length() == 1); | 4251 ASSERT(args.length() == 1); |
| 3995 | 4252 |
| 3996 CONVERT_CHECKED(String, string, args[0]); | 4253 CONVERT_CHECKED(String, string, args[0]); |
| 3997 StringInputBuffer buffer(string); | 4254 StringInputBuffer buffer(string); |
| 3998 while (buffer.has_more()) { | 4255 while (buffer.has_more()) { |
| 3999 uint16_t character = buffer.GetNext(); | 4256 uint16_t character = buffer.GetNext(); |
| (...skipping 1516 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5516 if (strcmp(f->name, name) == 0) { | 5773 if (strcmp(f->name, name) == 0) { |
| 5517 return f; | 5774 return f; |
| 5518 } | 5775 } |
| 5519 } | 5776 } |
| 5520 return NULL; | 5777 return NULL; |
| 5521 } | 5778 } |
| 5522 | 5779 |
| 5523 | 5780 |
| 5524 void Runtime::PerformGC(Object* result) { | 5781 void Runtime::PerformGC(Object* result) { |
| 5525 Failure* failure = Failure::cast(result); | 5782 Failure* failure = Failure::cast(result); |
| 5526 // Try to do a garbage collection; ignore it if it fails. The C | 5783 if (failure->IsRetryAfterGC()) { |
| 5527 // entry stub will throw an out-of-memory exception in that case. | 5784 // Try to do a garbage collection; ignore it if it fails. The C |
| 5528 Heap::CollectGarbage(failure->requested(), failure->allocation_space()); | 5785 // entry stub will throw an out-of-memory exception in that case. |
| 5786 Heap::CollectGarbage(failure->requested(), failure->allocation_space()); |
| 5787 } else { |
| 5788 // Handle last resort GC and make sure to allow future allocations |
| 5789 // to grow the heap without causing GCs (if possible). |
| 5790 Heap::CollectAllGarbage(); |
| 5791 } |
| 5529 } | 5792 } |
| 5530 | 5793 |
| 5531 | 5794 |
| 5532 } } // namespace v8::internal | 5795 } } // namespace v8::internal |
| OLD | NEW |