Line data Source code
1 : // Copyright 2017 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #include "src/builtins/builtins-iterator-gen.h"
6 :
7 : #include "src/factory-inl.h"
8 :
9 : namespace v8 {
10 : namespace internal {
11 :
12 : using compiler::Node;
13 :
14 124 : Node* IteratorBuiltinsAssembler::GetIterator(Node* context, Node* object,
15 : Label* if_exception,
16 : Variable* exception) {
17 248 : Node* method = GetProperty(context, object, factory()->iterator_symbol());
18 124 : GotoIfException(method, if_exception, exception);
19 :
20 124 : Callable callable = CodeFactory::Call(isolate());
21 124 : Node* iterator = CallJS(callable, context, method, object);
22 124 : GotoIfException(iterator, if_exception, exception);
23 :
24 124 : Label done(this), if_notobject(this, Label::kDeferred);
25 248 : GotoIf(TaggedIsSmi(iterator), &if_notobject);
26 248 : Branch(IsJSReceiver(iterator), &done, &if_notobject);
27 :
28 124 : BIND(&if_notobject);
29 : {
30 : Node* ret =
31 : CallRuntime(Runtime::kThrowTypeError, context,
32 124 : SmiConstant(MessageTemplate::kNotAnIterator), iterator);
33 124 : GotoIfException(ret, if_exception, exception);
34 124 : Unreachable();
35 : }
36 :
37 124 : BIND(&done);
38 124 : return iterator;
39 : }
40 :
41 124 : Node* IteratorBuiltinsAssembler::IteratorStep(Node* context, Node* iterator,
42 : Label* if_done,
43 : Node* fast_iterator_result_map,
44 : Label* if_exception,
45 : Variable* exception) {
46 : DCHECK_NOT_NULL(if_done);
47 :
48 : // IteratorNext
49 248 : Node* next_method = GetProperty(context, iterator, factory()->next_string());
50 124 : GotoIfException(next_method, if_exception, exception);
51 :
52 : // 1. a. Let result be ? Invoke(iterator, "next", « »).
53 124 : Callable callable = CodeFactory::Call(isolate());
54 124 : Node* result = CallJS(callable, context, next_method, iterator);
55 124 : GotoIfException(result, if_exception, exception);
56 :
57 : // 3. If Type(result) is not Object, throw a TypeError exception.
58 124 : Label if_notobject(this, Label::kDeferred), return_result(this);
59 248 : GotoIf(TaggedIsSmi(result), &if_notobject);
60 248 : GotoIfNot(IsJSReceiver(result), &if_notobject);
61 :
62 248 : VARIABLE(var_done, MachineRepresentation::kTagged);
63 :
64 124 : if (fast_iterator_result_map != nullptr) {
65 : // Fast iterator result case:
66 : Label if_generic(this);
67 :
68 : // 4. Return result.
69 248 : Node* map = LoadMap(result);
70 248 : GotoIfNot(WordEqual(map, fast_iterator_result_map), &if_generic);
71 :
72 : // IteratorComplete
73 : // 2. Return ToBoolean(? Get(iterResult, "done")).
74 : Node* done = LoadObjectField(result, JSIteratorResult::kDoneOffset);
75 : CSA_ASSERT(this, IsBoolean(done));
76 124 : var_done.Bind(done);
77 124 : Goto(&return_result);
78 :
79 124 : BIND(&if_generic);
80 : }
81 :
82 : // Generic iterator result case:
83 : {
84 : // IteratorComplete
85 : // 2. Return ToBoolean(? Get(iterResult, "done")).
86 248 : Node* done = GetProperty(context, result, factory()->done_string());
87 124 : GotoIfException(done, if_exception, exception);
88 124 : var_done.Bind(done);
89 :
90 : Label to_boolean(this, Label::kDeferred);
91 248 : GotoIf(TaggedIsSmi(done), &to_boolean);
92 248 : Branch(IsBoolean(done), &return_result, &to_boolean);
93 :
94 124 : BIND(&to_boolean);
95 124 : var_done.Bind(CallBuiltin(Builtins::kToBoolean, context, done));
96 124 : Goto(&return_result);
97 : }
98 :
99 124 : BIND(&if_notobject);
100 : {
101 : Node* ret =
102 : CallRuntime(Runtime::kThrowIteratorResultNotAnObject, context, result);
103 124 : GotoIfException(ret, if_exception, exception);
104 124 : Unreachable();
105 : }
106 :
107 124 : BIND(&return_result);
108 372 : GotoIf(IsTrue(var_done.value()), if_done);
109 124 : return result;
110 : }
111 :
112 124 : Node* IteratorBuiltinsAssembler::IteratorValue(Node* context, Node* result,
113 : Node* fast_iterator_result_map,
114 : Label* if_exception,
115 : Variable* exception) {
116 : CSA_ASSERT(this, IsJSReceiver(result));
117 :
118 124 : Label exit(this);
119 248 : VARIABLE(var_value, MachineRepresentation::kTagged);
120 124 : if (fast_iterator_result_map != nullptr) {
121 : // Fast iterator result case:
122 : Label if_generic(this);
123 248 : Node* map = LoadMap(result);
124 248 : GotoIfNot(WordEqual(map, fast_iterator_result_map), &if_generic);
125 124 : var_value.Bind(LoadObjectField(result, JSIteratorResult::kValueOffset));
126 124 : Goto(&exit);
127 :
128 124 : BIND(&if_generic);
129 : }
130 :
131 : // Generic iterator result case:
132 : {
133 248 : Node* value = GetProperty(context, result, factory()->value_string());
134 124 : GotoIfException(value, if_exception, exception);
135 124 : var_value.Bind(value);
136 124 : Goto(&exit);
137 : }
138 :
139 124 : BIND(&exit);
140 248 : return var_value.value();
141 : }
142 :
143 124 : void IteratorBuiltinsAssembler::IteratorCloseOnException(Node* context,
144 : Node* iterator,
145 : Label* if_exception,
146 : Variable* exception) {
147 : // Perform ES #sec-iteratorclose when an exception occurs. This simpler
148 : // algorithm does not include redundant steps which are never reachable from
149 : // the spec IteratorClose algorithm.
150 : DCHECK_NOT_NULL(if_exception);
151 : DCHECK_NOT_NULL(exception);
152 : CSA_ASSERT(this, IsNotTheHole(exception->value()));
153 : CSA_ASSERT(this, IsJSReceiver(iterator));
154 :
155 : // Let return be ? GetMethod(iterator, "return").
156 248 : Node* method = GetProperty(context, iterator, factory()->return_string());
157 124 : GotoIfException(method, if_exception, exception);
158 :
159 : // If return is undefined, return Completion(completion).
160 496 : GotoIf(Word32Or(IsUndefined(method), IsNull(method)), if_exception);
161 :
162 : {
163 : // Let innerResult be Call(return, iterator, « »).
164 : // If an exception occurs, the original exception remains bound
165 : Node* inner_result =
166 124 : CallJS(CodeFactory::Call(isolate()), context, method, iterator);
167 124 : GotoIfException(inner_result, if_exception, nullptr);
168 :
169 : // (If completion.[[Type]] is throw) return Completion(completion).
170 124 : Goto(if_exception);
171 : }
172 124 : }
173 :
174 62 : void IteratorBuiltinsAssembler::IteratorCloseOnException(Node* context,
175 : Node* iterator,
176 : Variable* exception) {
177 62 : Label rethrow(this, Label::kDeferred);
178 62 : IteratorCloseOnException(context, iterator, &rethrow, exception);
179 :
180 62 : BIND(&rethrow);
181 62 : CallRuntime(Runtime::kReThrow, context, exception->value());
182 62 : Unreachable();
183 62 : }
184 :
185 : } // namespace internal
186 : } // namespace v8
|