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

Side by Side Diff: src/builtins.cc

Issue 1843613002: Add initial code-stub version of Object.prototype.hasOwnProperty (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Rebase Created 4 years, 8 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
« no previous file with comments | « src/builtins.h ('k') | src/compiler/code-stub-assembler.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 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
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
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
OLDNEW
« no previous file with comments | « src/builtins.h ('k') | src/compiler/code-stub-assembler.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698