blob: a92215c85d046ab8121dab8248d336c96e55fe15 [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/arguments.h"
Ben Murdochda12d292016-06-02 14:46:10 +01008#include "src/code-stubs.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00009#include "src/conversions-inl.h"
10#include "src/elements.h"
11#include "src/factory.h"
12#include "src/isolate-inl.h"
Ben Murdochda12d292016-06-02 14:46:10 +010013#include "src/keys.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000014#include "src/messages.h"
15#include "src/prototype.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040016
17namespace v8 {
18namespace internal {
19
20RUNTIME_FUNCTION(Runtime_FinishArrayPrototypeSetup) {
21 HandleScope scope(isolate);
22 DCHECK(args.length() == 1);
23 CONVERT_ARG_HANDLE_CHECKED(JSArray, prototype, 0);
24 Object* length = prototype->length();
Ben Murdoch61f157c2016-09-16 13:49:30 +010025 CHECK(length->IsSmi());
26 CHECK(Smi::cast(length)->value() == 0);
27 CHECK(prototype->HasFastSmiOrObjectElements());
Emily Bernierd0a1eb72015-03-24 16:35:39 -040028 // This is necessary to enable fast checks for absence of elements
29 // on Array.prototype and below.
30 prototype->set_elements(isolate->heap()->empty_fixed_array());
31 return Smi::FromInt(0);
32}
33
Ben Murdochda12d292016-06-02 14:46:10 +010034static void InstallCode(Isolate* isolate, Handle<JSObject> holder,
35 const char* name, Handle<Code> code) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040036 Handle<String> key = isolate->factory()->InternalizeUtf8String(name);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040037 Handle<JSFunction> optimized =
38 isolate->factory()->NewFunctionWithoutPrototype(key, code);
39 optimized->shared()->DontAdaptArguments();
40 JSObject::AddProperty(holder, key, optimized, NONE);
41}
42
Ben Murdochda12d292016-06-02 14:46:10 +010043static void InstallBuiltin(Isolate* isolate, Handle<JSObject> holder,
44 const char* name, Builtins::Name builtin_name) {
45 InstallCode(isolate, holder, name,
46 handle(isolate->builtins()->builtin(builtin_name), isolate));
47}
Emily Bernierd0a1eb72015-03-24 16:35:39 -040048
49RUNTIME_FUNCTION(Runtime_SpecialArrayFunctions) {
50 HandleScope scope(isolate);
51 DCHECK(args.length() == 0);
52 Handle<JSObject> holder =
53 isolate->factory()->NewJSObject(isolate->object_function());
54
55 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
Ben Murdochda12d292016-06-02 14:46:10 +010056 FastArrayPushStub stub(isolate);
57 InstallCode(isolate, holder, "push", stub.GetCode());
Emily Bernierd0a1eb72015-03-24 16:35:39 -040058 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
59 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
60 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
61 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040062
63 return *holder;
64}
65
66
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000067RUNTIME_FUNCTION(Runtime_FixedArrayGet) {
68 SealHandleScope shs(isolate);
69 DCHECK(args.length() == 2);
70 CONVERT_ARG_CHECKED(FixedArray, object, 0);
71 CONVERT_SMI_ARG_CHECKED(index, 1);
72 return object->get(index);
73}
74
75
76RUNTIME_FUNCTION(Runtime_FixedArraySet) {
77 SealHandleScope shs(isolate);
78 DCHECK(args.length() == 3);
79 CONVERT_ARG_CHECKED(FixedArray, object, 0);
80 CONVERT_SMI_ARG_CHECKED(index, 1);
81 CONVERT_ARG_CHECKED(Object, value, 2);
82 object->set(index, value);
83 return isolate->heap()->undefined_value();
84}
85
86
Emily Bernierd0a1eb72015-03-24 16:35:39 -040087RUNTIME_FUNCTION(Runtime_TransitionElementsKind) {
88 HandleScope scope(isolate);
Ben Murdoch61f157c2016-09-16 13:49:30 +010089 DCHECK(args.length() == 2);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040090 CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0);
91 CONVERT_ARG_HANDLE_CHECKED(Map, map, 1);
92 JSObject::TransitionElementsKind(array, map->elements_kind());
93 return *array;
94}
95
96
Emily Bernierd0a1eb72015-03-24 16:35:39 -040097// Moves all own elements of an object, that are below a limit, to positions
98// starting at zero. All undefined values are placed after non-undefined values,
99// and are followed by non-existing element. Does not change the length
100// property.
101// Returns the number of non-undefined elements collected.
102// Returns -1 if hole removal is not supported by this method.
103RUNTIME_FUNCTION(Runtime_RemoveArrayHoles) {
104 HandleScope scope(isolate);
105 DCHECK(args.length() == 2);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100106 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400107 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100108 if (object->IsJSProxy()) return Smi::FromInt(-1);
109 return *JSObject::PrepareElementsForSort(Handle<JSObject>::cast(object),
110 limit);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400111}
112
113
114// Move contents of argument 0 (an array) to argument 1 (an array)
115RUNTIME_FUNCTION(Runtime_MoveArrayContents) {
116 HandleScope scope(isolate);
117 DCHECK(args.length() == 2);
118 CONVERT_ARG_HANDLE_CHECKED(JSArray, from, 0);
119 CONVERT_ARG_HANDLE_CHECKED(JSArray, to, 1);
120 JSObject::ValidateElements(from);
121 JSObject::ValidateElements(to);
122
123 Handle<FixedArrayBase> new_elements(from->elements());
124 ElementsKind from_kind = from->GetElementsKind();
125 Handle<Map> new_map = JSObject::GetElementsTransitionMap(to, from_kind);
126 JSObject::SetMapAndElements(to, new_map, new_elements);
127 to->set_length(from->length());
128
129 JSObject::ResetElements(from);
130 from->set_length(Smi::FromInt(0));
131
132 JSObject::ValidateElements(to);
133 return *to;
134}
135
136
137// How many elements does this object/array have?
138RUNTIME_FUNCTION(Runtime_EstimateNumberOfElements) {
139 HandleScope scope(isolate);
140 DCHECK(args.length() == 1);
141 CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0);
142 Handle<FixedArrayBase> elements(array->elements(), isolate);
143 SealHandleScope shs(isolate);
144 if (elements->IsDictionary()) {
145 int result =
146 Handle<SeededNumberDictionary>::cast(elements)->NumberOfElements();
147 return Smi::FromInt(result);
148 } else {
149 DCHECK(array->length()->IsSmi());
150 // For packed elements, we know the exact number of elements
151 int length = elements->length();
152 ElementsKind kind = array->GetElementsKind();
153 if (IsFastPackedElementsKind(kind)) {
154 return Smi::FromInt(length);
155 }
156 // For holey elements, take samples from the buffer checking for holes
157 // to generate the estimate.
158 const int kNumberOfHoleCheckSamples = 97;
159 int increment = (length < kNumberOfHoleCheckSamples)
160 ? 1
161 : static_cast<int>(length / kNumberOfHoleCheckSamples);
162 ElementsAccessor* accessor = array->GetElementsAccessor();
163 int holes = 0;
164 for (int i = 0; i < length; i += increment) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000165 if (!accessor->HasElement(array, i, elements)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400166 ++holes;
167 }
168 }
169 int estimate = static_cast<int>((kNumberOfHoleCheckSamples - holes) /
170 kNumberOfHoleCheckSamples * length);
171 return Smi::FromInt(estimate);
172 }
173}
174
175
176// Returns an array that tells you where in the [0, length) interval an array
177// might have elements. Can either return an array of keys (positive integers
178// or undefined) or a number representing the positive length of an interval
179// starting at index 0.
180// Intervals can span over some keys that are not in the object.
181RUNTIME_FUNCTION(Runtime_GetArrayKeys) {
182 HandleScope scope(isolate);
183 DCHECK(args.length() == 2);
184 CONVERT_ARG_HANDLE_CHECKED(JSObject, array, 0);
185 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100186 ElementsKind kind = array->GetElementsKind();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000187
Ben Murdoch61f157c2016-09-16 13:49:30 +0100188 if (IsFastElementsKind(kind) || IsFixedTypedArrayElementsKind(kind)) {
189 uint32_t actual_length = static_cast<uint32_t>(array->elements()->length());
190 return *isolate->factory()->NewNumberFromUint(Min(actual_length, length));
191 }
192
193 if (kind == FAST_STRING_WRAPPER_ELEMENTS) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100194 int string_length =
195 String::cast(Handle<JSValue>::cast(array)->value())->length();
196 int backing_store_length = array->elements()->length();
197 return *isolate->factory()->NewNumberFromUint(
198 Min(length,
199 static_cast<uint32_t>(Max(string_length, backing_store_length))));
200 }
201
Ben Murdoch61f157c2016-09-16 13:49:30 +0100202 KeyAccumulator accumulator(isolate, KeyCollectionMode::kOwnOnly,
203 ALL_PROPERTIES);
204 for (PrototypeIterator iter(isolate, array, kStartAtReceiver);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000205 !iter.IsAtEnd(); iter.Advance()) {
206 if (PrototypeIterator::GetCurrent(iter)->IsJSProxy() ||
207 PrototypeIterator::GetCurrent<JSObject>(iter)
208 ->HasIndexedInterceptor()) {
209 // Bail out if we find a proxy or interceptor, likely not worth
210 // collecting keys in that case.
211 return *isolate->factory()->NewNumberFromUint(length);
212 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000213 Handle<JSObject> current = PrototypeIterator::GetCurrent<JSObject>(iter);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100214 accumulator.CollectOwnElementIndices(array, current);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000215 }
216 // Erase any keys >= length.
Ben Murdoch61f157c2016-09-16 13:49:30 +0100217 Handle<FixedArray> keys =
218 accumulator.GetKeys(GetKeysConversion::kKeepNumbers);
Ben Murdochda12d292016-06-02 14:46:10 +0100219 int j = 0;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000220 for (int i = 0; i < keys->length(); i++) {
Ben Murdochda12d292016-06-02 14:46:10 +0100221 if (NumberToUint32(keys->get(i)) >= length) continue;
222 if (i != j) keys->set(j, keys->get(i));
223 j++;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000224 }
Ben Murdochda12d292016-06-02 14:46:10 +0100225
226 if (j != keys->length()) {
227 isolate->heap()->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>(
228 *keys, keys->length() - j);
229 }
230
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000231 return *isolate->factory()->NewJSArrayWithElements(keys);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400232}
233
234
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000235namespace {
236
237Object* ArrayConstructorCommon(Isolate* isolate, Handle<JSFunction> constructor,
238 Handle<JSReceiver> new_target,
239 Handle<AllocationSite> site,
240 Arguments* caller_args) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400241 Factory* factory = isolate->factory();
242
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000243 // If called through new, new.target can be:
244 // - a subclass of constructor,
245 // - a proxy wrapper around constructor, or
246 // - the constructor itself.
247 // If called through Reflect.construct, it's guaranteed to be a constructor by
248 // REFLECT_CONSTRUCT_PREPARE.
249 DCHECK(new_target->IsConstructor());
250
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400251 bool holey = false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000252 bool can_use_type_feedback = !site.is_null();
253 bool can_inline_array_constructor = true;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400254 if (caller_args->length() == 1) {
255 Handle<Object> argument_one = caller_args->at<Object>(0);
256 if (argument_one->IsSmi()) {
257 int value = Handle<Smi>::cast(argument_one)->value();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000258 if (value < 0 ||
259 JSArray::SetLengthWouldNormalize(isolate->heap(), value)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400260 // the array is a dictionary in this case.
261 can_use_type_feedback = false;
262 } else if (value != 0) {
263 holey = true;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000264 if (value >= JSArray::kInitialMaxFastElementArray) {
265 can_inline_array_constructor = false;
266 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400267 }
268 } else {
269 // Non-smi length argument produces a dictionary
270 can_use_type_feedback = false;
271 }
272 }
273
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000274 Handle<Map> initial_map;
275 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
276 isolate, initial_map,
277 JSFunction::GetDerivedMap(isolate, constructor, new_target));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400278
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000279 ElementsKind to_kind = can_use_type_feedback ? site->GetElementsKind()
280 : initial_map->elements_kind();
281 if (holey && !IsFastHoleyElementsKind(to_kind)) {
282 to_kind = GetHoleyElementsKind(to_kind);
283 // Update the allocation site info to reflect the advice alteration.
284 if (!site.is_null()) site->SetElementsKind(to_kind);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400285 }
286
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000287 // We should allocate with an initial map that reflects the allocation site
288 // advice. Therefore we use AllocateJSObjectFromMap instead of passing
289 // the constructor.
290 if (to_kind != initial_map->elements_kind()) {
291 initial_map = Map::AsElementsKind(initial_map, to_kind);
292 }
293
294 // If we don't care to track arrays of to_kind ElementsKind, then
295 // don't emit a memento for them.
296 Handle<AllocationSite> allocation_site;
297 if (AllocationSite::GetMode(to_kind) == TRACK_ALLOCATION_SITE) {
298 allocation_site = site;
299 }
300
301 Handle<JSArray> array = Handle<JSArray>::cast(
302 factory->NewJSObjectFromMap(initial_map, NOT_TENURED, allocation_site));
303
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400304 factory->NewJSArrayStorage(array, 0, 0, DONT_INITIALIZE_ARRAY_ELEMENTS);
305
306 ElementsKind old_kind = array->GetElementsKind();
307 RETURN_FAILURE_ON_EXCEPTION(
308 isolate, ArrayConstructInitializeElements(array, caller_args));
309 if (!site.is_null() &&
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000310 (old_kind != array->GetElementsKind() || !can_use_type_feedback ||
311 !can_inline_array_constructor)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400312 // The arguments passed in caused a transition. This kind of complexity
313 // can't be dealt with in the inlined hydrogen array constructor case.
314 // We must mark the allocationsite as un-inlinable.
315 site->SetDoNotInlineCall();
316 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000317
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400318 return *array;
319}
320
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000321} // namespace
322
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000323RUNTIME_FUNCTION(Runtime_NewArray) {
324 HandleScope scope(isolate);
325 DCHECK_LE(3, args.length());
326 int const argc = args.length() - 3;
327 // TODO(bmeurer): Remove this Arguments nonsense.
328 Arguments argv(argc, args.arguments() - 1);
329 CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, 0);
330 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, new_target, argc + 1);
331 CONVERT_ARG_HANDLE_CHECKED(HeapObject, type_info, argc + 2);
332 // TODO(bmeurer): Use MaybeHandle to pass around the AllocationSite.
333 Handle<AllocationSite> site = type_info->IsAllocationSite()
334 ? Handle<AllocationSite>::cast(type_info)
335 : Handle<AllocationSite>::null();
336 return ArrayConstructorCommon(isolate, constructor, new_target, site, &argv);
337}
338
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400339RUNTIME_FUNCTION(Runtime_NormalizeElements) {
340 HandleScope scope(isolate);
341 DCHECK(args.length() == 1);
342 CONVERT_ARG_HANDLE_CHECKED(JSObject, array, 0);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100343 CHECK(!array->HasFixedTypedArrayElements());
344 CHECK(!array->IsJSGlobalProxy());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400345 JSObject::NormalizeElements(array);
346 return *array;
347}
348
349
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000350// GrowArrayElements returns a sentinel Smi if the object was normalized.
351RUNTIME_FUNCTION(Runtime_GrowArrayElements) {
352 HandleScope scope(isolate);
353 DCHECK(args.length() == 2);
354 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
355 CONVERT_NUMBER_CHECKED(int, key, Int32, args[1]);
356
357 if (key < 0) {
358 return object->elements();
359 }
360
361 uint32_t capacity = static_cast<uint32_t>(object->elements()->length());
362 uint32_t index = static_cast<uint32_t>(key);
363
364 if (index >= capacity) {
365 if (object->WouldConvertToSlowElements(index)) {
366 // We don't want to allow operations that cause lazy deopt. Return a Smi
367 // as a signal that optimized code should eagerly deoptimize.
368 return Smi::FromInt(0);
369 }
370
371 uint32_t new_capacity = JSObject::NewElementsCapacity(index + 1);
372 object->GetElementsAccessor()->GrowCapacityAndConvert(object, new_capacity);
373 }
374
375 // On success, return the fixed array elements.
376 return object->elements();
377}
378
379
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400380RUNTIME_FUNCTION(Runtime_HasComplexElements) {
381 HandleScope scope(isolate);
382 DCHECK(args.length() == 1);
383 CONVERT_ARG_HANDLE_CHECKED(JSObject, array, 0);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100384 for (PrototypeIterator iter(isolate, array, kStartAtReceiver);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400385 !iter.IsAtEnd(); iter.Advance()) {
386 if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) {
387 return isolate->heap()->true_value();
388 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000389 Handle<JSObject> current = PrototypeIterator::GetCurrent<JSObject>(iter);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400390 if (current->HasIndexedInterceptor()) {
391 return isolate->heap()->true_value();
392 }
393 if (!current->HasDictionaryElements()) continue;
394 if (current->element_dictionary()->HasComplexElements()) {
395 return isolate->heap()->true_value();
396 }
397 }
398 return isolate->heap()->false_value();
399}
400
Ben Murdochc5610432016-08-08 18:44:38 +0100401// ES6 22.1.2.2 Array.isArray
402RUNTIME_FUNCTION(Runtime_ArrayIsArray) {
403 HandleScope shs(isolate);
404 DCHECK(args.length() == 1);
405 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
406 Maybe<bool> result = Object::IsArray(object);
407 MAYBE_RETURN(result, isolate->heap()->exception());
408 return isolate->heap()->ToBoolean(result.FromJust());
409}
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400410
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000411RUNTIME_FUNCTION(Runtime_IsArray) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400412 SealHandleScope shs(isolate);
413 DCHECK(args.length() == 1);
414 CONVERT_ARG_CHECKED(Object, obj, 0);
415 return isolate->heap()->ToBoolean(obj->IsJSArray());
416}
417
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000418RUNTIME_FUNCTION(Runtime_HasCachedArrayIndex) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400419 SealHandleScope shs(isolate);
420 DCHECK(args.length() == 1);
421 return isolate->heap()->false_value();
422}
423
424
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000425RUNTIME_FUNCTION(Runtime_GetCachedArrayIndex) {
426 // This can never be reached, because Runtime_HasCachedArrayIndex always
427 // returns false.
428 UNIMPLEMENTED();
429 return nullptr;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400430}
431
432
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000433RUNTIME_FUNCTION(Runtime_ArraySpeciesConstructor) {
434 HandleScope scope(isolate);
435 DCHECK(args.length() == 1);
436 CONVERT_ARG_HANDLE_CHECKED(Object, original_array, 0);
Ben Murdoch61f157c2016-09-16 13:49:30 +0100437 RETURN_RESULT_OR_FAILURE(
438 isolate, Object::ArraySpeciesConstructor(isolate, original_array));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400439}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000440
441} // namespace internal
442} // namespace v8