1 // Copyright 2014 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/runtime/runtime-utils.h"
6
7 #include "src/arguments.h"
8 #include "src/conversions-inl.h"
9 #include "src/factory.h"
10
11 namespace v8 {
12 namespace internal {
13
14
RUNTIME_FUNCTION(Runtime_StringGetRawHashField)15 RUNTIME_FUNCTION(Runtime_StringGetRawHashField) {
16 HandleScope scope(isolate);
17 DCHECK(args.length() == 1);
18 CONVERT_ARG_HANDLE_CHECKED(String, string, 0);
19 return *isolate->factory()->NewNumberFromUint(string->hash_field());
20 }
21
22
RUNTIME_FUNCTION(Runtime_TheHole)23 RUNTIME_FUNCTION(Runtime_TheHole) {
24 SealHandleScope shs(isolate);
25 DCHECK(args.length() == 0);
26 return isolate->heap()->the_hole_value();
27 }
28
29
RUNTIME_FUNCTION(Runtime_JSCollectionGetTable)30 RUNTIME_FUNCTION(Runtime_JSCollectionGetTable) {
31 SealHandleScope shs(isolate);
32 DCHECK(args.length() == 1);
33 CONVERT_ARG_CHECKED(JSObject, object, 0);
34 CHECK(object->IsJSSet() || object->IsJSMap());
35 return static_cast<JSCollection*>(object)->table();
36 }
37
38
RUNTIME_FUNCTION(Runtime_GenericHash)39 RUNTIME_FUNCTION(Runtime_GenericHash) {
40 HandleScope scope(isolate);
41 DCHECK(args.length() == 1);
42 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
43 Smi* hash = Object::GetOrCreateHash(isolate, object);
44 return hash;
45 }
46
47
RUNTIME_FUNCTION(Runtime_SetInitialize)48 RUNTIME_FUNCTION(Runtime_SetInitialize) {
49 HandleScope scope(isolate);
50 DCHECK(args.length() == 1);
51 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
52 JSSet::Initialize(holder, isolate);
53 return *holder;
54 }
55
56
RUNTIME_FUNCTION(Runtime_SetGrow)57 RUNTIME_FUNCTION(Runtime_SetGrow) {
58 HandleScope scope(isolate);
59 DCHECK(args.length() == 1);
60 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
61 Handle<OrderedHashSet> table(OrderedHashSet::cast(holder->table()));
62 table = OrderedHashSet::EnsureGrowable(table);
63 holder->set_table(*table);
64 return isolate->heap()->undefined_value();
65 }
66
67
RUNTIME_FUNCTION(Runtime_SetShrink)68 RUNTIME_FUNCTION(Runtime_SetShrink) {
69 HandleScope scope(isolate);
70 DCHECK(args.length() == 1);
71 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
72 Handle<OrderedHashSet> table(OrderedHashSet::cast(holder->table()));
73 table = OrderedHashSet::Shrink(table);
74 holder->set_table(*table);
75 return isolate->heap()->undefined_value();
76 }
77
78
RUNTIME_FUNCTION(Runtime_SetClear)79 RUNTIME_FUNCTION(Runtime_SetClear) {
80 HandleScope scope(isolate);
81 DCHECK(args.length() == 1);
82 CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
83 JSSet::Clear(holder);
84 return isolate->heap()->undefined_value();
85 }
86
87
RUNTIME_FUNCTION(Runtime_SetIteratorInitialize)88 RUNTIME_FUNCTION(Runtime_SetIteratorInitialize) {
89 HandleScope scope(isolate);
90 DCHECK(args.length() == 3);
91 CONVERT_ARG_HANDLE_CHECKED(JSSetIterator, holder, 0);
92 CONVERT_ARG_HANDLE_CHECKED(JSSet, set, 1);
93 CONVERT_SMI_ARG_CHECKED(kind, 2)
94 CHECK(kind == JSSetIterator::kKindValues ||
95 kind == JSSetIterator::kKindEntries);
96 Handle<OrderedHashSet> table(OrderedHashSet::cast(set->table()));
97 holder->set_table(*table);
98 holder->set_index(Smi::FromInt(0));
99 holder->set_kind(Smi::FromInt(kind));
100 return isolate->heap()->undefined_value();
101 }
102
103
RUNTIME_FUNCTION(Runtime_SetIteratorClone)104 RUNTIME_FUNCTION(Runtime_SetIteratorClone) {
105 HandleScope scope(isolate);
106 DCHECK(args.length() == 1);
107 CONVERT_ARG_HANDLE_CHECKED(JSSetIterator, holder, 0);
108
109 Handle<JSSetIterator> result = isolate->factory()->NewJSSetIterator();
110 result->set_table(holder->table());
111 result->set_index(Smi::FromInt(Smi::cast(holder->index())->value()));
112 result->set_kind(Smi::FromInt(Smi::cast(holder->kind())->value()));
113
114 return *result;
115 }
116
117
RUNTIME_FUNCTION(Runtime_SetIteratorNext)118 RUNTIME_FUNCTION(Runtime_SetIteratorNext) {
119 SealHandleScope shs(isolate);
120 DCHECK(args.length() == 2);
121 CONVERT_ARG_CHECKED(JSSetIterator, holder, 0);
122 CONVERT_ARG_CHECKED(JSArray, value_array, 1);
123 return holder->Next(value_array);
124 }
125
126
127 // The array returned contains the following information:
128 // 0: HasMore flag
129 // 1: Iteration index
130 // 2: Iteration kind
RUNTIME_FUNCTION(Runtime_SetIteratorDetails)131 RUNTIME_FUNCTION(Runtime_SetIteratorDetails) {
132 HandleScope scope(isolate);
133 DCHECK(args.length() == 1);
134 CONVERT_ARG_HANDLE_CHECKED(JSSetIterator, holder, 0);
135 Handle<FixedArray> details = isolate->factory()->NewFixedArray(4);
136 details->set(0, isolate->heap()->ToBoolean(holder->HasMore()));
137 details->set(1, holder->index());
138 details->set(2, holder->kind());
139 return *isolate->factory()->NewJSArrayWithElements(details);
140 }
141
142
RUNTIME_FUNCTION(Runtime_MapInitialize)143 RUNTIME_FUNCTION(Runtime_MapInitialize) {
144 HandleScope scope(isolate);
145 DCHECK(args.length() == 1);
146 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
147 JSMap::Initialize(holder, isolate);
148 return *holder;
149 }
150
151
RUNTIME_FUNCTION(Runtime_MapShrink)152 RUNTIME_FUNCTION(Runtime_MapShrink) {
153 HandleScope scope(isolate);
154 DCHECK(args.length() == 1);
155 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
156 Handle<OrderedHashMap> table(OrderedHashMap::cast(holder->table()));
157 table = OrderedHashMap::Shrink(table);
158 holder->set_table(*table);
159 return isolate->heap()->undefined_value();
160 }
161
162
RUNTIME_FUNCTION(Runtime_MapClear)163 RUNTIME_FUNCTION(Runtime_MapClear) {
164 HandleScope scope(isolate);
165 DCHECK(args.length() == 1);
166 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
167 JSMap::Clear(holder);
168 return isolate->heap()->undefined_value();
169 }
170
171
RUNTIME_FUNCTION(Runtime_MapGrow)172 RUNTIME_FUNCTION(Runtime_MapGrow) {
173 HandleScope scope(isolate);
174 DCHECK(args.length() == 1);
175 CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
176 Handle<OrderedHashMap> table(OrderedHashMap::cast(holder->table()));
177 table = OrderedHashMap::EnsureGrowable(table);
178 holder->set_table(*table);
179 return isolate->heap()->undefined_value();
180 }
181
182
RUNTIME_FUNCTION(Runtime_MapIteratorInitialize)183 RUNTIME_FUNCTION(Runtime_MapIteratorInitialize) {
184 HandleScope scope(isolate);
185 DCHECK(args.length() == 3);
186 CONVERT_ARG_HANDLE_CHECKED(JSMapIterator, holder, 0);
187 CONVERT_ARG_HANDLE_CHECKED(JSMap, map, 1);
188 CONVERT_SMI_ARG_CHECKED(kind, 2)
189 CHECK(kind == JSMapIterator::kKindKeys ||
190 kind == JSMapIterator::kKindValues ||
191 kind == JSMapIterator::kKindEntries);
192 Handle<OrderedHashMap> table(OrderedHashMap::cast(map->table()));
193 holder->set_table(*table);
194 holder->set_index(Smi::FromInt(0));
195 holder->set_kind(Smi::FromInt(kind));
196 return isolate->heap()->undefined_value();
197 }
198
199
RUNTIME_FUNCTION(Runtime_MapIteratorClone)200 RUNTIME_FUNCTION(Runtime_MapIteratorClone) {
201 HandleScope scope(isolate);
202 DCHECK(args.length() == 1);
203 CONVERT_ARG_HANDLE_CHECKED(JSMapIterator, holder, 0);
204
205 Handle<JSMapIterator> result = isolate->factory()->NewJSMapIterator();
206 result->set_table(holder->table());
207 result->set_index(Smi::FromInt(Smi::cast(holder->index())->value()));
208 result->set_kind(Smi::FromInt(Smi::cast(holder->kind())->value()));
209
210 return *result;
211 }
212
213
214 // The array returned contains the following information:
215 // 0: HasMore flag
216 // 1: Iteration index
217 // 2: Iteration kind
RUNTIME_FUNCTION(Runtime_MapIteratorDetails)218 RUNTIME_FUNCTION(Runtime_MapIteratorDetails) {
219 HandleScope scope(isolate);
220 DCHECK(args.length() == 1);
221 CONVERT_ARG_HANDLE_CHECKED(JSMapIterator, holder, 0);
222 Handle<FixedArray> details = isolate->factory()->NewFixedArray(4);
223 details->set(0, isolate->heap()->ToBoolean(holder->HasMore()));
224 details->set(1, holder->index());
225 details->set(2, holder->kind());
226 return *isolate->factory()->NewJSArrayWithElements(details);
227 }
228
229
RUNTIME_FUNCTION(Runtime_GetWeakMapEntries)230 RUNTIME_FUNCTION(Runtime_GetWeakMapEntries) {
231 HandleScope scope(isolate);
232 DCHECK(args.length() == 2);
233 CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, holder, 0);
234 CONVERT_NUMBER_CHECKED(int, max_entries, Int32, args[1]);
235 CHECK(max_entries >= 0);
236
237 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
238 if (max_entries == 0 || max_entries > table->NumberOfElements()) {
239 max_entries = table->NumberOfElements();
240 }
241 Handle<FixedArray> entries =
242 isolate->factory()->NewFixedArray(max_entries * 2);
243 // Allocation can cause GC can delete weak elements. Reload.
244 if (max_entries > table->NumberOfElements()) {
245 max_entries = table->NumberOfElements();
246 }
247
248 {
249 DisallowHeapAllocation no_gc;
250 int count = 0;
251 for (int i = 0; count / 2 < max_entries && i < table->Capacity(); i++) {
252 Handle<Object> key(table->KeyAt(i), isolate);
253 if (table->IsKey(isolate, *key)) {
254 entries->set(count++, *key);
255 Object* value = table->Lookup(key);
256 entries->set(count++, value);
257 }
258 }
259 DCHECK_EQ(max_entries * 2, count);
260 }
261 return *isolate->factory()->NewJSArrayWithElements(entries);
262 }
263
264
RUNTIME_FUNCTION(Runtime_MapIteratorNext)265 RUNTIME_FUNCTION(Runtime_MapIteratorNext) {
266 SealHandleScope shs(isolate);
267 DCHECK(args.length() == 2);
268 CONVERT_ARG_CHECKED(JSMapIterator, holder, 0);
269 CONVERT_ARG_CHECKED(JSArray, value_array, 1);
270 return holder->Next(value_array);
271 }
272
273
RUNTIME_FUNCTION(Runtime_WeakCollectionInitialize)274 RUNTIME_FUNCTION(Runtime_WeakCollectionInitialize) {
275 HandleScope scope(isolate);
276 DCHECK(args.length() == 1);
277 CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0);
278 JSWeakCollection::Initialize(weak_collection, isolate);
279 return *weak_collection;
280 }
281
282
RUNTIME_FUNCTION(Runtime_WeakCollectionGet)283 RUNTIME_FUNCTION(Runtime_WeakCollectionGet) {
284 HandleScope scope(isolate);
285 DCHECK(args.length() == 3);
286 CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0);
287 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
288 CONVERT_SMI_ARG_CHECKED(hash, 2)
289 CHECK(key->IsJSReceiver() || key->IsSymbol());
290 Handle<ObjectHashTable> table(
291 ObjectHashTable::cast(weak_collection->table()));
292 CHECK(table->IsKey(isolate, *key));
293 Handle<Object> lookup(table->Lookup(key, hash), isolate);
294 return lookup->IsTheHole(isolate) ? isolate->heap()->undefined_value()
295 : *lookup;
296 }
297
298
RUNTIME_FUNCTION(Runtime_WeakCollectionHas)299 RUNTIME_FUNCTION(Runtime_WeakCollectionHas) {
300 HandleScope scope(isolate);
301 DCHECK(args.length() == 3);
302 CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0);
303 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
304 CONVERT_SMI_ARG_CHECKED(hash, 2)
305 CHECK(key->IsJSReceiver() || key->IsSymbol());
306 Handle<ObjectHashTable> table(
307 ObjectHashTable::cast(weak_collection->table()));
308 CHECK(table->IsKey(isolate, *key));
309 Handle<Object> lookup(table->Lookup(key, hash), isolate);
310 return isolate->heap()->ToBoolean(!lookup->IsTheHole(isolate));
311 }
312
313
RUNTIME_FUNCTION(Runtime_WeakCollectionDelete)314 RUNTIME_FUNCTION(Runtime_WeakCollectionDelete) {
315 HandleScope scope(isolate);
316 DCHECK(args.length() == 3);
317 CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0);
318 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
319 CONVERT_SMI_ARG_CHECKED(hash, 2)
320 CHECK(key->IsJSReceiver() || key->IsSymbol());
321 Handle<ObjectHashTable> table(
322 ObjectHashTable::cast(weak_collection->table()));
323 CHECK(table->IsKey(isolate, *key));
324 bool was_present = JSWeakCollection::Delete(weak_collection, key, hash);
325 return isolate->heap()->ToBoolean(was_present);
326 }
327
328
RUNTIME_FUNCTION(Runtime_WeakCollectionSet)329 RUNTIME_FUNCTION(Runtime_WeakCollectionSet) {
330 HandleScope scope(isolate);
331 DCHECK(args.length() == 4);
332 CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0);
333 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
334 CHECK(key->IsJSReceiver() || key->IsSymbol());
335 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
336 CONVERT_SMI_ARG_CHECKED(hash, 3)
337 Handle<ObjectHashTable> table(
338 ObjectHashTable::cast(weak_collection->table()));
339 CHECK(table->IsKey(isolate, *key));
340 JSWeakCollection::Set(weak_collection, key, value, hash);
341 return *weak_collection;
342 }
343
344
RUNTIME_FUNCTION(Runtime_GetWeakSetValues)345 RUNTIME_FUNCTION(Runtime_GetWeakSetValues) {
346 HandleScope scope(isolate);
347 DCHECK(args.length() == 2);
348 CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, holder, 0);
349 CONVERT_NUMBER_CHECKED(int, max_values, Int32, args[1]);
350 CHECK(max_values >= 0);
351
352 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
353 if (max_values == 0 || max_values > table->NumberOfElements()) {
354 max_values = table->NumberOfElements();
355 }
356 Handle<FixedArray> values = isolate->factory()->NewFixedArray(max_values);
357 // Recompute max_values because GC could have removed elements from the table.
358 if (max_values > table->NumberOfElements()) {
359 max_values = table->NumberOfElements();
360 }
361 {
362 DisallowHeapAllocation no_gc;
363 int count = 0;
364 for (int i = 0; count < max_values && i < table->Capacity(); i++) {
365 Object* key = table->KeyAt(i);
366 if (table->IsKey(isolate, key)) values->set(count++, key);
367 }
368 DCHECK_EQ(max_values, count);
369 }
370 return *isolate->factory()->NewJSArrayWithElements(values);
371 }
372 } // namespace internal
373 } // namespace v8
374