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 |