blob: c44945c94ce64141006ee7293b30b4ceb068606a [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// Copyright 2015 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"
Ben Murdoch097c5b22016-05-18 11:27:45 +01008#include "src/factory.h"
9#include "src/isolate-inl.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010#include "src/objects-inl.h"
11
12namespace v8 {
13namespace internal {
14
Ben Murdoch097c5b22016-05-18 11:27:45 +010015namespace {
16
17// Returns either a FixedArray or, if the given {receiver} has an enum cache
18// that contains all enumerable properties of the {receiver} and its prototypes
19// have none, the map of the {receiver}. This is used to speed up the check for
20// deletions during a for-in.
21MaybeHandle<HeapObject> Enumerate(Handle<JSReceiver> receiver) {
22 Isolate* const isolate = receiver->GetIsolate();
23 // Test if we have an enum cache for {receiver}.
24 if (!receiver->IsSimpleEnum()) {
25 Handle<FixedArray> keys;
26 ASSIGN_RETURN_ON_EXCEPTION(
27 isolate, keys,
28 JSReceiver::GetKeys(receiver, INCLUDE_PROTOS, ENUMERABLE_STRINGS),
29 HeapObject);
30 // Test again, since cache may have been built by GetKeys() calls above.
31 if (!receiver->IsSimpleEnum()) return keys;
32 }
33 return handle(receiver->map(), isolate);
34}
35
36
37MaybeHandle<Object> Filter(Handle<JSReceiver> receiver, Handle<Object> key) {
38 Isolate* const isolate = receiver->GetIsolate();
39 // TODO(turbofan): Fast case for array indices.
40 Handle<Name> name;
41 ASSIGN_RETURN_ON_EXCEPTION(isolate, name, Object::ToName(isolate, key),
42 Object);
43 Maybe<bool> result = JSReceiver::HasProperty(receiver, name);
44 MAYBE_RETURN_NULL(result);
45 if (result.FromJust()) return name;
46 return isolate->factory()->undefined_value();
47}
48
49} // namespace
50
51
52RUNTIME_FUNCTION(Runtime_ForInEnumerate) {
53 HandleScope scope(isolate);
54 DCHECK_EQ(1, args.length());
55 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0);
56 Handle<HeapObject> result;
57 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, Enumerate(receiver));
58 return *result;
59}
60
61
62RUNTIME_FUNCTION_RETURN_TRIPLE(Runtime_ForInPrepare) {
63 HandleScope scope(isolate);
64 DCHECK_EQ(1, args.length());
65 Handle<JSReceiver> receiver = args.at<JSReceiver>(0);
66 Handle<Object> cache_type;
67 if (!Enumerate(receiver).ToHandle(&cache_type)) {
68 return MakeTriple(isolate->heap()->exception(), nullptr, nullptr);
69 }
70 Handle<FixedArray> cache_array;
71 int cache_length;
72 if (cache_type->IsMap()) {
73 Handle<Map> cache_map = Handle<Map>::cast(cache_type);
74 Handle<DescriptorArray> descriptors(cache_map->instance_descriptors(),
75 isolate);
76 cache_length = cache_map->EnumLength();
77 if (cache_length && descriptors->HasEnumCache()) {
78 cache_array = handle(descriptors->GetEnumCache(), isolate);
79 } else {
80 cache_array = isolate->factory()->empty_fixed_array();
81 cache_length = 0;
82 }
83 } else {
84 cache_array = Handle<FixedArray>::cast(cache_type);
85 cache_length = cache_array->length();
86 cache_type = handle(Smi::FromInt(1), isolate);
87 }
88 return MakeTriple(*cache_type, *cache_array, Smi::FromInt(cache_length));
89}
90
91
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000092RUNTIME_FUNCTION(Runtime_ForInDone) {
93 SealHandleScope scope(isolate);
94 DCHECK_EQ(2, args.length());
95 CONVERT_SMI_ARG_CHECKED(index, 0);
96 CONVERT_SMI_ARG_CHECKED(length, 1);
97 DCHECK_LE(0, index);
98 DCHECK_LE(index, length);
99 return isolate->heap()->ToBoolean(index == length);
100}
101
102
103RUNTIME_FUNCTION(Runtime_ForInFilter) {
104 HandleScope scope(isolate);
105 DCHECK_EQ(2, args.length());
106 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0);
107 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100108 Handle<Object> result;
109 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, Filter(receiver, key));
110 return *result;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000111}
112
113
114RUNTIME_FUNCTION(Runtime_ForInNext) {
115 HandleScope scope(isolate);
116 DCHECK_EQ(4, args.length());
117 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0);
118 CONVERT_ARG_HANDLE_CHECKED(FixedArray, cache_array, 1);
119 CONVERT_ARG_HANDLE_CHECKED(Object, cache_type, 2);
120 CONVERT_SMI_ARG_CHECKED(index, 3);
121 Handle<Object> key = handle(cache_array->get(index), isolate);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100122 // Don't need filtering if expected map still matches that of the receiver.
123 if (receiver->map() == *cache_type) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000124 return *key;
125 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100126 Handle<Object> result;
127 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, Filter(receiver, key));
128 return *result;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000129}
130
131
132RUNTIME_FUNCTION(Runtime_ForInStep) {
133 SealHandleScope scope(isolate);
134 DCHECK_EQ(1, args.length());
135 CONVERT_SMI_ARG_CHECKED(index, 0);
136 DCHECK_LE(0, index);
137 DCHECK_LT(index, Smi::kMaxValue);
138 return Smi::FromInt(index + 1);
139}
140
141} // namespace internal
142} // namespace v8