OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/builtins.h" | 5 #include "src/builtins.h" |
6 | 6 |
7 #include "src/api.h" | 7 #include "src/api.h" |
8 #include "src/api-arguments.h" | 8 #include "src/api-arguments.h" |
9 #include "src/api-natives.h" | 9 #include "src/api-natives.h" |
10 #include "src/base/once.h" | 10 #include "src/base/once.h" |
(...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
207 int* out) { | 207 int* out) { |
208 Map* arguments_map = isolate->native_context()->sloppy_arguments_map(); | 208 Map* arguments_map = isolate->native_context()->sloppy_arguments_map(); |
209 if (object->map() != arguments_map) return false; | 209 if (object->map() != arguments_map) return false; |
210 DCHECK(object->HasFastElements()); | 210 DCHECK(object->HasFastElements()); |
211 Object* len_obj = object->InObjectPropertyAt(JSArgumentsObject::kLengthIndex); | 211 Object* len_obj = object->InObjectPropertyAt(JSArgumentsObject::kLengthIndex); |
212 if (!len_obj->IsSmi()) return false; | 212 if (!len_obj->IsSmi()) return false; |
213 *out = Max(0, Smi::cast(len_obj)->value()); | 213 *out = Max(0, Smi::cast(len_obj)->value()); |
214 return *out <= object->elements()->length(); | 214 return *out <= object->elements()->length(); |
215 } | 215 } |
216 | 216 |
217 | 217 inline bool PrototypeHasNoElements(Isolate* isolate, JSObject* object) { |
218 inline bool PrototypeHasNoElements(PrototypeIterator* iter) { | |
219 DisallowHeapAllocation no_gc; | 218 DisallowHeapAllocation no_gc; |
220 for (; !iter->IsAtEnd(); iter->Advance()) { | 219 HeapObject* prototype = HeapObject::cast(object->map()->prototype()); |
221 if (iter->GetCurrent()->IsJSProxy()) return false; | 220 HeapObject* null = isolate->heap()->null_value(); |
222 JSObject* current = iter->GetCurrent<JSObject>(); | 221 HeapObject* empty = isolate->heap()->empty_fixed_array(); |
223 if (current->IsAccessCheckNeeded()) return false; | 222 while (prototype != null) { |
224 if (current->HasIndexedInterceptor()) return false; | 223 Map* map = prototype->map(); |
225 if (current->HasStringWrapperElements()) return false; | 224 if (map->instance_type() <= LAST_CUSTOM_ELEMENTS_RECEIVER) return false; |
226 if (current->elements()->length() != 0) return false; | 225 if (JSObject::cast(prototype)->elements() != empty) return false; |
| 226 prototype = HeapObject::cast(map->prototype()); |
227 } | 227 } |
228 return true; | 228 return true; |
229 } | 229 } |
230 | 230 |
231 inline bool IsJSArrayFastElementMovingAllowed(Isolate* isolate, | 231 inline bool IsJSArrayFastElementMovingAllowed(Isolate* isolate, |
232 JSArray* receiver) { | 232 JSArray* receiver) { |
233 DisallowHeapAllocation no_gc; | 233 return PrototypeHasNoElements(isolate, receiver); |
234 // If the array prototype chain is intact (and free of elements), and if the | |
235 // receiver's prototype is the array prototype, then we are done. | |
236 Object* prototype = receiver->map()->prototype(); | |
237 if (prototype->IsJSArray() && | |
238 isolate->is_initial_array_prototype(JSArray::cast(prototype)) && | |
239 isolate->IsFastArrayConstructorPrototypeChainIntact()) { | |
240 return true; | |
241 } | |
242 // Slow case. | |
243 PrototypeIterator iter(isolate, receiver); | |
244 return PrototypeHasNoElements(&iter); | |
245 } | 234 } |
246 | 235 |
247 inline bool HasSimpleElements(JSObject* current) { | 236 inline bool HasSimpleElements(JSObject* current) { |
248 if (current->IsAccessCheckNeeded()) return false; | 237 return current->map()->instance_type() > LAST_CUSTOM_ELEMENTS_RECEIVER && |
249 if (current->HasIndexedInterceptor()) return false; | 238 !current->GetElementsAccessor()->HasAccessors(current); |
250 if (current->HasStringWrapperElements()) return false; | |
251 if (current->GetElementsAccessor()->HasAccessors(current)) return false; | |
252 return true; | |
253 } | 239 } |
254 | 240 |
255 inline bool HasOnlySimpleReceiverElements(Isolate* isolate, | 241 inline bool HasOnlySimpleReceiverElements(Isolate* isolate, |
256 JSReceiver* receiver) { | 242 JSObject* receiver) { |
257 // Check that we have no accessors on the receiver's elements. | 243 // Check that we have no accessors on the receiver's elements. |
258 JSObject* object = JSObject::cast(receiver); | 244 if (!HasSimpleElements(receiver)) return false; |
259 if (!HasSimpleElements(object)) return false; | 245 return PrototypeHasNoElements(isolate, receiver); |
260 // Check that ther are not elements on the prototype. | |
261 DisallowHeapAllocation no_gc; | |
262 PrototypeIterator iter(isolate, receiver); | |
263 return PrototypeHasNoElements(&iter); | |
264 } | 246 } |
265 | 247 |
266 inline bool HasOnlySimpleElements(Isolate* isolate, JSReceiver* receiver) { | 248 inline bool HasOnlySimpleElements(Isolate* isolate, JSReceiver* receiver) { |
267 // Check that ther are not elements on the prototype. | |
268 DisallowHeapAllocation no_gc; | 249 DisallowHeapAllocation no_gc; |
269 PrototypeIterator iter(isolate, receiver, | 250 PrototypeIterator iter(isolate, receiver, |
270 PrototypeIterator::START_AT_RECEIVER); | 251 PrototypeIterator::START_AT_RECEIVER); |
271 for (; !iter.IsAtEnd(); iter.Advance()) { | 252 for (; !iter.IsAtEnd(); iter.Advance()) { |
272 if (iter.GetCurrent()->IsJSProxy()) return false; | 253 if (iter.GetCurrent()->IsJSProxy()) return false; |
273 JSObject* current = iter.GetCurrent<JSObject>(); | 254 JSObject* current = iter.GetCurrent<JSObject>(); |
274 if (!HasSimpleElements(current)) return false; | 255 if (!HasSimpleElements(current)) return false; |
275 } | 256 } |
276 return true; | 257 return true; |
277 } | 258 } |
278 | 259 |
279 // Returns |false| if not applicable. | 260 // Returns |false| if not applicable. |
280 MUST_USE_RESULT | 261 MUST_USE_RESULT |
281 inline bool EnsureJSArrayWithWritableFastElements(Isolate* isolate, | 262 inline bool EnsureJSArrayWithWritableFastElements(Isolate* isolate, |
282 Handle<Object> receiver, | 263 Handle<Object> receiver, |
283 Arguments* args, | 264 Arguments* args, |
284 int first_added_arg) { | 265 int first_added_arg) { |
285 if (!receiver->IsJSArray()) return false; | 266 if (!receiver->IsJSArray()) return false; |
286 Handle<JSArray> array = Handle<JSArray>::cast(receiver); | 267 Handle<JSArray> array = Handle<JSArray>::cast(receiver); |
287 // If there may be elements accessors in the prototype chain, the fast path | |
288 // cannot be used if there arguments to add to the array. | |
289 if (args != nullptr && !IsJSArrayFastElementMovingAllowed(isolate, *array)) { | |
290 return false; | |
291 } | |
292 ElementsKind origin_kind = array->GetElementsKind(); | 268 ElementsKind origin_kind = array->GetElementsKind(); |
293 if (IsDictionaryElementsKind(origin_kind)) return false; | 269 if (IsDictionaryElementsKind(origin_kind)) return false; |
294 if (array->map()->is_observed()) return false; | 270 if (array->map()->is_observed()) return false; |
295 if (!array->map()->is_extensible()) return false; | 271 if (!array->map()->is_extensible()) return false; |
296 if (args == nullptr) return true; | 272 if (args == nullptr) return true; |
297 | 273 |
| 274 // If there may be elements accessors in the prototype chain, the fast path |
| 275 // cannot be used if there arguments to add to the array. |
| 276 if (!IsJSArrayFastElementMovingAllowed(isolate, *array)) return false; |
| 277 |
298 // Adding elements to the array prototype would break code that makes sure | 278 // Adding elements to the array prototype would break code that makes sure |
299 // it has no elements. Handle that elsewhere. | 279 // it has no elements. Handle that elsewhere. |
300 if (isolate->IsAnyInitialArrayPrototype(array)) return false; | 280 if (isolate->IsAnyInitialArrayPrototype(array)) return false; |
301 | 281 |
302 // Need to ensure that the arguments passed in args can be contained in | 282 // Need to ensure that the arguments passed in args can be contained in |
303 // the array. | 283 // the array. |
304 int args_length = args->length(); | 284 int args_length = args->length(); |
305 if (first_added_arg >= args_length) return true; | 285 if (first_added_arg >= args_length) return true; |
306 | 286 |
307 if (IsFastObjectElementsKind(origin_kind)) return true; | 287 if (IsFastObjectElementsKind(origin_kind)) return true; |
308 ElementsKind target_kind = origin_kind; | 288 ElementsKind target_kind = origin_kind; |
309 { | 289 { |
310 DisallowHeapAllocation no_gc; | 290 DisallowHeapAllocation no_gc; |
311 int arg_count = args_length - first_added_arg; | 291 for (int i = first_added_arg; i < args_length; i++) { |
312 Object** arguments = args->arguments() - first_added_arg - (arg_count - 1); | 292 Object* arg = (*args)[i]; |
313 for (int i = 0; i < arg_count; i++) { | |
314 Object* arg = arguments[i]; | |
315 if (arg->IsHeapObject()) { | 293 if (arg->IsHeapObject()) { |
316 if (arg->IsHeapNumber()) { | 294 if (arg->IsHeapNumber()) { |
317 target_kind = FAST_DOUBLE_ELEMENTS; | 295 target_kind = FAST_DOUBLE_ELEMENTS; |
318 } else { | 296 } else { |
319 target_kind = FAST_ELEMENTS; | 297 target_kind = FAST_ELEMENTS; |
320 break; | 298 break; |
321 } | 299 } |
322 } | 300 } |
323 } | 301 } |
324 } | 302 } |
(...skipping 4212 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4537 BUILTIN_LIST_C(DEFINE_BUILTIN_ACCESSOR_C) | 4515 BUILTIN_LIST_C(DEFINE_BUILTIN_ACCESSOR_C) |
4538 BUILTIN_LIST_A(DEFINE_BUILTIN_ACCESSOR_A) | 4516 BUILTIN_LIST_A(DEFINE_BUILTIN_ACCESSOR_A) |
4539 BUILTIN_LIST_H(DEFINE_BUILTIN_ACCESSOR_H) | 4517 BUILTIN_LIST_H(DEFINE_BUILTIN_ACCESSOR_H) |
4540 BUILTIN_LIST_DEBUG_A(DEFINE_BUILTIN_ACCESSOR_A) | 4518 BUILTIN_LIST_DEBUG_A(DEFINE_BUILTIN_ACCESSOR_A) |
4541 #undef DEFINE_BUILTIN_ACCESSOR_C | 4519 #undef DEFINE_BUILTIN_ACCESSOR_C |
4542 #undef DEFINE_BUILTIN_ACCESSOR_A | 4520 #undef DEFINE_BUILTIN_ACCESSOR_A |
4543 | 4521 |
4544 | 4522 |
4545 } // namespace internal | 4523 } // namespace internal |
4546 } // namespace v8 | 4524 } // namespace v8 |
OLD | NEW |