| Index: src/builtins/builtins-forin.cc
|
| diff --git a/src/builtins/builtins-forin.cc b/src/builtins/builtins-forin.cc
|
| deleted file mode 100644
|
| index 9d4dc49e376d3e1567bfbb51c8e71e895c3fba42..0000000000000000000000000000000000000000
|
| --- a/src/builtins/builtins-forin.cc
|
| +++ /dev/null
|
| @@ -1,222 +0,0 @@
|
| -// Copyright 2016 the V8 project authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#include "src/builtins/builtins-forin.h"
|
| -
|
| -#include "src/builtins/builtins-utils.h"
|
| -#include "src/builtins/builtins.h"
|
| -#include "src/code-factory.h"
|
| -#include "src/code-stub-assembler.h"
|
| -#include "src/counters.h"
|
| -#include "src/keys.h"
|
| -#include "src/lookup.h"
|
| -#include "src/objects-inl.h"
|
| -#include "src/property-descriptor.h"
|
| -
|
| -namespace v8 {
|
| -namespace internal {
|
| -
|
| -typedef compiler::Node Node;
|
| -
|
| -Node* ForInBuiltinsAssembler::ForInFilter(Node* key, Node* object,
|
| - Node* context) {
|
| - Label return_undefined(this, Label::kDeferred), return_to_name(this),
|
| - end(this);
|
| -
|
| - Variable var_result(this, MachineRepresentation::kTagged);
|
| -
|
| - Node* has_property =
|
| - HasProperty(object, key, context, Runtime::kForInHasProperty);
|
| -
|
| - Branch(WordEqual(has_property, BooleanConstant(true)), &return_to_name,
|
| - &return_undefined);
|
| -
|
| - Bind(&return_to_name);
|
| - {
|
| - var_result.Bind(ToName(context, key));
|
| - Goto(&end);
|
| - }
|
| -
|
| - Bind(&return_undefined);
|
| - {
|
| - var_result.Bind(UndefinedConstant());
|
| - Goto(&end);
|
| - }
|
| -
|
| - Bind(&end);
|
| - return var_result.value();
|
| -}
|
| -
|
| -std::tuple<Node*, Node*, Node*> ForInBuiltinsAssembler::EmitForInPrepare(
|
| - Node* object, Node* context, Label* call_runtime,
|
| - Label* nothing_to_iterate) {
|
| - Label use_cache(this);
|
| - CSA_ASSERT(this, IsJSReceiver(object));
|
| -
|
| - CheckEnumCache(object, &use_cache, nothing_to_iterate, call_runtime);
|
| -
|
| - Bind(&use_cache);
|
| - Node* map = LoadMap(object);
|
| - Node* enum_length = EnumLength(map);
|
| - GotoIf(WordEqual(enum_length, SmiConstant(0)), nothing_to_iterate);
|
| - Node* descriptors = LoadMapDescriptors(map);
|
| - Node* cache_offset =
|
| - LoadObjectField(descriptors, DescriptorArray::kEnumCacheOffset);
|
| - Node* enum_cache = LoadObjectField(
|
| - cache_offset, DescriptorArray::kEnumCacheBridgeCacheOffset);
|
| -
|
| - return std::make_tuple(map, enum_cache, enum_length);
|
| -}
|
| -
|
| -Node* ForInBuiltinsAssembler::EnumLength(Node* map) {
|
| - CSA_ASSERT(this, IsMap(map));
|
| - Node* bitfield_3 = LoadMapBitField3(map);
|
| - Node* enum_length = DecodeWordFromWord32<Map::EnumLengthBits>(bitfield_3);
|
| - return SmiTag(enum_length);
|
| -}
|
| -
|
| -void ForInBuiltinsAssembler::CheckPrototypeEnumCache(Node* receiver, Node* map,
|
| - Label* use_cache,
|
| - Label* use_runtime) {
|
| - Variable current_js_object(this, MachineRepresentation::kTagged, receiver);
|
| - Variable current_map(this, MachineRepresentation::kTagged, map);
|
| -
|
| - // These variables are updated in the loop below.
|
| - Variable* loop_vars[2] = {¤t_js_object, ¤t_map};
|
| - Label loop(this, 2, loop_vars), next(this);
|
| -
|
| - Goto(&loop);
|
| - // Check that there are no elements. |current_js_object| contains
|
| - // the current JS object we've reached through the prototype chain.
|
| - Bind(&loop);
|
| - {
|
| - Label if_elements(this), if_no_elements(this);
|
| - Node* elements = LoadElements(current_js_object.value());
|
| - Node* empty_fixed_array = LoadRoot(Heap::kEmptyFixedArrayRootIndex);
|
| - // Check that there are no elements.
|
| - Branch(WordEqual(elements, empty_fixed_array), &if_no_elements,
|
| - &if_elements);
|
| - Bind(&if_elements);
|
| - {
|
| - // Second chance, the object may be using the empty slow element
|
| - // dictionary.
|
| - Node* slow_empty_dictionary =
|
| - LoadRoot(Heap::kEmptySlowElementDictionaryRootIndex);
|
| - Branch(WordNotEqual(elements, slow_empty_dictionary), use_runtime,
|
| - &if_no_elements);
|
| - }
|
| -
|
| - Bind(&if_no_elements);
|
| - {
|
| - // Update map prototype.
|
| - current_js_object.Bind(LoadMapPrototype(current_map.value()));
|
| - Branch(WordEqual(current_js_object.value(), NullConstant()), use_cache,
|
| - &next);
|
| - }
|
| - }
|
| -
|
| - Bind(&next);
|
| - {
|
| - // For all objects but the receiver, check that the cache is empty.
|
| - current_map.Bind(LoadMap(current_js_object.value()));
|
| - Node* enum_length = EnumLength(current_map.value());
|
| - Node* zero_constant = SmiConstant(Smi::kZero);
|
| - Branch(WordEqual(enum_length, zero_constant), &loop, use_runtime);
|
| - }
|
| -}
|
| -
|
| -void ForInBuiltinsAssembler::CheckEnumCache(Node* receiver, Label* use_cache,
|
| - Label* nothing_to_iterate,
|
| - Label* use_runtime) {
|
| - Node* map = LoadMap(receiver);
|
| -
|
| - Label check_empty_prototype(this),
|
| - check_dict_receiver(this, Label::kDeferred);
|
| -
|
| - // Check if the enum length field is properly initialized, indicating that
|
| - // there is an enum cache.
|
| - {
|
| - Node* invalid_enum_cache_sentinel =
|
| - SmiConstant(Smi::FromInt(kInvalidEnumCacheSentinel));
|
| - Node* enum_length = EnumLength(map);
|
| - Branch(WordEqual(enum_length, invalid_enum_cache_sentinel),
|
| - &check_dict_receiver, &check_empty_prototype);
|
| - }
|
| -
|
| - // Check that there are no elements on the fast |receiver| and its prototype
|
| - // chain.
|
| - Bind(&check_empty_prototype);
|
| - CheckPrototypeEnumCache(receiver, map, use_cache, use_runtime);
|
| -
|
| - Label dict_loop(this);
|
| - Bind(&check_dict_receiver);
|
| - {
|
| - // Avoid runtime-call for empty dictionary receivers.
|
| - GotoIfNot(IsDictionaryMap(map), use_runtime);
|
| - Node* properties = LoadProperties(receiver);
|
| - Node* length = LoadFixedArrayElement(
|
| - properties, NameDictionary::kNumberOfElementsIndex);
|
| - GotoIfNot(WordEqual(length, SmiConstant(0)), use_runtime);
|
| - // Check that there are no elements on the |receiver| and its prototype
|
| - // chain. Given that we do not create an EnumCache for dict-mode objects,
|
| - // directly jump to |nothing_to_iterate| if there are no elements and no
|
| - // properties on the |receiver|.
|
| - CheckPrototypeEnumCache(receiver, map, nothing_to_iterate, use_runtime);
|
| - }
|
| -}
|
| -
|
| -TF_BUILTIN(ForInFilter, ForInBuiltinsAssembler) {
|
| - typedef ForInFilterDescriptor Descriptor;
|
| -
|
| - Node* key = Parameter(Descriptor::kKey);
|
| - Node* object = Parameter(Descriptor::kObject);
|
| - Node* context = Parameter(Descriptor::kContext);
|
| -
|
| - Return(ForInFilter(key, object, context));
|
| -}
|
| -
|
| -TF_BUILTIN(ForInNext, ForInBuiltinsAssembler) {
|
| - typedef ForInNextDescriptor Descriptor;
|
| -
|
| - Label filter(this);
|
| - Node* object = Parameter(Descriptor::kObject);
|
| - Node* cache_array = Parameter(Descriptor::kCacheArray);
|
| - Node* cache_type = Parameter(Descriptor::kCacheType);
|
| - Node* index = Parameter(Descriptor::kIndex);
|
| - Node* context = Parameter(Descriptor::kContext);
|
| -
|
| - Node* key = LoadFixedArrayElement(cache_array, SmiUntag(index));
|
| - Node* map = LoadMap(object);
|
| - GotoIfNot(WordEqual(map, cache_type), &filter);
|
| - Return(key);
|
| - Bind(&filter);
|
| - Return(ForInFilter(key, object, context));
|
| -}
|
| -
|
| -TF_BUILTIN(ForInPrepare, ForInBuiltinsAssembler) {
|
| - typedef ForInPrepareDescriptor Descriptor;
|
| -
|
| - Label call_runtime(this), nothing_to_iterate(this);
|
| - Node* object = Parameter(Descriptor::kObject);
|
| - Node* context = Parameter(Descriptor::kContext);
|
| -
|
| - Node* cache_type;
|
| - Node* cache_array;
|
| - Node* cache_length;
|
| - std::tie(cache_type, cache_array, cache_length) =
|
| - EmitForInPrepare(object, context, &call_runtime, ¬hing_to_iterate);
|
| -
|
| - Return(cache_type, cache_array, cache_length);
|
| -
|
| - Bind(&call_runtime);
|
| - TailCallRuntime(Runtime::kForInPrepare, context, object);
|
| -
|
| - Bind(¬hing_to_iterate);
|
| - {
|
| - Node* zero = SmiConstant(0);
|
| - Return(zero, zero, zero);
|
| - }
|
| -}
|
| -} // namespace internal
|
| -} // namespace v8
|
|
|