blob: 9c43b40dbe32428fb3c7aad2cb0b4a6a324ffcbe [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
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005#include "src/runtime/runtime-utils.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006
7#include "src/allocation-site-scopes.h"
8#include "src/arguments.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009#include "src/ast/ast.h"
10#include "src/isolate-inl.h"
11#include "src/parsing/parser.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012#include "src/runtime/runtime.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040013
14namespace v8 {
15namespace internal {
16
17static Handle<Map> ComputeObjectLiteralMap(
18 Handle<Context> context, Handle<FixedArray> constant_properties,
Ben Murdochda12d292016-06-02 14:46:10 +010019 bool* is_result_from_cache) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040020 int properties_length = constant_properties->length();
21 int number_of_properties = properties_length / 2;
22
23 for (int p = 0; p != properties_length; p += 2) {
24 Object* key = constant_properties->get(p);
25 uint32_t element_index = 0;
26 if (key->ToArrayIndex(&element_index)) {
27 // An index key does not require space in the property backing store.
28 number_of_properties--;
29 }
30 }
31 Isolate* isolate = context->GetIsolate();
32 return isolate->factory()->ObjectLiteralMapFromCache(
Ben Murdochda12d292016-06-02 14:46:10 +010033 context, number_of_properties, is_result_from_cache);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040034}
35
36MUST_USE_RESULT static MaybeHandle<Object> CreateLiteralBoilerplate(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000037 Isolate* isolate, Handle<LiteralsArray> literals,
Ben Murdochda12d292016-06-02 14:46:10 +010038 Handle<FixedArray> constant_properties);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040039
40MUST_USE_RESULT static MaybeHandle<Object> CreateObjectLiteralBoilerplate(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000041 Isolate* isolate, Handle<LiteralsArray> literals,
Ben Murdochda12d292016-06-02 14:46:10 +010042 Handle<FixedArray> constant_properties, bool should_have_fast_elements) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000043 Handle<Context> context = isolate->native_context();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040044
45 // In case we have function literals, we want the object to be in
46 // slow properties mode for now. We don't go in the map cache because
47 // maps with constant functions can't be shared if the functions are
48 // not the same (which is the common case).
49 bool is_result_from_cache = false;
Ben Murdochda12d292016-06-02 14:46:10 +010050 Handle<Map> map = ComputeObjectLiteralMap(context, constant_properties,
51 &is_result_from_cache);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040052
53 PretenureFlag pretenure_flag =
54 isolate->heap()->InNewSpace(*literals) ? NOT_TENURED : TENURED;
55
56 Handle<JSObject> boilerplate =
57 isolate->factory()->NewJSObjectFromMap(map, pretenure_flag);
58
59 // Normalize the elements of the boilerplate to save space if needed.
60 if (!should_have_fast_elements) JSObject::NormalizeElements(boilerplate);
61
62 // Add the constant properties to the boilerplate.
63 int length = constant_properties->length();
64 bool should_transform =
65 !is_result_from_cache && boilerplate->HasFastProperties();
Ben Murdochda12d292016-06-02 14:46:10 +010066 bool should_normalize = should_transform;
Emily Bernierd0a1eb72015-03-24 16:35:39 -040067 if (should_normalize) {
68 // TODO(verwaest): We might not want to ever normalize here.
69 JSObject::NormalizeProperties(boilerplate, KEEP_INOBJECT_PROPERTIES,
70 length / 2, "Boilerplate");
71 }
72 // TODO(verwaest): Support tracking representations in the boilerplate.
73 for (int index = 0; index < length; index += 2) {
74 Handle<Object> key(constant_properties->get(index + 0), isolate);
75 Handle<Object> value(constant_properties->get(index + 1), isolate);
76 if (value->IsFixedArray()) {
77 // The value contains the constant_properties of a
78 // simple object or array literal.
79 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
80 ASSIGN_RETURN_ON_EXCEPTION(
Ben Murdochda12d292016-06-02 14:46:10 +010081 isolate, value, CreateLiteralBoilerplate(isolate, literals, array),
Emily Bernierd0a1eb72015-03-24 16:35:39 -040082 Object);
83 }
84 MaybeHandle<Object> maybe_result;
85 uint32_t element_index = 0;
Ben Murdochda12d292016-06-02 14:46:10 +010086 if (key->ToArrayIndex(&element_index)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040087 // Array index (uint32).
Ben Murdoch61f157c2016-09-16 13:49:30 +010088 if (value->IsUninitialized(isolate)) {
89 value = handle(Smi::FromInt(0), isolate);
90 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000091 maybe_result = JSObject::SetOwnElementIgnoreAttributes(
92 boilerplate, element_index, value, NONE);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040093 } else {
Ben Murdochda12d292016-06-02 14:46:10 +010094 Handle<String> name = Handle<String>::cast(key);
95 DCHECK(!name->AsArrayIndex(&element_index));
Emily Bernierd0a1eb72015-03-24 16:35:39 -040096 maybe_result = JSObject::SetOwnPropertyIgnoreAttributes(boilerplate, name,
97 value, NONE);
98 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -040099 RETURN_ON_EXCEPTION(isolate, maybe_result, Object);
100 }
101
102 // Transform to fast properties if necessary. For object literals with
103 // containing function literals we defer this operation until after all
104 // computed properties have been assigned so that we can generate
105 // constant function properties.
Ben Murdochda12d292016-06-02 14:46:10 +0100106 if (should_transform) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400107 JSObject::MigrateSlowToFast(boilerplate,
108 boilerplate->map()->unused_property_fields(),
109 "FastLiteral");
110 }
111 return boilerplate;
112}
113
Ben Murdochc5610432016-08-08 18:44:38 +0100114static MaybeHandle<Object> CreateArrayLiteralBoilerplate(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000115 Isolate* isolate, Handle<LiteralsArray> literals,
Ben Murdochda12d292016-06-02 14:46:10 +0100116 Handle<FixedArray> elements) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400117 // Create the JSArray.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000118 Handle<JSFunction> constructor = isolate->array_function();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400119
120 PretenureFlag pretenure_flag =
121 isolate->heap()->InNewSpace(*literals) ? NOT_TENURED : TENURED;
122
123 Handle<JSArray> object = Handle<JSArray>::cast(
124 isolate->factory()->NewJSObject(constructor, pretenure_flag));
125
126 ElementsKind constant_elements_kind =
127 static_cast<ElementsKind>(Smi::cast(elements->get(0))->value());
128 Handle<FixedArrayBase> constant_elements_values(
129 FixedArrayBase::cast(elements->get(1)));
130
131 {
132 DisallowHeapAllocation no_gc;
133 DCHECK(IsFastElementsKind(constant_elements_kind));
134 Context* native_context = isolate->context()->native_context();
Ben Murdochda12d292016-06-02 14:46:10 +0100135 Object* map =
136 native_context->get(Context::ArrayMapIndex(constant_elements_kind));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400137 object->set_map(Map::cast(map));
138 }
139
140 Handle<FixedArrayBase> copied_elements_values;
141 if (IsFastDoubleElementsKind(constant_elements_kind)) {
142 copied_elements_values = isolate->factory()->CopyFixedDoubleArray(
143 Handle<FixedDoubleArray>::cast(constant_elements_values));
144 } else {
145 DCHECK(IsFastSmiOrObjectElementsKind(constant_elements_kind));
146 const bool is_cow = (constant_elements_values->map() ==
147 isolate->heap()->fixed_cow_array_map());
148 if (is_cow) {
149 copied_elements_values = constant_elements_values;
150#if DEBUG
151 Handle<FixedArray> fixed_array_values =
152 Handle<FixedArray>::cast(copied_elements_values);
153 for (int i = 0; i < fixed_array_values->length(); i++) {
154 DCHECK(!fixed_array_values->get(i)->IsFixedArray());
155 }
156#endif
157 } else {
158 Handle<FixedArray> fixed_array_values =
159 Handle<FixedArray>::cast(constant_elements_values);
160 Handle<FixedArray> fixed_array_values_copy =
161 isolate->factory()->CopyFixedArray(fixed_array_values);
162 copied_elements_values = fixed_array_values_copy;
Ben Murdochda12d292016-06-02 14:46:10 +0100163 FOR_WITH_HANDLE_SCOPE(
164 isolate, int, i = 0, i, i < fixed_array_values->length(), i++, {
165 if (fixed_array_values->get(i)->IsFixedArray()) {
166 // The value contains the constant_properties of a
167 // simple object or array literal.
168 Handle<FixedArray> fa(
169 FixedArray::cast(fixed_array_values->get(i)));
170 Handle<Object> result;
171 ASSIGN_RETURN_ON_EXCEPTION(
172 isolate, result,
173 CreateLiteralBoilerplate(isolate, literals, fa), Object);
174 fixed_array_values_copy->set(i, *result);
175 }
176 });
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400177 }
178 }
179 object->set_elements(*copied_elements_values);
180 object->set_length(Smi::FromInt(copied_elements_values->length()));
181
182 JSObject::ValidateElements(object);
183 return object;
184}
185
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400186MUST_USE_RESULT static MaybeHandle<Object> CreateLiteralBoilerplate(
Ben Murdochda12d292016-06-02 14:46:10 +0100187 Isolate* isolate, Handle<LiteralsArray> literals,
188 Handle<FixedArray> array) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400189 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400190 switch (CompileTimeValue::GetLiteralType(array)) {
191 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
Ben Murdochda12d292016-06-02 14:46:10 +0100192 return CreateObjectLiteralBoilerplate(isolate, literals, elements, true);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400193 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
Ben Murdochda12d292016-06-02 14:46:10 +0100194 return CreateObjectLiteralBoilerplate(isolate, literals, elements, false);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400195 case CompileTimeValue::ARRAY_LITERAL:
Ben Murdochc5610432016-08-08 18:44:38 +0100196 return CreateArrayLiteralBoilerplate(isolate, literals, elements);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400197 default:
198 UNREACHABLE();
199 return MaybeHandle<Object>();
200 }
201}
202
203
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000204RUNTIME_FUNCTION(Runtime_CreateRegExpLiteral) {
205 HandleScope scope(isolate);
206 DCHECK_EQ(4, args.length());
207 CONVERT_ARG_HANDLE_CHECKED(JSFunction, closure, 0);
208 CONVERT_SMI_ARG_CHECKED(index, 1);
209 CONVERT_ARG_HANDLE_CHECKED(String, pattern, 2);
210 CONVERT_SMI_ARG_CHECKED(flags, 3);
211
212 // Check if boilerplate exists. If not, create it first.
213 Handle<Object> boilerplate(closure->literals()->literal(index), isolate);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100214 if (boilerplate->IsUndefined(isolate)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000215 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
216 isolate, boilerplate, JSRegExp::New(pattern, JSRegExp::Flags(flags)));
217 closure->literals()->set_literal(index, *boilerplate);
218 }
219 return *JSRegExp::Copy(Handle<JSRegExp>::cast(boilerplate));
220}
221
222
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400223RUNTIME_FUNCTION(Runtime_CreateObjectLiteral) {
224 HandleScope scope(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000225 DCHECK_EQ(4, args.length());
226 CONVERT_ARG_HANDLE_CHECKED(JSFunction, closure, 0);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400227 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
228 CONVERT_ARG_HANDLE_CHECKED(FixedArray, constant_properties, 2);
229 CONVERT_SMI_ARG_CHECKED(flags, 3);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000230 Handle<LiteralsArray> literals(closure->literals(), isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400231 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000232 bool enable_mementos = (flags & ObjectLiteral::kDisableMementos) == 0;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400233
Ben Murdoch61f157c2016-09-16 13:49:30 +0100234 CHECK(literals_index >= 0);
235 CHECK(literals_index < literals->literals_count());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400236
237 // Check if boilerplate exists. If not, create it first.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000238 Handle<Object> literal_site(literals->literal(literals_index), isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400239 Handle<AllocationSite> site;
240 Handle<JSObject> boilerplate;
Ben Murdoch61f157c2016-09-16 13:49:30 +0100241 if (literal_site->IsUndefined(isolate)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400242 Handle<Object> raw_boilerplate;
243 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
244 isolate, raw_boilerplate,
245 CreateObjectLiteralBoilerplate(isolate, literals, constant_properties,
Ben Murdochda12d292016-06-02 14:46:10 +0100246 should_have_fast_elements));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400247 boilerplate = Handle<JSObject>::cast(raw_boilerplate);
248
249 AllocationSiteCreationContext creation_context(isolate);
250 site = creation_context.EnterNewScope();
251 RETURN_FAILURE_ON_EXCEPTION(
252 isolate, JSObject::DeepWalk(boilerplate, &creation_context));
253 creation_context.ExitScope(site, boilerplate);
254
255 // Update the functions literal and return the boilerplate.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000256 literals->set_literal(literals_index, *site);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400257 } else {
258 site = Handle<AllocationSite>::cast(literal_site);
259 boilerplate =
260 Handle<JSObject>(JSObject::cast(site->transition_info()), isolate);
261 }
262
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000263 AllocationSiteUsageContext usage_context(isolate, site, enable_mementos);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400264 usage_context.EnterNewScope();
265 MaybeHandle<Object> maybe_copy =
266 JSObject::DeepCopy(boilerplate, &usage_context);
267 usage_context.ExitScope(site, boilerplate);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100268 RETURN_RESULT_OR_FAILURE(isolate, maybe_copy);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400269}
270
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400271MUST_USE_RESULT static MaybeHandle<AllocationSite> GetLiteralAllocationSite(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000272 Isolate* isolate, Handle<LiteralsArray> literals, int literals_index,
Ben Murdochda12d292016-06-02 14:46:10 +0100273 Handle<FixedArray> elements) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400274 // Check if boilerplate exists. If not, create it first.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000275 Handle<Object> literal_site(literals->literal(literals_index), isolate);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400276 Handle<AllocationSite> site;
Ben Murdoch61f157c2016-09-16 13:49:30 +0100277 if (literal_site->IsUndefined(isolate)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400278 DCHECK(*elements != isolate->heap()->empty_fixed_array());
279 Handle<Object> boilerplate;
280 ASSIGN_RETURN_ON_EXCEPTION(
281 isolate, boilerplate,
Ben Murdochc5610432016-08-08 18:44:38 +0100282 CreateArrayLiteralBoilerplate(isolate, literals, elements),
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400283 AllocationSite);
284
285 AllocationSiteCreationContext creation_context(isolate);
286 site = creation_context.EnterNewScope();
287 if (JSObject::DeepWalk(Handle<JSObject>::cast(boilerplate),
288 &creation_context).is_null()) {
289 return Handle<AllocationSite>::null();
290 }
291 creation_context.ExitScope(site, Handle<JSObject>::cast(boilerplate));
292
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000293 literals->set_literal(literals_index, *site);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400294 } else {
295 site = Handle<AllocationSite>::cast(literal_site);
296 }
297
298 return site;
299}
300
301
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000302static MaybeHandle<JSObject> CreateArrayLiteralImpl(
303 Isolate* isolate, Handle<LiteralsArray> literals, int literals_index,
304 Handle<FixedArray> elements, int flags) {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100305 CHECK(literals_index >= 0 && literals_index < literals->literals_count());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400306 Handle<AllocationSite> site;
307 ASSIGN_RETURN_ON_EXCEPTION(
308 isolate, site,
Ben Murdochda12d292016-06-02 14:46:10 +0100309 GetLiteralAllocationSite(isolate, literals, literals_index, elements),
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400310 JSObject);
311
312 bool enable_mementos = (flags & ArrayLiteral::kDisableMementos) == 0;
313 Handle<JSObject> boilerplate(JSObject::cast(site->transition_info()));
314 AllocationSiteUsageContext usage_context(isolate, site, enable_mementos);
315 usage_context.EnterNewScope();
316 JSObject::DeepCopyHints hints = (flags & ArrayLiteral::kShallowElements) == 0
317 ? JSObject::kNoHints
318 : JSObject::kObjectIsShallow;
319 MaybeHandle<JSObject> copy =
320 JSObject::DeepCopy(boilerplate, &usage_context, hints);
321 usage_context.ExitScope(site, boilerplate);
322 return copy;
323}
324
325
326RUNTIME_FUNCTION(Runtime_CreateArrayLiteral) {
327 HandleScope scope(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000328 DCHECK_EQ(4, args.length());
329 CONVERT_ARG_HANDLE_CHECKED(JSFunction, closure, 0);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400330 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
331 CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2);
332 CONVERT_SMI_ARG_CHECKED(flags, 3);
333
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000334 Handle<LiteralsArray> literals(closure->literals(), isolate);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100335 RETURN_RESULT_OR_FAILURE(
336 isolate, CreateArrayLiteralImpl(isolate, literals, literals_index,
337 elements, flags));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400338}
339
340
341RUNTIME_FUNCTION(Runtime_CreateArrayLiteralStubBailout) {
342 HandleScope scope(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000343 DCHECK_EQ(3, args.length());
344 CONVERT_ARG_HANDLE_CHECKED(JSFunction, closure, 0);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400345 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
346 CONVERT_ARG_HANDLE_CHECKED(FixedArray, elements, 2);
347
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000348 Handle<LiteralsArray> literals(closure->literals(), isolate);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100349 RETURN_RESULT_OR_FAILURE(
350 isolate,
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400351 CreateArrayLiteralImpl(isolate, literals, literals_index, elements,
352 ArrayLiteral::kShallowElements));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400353}
354
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000355} // namespace internal
356} // namespace v8