1ba1e34356caf5d93e425c7f3b0e6c337b655107
[platform/upstream/v8.git] / src / runtime / runtime-collections.cc
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/v8.h"
6
7 #include "src/arguments.h"
8 #include "src/runtime/runtime-utils.h"
9
10
11 namespace v8 {
12 namespace internal {
13
14
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
23 RUNTIME_FUNCTION(Runtime_TheHole) {
24   SealHandleScope shs(isolate);
25   DCHECK(args.length() == 0);
26   return isolate->heap()->the_hole_value();
27 }
28
29
30 RUNTIME_FUNCTION(Runtime_JSCollectionGetTable) {
31   SealHandleScope shs(isolate);
32   DCHECK(args.length() == 1);
33   CONVERT_ARG_CHECKED(JSObject, object, 0);
34   RUNTIME_ASSERT(object->IsJSSet() || object->IsJSMap());
35   return static_cast<JSCollection*>(object)->table();
36 }
37
38
39 RUNTIME_FUNCTION(Runtime_GenericHash) {
40   HandleScope scope(isolate);
41   DCHECK(args.length() == 1);
42   CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
43   Handle<Smi> hash = Object::GetOrCreateHash(isolate, object);
44   return *hash;
45 }
46
47
48 void Runtime::JSSetInitialize(Isolate* isolate, Handle<JSSet> set) {
49   Handle<OrderedHashSet> table = isolate->factory()->NewOrderedHashSet();
50   set->set_table(*table);
51 }
52
53
54 RUNTIME_FUNCTION(Runtime_SetInitialize) {
55   HandleScope scope(isolate);
56   DCHECK(args.length() == 1);
57   CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
58   Runtime::JSSetInitialize(isolate, holder);
59   return *holder;
60 }
61
62
63 RUNTIME_FUNCTION(Runtime_SetGrow) {
64   HandleScope scope(isolate);
65   DCHECK(args.length() == 1);
66   CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
67   Handle<OrderedHashSet> table(OrderedHashSet::cast(holder->table()));
68   table = OrderedHashSet::EnsureGrowable(table);
69   holder->set_table(*table);
70   return isolate->heap()->undefined_value();
71 }
72
73
74 RUNTIME_FUNCTION(Runtime_SetShrink) {
75   HandleScope scope(isolate);
76   DCHECK(args.length() == 1);
77   CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
78   Handle<OrderedHashSet> table(OrderedHashSet::cast(holder->table()));
79   table = OrderedHashSet::Shrink(table);
80   holder->set_table(*table);
81   return isolate->heap()->undefined_value();
82 }
83
84
85 void Runtime::JSSetClear(Isolate* isolate, Handle<JSSet> set) {
86   Handle<OrderedHashSet> table(OrderedHashSet::cast(set->table()));
87   table = OrderedHashSet::Clear(table);
88   set->set_table(*table);
89 }
90
91
92 RUNTIME_FUNCTION(Runtime_SetClear) {
93   HandleScope scope(isolate);
94   DCHECK(args.length() == 1);
95   CONVERT_ARG_HANDLE_CHECKED(JSSet, holder, 0);
96   Runtime::JSSetClear(isolate, holder);
97   return isolate->heap()->undefined_value();
98 }
99
100
101 RUNTIME_FUNCTION(Runtime_SetIteratorInitialize) {
102   HandleScope scope(isolate);
103   DCHECK(args.length() == 3);
104   CONVERT_ARG_HANDLE_CHECKED(JSSetIterator, holder, 0);
105   CONVERT_ARG_HANDLE_CHECKED(JSSet, set, 1);
106   CONVERT_SMI_ARG_CHECKED(kind, 2)
107   RUNTIME_ASSERT(kind == JSSetIterator::kKindValues ||
108                  kind == JSSetIterator::kKindEntries);
109   Handle<OrderedHashSet> table(OrderedHashSet::cast(set->table()));
110   holder->set_table(*table);
111   holder->set_index(Smi::FromInt(0));
112   holder->set_kind(Smi::FromInt(kind));
113   return isolate->heap()->undefined_value();
114 }
115
116
117 RUNTIME_FUNCTION(Runtime_SetIteratorClone) {
118   HandleScope scope(isolate);
119   DCHECK(args.length() == 1);
120   CONVERT_ARG_HANDLE_CHECKED(JSSetIterator, holder, 0);
121
122   Handle<JSSetIterator> result = isolate->factory()->NewJSSetIterator();
123   result->set_table(holder->table());
124   result->set_index(Smi::FromInt(Smi::cast(holder->index())->value()));
125   result->set_kind(Smi::FromInt(Smi::cast(holder->kind())->value()));
126
127   return *result;
128 }
129
130
131 RUNTIME_FUNCTION(Runtime_SetIteratorNext) {
132   SealHandleScope shs(isolate);
133   DCHECK(args.length() == 2);
134   CONVERT_ARG_CHECKED(JSSetIterator, holder, 0);
135   CONVERT_ARG_CHECKED(JSArray, value_array, 1);
136   return holder->Next(value_array);
137 }
138
139
140 // The array returned contains the following information:
141 // 0: HasMore flag
142 // 1: Iteration index
143 // 2: Iteration kind
144 RUNTIME_FUNCTION(Runtime_SetIteratorDetails) {
145   HandleScope scope(isolate);
146   DCHECK(args.length() == 1);
147   CONVERT_ARG_HANDLE_CHECKED(JSSetIterator, holder, 0);
148   Handle<FixedArray> details = isolate->factory()->NewFixedArray(4);
149   details->set(0, isolate->heap()->ToBoolean(holder->HasMore()));
150   details->set(1, holder->index());
151   details->set(2, holder->kind());
152   return *isolate->factory()->NewJSArrayWithElements(details);
153 }
154
155
156 void Runtime::JSMapInitialize(Isolate* isolate, Handle<JSMap> map) {
157   Handle<OrderedHashMap> table = isolate->factory()->NewOrderedHashMap();
158   map->set_table(*table);
159 }
160
161
162 RUNTIME_FUNCTION(Runtime_MapInitialize) {
163   HandleScope scope(isolate);
164   DCHECK(args.length() == 1);
165   CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
166   Runtime::JSMapInitialize(isolate, holder);
167   return *holder;
168 }
169
170
171 RUNTIME_FUNCTION(Runtime_MapShrink) {
172   HandleScope scope(isolate);
173   DCHECK(args.length() == 1);
174   CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
175   Handle<OrderedHashMap> table(OrderedHashMap::cast(holder->table()));
176   table = OrderedHashMap::Shrink(table);
177   holder->set_table(*table);
178   return isolate->heap()->undefined_value();
179 }
180
181
182 void Runtime::JSMapClear(Isolate* isolate, Handle<JSMap> map) {
183   Handle<OrderedHashMap> table(OrderedHashMap::cast(map->table()));
184   table = OrderedHashMap::Clear(table);
185   map->set_table(*table);
186 }
187
188
189 RUNTIME_FUNCTION(Runtime_MapClear) {
190   HandleScope scope(isolate);
191   DCHECK(args.length() == 1);
192   CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
193   Runtime::JSMapClear(isolate, holder);
194   return isolate->heap()->undefined_value();
195 }
196
197
198 RUNTIME_FUNCTION(Runtime_MapGrow) {
199   HandleScope scope(isolate);
200   DCHECK(args.length() == 1);
201   CONVERT_ARG_HANDLE_CHECKED(JSMap, holder, 0);
202   Handle<OrderedHashMap> table(OrderedHashMap::cast(holder->table()));
203   table = OrderedHashMap::EnsureGrowable(table);
204   holder->set_table(*table);
205   return isolate->heap()->undefined_value();
206 }
207
208
209 RUNTIME_FUNCTION(Runtime_MapIteratorInitialize) {
210   HandleScope scope(isolate);
211   DCHECK(args.length() == 3);
212   CONVERT_ARG_HANDLE_CHECKED(JSMapIterator, holder, 0);
213   CONVERT_ARG_HANDLE_CHECKED(JSMap, map, 1);
214   CONVERT_SMI_ARG_CHECKED(kind, 2)
215   RUNTIME_ASSERT(kind == JSMapIterator::kKindKeys ||
216                  kind == JSMapIterator::kKindValues ||
217                  kind == JSMapIterator::kKindEntries);
218   Handle<OrderedHashMap> table(OrderedHashMap::cast(map->table()));
219   holder->set_table(*table);
220   holder->set_index(Smi::FromInt(0));
221   holder->set_kind(Smi::FromInt(kind));
222   return isolate->heap()->undefined_value();
223 }
224
225
226 RUNTIME_FUNCTION(Runtime_MapIteratorClone) {
227   HandleScope scope(isolate);
228   DCHECK(args.length() == 1);
229   CONVERT_ARG_HANDLE_CHECKED(JSMapIterator, holder, 0);
230
231   Handle<JSMapIterator> result = isolate->factory()->NewJSMapIterator();
232   result->set_table(holder->table());
233   result->set_index(Smi::FromInt(Smi::cast(holder->index())->value()));
234   result->set_kind(Smi::FromInt(Smi::cast(holder->kind())->value()));
235
236   return *result;
237 }
238
239
240 // The array returned contains the following information:
241 // 0: HasMore flag
242 // 1: Iteration index
243 // 2: Iteration kind
244 RUNTIME_FUNCTION(Runtime_MapIteratorDetails) {
245   HandleScope scope(isolate);
246   DCHECK(args.length() == 1);
247   CONVERT_ARG_HANDLE_CHECKED(JSMapIterator, holder, 0);
248   Handle<FixedArray> details = isolate->factory()->NewFixedArray(4);
249   details->set(0, isolate->heap()->ToBoolean(holder->HasMore()));
250   details->set(1, holder->index());
251   details->set(2, holder->kind());
252   return *isolate->factory()->NewJSArrayWithElements(details);
253 }
254
255
256 RUNTIME_FUNCTION(Runtime_GetWeakMapEntries) {
257   HandleScope scope(isolate);
258   DCHECK(args.length() == 2);
259   CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, holder, 0);
260   CONVERT_NUMBER_CHECKED(int, max_entries, Int32, args[1]);
261   RUNTIME_ASSERT(max_entries >= 0);
262
263   Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
264   if (max_entries == 0 || max_entries > table->NumberOfElements()) {
265     max_entries = table->NumberOfElements();
266   }
267   Handle<FixedArray> entries =
268       isolate->factory()->NewFixedArray(max_entries * 2);
269   // Allocation can cause GC can delete weak elements. Reload.
270   if (max_entries > table->NumberOfElements()) {
271     max_entries = table->NumberOfElements();
272   }
273
274   {
275     DisallowHeapAllocation no_gc;
276     int count = 0;
277     for (int i = 0; count / 2 < max_entries && i < table->Capacity(); i++) {
278       Handle<Object> key(table->KeyAt(i), isolate);
279       if (table->IsKey(*key)) {
280         entries->set(count++, *key);
281         Object* value = table->Lookup(key);
282         entries->set(count++, value);
283       }
284     }
285     DCHECK_EQ(max_entries * 2, count);
286   }
287   return *isolate->factory()->NewJSArrayWithElements(entries);
288 }
289
290
291 RUNTIME_FUNCTION(Runtime_MapIteratorNext) {
292   SealHandleScope shs(isolate);
293   DCHECK(args.length() == 2);
294   CONVERT_ARG_CHECKED(JSMapIterator, holder, 0);
295   CONVERT_ARG_CHECKED(JSArray, value_array, 1);
296   return holder->Next(value_array);
297 }
298
299
300 void Runtime::WeakCollectionInitialize(
301     Isolate* isolate, Handle<JSWeakCollection> weak_collection) {
302   DCHECK(weak_collection->map()->inobject_properties() == 0);
303   Handle<ObjectHashTable> table = ObjectHashTable::New(isolate, 0);
304   weak_collection->set_table(*table);
305 }
306
307
308 RUNTIME_FUNCTION(Runtime_WeakCollectionInitialize) {
309   HandleScope scope(isolate);
310   DCHECK(args.length() == 1);
311   CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0);
312   Runtime::WeakCollectionInitialize(isolate, weak_collection);
313   return *weak_collection;
314 }
315
316
317 RUNTIME_FUNCTION(Runtime_WeakCollectionGet) {
318   HandleScope scope(isolate);
319   DCHECK(args.length() == 3);
320   CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0);
321   CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
322   CONVERT_SMI_ARG_CHECKED(hash, 2)
323   RUNTIME_ASSERT(key->IsJSReceiver() || key->IsSymbol());
324   Handle<ObjectHashTable> table(
325       ObjectHashTable::cast(weak_collection->table()));
326   RUNTIME_ASSERT(table->IsKey(*key));
327   Handle<Object> lookup(table->Lookup(key, hash), isolate);
328   return lookup->IsTheHole() ? isolate->heap()->undefined_value() : *lookup;
329 }
330
331
332 RUNTIME_FUNCTION(Runtime_WeakCollectionHas) {
333   HandleScope scope(isolate);
334   DCHECK(args.length() == 3);
335   CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0);
336   CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
337   CONVERT_SMI_ARG_CHECKED(hash, 2)
338   RUNTIME_ASSERT(key->IsJSReceiver() || key->IsSymbol());
339   Handle<ObjectHashTable> table(
340       ObjectHashTable::cast(weak_collection->table()));
341   RUNTIME_ASSERT(table->IsKey(*key));
342   Handle<Object> lookup(table->Lookup(key, hash), isolate);
343   return isolate->heap()->ToBoolean(!lookup->IsTheHole());
344 }
345
346
347 bool Runtime::WeakCollectionDelete(Handle<JSWeakCollection> weak_collection,
348                                    Handle<Object> key) {
349   int32_t hash =
350       Object::GetOrCreateHash(weak_collection->GetIsolate(), key)->value();
351   return WeakCollectionDelete(weak_collection, key, hash);
352 }
353
354
355 bool Runtime::WeakCollectionDelete(Handle<JSWeakCollection> weak_collection,
356                                    Handle<Object> key, int32_t hash) {
357   DCHECK(key->IsJSReceiver() || key->IsSymbol());
358   Handle<ObjectHashTable> table(
359       ObjectHashTable::cast(weak_collection->table()));
360   DCHECK(table->IsKey(*key));
361   bool was_present = false;
362   Handle<ObjectHashTable> new_table =
363       ObjectHashTable::Remove(table, key, &was_present, hash);
364   weak_collection->set_table(*new_table);
365   if (*table != *new_table) {
366     // Zap the old table since we didn't record slots for its elements.
367     table->FillWithHoles(0, table->length());
368   }
369   return was_present;
370 }
371
372
373 RUNTIME_FUNCTION(Runtime_WeakCollectionDelete) {
374   HandleScope scope(isolate);
375   DCHECK(args.length() == 3);
376   CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0);
377   CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
378   CONVERT_SMI_ARG_CHECKED(hash, 2)
379   RUNTIME_ASSERT(key->IsJSReceiver() || key->IsSymbol());
380   Handle<ObjectHashTable> table(
381       ObjectHashTable::cast(weak_collection->table()));
382   RUNTIME_ASSERT(table->IsKey(*key));
383   bool was_present = Runtime::WeakCollectionDelete(weak_collection, key, hash);
384   return isolate->heap()->ToBoolean(was_present);
385 }
386
387
388 void Runtime::WeakCollectionSet(Handle<JSWeakCollection> weak_collection,
389                                 Handle<Object> key, Handle<Object> value,
390                                 int32_t hash) {
391   DCHECK(key->IsJSReceiver() || key->IsSymbol());
392   Handle<ObjectHashTable> table(
393       ObjectHashTable::cast(weak_collection->table()));
394   DCHECK(table->IsKey(*key));
395   Handle<ObjectHashTable> new_table =
396       ObjectHashTable::Put(table, key, value, hash);
397   weak_collection->set_table(*new_table);
398   if (*table != *new_table) {
399     // Zap the old table since we didn't record slots for its elements.
400     table->FillWithHoles(0, table->length());
401   }
402 }
403
404
405 RUNTIME_FUNCTION(Runtime_WeakCollectionSet) {
406   HandleScope scope(isolate);
407   DCHECK(args.length() == 4);
408   CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, weak_collection, 0);
409   CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
410   RUNTIME_ASSERT(key->IsJSReceiver() || key->IsSymbol());
411   CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
412   CONVERT_SMI_ARG_CHECKED(hash, 3)
413   Handle<ObjectHashTable> table(
414       ObjectHashTable::cast(weak_collection->table()));
415   RUNTIME_ASSERT(table->IsKey(*key));
416   Runtime::WeakCollectionSet(weak_collection, key, value, hash);
417   return *weak_collection;
418 }
419
420
421 RUNTIME_FUNCTION(Runtime_GetWeakSetValues) {
422   HandleScope scope(isolate);
423   DCHECK(args.length() == 2);
424   CONVERT_ARG_HANDLE_CHECKED(JSWeakCollection, holder, 0);
425   CONVERT_NUMBER_CHECKED(int, max_values, Int32, args[1]);
426   RUNTIME_ASSERT(max_values >= 0);
427
428   Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
429   if (max_values == 0 || max_values > table->NumberOfElements()) {
430     max_values = table->NumberOfElements();
431   }
432   Handle<FixedArray> values = isolate->factory()->NewFixedArray(max_values);
433   // Recompute max_values because GC could have removed elements from the table.
434   if (max_values > table->NumberOfElements()) {
435     max_values = table->NumberOfElements();
436   }
437   {
438     DisallowHeapAllocation no_gc;
439     int count = 0;
440     for (int i = 0; count < max_values && i < table->Capacity(); i++) {
441       Handle<Object> key(table->KeyAt(i), isolate);
442       if (table->IsKey(*key)) values->set(count++, *key);
443     }
444     DCHECK_EQ(max_values, count);
445   }
446   return *isolate->factory()->NewJSArrayWithElements(values);
447 }
448
449
450 RUNTIME_FUNCTION(Runtime_ObservationWeakMapCreate) {
451   HandleScope scope(isolate);
452   DCHECK(args.length() == 0);
453   Handle<JSWeakMap> weakmap = isolate->factory()->NewJSWeakMap();
454   Runtime::WeakCollectionInitialize(isolate, weakmap);
455   return *weakmap;
456 }
457 }  // namespace internal
458 }  // namespace v8