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 326 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
337 | 337 |
338 | 338 |
339 BUILTIN(Illegal) { | 339 BUILTIN(Illegal) { |
340 UNREACHABLE(); | 340 UNREACHABLE(); |
341 return isolate->heap()->undefined_value(); // Make compiler happy. | 341 return isolate->heap()->undefined_value(); // Make compiler happy. |
342 } | 342 } |
343 | 343 |
344 | 344 |
345 BUILTIN(EmptyFunction) { return isolate->heap()->undefined_value(); } | 345 BUILTIN(EmptyFunction) { return isolate->heap()->undefined_value(); } |
346 | 346 |
347 // ES6 7.3.11 | 347 void Builtins::Generate_ObjectHasOwnProperty( |
348 BUILTIN(ObjectHasOwnProperty) { | 348 compiler::CodeStubAssembler* assembler) { |
349 HandleScope scope(isolate); | 349 typedef compiler::Node Node; |
350 typedef compiler::CodeStubAssembler::Label Label; | |
351 typedef compiler::CodeStubAssembler::Variable Variable; | |
350 | 352 |
351 Handle<Object> property = args.atOrUndefined(isolate, 1); | 353 Node* object = assembler->Parameter(0); |
354 Node* key = assembler->Parameter(1); | |
355 Node* context = assembler->Parameter(4); | |
352 | 356 |
353 Handle<Name> key; | 357 Label call_runtime(assembler), return_true(assembler), |
354 uint32_t index; | 358 return_false(assembler); |
355 bool key_is_array_index = property->ToArrayIndex(&index); | |
356 | 359 |
357 if (!key_is_array_index) { | 360 // Smi receivers do not have own properties. |
358 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, key, | 361 Label if_objectisnotsmi(assembler); |
359 Object::ToName(isolate, property)); | 362 assembler->Branch(assembler->WordIsSmi(object), &return_false, |
360 key_is_array_index = key->AsArrayIndex(&index); | 363 &if_objectisnotsmi); |
364 assembler->Bind(&if_objectisnotsmi); | |
365 | |
366 Node* map = assembler->LoadMap(object); | |
367 Node* instance_type = assembler->LoadMapInstanceType(map); | |
368 | |
369 Variable var_index(assembler, MachineRepresentation::kWord32); | |
370 | |
371 Label if_keyissmi(assembler), if_keyisnotsmi(assembler), | |
372 keyisindex(assembler); | |
373 assembler->Branch(assembler->WordIsSmi(key), &if_keyissmi, &if_keyisnotsmi); | |
374 assembler->Bind(&if_keyissmi); | |
375 { | |
376 // Negative smi keys are named properties. Handle in the runtime. | |
377 Label if_keyispositive(assembler); | |
378 assembler->Branch(assembler->WordIsPositiveSmi(key), &if_keyispositive, | |
379 &call_runtime); | |
380 assembler->Bind(&if_keyispositive); | |
381 | |
382 var_index.Bind(assembler->SmiUntag(key)); | |
Rodolph Perfetta (ARM)
2016/03/31 08:06:23
This should be a SmiToWord32 too as var_index is d
| |
383 assembler->Goto(&keyisindex); | |
361 } | 384 } |
362 | 385 |
363 Handle<Object> object = args.receiver(); | 386 assembler->Bind(&if_keyisnotsmi); |
364 | 387 |
365 if (object->IsJSObject()) { | 388 Node* key_instance_type = assembler->LoadInstanceType(key); |
366 Handle<JSObject> js_obj = Handle<JSObject>::cast(object); | 389 Label if_iskeyunique(assembler), if_iskeynotsymbol(assembler); |
367 // Fast case: either the key is a real named property or it is not | 390 assembler->Branch( |
368 // an array index and there are no interceptors or hidden | 391 assembler->Word32Equal(key_instance_type, |
369 // prototypes. | 392 assembler->Int32Constant(SYMBOL_TYPE)), |
370 // TODO(jkummerow): Make JSReceiver::HasOwnProperty fast enough to | 393 &if_iskeyunique, &if_iskeynotsymbol); |
371 // handle all cases directly (without this custom fast path). | 394 assembler->Bind(&if_iskeynotsymbol); |
372 { | 395 { |
373 LookupIterator::Configuration c = LookupIterator::OWN_SKIP_INTERCEPTOR; | 396 Label if_iskeyinternalized(assembler); |
374 LookupIterator it = | 397 Node* bits = assembler->WordAnd( |
375 key_is_array_index ? LookupIterator(isolate, js_obj, index, js_obj, c) | 398 key_instance_type, |
376 : LookupIterator(js_obj, key, js_obj, c); | 399 assembler->Int32Constant(kIsNotStringMask | kIsNotInternalizedMask)); |
377 Maybe<bool> maybe = JSReceiver::HasProperty(&it); | 400 assembler->Branch( |
378 if (maybe.IsNothing()) return isolate->heap()->exception(); | 401 assembler->Word32Equal( |
379 DCHECK(!isolate->has_pending_exception()); | 402 bits, assembler->Int32Constant(kStringTag | kInternalizedTag)), |
380 if (maybe.FromJust()) return isolate->heap()->true_value(); | 403 &if_iskeyinternalized, &call_runtime); |
381 } | 404 assembler->Bind(&if_iskeyinternalized); |
382 | 405 |
383 Map* map = js_obj->map(); | 406 // Check whether the key is an array index passed in as string. Handle |
384 if (!map->has_hidden_prototype() && | 407 // uniform with smi keys if so. |
385 (key_is_array_index ? !map->has_indexed_interceptor() | 408 // TODO(verwaest): Also support non-internalized strings. |
386 : !map->has_named_interceptor())) { | 409 Node* hash = assembler->LoadNameHash(key); |
387 return isolate->heap()->false_value(); | 410 Node* bit = assembler->Word32And( |
388 } | 411 hash, assembler->Int32Constant(internal::Name::kIsNotArrayIndexMask)); |
412 Label if_isarrayindex(assembler); | |
413 assembler->Branch(assembler->Word32Equal(bit, assembler->Int32Constant(0)), | |
414 &if_isarrayindex, &if_iskeyunique); | |
415 assembler->Bind(&if_isarrayindex); | |
416 var_index.Bind( | |
417 assembler->BitFieldDecode<internal::Name::ArrayIndexValueBits>(hash)); | |
418 assembler->Goto(&keyisindex); | |
419 } | |
420 assembler->Bind(&if_iskeyunique); | |
389 | 421 |
390 // Slow case. | 422 { |
391 LookupIterator::Configuration c = LookupIterator::HIDDEN; | 423 Label if_objectissimple(assembler); |
392 LookupIterator it = key_is_array_index | 424 assembler->Branch(assembler->Int32LessThanOrEqual( |
393 ? LookupIterator(isolate, js_obj, index, js_obj, c) | 425 instance_type, |
394 : LookupIterator(js_obj, key, js_obj, c); | 426 assembler->Int32Constant(LAST_SPECIAL_RECEIVER_TYPE)), |
395 | 427 &call_runtime, &if_objectissimple); |
396 Maybe<bool> maybe = JSReceiver::HasProperty(&it); | 428 assembler->Bind(&if_objectissimple); |
397 if (maybe.IsNothing()) return isolate->heap()->exception(); | |
398 DCHECK(!isolate->has_pending_exception()); | |
399 return isolate->heap()->ToBoolean(maybe.FromJust()); | |
400 | |
401 } else if (object->IsJSProxy()) { | |
402 if (key.is_null()) { | |
403 DCHECK(key_is_array_index); | |
404 key = isolate->factory()->Uint32ToString(index); | |
405 } | |
406 | |
407 Maybe<bool> result = | |
408 JSReceiver::HasOwnProperty(Handle<JSProxy>::cast(object), key); | |
409 if (!result.IsJust()) return isolate->heap()->exception(); | |
410 return isolate->heap()->ToBoolean(result.FromJust()); | |
411 | |
412 } else if (object->IsString()) { | |
413 return isolate->heap()->ToBoolean( | |
414 key_is_array_index | |
415 ? index < static_cast<uint32_t>(String::cast(*object)->length()) | |
416 : key->Equals(isolate->heap()->length_string())); | |
417 } else if (object->IsNull() || object->IsUndefined()) { | |
418 THROW_NEW_ERROR_RETURN_FAILURE( | |
419 isolate, NewTypeError(MessageTemplate::kUndefinedOrNullToObject)); | |
420 } | 429 } |
421 | 430 |
422 return isolate->heap()->false_value(); | 431 // TODO(verwaest): Perform a dictonary lookup on slow-mode receivers. |
432 Node* bit_field3 = assembler->LoadMapBitField3(map); | |
433 Node* bit = assembler->BitFieldDecode<Map::DictionaryMap>(bit_field3); | |
434 Label if_isfastmap(assembler); | |
435 assembler->Branch(assembler->Word32Equal(bit, assembler->Int32Constant(0)), | |
436 &if_isfastmap, &call_runtime); | |
437 assembler->Bind(&if_isfastmap); | |
438 Node* nof = | |
439 assembler->BitFieldDecode<Map::NumberOfOwnDescriptorsBits>(bit_field3); | |
440 // Bail out to the runtime for large numbers of own descriptors. The stub only | |
441 // does linear search, which becomes too expensive in that case. | |
442 { | |
443 static const int32_t kMaxLinear = 256; | |
444 Label above_max(assembler), below_max(assembler); | |
445 assembler->Branch(assembler->Int32LessThanOrEqual( | |
446 nof, assembler->Int32Constant(kMaxLinear)), | |
447 &below_max, &call_runtime); | |
448 assembler->Bind(&below_max); | |
449 } | |
450 Node* descriptors = assembler->LoadMapDescriptors(map); | |
451 | |
452 Variable var_descriptor(assembler, MachineRepresentation::kWord32); | |
453 Label loop(assembler, &var_descriptor); | |
454 var_descriptor.Bind(assembler->Int32Constant(0)); | |
455 assembler->Goto(&loop); | |
456 assembler->Bind(&loop); | |
457 { | |
458 Node* index = var_descriptor.value(); | |
459 Node* offset = assembler->Int32Constant(DescriptorArray::ToKeyIndex(0)); | |
460 Node* factor = assembler->Int32Constant(DescriptorArray::kDescriptorSize); | |
461 Label if_notdone(assembler); | |
462 assembler->Branch(assembler->Word32Equal(index, nof), &return_false, | |
463 &if_notdone); | |
464 assembler->Bind(&if_notdone); | |
465 { | |
466 Node* array_index = | |
467 assembler->Int32Add(offset, assembler->Int32Mul(index, factor)); | |
468 Node* current = | |
469 assembler->LoadFixedArrayElementInt32Index(descriptors, array_index); | |
470 Label if_unequal(assembler); | |
471 assembler->Branch(assembler->WordEqual(current, key), &return_true, | |
472 &if_unequal); | |
473 assembler->Bind(&if_unequal); | |
474 | |
475 var_descriptor.Bind( | |
476 assembler->Int32Add(index, assembler->Int32Constant(1))); | |
477 assembler->Goto(&loop); | |
478 } | |
479 } | |
480 | |
481 assembler->Bind(&keyisindex); | |
482 { | |
483 Label if_objectissimple(assembler); | |
484 assembler->Branch(assembler->Int32LessThanOrEqual( | |
485 instance_type, assembler->Int32Constant( | |
486 LAST_CUSTOM_ELEMENTS_RECEIVER)), | |
487 &call_runtime, &if_objectissimple); | |
488 assembler->Bind(&if_objectissimple); | |
489 } | |
490 | |
491 Node* index = var_index.value(); | |
492 Node* bit_field2 = assembler->LoadMapBitField2(map); | |
493 Node* elements_kind = | |
494 assembler->BitFieldDecode<Map::ElementsKindBits>(bit_field2); | |
495 | |
496 // TODO(verwaest): Support other elements kinds as well. | |
497 Label if_isobjectorsmi(assembler); | |
498 assembler->Branch( | |
499 assembler->Int32LessThanOrEqual( | |
500 elements_kind, assembler->Int32Constant(FAST_HOLEY_ELEMENTS)), | |
501 &if_isobjectorsmi, &call_runtime); | |
502 assembler->Bind(&if_isobjectorsmi); | |
503 { | |
504 Node* elements = assembler->LoadElements(object); | |
505 Node* length = assembler->LoadFixedArrayBaseLength(elements); | |
506 | |
507 Label if_iskeyinrange(assembler); | |
508 assembler->Branch( | |
509 assembler->Int32LessThan(index, assembler->SmiToWord32(length)), | |
510 &if_iskeyinrange, &return_false); | |
511 | |
512 assembler->Bind(&if_iskeyinrange); | |
513 Node* element = assembler->LoadFixedArrayElementInt32Index(elements, index); | |
514 Node* the_hole = assembler->LoadRoot(Heap::kTheHoleValueRootIndex); | |
515 assembler->Branch(assembler->WordEqual(element, the_hole), &return_false, | |
516 &return_true); | |
517 } | |
518 | |
519 assembler->Bind(&return_true); | |
520 assembler->Return(assembler->BooleanConstant(true)); | |
521 | |
522 assembler->Bind(&return_false); | |
523 assembler->Return(assembler->BooleanConstant(false)); | |
524 | |
525 assembler->Bind(&call_runtime); | |
526 assembler->Return(assembler->CallRuntime(Runtime::kObjectHasOwnProperty, | |
527 context, object, key)); | |
423 } | 528 } |
424 | 529 |
425 namespace { | 530 namespace { |
426 | 531 |
427 Object* DoArrayPush(Isolate* isolate, | 532 Object* DoArrayPush(Isolate* isolate, |
428 BuiltinArguments<BuiltinExtraArguments::kNone> args) { | 533 BuiltinArguments<BuiltinExtraArguments::kNone> args) { |
429 HandleScope scope(isolate); | 534 HandleScope scope(isolate); |
430 Handle<Object> receiver = args.receiver(); | 535 Handle<Object> receiver = args.receiver(); |
431 if (!EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 1)) { | 536 if (!EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 1)) { |
432 return CallJsIntrinsic(isolate, isolate->array_push(), args); | 537 return CallJsIntrinsic(isolate, isolate->array_push(), args); |
(...skipping 4229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4662 BUILTIN_LIST_T(DEFINE_BUILTIN_ACCESSOR_T) | 4767 BUILTIN_LIST_T(DEFINE_BUILTIN_ACCESSOR_T) |
4663 BUILTIN_LIST_H(DEFINE_BUILTIN_ACCESSOR_H) | 4768 BUILTIN_LIST_H(DEFINE_BUILTIN_ACCESSOR_H) |
4664 BUILTIN_LIST_DEBUG_A(DEFINE_BUILTIN_ACCESSOR_A) | 4769 BUILTIN_LIST_DEBUG_A(DEFINE_BUILTIN_ACCESSOR_A) |
4665 #undef DEFINE_BUILTIN_ACCESSOR_C | 4770 #undef DEFINE_BUILTIN_ACCESSOR_C |
4666 #undef DEFINE_BUILTIN_ACCESSOR_A | 4771 #undef DEFINE_BUILTIN_ACCESSOR_A |
4667 #undef DEFINE_BUILTIN_ACCESSOR_T | 4772 #undef DEFINE_BUILTIN_ACCESSOR_T |
4668 #undef DEFINE_BUILTIN_ACCESSOR_H | 4773 #undef DEFINE_BUILTIN_ACCESSOR_H |
4669 | 4774 |
4670 } // namespace internal | 4775 } // namespace internal |
4671 } // namespace v8 | 4776 } // namespace v8 |
OLD | NEW |