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