Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(31)

Side by Side Diff: src/runtime/runtime.cc

Issue 638423003: Split off remaining runtime functions in runtime.cc. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/macros.py ('k') | src/runtime/runtime-api.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2012 the V8 project authors. All rights reserved. 1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <stdlib.h>
6 #include <limits>
7
8 #include "src/v8.h" 5 #include "src/v8.h"
9 6
10 #include "src/accessors.h"
11 #include "src/api.h"
12 #include "src/arguments.h"
13 #include "src/bailout-reason.h"
14 #include "src/base/cpu.h"
15 #include "src/base/platform/platform.h"
16 #include "src/bootstrapper.h"
17 #include "src/conversions.h"
18 #include "src/global-handles.h"
19 #include "src/isolate-inl.h"
20 #include "src/prototype.h"
21 #include "src/runtime/runtime.h" 7 #include "src/runtime/runtime.h"
22 #include "src/runtime/runtime-utils.h" 8 #include "src/runtime/runtime-utils.h"
23 #include "src/utils.h"
24
25 9
26 namespace v8 { 10 namespace v8 {
27 namespace internal { 11 namespace internal {
28 12
29 // Header of runtime functions. 13 // Header of runtime functions.
30 #define F(name, number_of_args, result_size) \ 14 #define F(name, number_of_args, result_size) \
31 Object* Runtime_##name(int args_length, Object** args_object, \ 15 Object* Runtime_##name(int args_length, Object** args_object, \
32 Isolate* isolate); 16 Isolate* isolate);
33 17
34 #define P(name, number_of_args, result_size) \ 18 #define P(name, number_of_args, result_size) \
35 ObjectPair Runtime_##name(int args_length, Object** args_object, \ 19 ObjectPair Runtime_##name(int args_length, Object** args_object, \
36 Isolate* isolate); 20 Isolate* isolate);
37 21
22 // Reference implementation for inlined runtime functions. Only used when the
23 // compiler does not support a certain intrinsic. Don't optimize these, but
24 // implement the intrinsic in the respective compiler instead.
25 // TODO(mstarzinger): These are place-holder stubs for TurboFan and will
26 // eventually all have a C++ implementation and this macro will be gone.
38 #define I(name, number_of_args, result_size) \ 27 #define I(name, number_of_args, result_size) \
39 Object* RuntimeReference_##name(int args_length, Object** args_object, \ 28 Object* RuntimeReference_##name(int args_length, Object** args_object, \
40 Isolate* isolate); 29 Isolate* isolate);
41 30
42 RUNTIME_FUNCTION_LIST_RETURN_OBJECT(F) 31 RUNTIME_FUNCTION_LIST_RETURN_OBJECT(F)
43 RUNTIME_FUNCTION_LIST_RETURN_PAIR(P) 32 RUNTIME_FUNCTION_LIST_RETURN_PAIR(P)
44 INLINE_OPTIMIZED_FUNCTION_LIST(F) 33 INLINE_OPTIMIZED_FUNCTION_LIST(F)
45 INLINE_FUNCTION_LIST(I) 34 INLINE_FUNCTION_LIST(I)
46 35
47 #undef I 36 #undef I
48 #undef F 37 #undef F
49 #undef P 38 #undef P
50 39
51 40
52 MUST_USE_RESULT static MaybeHandle<Object> TransitionElements(
53 Handle<Object> object, ElementsKind to_kind, Isolate* isolate) {
54 HandleScope scope(isolate);
55 if (!object->IsJSObject()) {
56 isolate->ThrowIllegalOperation();
57 return MaybeHandle<Object>();
58 }
59 ElementsKind from_kind =
60 Handle<JSObject>::cast(object)->map()->elements_kind();
61 if (Map::IsValidElementsTransition(from_kind, to_kind)) {
62 JSObject::TransitionElementsKind(Handle<JSObject>::cast(object), to_kind);
63 return object;
64 }
65 isolate->ThrowIllegalOperation();
66 return MaybeHandle<Object>();
67 }
68
69
70 RUNTIME_FUNCTION(Runtime_GetPrototype) {
71 HandleScope scope(isolate);
72 DCHECK(args.length() == 1);
73 CONVERT_ARG_HANDLE_CHECKED(Object, obj, 0);
74 // We don't expect access checks to be needed on JSProxy objects.
75 DCHECK(!obj->IsAccessCheckNeeded() || obj->IsJSObject());
76 PrototypeIterator iter(isolate, obj, PrototypeIterator::START_AT_RECEIVER);
77 do {
78 if (PrototypeIterator::GetCurrent(iter)->IsAccessCheckNeeded() &&
79 !isolate->MayNamedAccess(
80 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)),
81 isolate->factory()->proto_string(), v8::ACCESS_GET)) {
82 isolate->ReportFailedAccessCheck(
83 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)),
84 v8::ACCESS_GET);
85 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
86 return isolate->heap()->undefined_value();
87 }
88 iter.AdvanceIgnoringProxies();
89 if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) {
90 return *PrototypeIterator::GetCurrent(iter);
91 }
92 } while (!iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN));
93 return *PrototypeIterator::GetCurrent(iter);
94 }
95
96
97 RUNTIME_FUNCTION(Runtime_InternalSetPrototype) {
98 HandleScope scope(isolate);
99 DCHECK(args.length() == 2);
100 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
101 CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1);
102 DCHECK(!obj->IsAccessCheckNeeded());
103 DCHECK(!obj->map()->is_observed());
104 Handle<Object> result;
105 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
106 isolate, result, JSObject::SetPrototype(obj, prototype, false));
107 return *result;
108 }
109
110
111 RUNTIME_FUNCTION(Runtime_SetPrototype) {
112 HandleScope scope(isolate);
113 DCHECK(args.length() == 2);
114 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
115 CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1);
116 if (obj->IsAccessCheckNeeded() &&
117 !isolate->MayNamedAccess(obj, isolate->factory()->proto_string(),
118 v8::ACCESS_SET)) {
119 isolate->ReportFailedAccessCheck(obj, v8::ACCESS_SET);
120 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
121 return isolate->heap()->undefined_value();
122 }
123 if (obj->map()->is_observed()) {
124 Handle<Object> old_value =
125 Object::GetPrototypeSkipHiddenPrototypes(isolate, obj);
126 Handle<Object> result;
127 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
128 isolate, result, JSObject::SetPrototype(obj, prototype, true));
129
130 Handle<Object> new_value =
131 Object::GetPrototypeSkipHiddenPrototypes(isolate, obj);
132 if (!new_value->SameValue(*old_value)) {
133 JSObject::EnqueueChangeRecord(
134 obj, "setPrototype", isolate->factory()->proto_string(), old_value);
135 }
136 return *result;
137 }
138 Handle<Object> result;
139 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
140 isolate, result, JSObject::SetPrototype(obj, prototype, true));
141 return *result;
142 }
143
144
145 RUNTIME_FUNCTION(Runtime_IsInPrototypeChain) {
146 HandleScope shs(isolate);
147 DCHECK(args.length() == 2);
148 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
149 CONVERT_ARG_HANDLE_CHECKED(Object, O, 0);
150 CONVERT_ARG_HANDLE_CHECKED(Object, V, 1);
151 PrototypeIterator iter(isolate, V, PrototypeIterator::START_AT_RECEIVER);
152 while (true) {
153 iter.AdvanceIgnoringProxies();
154 if (iter.IsAtEnd()) return isolate->heap()->false_value();
155 if (iter.IsAtEnd(O)) return isolate->heap()->true_value();
156 }
157 }
158
159
160 // Enumerator used as indices into the array returned from GetOwnProperty
161 enum PropertyDescriptorIndices {
162 IS_ACCESSOR_INDEX,
163 VALUE_INDEX,
164 GETTER_INDEX,
165 SETTER_INDEX,
166 WRITABLE_INDEX,
167 ENUMERABLE_INDEX,
168 CONFIGURABLE_INDEX,
169 DESCRIPTOR_SIZE
170 };
171
172
173 MUST_USE_RESULT static MaybeHandle<Object> GetOwnProperty(Isolate* isolate,
174 Handle<JSObject> obj,
175 Handle<Name> name) {
176 Heap* heap = isolate->heap();
177 Factory* factory = isolate->factory();
178
179 PropertyAttributes attrs;
180 uint32_t index = 0;
181 Handle<Object> value;
182 MaybeHandle<AccessorPair> maybe_accessors;
183 // TODO(verwaest): Unify once indexed properties can be handled by the
184 // LookupIterator.
185 if (name->AsArrayIndex(&index)) {
186 // Get attributes.
187 Maybe<PropertyAttributes> maybe =
188 JSReceiver::GetOwnElementAttribute(obj, index);
189 if (!maybe.has_value) return MaybeHandle<Object>();
190 attrs = maybe.value;
191 if (attrs == ABSENT) return factory->undefined_value();
192
193 // Get AccessorPair if present.
194 maybe_accessors = JSObject::GetOwnElementAccessorPair(obj, index);
195
196 // Get value if not an AccessorPair.
197 if (maybe_accessors.is_null()) {
198 ASSIGN_RETURN_ON_EXCEPTION(
199 isolate, value, Runtime::GetElementOrCharAt(isolate, obj, index),
200 Object);
201 }
202 } else {
203 // Get attributes.
204 LookupIterator it(obj, name, LookupIterator::HIDDEN);
205 Maybe<PropertyAttributes> maybe = JSObject::GetPropertyAttributes(&it);
206 if (!maybe.has_value) return MaybeHandle<Object>();
207 attrs = maybe.value;
208 if (attrs == ABSENT) return factory->undefined_value();
209
210 // Get AccessorPair if present.
211 if (it.state() == LookupIterator::ACCESSOR &&
212 it.GetAccessors()->IsAccessorPair()) {
213 maybe_accessors = Handle<AccessorPair>::cast(it.GetAccessors());
214 }
215
216 // Get value if not an AccessorPair.
217 if (maybe_accessors.is_null()) {
218 ASSIGN_RETURN_ON_EXCEPTION(isolate, value, Object::GetProperty(&it),
219 Object);
220 }
221 }
222 DCHECK(!isolate->has_pending_exception());
223 Handle<FixedArray> elms = factory->NewFixedArray(DESCRIPTOR_SIZE);
224 elms->set(ENUMERABLE_INDEX, heap->ToBoolean((attrs & DONT_ENUM) == 0));
225 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean((attrs & DONT_DELETE) == 0));
226 elms->set(IS_ACCESSOR_INDEX, heap->ToBoolean(!maybe_accessors.is_null()));
227
228 Handle<AccessorPair> accessors;
229 if (maybe_accessors.ToHandle(&accessors)) {
230 Handle<Object> getter(accessors->GetComponent(ACCESSOR_GETTER), isolate);
231 Handle<Object> setter(accessors->GetComponent(ACCESSOR_SETTER), isolate);
232 elms->set(GETTER_INDEX, *getter);
233 elms->set(SETTER_INDEX, *setter);
234 } else {
235 elms->set(WRITABLE_INDEX, heap->ToBoolean((attrs & READ_ONLY) == 0));
236 elms->set(VALUE_INDEX, *value);
237 }
238
239 return factory->NewJSArrayWithElements(elms);
240 }
241
242
243 // Returns an array with the property description:
244 // if args[1] is not a property on args[0]
245 // returns undefined
246 // if args[1] is a data property on args[0]
247 // [false, value, Writeable, Enumerable, Configurable]
248 // if args[1] is an accessor on args[0]
249 // [true, GetFunction, SetFunction, Enumerable, Configurable]
250 RUNTIME_FUNCTION(Runtime_GetOwnProperty) {
251 HandleScope scope(isolate);
252 DCHECK(args.length() == 2);
253 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
254 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
255 Handle<Object> result;
256 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
257 GetOwnProperty(isolate, obj, name));
258 return *result;
259 }
260
261
262 RUNTIME_FUNCTION(Runtime_PreventExtensions) {
263 HandleScope scope(isolate);
264 DCHECK(args.length() == 1);
265 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
266 Handle<Object> result;
267 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
268 JSObject::PreventExtensions(obj));
269 return *result;
270 }
271
272
273 RUNTIME_FUNCTION(Runtime_IsExtensible) {
274 SealHandleScope shs(isolate);
275 DCHECK(args.length() == 1);
276 CONVERT_ARG_CHECKED(JSObject, obj, 0);
277 if (obj->IsJSGlobalProxy()) {
278 PrototypeIterator iter(isolate, obj);
279 if (iter.IsAtEnd()) return isolate->heap()->false_value();
280 DCHECK(iter.GetCurrent()->IsJSGlobalObject());
281 obj = JSObject::cast(iter.GetCurrent());
282 }
283 return isolate->heap()->ToBoolean(obj->map()->is_extensible());
284 }
285
286
287 RUNTIME_FUNCTION(Runtime_CreateApiFunction) {
288 HandleScope scope(isolate);
289 DCHECK(args.length() == 2);
290 CONVERT_ARG_HANDLE_CHECKED(FunctionTemplateInfo, data, 0);
291 CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1);
292 return *isolate->factory()->CreateApiFunction(data, prototype);
293 }
294
295
296 RUNTIME_FUNCTION(Runtime_IsTemplate) {
297 SealHandleScope shs(isolate);
298 DCHECK(args.length() == 1);
299 CONVERT_ARG_HANDLE_CHECKED(Object, arg, 0);
300 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
301 return isolate->heap()->ToBoolean(result);
302 }
303
304
305 RUNTIME_FUNCTION(Runtime_GetTemplateField) {
306 SealHandleScope shs(isolate);
307 DCHECK(args.length() == 2);
308 CONVERT_ARG_CHECKED(HeapObject, templ, 0);
309 CONVERT_SMI_ARG_CHECKED(index, 1);
310 int offset = index * kPointerSize + HeapObject::kHeaderSize;
311 InstanceType type = templ->map()->instance_type();
312 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
313 type == OBJECT_TEMPLATE_INFO_TYPE);
314 RUNTIME_ASSERT(offset > 0);
315 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
316 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
317 } else {
318 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
319 }
320 return *HeapObject::RawField(templ, offset);
321 }
322
323
324 RUNTIME_FUNCTION(Runtime_DisableAccessChecks) {
325 HandleScope scope(isolate);
326 DCHECK(args.length() == 1);
327 CONVERT_ARG_HANDLE_CHECKED(HeapObject, object, 0);
328 Handle<Map> old_map(object->map());
329 bool needs_access_checks = old_map->is_access_check_needed();
330 if (needs_access_checks) {
331 // Copy map so it won't interfere constructor's initial map.
332 Handle<Map> new_map = Map::Copy(old_map);
333 new_map->set_is_access_check_needed(false);
334 JSObject::MigrateToMap(Handle<JSObject>::cast(object), new_map);
335 }
336 return isolate->heap()->ToBoolean(needs_access_checks);
337 }
338
339
340 RUNTIME_FUNCTION(Runtime_EnableAccessChecks) {
341 HandleScope scope(isolate);
342 DCHECK(args.length() == 1);
343 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
344 Handle<Map> old_map(object->map());
345 RUNTIME_ASSERT(!old_map->is_access_check_needed());
346 // Copy map so it won't interfere constructor's initial map.
347 Handle<Map> new_map = Map::Copy(old_map);
348 new_map->set_is_access_check_needed(true);
349 JSObject::MigrateToMap(object, new_map);
350 return isolate->heap()->undefined_value();
351 }
352
353
354 RUNTIME_FUNCTION(Runtime_OptimizeObjectForAddingMultipleProperties) {
355 HandleScope scope(isolate);
356 DCHECK(args.length() == 2);
357 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
358 CONVERT_SMI_ARG_CHECKED(properties, 1);
359 // Conservative upper limit to prevent fuzz tests from going OOM.
360 RUNTIME_ASSERT(properties <= 100000);
361 if (object->HasFastProperties() && !object->IsJSGlobalProxy()) {
362 JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
363 }
364 return *object;
365 }
366
367
368 RUNTIME_FUNCTION(Runtime_FinishArrayPrototypeSetup) {
369 HandleScope scope(isolate);
370 DCHECK(args.length() == 1);
371 CONVERT_ARG_HANDLE_CHECKED(JSArray, prototype, 0);
372 Object* length = prototype->length();
373 RUNTIME_ASSERT(length->IsSmi() && Smi::cast(length)->value() == 0);
374 RUNTIME_ASSERT(prototype->HasFastSmiOrObjectElements());
375 // This is necessary to enable fast checks for absence of elements
376 // on Array.prototype and below.
377 prototype->set_elements(isolate->heap()->empty_fixed_array());
378 return Smi::FromInt(0);
379 }
380
381
382 static void InstallBuiltin(Isolate* isolate, Handle<JSObject> holder,
383 const char* name, Builtins::Name builtin_name) {
384 Handle<String> key = isolate->factory()->InternalizeUtf8String(name);
385 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
386 Handle<JSFunction> optimized =
387 isolate->factory()->NewFunctionWithoutPrototype(key, code);
388 optimized->shared()->DontAdaptArguments();
389 JSObject::AddProperty(holder, key, optimized, NONE);
390 }
391
392
393 RUNTIME_FUNCTION(Runtime_SpecialArrayFunctions) {
394 HandleScope scope(isolate);
395 DCHECK(args.length() == 0);
396 Handle<JSObject> holder =
397 isolate->factory()->NewJSObject(isolate->object_function());
398
399 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
400 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
401 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
402 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
403 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
404 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
405 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
406
407 return *holder;
408 }
409
410
411 RUNTIME_FUNCTION(Runtime_ObjectFreeze) {
412 HandleScope scope(isolate);
413 DCHECK(args.length() == 1);
414 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
415
416 // %ObjectFreeze is a fast path and these cases are handled elsewhere.
417 RUNTIME_ASSERT(!object->HasSloppyArgumentsElements() &&
418 !object->map()->is_observed() && !object->IsJSProxy());
419
420 Handle<Object> result;
421 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, JSObject::Freeze(object));
422 return *result;
423 }
424
425
426 // Returns a single character string where first character equals
427 // string->Get(index).
428 static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
429 if (index < static_cast<uint32_t>(string->length())) {
430 Factory* factory = string->GetIsolate()->factory();
431 return factory->LookupSingleCharacterStringFromCode(
432 String::Flatten(string)->Get(index));
433 }
434 return Execution::CharAt(string, index);
435 }
436
437
438 MaybeHandle<Object> Runtime::GetElementOrCharAt(Isolate* isolate,
439 Handle<Object> object,
440 uint32_t index) {
441 // Handle [] indexing on Strings
442 if (object->IsString()) {
443 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
444 if (!result->IsUndefined()) return result;
445 }
446
447 // Handle [] indexing on String objects
448 if (object->IsStringObjectWithCharacterAt(index)) {
449 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
450 Handle<Object> result =
451 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
452 if (!result->IsUndefined()) return result;
453 }
454
455 Handle<Object> result;
456 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
457 PrototypeIterator iter(isolate, object);
458 return Object::GetElement(isolate, PrototypeIterator::GetCurrent(iter),
459 index);
460 } else {
461 return Object::GetElement(isolate, object, index);
462 }
463 }
464
465
466 MaybeHandle<Name> Runtime::ToName(Isolate* isolate, Handle<Object> key) {
467 if (key->IsName()) {
468 return Handle<Name>::cast(key);
469 } else {
470 Handle<Object> converted;
471 ASSIGN_RETURN_ON_EXCEPTION(isolate, converted,
472 Execution::ToString(isolate, key), Name);
473 return Handle<Name>::cast(converted);
474 }
475 }
476
477
478 MaybeHandle<Object> Runtime::HasObjectProperty(Isolate* isolate,
479 Handle<JSReceiver> object,
480 Handle<Object> key) {
481 Maybe<bool> maybe;
482 // Check if the given key is an array index.
483 uint32_t index;
484 if (key->ToArrayIndex(&index)) {
485 maybe = JSReceiver::HasElement(object, index);
486 } else {
487 // Convert the key to a name - possibly by calling back into JavaScript.
488 Handle<Name> name;
489 ASSIGN_RETURN_ON_EXCEPTION(isolate, name, ToName(isolate, key), Object);
490
491 maybe = JSReceiver::HasProperty(object, name);
492 }
493
494 if (!maybe.has_value) return MaybeHandle<Object>();
495 return isolate->factory()->ToBoolean(maybe.value);
496 }
497
498
499 MaybeHandle<Object> Runtime::GetObjectProperty(Isolate* isolate,
500 Handle<Object> object,
501 Handle<Object> key) {
502 if (object->IsUndefined() || object->IsNull()) {
503 Handle<Object> args[2] = {key, object};
504 THROW_NEW_ERROR(isolate, NewTypeError("non_object_property_load",
505 HandleVector(args, 2)),
506 Object);
507 }
508
509 // Check if the given key is an array index.
510 uint32_t index;
511 if (key->ToArrayIndex(&index)) {
512 return GetElementOrCharAt(isolate, object, index);
513 }
514
515 // Convert the key to a name - possibly by calling back into JavaScript.
516 Handle<Name> name;
517 ASSIGN_RETURN_ON_EXCEPTION(isolate, name, ToName(isolate, key), Object);
518
519 // Check if the name is trivially convertible to an index and get
520 // the element if so.
521 if (name->AsArrayIndex(&index)) {
522 return GetElementOrCharAt(isolate, object, index);
523 } else {
524 return Object::GetProperty(object, name);
525 }
526 }
527
528
529 RUNTIME_FUNCTION(Runtime_GetProperty) {
530 HandleScope scope(isolate);
531 DCHECK(args.length() == 2);
532
533 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
534 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
535 Handle<Object> result;
536 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
537 isolate, result, Runtime::GetObjectProperty(isolate, object, key));
538 return *result;
539 }
540
541
542 // KeyedGetProperty is called from KeyedLoadIC::GenerateGeneric.
543 RUNTIME_FUNCTION(Runtime_KeyedGetProperty) {
544 HandleScope scope(isolate);
545 DCHECK(args.length() == 2);
546
547 CONVERT_ARG_HANDLE_CHECKED(Object, receiver_obj, 0);
548 CONVERT_ARG_HANDLE_CHECKED(Object, key_obj, 1);
549
550 // Fast cases for getting named properties of the receiver JSObject
551 // itself.
552 //
553 // The global proxy objects has to be excluded since LookupOwn on
554 // the global proxy object can return a valid result even though the
555 // global proxy object never has properties. This is the case
556 // because the global proxy object forwards everything to its hidden
557 // prototype including own lookups.
558 //
559 // Additionally, we need to make sure that we do not cache results
560 // for objects that require access checks.
561 if (receiver_obj->IsJSObject()) {
562 if (!receiver_obj->IsJSGlobalProxy() &&
563 !receiver_obj->IsAccessCheckNeeded() && key_obj->IsName()) {
564 DisallowHeapAllocation no_allocation;
565 Handle<JSObject> receiver = Handle<JSObject>::cast(receiver_obj);
566 Handle<Name> key = Handle<Name>::cast(key_obj);
567 if (receiver->HasFastProperties()) {
568 // Attempt to use lookup cache.
569 Handle<Map> receiver_map(receiver->map(), isolate);
570 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
571 int index = keyed_lookup_cache->Lookup(receiver_map, key);
572 if (index != -1) {
573 // Doubles are not cached, so raw read the value.
574 return receiver->RawFastPropertyAt(
575 FieldIndex::ForKeyedLookupCacheIndex(*receiver_map, index));
576 }
577 // Lookup cache miss. Perform lookup and update the cache if
578 // appropriate.
579 LookupIterator it(receiver, key, LookupIterator::OWN);
580 if (it.state() == LookupIterator::DATA &&
581 it.property_details().type() == FIELD) {
582 FieldIndex field_index = it.GetFieldIndex();
583 // Do not track double fields in the keyed lookup cache. Reading
584 // double values requires boxing.
585 if (!it.representation().IsDouble()) {
586 keyed_lookup_cache->Update(receiver_map, key,
587 field_index.GetKeyedLookupCacheIndex());
588 }
589 AllowHeapAllocation allow_allocation;
590 return *JSObject::FastPropertyAt(receiver, it.representation(),
591 field_index);
592 }
593 } else {
594 // Attempt dictionary lookup.
595 NameDictionary* dictionary = receiver->property_dictionary();
596 int entry = dictionary->FindEntry(key);
597 if ((entry != NameDictionary::kNotFound) &&
598 (dictionary->DetailsAt(entry).type() == NORMAL)) {
599 Object* value = dictionary->ValueAt(entry);
600 if (!receiver->IsGlobalObject()) return value;
601 value = PropertyCell::cast(value)->value();
602 if (!value->IsTheHole()) return value;
603 // If value is the hole (meaning, absent) do the general lookup.
604 }
605 }
606 } else if (key_obj->IsSmi()) {
607 // JSObject without a name key. If the key is a Smi, check for a
608 // definite out-of-bounds access to elements, which is a strong indicator
609 // that subsequent accesses will also call the runtime. Proactively
610 // transition elements to FAST_*_ELEMENTS to avoid excessive boxing of
611 // doubles for those future calls in the case that the elements would
612 // become FAST_DOUBLE_ELEMENTS.
613 Handle<JSObject> js_object = Handle<JSObject>::cast(receiver_obj);
614 ElementsKind elements_kind = js_object->GetElementsKind();
615 if (IsFastDoubleElementsKind(elements_kind)) {
616 Handle<Smi> key = Handle<Smi>::cast(key_obj);
617 if (key->value() >= js_object->elements()->length()) {
618 if (IsFastHoleyElementsKind(elements_kind)) {
619 elements_kind = FAST_HOLEY_ELEMENTS;
620 } else {
621 elements_kind = FAST_ELEMENTS;
622 }
623 RETURN_FAILURE_ON_EXCEPTION(
624 isolate, TransitionElements(js_object, elements_kind, isolate));
625 }
626 } else {
627 DCHECK(IsFastSmiOrObjectElementsKind(elements_kind) ||
628 !IsFastElementsKind(elements_kind));
629 }
630 }
631 } else if (receiver_obj->IsString() && key_obj->IsSmi()) {
632 // Fast case for string indexing using [] with a smi index.
633 Handle<String> str = Handle<String>::cast(receiver_obj);
634 int index = args.smi_at(1);
635 if (index >= 0 && index < str->length()) {
636 return *GetCharAt(str, index);
637 }
638 }
639
640 // Fall back to GetObjectProperty.
641 Handle<Object> result;
642 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
643 isolate, result,
644 Runtime::GetObjectProperty(isolate, receiver_obj, key_obj));
645 return *result;
646 }
647
648
649 static bool IsValidAccessor(Handle<Object> obj) {
650 return obj->IsUndefined() || obj->IsSpecFunction() || obj->IsNull();
651 }
652
653
654 // Transform getter or setter into something DefineAccessor can handle.
655 static Handle<Object> InstantiateAccessorComponent(Isolate* isolate,
656 Handle<Object> component) {
657 if (component->IsUndefined()) return isolate->factory()->undefined_value();
658 Handle<FunctionTemplateInfo> info =
659 Handle<FunctionTemplateInfo>::cast(component);
660 return Utils::OpenHandle(*Utils::ToLocal(info)->GetFunction());
661 }
662
663
664 RUNTIME_FUNCTION(Runtime_DefineApiAccessorProperty) {
665 HandleScope scope(isolate);
666 DCHECK(args.length() == 5);
667 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
668 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
669 CONVERT_ARG_HANDLE_CHECKED(Object, getter, 2);
670 CONVERT_ARG_HANDLE_CHECKED(Object, setter, 3);
671 CONVERT_SMI_ARG_CHECKED(attribute, 4);
672 RUNTIME_ASSERT(getter->IsUndefined() || getter->IsFunctionTemplateInfo());
673 RUNTIME_ASSERT(setter->IsUndefined() || setter->IsFunctionTemplateInfo());
674 RUNTIME_ASSERT(PropertyDetails::AttributesField::is_valid(
675 static_cast<PropertyAttributes>(attribute)));
676 RETURN_FAILURE_ON_EXCEPTION(
677 isolate, JSObject::DefineAccessor(
678 object, name, InstantiateAccessorComponent(isolate, getter),
679 InstantiateAccessorComponent(isolate, setter),
680 static_cast<PropertyAttributes>(attribute)));
681 return isolate->heap()->undefined_value();
682 }
683
684
685 // Implements part of 8.12.9 DefineOwnProperty.
686 // There are 3 cases that lead here:
687 // Step 4b - define a new accessor property.
688 // Steps 9c & 12 - replace an existing data property with an accessor property.
689 // Step 12 - update an existing accessor property with an accessor or generic
690 // descriptor.
691 RUNTIME_FUNCTION(Runtime_DefineAccessorPropertyUnchecked) {
692 HandleScope scope(isolate);
693 DCHECK(args.length() == 5);
694 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
695 RUNTIME_ASSERT(!obj->IsNull());
696 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
697 CONVERT_ARG_HANDLE_CHECKED(Object, getter, 2);
698 RUNTIME_ASSERT(IsValidAccessor(getter));
699 CONVERT_ARG_HANDLE_CHECKED(Object, setter, 3);
700 RUNTIME_ASSERT(IsValidAccessor(setter));
701 CONVERT_SMI_ARG_CHECKED(unchecked, 4);
702 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
703 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
704
705 bool fast = obj->HasFastProperties();
706 RETURN_FAILURE_ON_EXCEPTION(
707 isolate, JSObject::DefineAccessor(obj, name, getter, setter, attr));
708 if (fast) JSObject::MigrateSlowToFast(obj, 0);
709 return isolate->heap()->undefined_value();
710 }
711
712
713 // Implements part of 8.12.9 DefineOwnProperty.
714 // There are 3 cases that lead here:
715 // Step 4a - define a new data property.
716 // Steps 9b & 12 - replace an existing accessor property with a data property.
717 // Step 12 - update an existing data property with a data or generic
718 // descriptor.
719 RUNTIME_FUNCTION(Runtime_DefineDataPropertyUnchecked) {
720 HandleScope scope(isolate);
721 DCHECK(args.length() == 4);
722 CONVERT_ARG_HANDLE_CHECKED(JSObject, js_object, 0);
723 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
724 CONVERT_ARG_HANDLE_CHECKED(Object, obj_value, 2);
725 CONVERT_SMI_ARG_CHECKED(unchecked, 3);
726 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
727 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
728
729 LookupIterator it(js_object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
730 if (it.IsFound() && it.state() == LookupIterator::ACCESS_CHECK) {
731 if (!isolate->MayNamedAccess(js_object, name, v8::ACCESS_SET)) {
732 return isolate->heap()->undefined_value();
733 }
734 it.Next();
735 }
736
737 // Take special care when attributes are different and there is already
738 // a property.
739 if (it.state() == LookupIterator::ACCESSOR) {
740 // Use IgnoreAttributes version since a readonly property may be
741 // overridden and SetProperty does not allow this.
742 Handle<Object> result;
743 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
744 isolate, result,
745 JSObject::SetOwnPropertyIgnoreAttributes(
746 js_object, name, obj_value, attr, JSObject::DONT_FORCE_FIELD));
747 return *result;
748 }
749
750 Handle<Object> result;
751 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
752 isolate, result,
753 Runtime::DefineObjectProperty(js_object, name, obj_value, attr));
754 return *result;
755 }
756
757
758 // Return property without being observable by accessors or interceptors.
759 RUNTIME_FUNCTION(Runtime_GetDataProperty) {
760 HandleScope scope(isolate);
761 DCHECK(args.length() == 2);
762 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
763 CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
764 return *JSObject::GetDataProperty(object, key);
765 }
766
767
768 MaybeHandle<Object> Runtime::SetObjectProperty(Isolate* isolate,
769 Handle<Object> object,
770 Handle<Object> key,
771 Handle<Object> value,
772 StrictMode strict_mode) {
773 if (object->IsUndefined() || object->IsNull()) {
774 Handle<Object> args[2] = {key, object};
775 THROW_NEW_ERROR(isolate, NewTypeError("non_object_property_store",
776 HandleVector(args, 2)),
777 Object);
778 }
779
780 if (object->IsJSProxy()) {
781 Handle<Object> name_object;
782 if (key->IsSymbol()) {
783 name_object = key;
784 } else {
785 ASSIGN_RETURN_ON_EXCEPTION(isolate, name_object,
786 Execution::ToString(isolate, key), Object);
787 }
788 Handle<Name> name = Handle<Name>::cast(name_object);
789 return Object::SetProperty(Handle<JSProxy>::cast(object), name, value,
790 strict_mode);
791 }
792
793 // Check if the given key is an array index.
794 uint32_t index;
795 if (key->ToArrayIndex(&index)) {
796 // TODO(verwaest): Support non-JSObject receivers.
797 if (!object->IsJSObject()) return value;
798 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
799
800 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
801 // of a string using [] notation. We need to support this too in
802 // JavaScript.
803 // In the case of a String object we just need to redirect the assignment to
804 // the underlying string if the index is in range. Since the underlying
805 // string does nothing with the assignment then we can ignore such
806 // assignments.
807 if (js_object->IsStringObjectWithCharacterAt(index)) {
808 return value;
809 }
810
811 JSObject::ValidateElements(js_object);
812 if (js_object->HasExternalArrayElements() ||
813 js_object->HasFixedTypedArrayElements()) {
814 if (!value->IsNumber() && !value->IsUndefined()) {
815 ASSIGN_RETURN_ON_EXCEPTION(isolate, value,
816 Execution::ToNumber(isolate, value), Object);
817 }
818 }
819
820 MaybeHandle<Object> result = JSObject::SetElement(
821 js_object, index, value, NONE, strict_mode, true, SET_PROPERTY);
822 JSObject::ValidateElements(js_object);
823
824 return result.is_null() ? result : value;
825 }
826
827 if (key->IsName()) {
828 Handle<Name> name = Handle<Name>::cast(key);
829 if (name->AsArrayIndex(&index)) {
830 // TODO(verwaest): Support non-JSObject receivers.
831 if (!object->IsJSObject()) return value;
832 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
833 if (js_object->HasExternalArrayElements()) {
834 if (!value->IsNumber() && !value->IsUndefined()) {
835 ASSIGN_RETURN_ON_EXCEPTION(
836 isolate, value, Execution::ToNumber(isolate, value), Object);
837 }
838 }
839 return JSObject::SetElement(js_object, index, value, NONE, strict_mode,
840 true, SET_PROPERTY);
841 } else {
842 if (name->IsString()) name = String::Flatten(Handle<String>::cast(name));
843 return Object::SetProperty(object, name, value, strict_mode);
844 }
845 }
846
847 // Call-back into JavaScript to convert the key to a string.
848 Handle<Object> converted;
849 ASSIGN_RETURN_ON_EXCEPTION(isolate, converted,
850 Execution::ToString(isolate, key), Object);
851 Handle<String> name = Handle<String>::cast(converted);
852
853 if (name->AsArrayIndex(&index)) {
854 // TODO(verwaest): Support non-JSObject receivers.
855 if (!object->IsJSObject()) return value;
856 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
857 return JSObject::SetElement(js_object, index, value, NONE, strict_mode,
858 true, SET_PROPERTY);
859 }
860 return Object::SetProperty(object, name, value, strict_mode);
861 }
862
863
864 MaybeHandle<Object> Runtime::DefineObjectProperty(Handle<JSObject> js_object,
865 Handle<Object> key,
866 Handle<Object> value,
867 PropertyAttributes attr) {
868 Isolate* isolate = js_object->GetIsolate();
869 // Check if the given key is an array index.
870 uint32_t index;
871 if (key->ToArrayIndex(&index)) {
872 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
873 // of a string using [] notation. We need to support this too in
874 // JavaScript.
875 // In the case of a String object we just need to redirect the assignment to
876 // the underlying string if the index is in range. Since the underlying
877 // string does nothing with the assignment then we can ignore such
878 // assignments.
879 if (js_object->IsStringObjectWithCharacterAt(index)) {
880 return value;
881 }
882
883 return JSObject::SetElement(js_object, index, value, attr, SLOPPY, false,
884 DEFINE_PROPERTY);
885 }
886
887 if (key->IsName()) {
888 Handle<Name> name = Handle<Name>::cast(key);
889 if (name->AsArrayIndex(&index)) {
890 return JSObject::SetElement(js_object, index, value, attr, SLOPPY, false,
891 DEFINE_PROPERTY);
892 } else {
893 if (name->IsString()) name = String::Flatten(Handle<String>::cast(name));
894 return JSObject::SetOwnPropertyIgnoreAttributes(js_object, name, value,
895 attr);
896 }
897 }
898
899 // Call-back into JavaScript to convert the key to a string.
900 Handle<Object> converted;
901 ASSIGN_RETURN_ON_EXCEPTION(isolate, converted,
902 Execution::ToString(isolate, key), Object);
903 Handle<String> name = Handle<String>::cast(converted);
904
905 if (name->AsArrayIndex(&index)) {
906 return JSObject::SetElement(js_object, index, value, attr, SLOPPY, false,
907 DEFINE_PROPERTY);
908 } else {
909 return JSObject::SetOwnPropertyIgnoreAttributes(js_object, name, value,
910 attr);
911 }
912 }
913
914
915 MaybeHandle<Object> Runtime::DeleteObjectProperty(Isolate* isolate,
916 Handle<JSReceiver> receiver,
917 Handle<Object> key,
918 JSReceiver::DeleteMode mode) {
919 // Check if the given key is an array index.
920 uint32_t index;
921 if (key->ToArrayIndex(&index)) {
922 // In Firefox/SpiderMonkey, Safari and Opera you can access the
923 // characters of a string using [] notation. In the case of a
924 // String object we just need to redirect the deletion to the
925 // underlying string if the index is in range. Since the
926 // underlying string does nothing with the deletion, we can ignore
927 // such deletions.
928 if (receiver->IsStringObjectWithCharacterAt(index)) {
929 return isolate->factory()->true_value();
930 }
931
932 return JSReceiver::DeleteElement(receiver, index, mode);
933 }
934
935 Handle<Name> name;
936 if (key->IsName()) {
937 name = Handle<Name>::cast(key);
938 } else {
939 // Call-back into JavaScript to convert the key to a string.
940 Handle<Object> converted;
941 ASSIGN_RETURN_ON_EXCEPTION(isolate, converted,
942 Execution::ToString(isolate, key), Object);
943 name = Handle<String>::cast(converted);
944 }
945
946 if (name->IsString()) name = String::Flatten(Handle<String>::cast(name));
947 return JSReceiver::DeleteProperty(receiver, name, mode);
948 }
949
950
951 RUNTIME_FUNCTION(Runtime_AddNamedProperty) {
952 HandleScope scope(isolate);
953 RUNTIME_ASSERT(args.length() == 4);
954
955 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
956 CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
957 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
958 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
959 RUNTIME_ASSERT(
960 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
961 // Compute attributes.
962 PropertyAttributes attributes =
963 static_cast<PropertyAttributes>(unchecked_attributes);
964
965 #ifdef DEBUG
966 uint32_t index = 0;
967 DCHECK(!key->ToArrayIndex(&index));
968 LookupIterator it(object, key, LookupIterator::OWN_SKIP_INTERCEPTOR);
969 Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
970 if (!maybe.has_value) return isolate->heap()->exception();
971 RUNTIME_ASSERT(!it.IsFound());
972 #endif
973
974 Handle<Object> result;
975 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
976 isolate, result,
977 JSObject::SetOwnPropertyIgnoreAttributes(object, key, value, attributes));
978 return *result;
979 }
980
981
982 RUNTIME_FUNCTION(Runtime_AddPropertyForTemplate) {
983 HandleScope scope(isolate);
984 RUNTIME_ASSERT(args.length() == 4);
985
986 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
987 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
988 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
989 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
990 RUNTIME_ASSERT(
991 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
992 // Compute attributes.
993 PropertyAttributes attributes =
994 static_cast<PropertyAttributes>(unchecked_attributes);
995
996 #ifdef DEBUG
997 bool duplicate;
998 if (key->IsName()) {
999 LookupIterator it(object, Handle<Name>::cast(key),
1000 LookupIterator::OWN_SKIP_INTERCEPTOR);
1001 Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
1002 DCHECK(maybe.has_value);
1003 duplicate = it.IsFound();
1004 } else {
1005 uint32_t index = 0;
1006 RUNTIME_ASSERT(key->ToArrayIndex(&index));
1007 Maybe<bool> maybe = JSReceiver::HasOwnElement(object, index);
1008 if (!maybe.has_value) return isolate->heap()->exception();
1009 duplicate = maybe.value;
1010 }
1011 if (duplicate) {
1012 Handle<Object> args[1] = {key};
1013 THROW_NEW_ERROR_RETURN_FAILURE(
1014 isolate,
1015 NewTypeError("duplicate_template_property", HandleVector(args, 1)));
1016 }
1017 #endif
1018
1019 Handle<Object> result;
1020 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
1021 isolate, result,
1022 Runtime::DefineObjectProperty(object, key, value, attributes));
1023 return *result;
1024 }
1025
1026
1027 RUNTIME_FUNCTION(Runtime_SetProperty) {
1028 HandleScope scope(isolate);
1029 RUNTIME_ASSERT(args.length() == 4);
1030
1031 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
1032 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
1033 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
1034 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode_arg, 3);
1035 StrictMode strict_mode = strict_mode_arg;
1036
1037 Handle<Object> result;
1038 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
1039 isolate, result,
1040 Runtime::SetObjectProperty(isolate, object, key, value, strict_mode));
1041 return *result;
1042 }
1043
1044
1045 // Adds an element to an array.
1046 // This is used to create an indexed data property into an array.
1047 RUNTIME_FUNCTION(Runtime_AddElement) {
1048 HandleScope scope(isolate);
1049 RUNTIME_ASSERT(args.length() == 4);
1050
1051 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
1052 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
1053 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
1054 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
1055 RUNTIME_ASSERT(
1056 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
1057 // Compute attributes.
1058 PropertyAttributes attributes =
1059 static_cast<PropertyAttributes>(unchecked_attributes);
1060
1061 uint32_t index = 0;
1062 key->ToArrayIndex(&index);
1063
1064 Handle<Object> result;
1065 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
1066 isolate, result, JSObject::SetElement(object, index, value, attributes,
1067 SLOPPY, false, DEFINE_PROPERTY));
1068 return *result;
1069 }
1070
1071
1072 RUNTIME_FUNCTION(Runtime_TransitionElementsKind) {
1073 HandleScope scope(isolate);
1074 RUNTIME_ASSERT(args.length() == 2);
1075 CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0);
1076 CONVERT_ARG_HANDLE_CHECKED(Map, map, 1);
1077 JSObject::TransitionElementsKind(array, map->elements_kind());
1078 return *array;
1079 }
1080
1081
1082 RUNTIME_FUNCTION(Runtime_DeleteProperty) {
1083 HandleScope scope(isolate);
1084 DCHECK(args.length() == 3);
1085 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0);
1086 CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
1087 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode, 2);
1088 JSReceiver::DeleteMode delete_mode = strict_mode == STRICT
1089 ? JSReceiver::STRICT_DELETION
1090 : JSReceiver::NORMAL_DELETION;
1091 Handle<Object> result;
1092 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
1093 isolate, result, JSReceiver::DeleteProperty(object, key, delete_mode));
1094 return *result;
1095 }
1096
1097
1098 static Object* HasOwnPropertyImplementation(Isolate* isolate,
1099 Handle<JSObject> object,
1100 Handle<Name> key) {
1101 Maybe<bool> maybe = JSReceiver::HasOwnProperty(object, key);
1102 if (!maybe.has_value) return isolate->heap()->exception();
1103 if (maybe.value) return isolate->heap()->true_value();
1104 // Handle hidden prototypes. If there's a hidden prototype above this thing
1105 // then we have to check it for properties, because they are supposed to
1106 // look like they are on this object.
1107 PrototypeIterator iter(isolate, object);
1108 if (!iter.IsAtEnd() &&
1109 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter))
1110 ->map()
1111 ->is_hidden_prototype()) {
1112 // TODO(verwaest): The recursion is not necessary for keys that are array
1113 // indices. Removing this.
1114 return HasOwnPropertyImplementation(
1115 isolate, Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)),
1116 key);
1117 }
1118 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
1119 return isolate->heap()->false_value();
1120 }
1121
1122
1123 RUNTIME_FUNCTION(Runtime_HasOwnProperty) {
1124 HandleScope scope(isolate);
1125 DCHECK(args.length() == 2);
1126 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0)
1127 CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
1128
1129 uint32_t index;
1130 const bool key_is_array_index = key->AsArrayIndex(&index);
1131
1132 // Only JS objects can have properties.
1133 if (object->IsJSObject()) {
1134 Handle<JSObject> js_obj = Handle<JSObject>::cast(object);
1135 // Fast case: either the key is a real named property or it is not
1136 // an array index and there are no interceptors or hidden
1137 // prototypes.
1138 Maybe<bool> maybe = JSObject::HasRealNamedProperty(js_obj, key);
1139 if (!maybe.has_value) return isolate->heap()->exception();
1140 DCHECK(!isolate->has_pending_exception());
1141 if (maybe.value) {
1142 return isolate->heap()->true_value();
1143 }
1144 Map* map = js_obj->map();
1145 if (!key_is_array_index && !map->has_named_interceptor() &&
1146 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
1147 return isolate->heap()->false_value();
1148 }
1149 // Slow case.
1150 return HasOwnPropertyImplementation(isolate, Handle<JSObject>(js_obj),
1151 Handle<Name>(key));
1152 } else if (object->IsString() && key_is_array_index) {
1153 // Well, there is one exception: Handle [] on strings.
1154 Handle<String> string = Handle<String>::cast(object);
1155 if (index < static_cast<uint32_t>(string->length())) {
1156 return isolate->heap()->true_value();
1157 }
1158 }
1159 return isolate->heap()->false_value();
1160 }
1161
1162
1163 RUNTIME_FUNCTION(Runtime_HasProperty) {
1164 HandleScope scope(isolate);
1165 DCHECK(args.length() == 2);
1166 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0);
1167 CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
1168
1169 Maybe<bool> maybe = JSReceiver::HasProperty(receiver, key);
1170 if (!maybe.has_value) return isolate->heap()->exception();
1171 return isolate->heap()->ToBoolean(maybe.value);
1172 }
1173
1174
1175 RUNTIME_FUNCTION(Runtime_HasElement) {
1176 HandleScope scope(isolate);
1177 DCHECK(args.length() == 2);
1178 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0);
1179 CONVERT_SMI_ARG_CHECKED(index, 1);
1180
1181 Maybe<bool> maybe = JSReceiver::HasElement(receiver, index);
1182 if (!maybe.has_value) return isolate->heap()->exception();
1183 return isolate->heap()->ToBoolean(maybe.value);
1184 }
1185
1186
1187 RUNTIME_FUNCTION(Runtime_IsPropertyEnumerable) {
1188 HandleScope scope(isolate);
1189 DCHECK(args.length() == 2);
1190
1191 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
1192 CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
1193
1194 Maybe<PropertyAttributes> maybe =
1195 JSReceiver::GetOwnPropertyAttributes(object, key);
1196 if (!maybe.has_value) return isolate->heap()->exception();
1197 if (maybe.value == ABSENT) maybe.value = DONT_ENUM;
1198 return isolate->heap()->ToBoolean((maybe.value & DONT_ENUM) == 0);
1199 }
1200
1201
1202 RUNTIME_FUNCTION(Runtime_GetPropertyNames) {
1203 HandleScope scope(isolate);
1204 DCHECK(args.length() == 1);
1205 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0);
1206 Handle<JSArray> result;
1207
1208 isolate->counters()->for_in()->Increment();
1209 Handle<FixedArray> elements;
1210 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
1211 isolate, elements,
1212 JSReceiver::GetKeys(object, JSReceiver::INCLUDE_PROTOS));
1213 return *isolate->factory()->NewJSArrayWithElements(elements);
1214 }
1215
1216
1217 // Returns either a FixedArray as Runtime_GetPropertyNames,
1218 // or, if the given object has an enum cache that contains
1219 // all enumerable properties of the object and its prototypes
1220 // have none, the map of the object. This is used to speed up
1221 // the check for deletions during a for-in.
1222 RUNTIME_FUNCTION(Runtime_GetPropertyNamesFast) {
1223 SealHandleScope shs(isolate);
1224 DCHECK(args.length() == 1);
1225
1226 CONVERT_ARG_CHECKED(JSReceiver, raw_object, 0);
1227
1228 if (raw_object->IsSimpleEnum()) return raw_object->map();
1229
1230 HandleScope scope(isolate);
1231 Handle<JSReceiver> object(raw_object);
1232 Handle<FixedArray> content;
1233 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
1234 isolate, content,
1235 JSReceiver::GetKeys(object, JSReceiver::INCLUDE_PROTOS));
1236
1237 // Test again, since cache may have been built by preceding call.
1238 if (object->IsSimpleEnum()) return object->map();
1239
1240 return *content;
1241 }
1242
1243
1244 // Find the length of the prototype chain that is to be handled as one. If a
1245 // prototype object is hidden it is to be viewed as part of the the object it
1246 // is prototype for.
1247 static int OwnPrototypeChainLength(JSObject* obj) {
1248 int count = 1;
1249 for (PrototypeIterator iter(obj->GetIsolate(), obj);
1250 !iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN); iter.Advance()) {
1251 count++;
1252 }
1253 return count;
1254 }
1255
1256
1257 // Return the names of the own named properties.
1258 // args[0]: object
1259 // args[1]: PropertyAttributes as int
1260 RUNTIME_FUNCTION(Runtime_GetOwnPropertyNames) {
1261 HandleScope scope(isolate);
1262 DCHECK(args.length() == 2);
1263 if (!args[0]->IsJSObject()) {
1264 return isolate->heap()->undefined_value();
1265 }
1266 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
1267 CONVERT_SMI_ARG_CHECKED(filter_value, 1);
1268 PropertyAttributes filter = static_cast<PropertyAttributes>(filter_value);
1269
1270 // Skip the global proxy as it has no properties and always delegates to the
1271 // real global object.
1272 if (obj->IsJSGlobalProxy()) {
1273 // Only collect names if access is permitted.
1274 if (obj->IsAccessCheckNeeded() &&
1275 !isolate->MayNamedAccess(obj, isolate->factory()->undefined_value(),
1276 v8::ACCESS_KEYS)) {
1277 isolate->ReportFailedAccessCheck(obj, v8::ACCESS_KEYS);
1278 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
1279 return *isolate->factory()->NewJSArray(0);
1280 }
1281 PrototypeIterator iter(isolate, obj);
1282 obj = Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
1283 }
1284
1285 // Find the number of objects making up this.
1286 int length = OwnPrototypeChainLength(*obj);
1287
1288 // Find the number of own properties for each of the objects.
1289 ScopedVector<int> own_property_count(length);
1290 int total_property_count = 0;
1291 {
1292 PrototypeIterator iter(isolate, obj, PrototypeIterator::START_AT_RECEIVER);
1293 for (int i = 0; i < length; i++) {
1294 DCHECK(!iter.IsAtEnd());
1295 Handle<JSObject> jsproto =
1296 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
1297 // Only collect names if access is permitted.
1298 if (jsproto->IsAccessCheckNeeded() &&
1299 !isolate->MayNamedAccess(jsproto,
1300 isolate->factory()->undefined_value(),
1301 v8::ACCESS_KEYS)) {
1302 isolate->ReportFailedAccessCheck(jsproto, v8::ACCESS_KEYS);
1303 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
1304 return *isolate->factory()->NewJSArray(0);
1305 }
1306 int n;
1307 n = jsproto->NumberOfOwnProperties(filter);
1308 own_property_count[i] = n;
1309 total_property_count += n;
1310 iter.Advance();
1311 }
1312 }
1313
1314 // Allocate an array with storage for all the property names.
1315 Handle<FixedArray> names =
1316 isolate->factory()->NewFixedArray(total_property_count);
1317
1318 // Get the property names.
1319 int next_copy_index = 0;
1320 int hidden_strings = 0;
1321 {
1322 PrototypeIterator iter(isolate, obj, PrototypeIterator::START_AT_RECEIVER);
1323 for (int i = 0; i < length; i++) {
1324 DCHECK(!iter.IsAtEnd());
1325 Handle<JSObject> jsproto =
1326 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
1327 jsproto->GetOwnPropertyNames(*names, next_copy_index, filter);
1328 if (i > 0) {
1329 // Names from hidden prototypes may already have been added
1330 // for inherited function template instances. Count the duplicates
1331 // and stub them out; the final copy pass at the end ignores holes.
1332 for (int j = next_copy_index;
1333 j < next_copy_index + own_property_count[i]; j++) {
1334 Object* name_from_hidden_proto = names->get(j);
1335 for (int k = 0; k < next_copy_index; k++) {
1336 if (names->get(k) != isolate->heap()->hidden_string()) {
1337 Object* name = names->get(k);
1338 if (name_from_hidden_proto == name) {
1339 names->set(j, isolate->heap()->hidden_string());
1340 hidden_strings++;
1341 break;
1342 }
1343 }
1344 }
1345 }
1346 }
1347 next_copy_index += own_property_count[i];
1348
1349 // Hidden properties only show up if the filter does not skip strings.
1350 if ((filter & STRING) == 0 && JSObject::HasHiddenProperties(jsproto)) {
1351 hidden_strings++;
1352 }
1353 iter.Advance();
1354 }
1355 }
1356
1357 // Filter out name of hidden properties object and
1358 // hidden prototype duplicates.
1359 if (hidden_strings > 0) {
1360 Handle<FixedArray> old_names = names;
1361 names = isolate->factory()->NewFixedArray(names->length() - hidden_strings);
1362 int dest_pos = 0;
1363 for (int i = 0; i < total_property_count; i++) {
1364 Object* name = old_names->get(i);
1365 if (name == isolate->heap()->hidden_string()) {
1366 hidden_strings--;
1367 continue;
1368 }
1369 names->set(dest_pos++, name);
1370 }
1371 DCHECK_EQ(0, hidden_strings);
1372 }
1373
1374 return *isolate->factory()->NewJSArrayWithElements(names);
1375 }
1376
1377
1378 // Return the names of the own indexed properties.
1379 // args[0]: object
1380 RUNTIME_FUNCTION(Runtime_GetOwnElementNames) {
1381 HandleScope scope(isolate);
1382 DCHECK(args.length() == 1);
1383 if (!args[0]->IsJSObject()) {
1384 return isolate->heap()->undefined_value();
1385 }
1386 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
1387
1388 int n = obj->NumberOfOwnElements(static_cast<PropertyAttributes>(NONE));
1389 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
1390 obj->GetOwnElementKeys(*names, static_cast<PropertyAttributes>(NONE));
1391 return *isolate->factory()->NewJSArrayWithElements(names);
1392 }
1393
1394
1395 // Return information on whether an object has a named or indexed interceptor.
1396 // args[0]: object
1397 RUNTIME_FUNCTION(Runtime_GetInterceptorInfo) {
1398 HandleScope scope(isolate);
1399 DCHECK(args.length() == 1);
1400 if (!args[0]->IsJSObject()) {
1401 return Smi::FromInt(0);
1402 }
1403 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
1404
1405 int result = 0;
1406 if (obj->HasNamedInterceptor()) result |= 2;
1407 if (obj->HasIndexedInterceptor()) result |= 1;
1408
1409 return Smi::FromInt(result);
1410 }
1411
1412
1413 // Return property names from named interceptor.
1414 // args[0]: object
1415 RUNTIME_FUNCTION(Runtime_GetNamedInterceptorPropertyNames) {
1416 HandleScope scope(isolate);
1417 DCHECK(args.length() == 1);
1418 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
1419
1420 if (obj->HasNamedInterceptor()) {
1421 Handle<JSObject> result;
1422 if (JSObject::GetKeysForNamedInterceptor(obj, obj).ToHandle(&result)) {
1423 return *result;
1424 }
1425 }
1426 return isolate->heap()->undefined_value();
1427 }
1428
1429
1430 // Return element names from indexed interceptor.
1431 // args[0]: object
1432 RUNTIME_FUNCTION(Runtime_GetIndexedInterceptorElementNames) {
1433 HandleScope scope(isolate);
1434 DCHECK(args.length() == 1);
1435 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
1436
1437 if (obj->HasIndexedInterceptor()) {
1438 Handle<JSObject> result;
1439 if (JSObject::GetKeysForIndexedInterceptor(obj, obj).ToHandle(&result)) {
1440 return *result;
1441 }
1442 }
1443 return isolate->heap()->undefined_value();
1444 }
1445
1446
1447 RUNTIME_FUNCTION(Runtime_OwnKeys) {
1448 HandleScope scope(isolate);
1449 DCHECK(args.length() == 1);
1450 CONVERT_ARG_CHECKED(JSObject, raw_object, 0);
1451 Handle<JSObject> object(raw_object);
1452
1453 if (object->IsJSGlobalProxy()) {
1454 // Do access checks before going to the global object.
1455 if (object->IsAccessCheckNeeded() &&
1456 !isolate->MayNamedAccess(object, isolate->factory()->undefined_value(),
1457 v8::ACCESS_KEYS)) {
1458 isolate->ReportFailedAccessCheck(object, v8::ACCESS_KEYS);
1459 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
1460 return *isolate->factory()->NewJSArray(0);
1461 }
1462
1463 PrototypeIterator iter(isolate, object);
1464 // If proxy is detached we simply return an empty array.
1465 if (iter.IsAtEnd()) return *isolate->factory()->NewJSArray(0);
1466 object = Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
1467 }
1468
1469 Handle<FixedArray> contents;
1470 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
1471 isolate, contents, JSReceiver::GetKeys(object, JSReceiver::OWN_ONLY));
1472
1473 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
1474 // property array and since the result is mutable we have to create
1475 // a fresh clone on each invocation.
1476 int length = contents->length();
1477 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
1478 for (int i = 0; i < length; i++) {
1479 Object* entry = contents->get(i);
1480 if (entry->IsString()) {
1481 copy->set(i, entry);
1482 } else {
1483 DCHECK(entry->IsNumber());
1484 HandleScope scope(isolate);
1485 Handle<Object> entry_handle(entry, isolate);
1486 Handle<Object> entry_str =
1487 isolate->factory()->NumberToString(entry_handle);
1488 copy->set(i, *entry_str);
1489 }
1490 }
1491 return *isolate->factory()->NewJSArrayWithElements(copy);
1492 }
1493
1494
1495 RUNTIME_FUNCTION(Runtime_ToFastProperties) {
1496 HandleScope scope(isolate);
1497 DCHECK(args.length() == 1);
1498 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
1499 if (object->IsJSObject() && !object->IsGlobalObject()) {
1500 JSObject::MigrateSlowToFast(Handle<JSObject>::cast(object), 0);
1501 }
1502 return *object;
1503 }
1504
1505
1506 RUNTIME_FUNCTION(Runtime_ToBool) {
1507 SealHandleScope shs(isolate);
1508 DCHECK(args.length() == 1);
1509 CONVERT_ARG_CHECKED(Object, object, 0);
1510
1511 return isolate->heap()->ToBoolean(object->BooleanValue());
1512 }
1513
1514
1515 // Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
1516 // Possible optimizations: put the type string into the oddballs.
1517 RUNTIME_FUNCTION(Runtime_Typeof) {
1518 SealHandleScope shs(isolate);
1519 DCHECK(args.length() == 1);
1520 CONVERT_ARG_CHECKED(Object, obj, 0);
1521 if (obj->IsNumber()) return isolate->heap()->number_string();
1522 HeapObject* heap_obj = HeapObject::cast(obj);
1523
1524 // typeof an undetectable object is 'undefined'
1525 if (heap_obj->map()->is_undetectable()) {
1526 return isolate->heap()->undefined_string();
1527 }
1528
1529 InstanceType instance_type = heap_obj->map()->instance_type();
1530 if (instance_type < FIRST_NONSTRING_TYPE) {
1531 return isolate->heap()->string_string();
1532 }
1533
1534 switch (instance_type) {
1535 case ODDBALL_TYPE:
1536 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
1537 return isolate->heap()->boolean_string();
1538 }
1539 if (heap_obj->IsNull()) {
1540 return isolate->heap()->object_string();
1541 }
1542 DCHECK(heap_obj->IsUndefined());
1543 return isolate->heap()->undefined_string();
1544 case SYMBOL_TYPE:
1545 return isolate->heap()->symbol_string();
1546 case JS_FUNCTION_TYPE:
1547 case JS_FUNCTION_PROXY_TYPE:
1548 return isolate->heap()->function_string();
1549 default:
1550 // For any kind of object not handled above, the spec rule for
1551 // host objects gives that it is okay to return "object"
1552 return isolate->heap()->object_string();
1553 }
1554 }
1555
1556
1557 RUNTIME_FUNCTION(Runtime_Booleanize) {
1558 SealHandleScope shs(isolate);
1559 DCHECK(args.length() == 2);
1560 CONVERT_ARG_CHECKED(Object, value_raw, 0);
1561 CONVERT_SMI_ARG_CHECKED(token_raw, 1);
1562 intptr_t value = reinterpret_cast<intptr_t>(value_raw);
1563 Token::Value token = static_cast<Token::Value>(token_raw);
1564 switch (token) {
1565 case Token::EQ:
1566 case Token::EQ_STRICT:
1567 return isolate->heap()->ToBoolean(value == 0);
1568 case Token::NE:
1569 case Token::NE_STRICT:
1570 return isolate->heap()->ToBoolean(value != 0);
1571 case Token::LT:
1572 return isolate->heap()->ToBoolean(value < 0);
1573 case Token::GT:
1574 return isolate->heap()->ToBoolean(value > 0);
1575 case Token::LTE:
1576 return isolate->heap()->ToBoolean(value <= 0);
1577 case Token::GTE:
1578 return isolate->heap()->ToBoolean(value >= 0);
1579 default:
1580 // This should only happen during natives fuzzing.
1581 return isolate->heap()->undefined_value();
1582 }
1583 }
1584
1585
1586 RUNTIME_FUNCTION(Runtime_NewStringWrapper) {
1587 HandleScope scope(isolate);
1588 DCHECK(args.length() == 1);
1589 CONVERT_ARG_HANDLE_CHECKED(String, value, 0);
1590 return *Object::ToObject(isolate, value).ToHandleChecked();
1591 }
1592
1593
1594 RUNTIME_FUNCTION(Runtime_AllocateHeapNumber) {
1595 HandleScope scope(isolate);
1596 DCHECK(args.length() == 0);
1597 return *isolate->factory()->NewHeapNumber(0);
1598 }
1599
1600
1601 static Object* Runtime_NewObjectHelper(Isolate* isolate,
1602 Handle<Object> constructor,
1603 Handle<AllocationSite> site) {
1604 // If the constructor isn't a proper function we throw a type error.
1605 if (!constructor->IsJSFunction()) {
1606 Vector<Handle<Object> > arguments = HandleVector(&constructor, 1);
1607 THROW_NEW_ERROR_RETURN_FAILURE(isolate,
1608 NewTypeError("not_constructor", arguments));
1609 }
1610
1611 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
1612
1613 // If function should not have prototype, construction is not allowed. In this
1614 // case generated code bailouts here, since function has no initial_map.
1615 if (!function->should_have_prototype() && !function->shared()->bound()) {
1616 Vector<Handle<Object> > arguments = HandleVector(&constructor, 1);
1617 THROW_NEW_ERROR_RETURN_FAILURE(isolate,
1618 NewTypeError("not_constructor", arguments));
1619 }
1620
1621 Debug* debug = isolate->debug();
1622 // Handle stepping into constructors if step into is active.
1623 if (debug->StepInActive()) {
1624 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
1625 }
1626
1627 if (function->has_initial_map()) {
1628 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
1629 // The 'Function' function ignores the receiver object when
1630 // called using 'new' and creates a new JSFunction object that
1631 // is returned. The receiver object is only used for error
1632 // reporting if an error occurs when constructing the new
1633 // JSFunction. Factory::NewJSObject() should not be used to
1634 // allocate JSFunctions since it does not properly initialize
1635 // the shared part of the function. Since the receiver is
1636 // ignored anyway, we use the global object as the receiver
1637 // instead of a new JSFunction object. This way, errors are
1638 // reported the same way whether or not 'Function' is called
1639 // using 'new'.
1640 return isolate->global_proxy();
1641 }
1642 }
1643
1644 // The function should be compiled for the optimization hints to be
1645 // available.
1646 Compiler::EnsureCompiled(function, CLEAR_EXCEPTION);
1647
1648 Handle<JSObject> result;
1649 if (site.is_null()) {
1650 result = isolate->factory()->NewJSObject(function);
1651 } else {
1652 result = isolate->factory()->NewJSObjectWithMemento(function, site);
1653 }
1654
1655 isolate->counters()->constructed_objects()->Increment();
1656 isolate->counters()->constructed_objects_runtime()->Increment();
1657
1658 return *result;
1659 }
1660
1661
1662 RUNTIME_FUNCTION(Runtime_NewObject) {
1663 HandleScope scope(isolate);
1664 DCHECK(args.length() == 1);
1665 CONVERT_ARG_HANDLE_CHECKED(Object, constructor, 0);
1666 return Runtime_NewObjectHelper(isolate, constructor,
1667 Handle<AllocationSite>::null());
1668 }
1669
1670
1671 RUNTIME_FUNCTION(Runtime_NewObjectWithAllocationSite) {
1672 HandleScope scope(isolate);
1673 DCHECK(args.length() == 2);
1674 CONVERT_ARG_HANDLE_CHECKED(Object, constructor, 1);
1675 CONVERT_ARG_HANDLE_CHECKED(Object, feedback, 0);
1676 Handle<AllocationSite> site;
1677 if (feedback->IsAllocationSite()) {
1678 // The feedback can be an AllocationSite or undefined.
1679 site = Handle<AllocationSite>::cast(feedback);
1680 }
1681 return Runtime_NewObjectHelper(isolate, constructor, site);
1682 }
1683
1684
1685 RUNTIME_FUNCTION(Runtime_FinalizeInstanceSize) {
1686 HandleScope scope(isolate);
1687 DCHECK(args.length() == 1);
1688
1689 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
1690 function->CompleteInobjectSlackTracking();
1691
1692 return isolate->heap()->undefined_value();
1693 }
1694
1695
1696 RUNTIME_FUNCTION(Runtime_CheckIsBootstrapping) {
1697 SealHandleScope shs(isolate);
1698 DCHECK(args.length() == 0);
1699 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
1700 return isolate->heap()->undefined_value();
1701 }
1702
1703
1704 RUNTIME_FUNCTION(Runtime_GetRootNaN) {
1705 SealHandleScope shs(isolate);
1706 DCHECK(args.length() == 0);
1707 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
1708 return isolate->heap()->nan_value();
1709 }
1710
1711
1712 RUNTIME_FUNCTION(Runtime_Throw) {
1713 HandleScope scope(isolate);
1714 DCHECK(args.length() == 1);
1715
1716 return isolate->Throw(args[0]);
1717 }
1718
1719
1720 RUNTIME_FUNCTION(Runtime_ReThrow) {
1721 HandleScope scope(isolate);
1722 DCHECK(args.length() == 1);
1723
1724 return isolate->ReThrow(args[0]);
1725 }
1726
1727
1728 RUNTIME_FUNCTION(Runtime_PromoteScheduledException) {
1729 SealHandleScope shs(isolate);
1730 DCHECK(args.length() == 0);
1731 return isolate->PromoteScheduledException();
1732 }
1733
1734
1735 RUNTIME_FUNCTION(Runtime_ThrowReferenceError) {
1736 HandleScope scope(isolate);
1737 DCHECK(args.length() == 1);
1738 CONVERT_ARG_HANDLE_CHECKED(Object, name, 0);
1739 THROW_NEW_ERROR_RETURN_FAILURE(
1740 isolate, NewReferenceError("not_defined", HandleVector(&name, 1)));
1741 }
1742
1743
1744 RUNTIME_FUNCTION(Runtime_PromiseRejectEvent) {
1745 DCHECK(args.length() == 3);
1746 HandleScope scope(isolate);
1747 CONVERT_ARG_HANDLE_CHECKED(JSObject, promise, 0);
1748 CONVERT_ARG_HANDLE_CHECKED(Object, value, 1);
1749 CONVERT_BOOLEAN_ARG_CHECKED(debug_event, 2);
1750 if (debug_event) isolate->debug()->OnPromiseReject(promise, value);
1751 Handle<Symbol> key = isolate->factory()->promise_has_handler_symbol();
1752 // Do not report if we actually have a handler.
1753 if (JSObject::GetDataProperty(promise, key)->IsUndefined()) {
1754 isolate->ReportPromiseReject(promise, value,
1755 v8::kPromiseRejectWithNoHandler);
1756 }
1757 return isolate->heap()->undefined_value();
1758 }
1759
1760
1761 RUNTIME_FUNCTION(Runtime_PromiseRevokeReject) {
1762 DCHECK(args.length() == 1);
1763 HandleScope scope(isolate);
1764 CONVERT_ARG_HANDLE_CHECKED(JSObject, promise, 0);
1765 Handle<Symbol> key = isolate->factory()->promise_has_handler_symbol();
1766 // At this point, no revocation has been issued before
1767 RUNTIME_ASSERT(JSObject::GetDataProperty(promise, key)->IsUndefined());
1768 isolate->ReportPromiseReject(promise, Handle<Object>(),
1769 v8::kPromiseHandlerAddedAfterReject);
1770 return isolate->heap()->undefined_value();
1771 }
1772
1773
1774 RUNTIME_FUNCTION(Runtime_PromiseHasHandlerSymbol) {
1775 DCHECK(args.length() == 0);
1776 return isolate->heap()->promise_has_handler_symbol();
1777 }
1778
1779
1780 RUNTIME_FUNCTION(Runtime_StackGuard) {
1781 SealHandleScope shs(isolate);
1782 DCHECK(args.length() == 0);
1783
1784 // First check if this is a real stack overflow.
1785 StackLimitCheck check(isolate);
1786 if (check.JsHasOverflowed()) {
1787 return isolate->StackOverflow();
1788 }
1789
1790 return isolate->stack_guard()->HandleInterrupts();
1791 }
1792
1793
1794 RUNTIME_FUNCTION(Runtime_Interrupt) {
1795 SealHandleScope shs(isolate);
1796 DCHECK(args.length() == 0);
1797 return isolate->stack_guard()->HandleInterrupts();
1798 }
1799
1800
1801 RUNTIME_FUNCTION(Runtime_GlobalProxy) {
1802 SealHandleScope shs(isolate);
1803 DCHECK(args.length() == 1);
1804 CONVERT_ARG_CHECKED(Object, global, 0);
1805 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
1806 return JSGlobalObject::cast(global)->global_proxy();
1807 }
1808
1809
1810 RUNTIME_FUNCTION(Runtime_IsAttachedGlobal) {
1811 SealHandleScope shs(isolate);
1812 DCHECK(args.length() == 1);
1813 CONVERT_ARG_CHECKED(Object, global, 0);
1814 if (!global->IsJSGlobalObject()) return isolate->heap()->false_value();
1815 return isolate->heap()->ToBoolean(
1816 !JSGlobalObject::cast(global)->IsDetached());
1817 }
1818
1819
1820 RUNTIME_FUNCTION(Runtime_AllocateInNewSpace) {
1821 HandleScope scope(isolate);
1822 DCHECK(args.length() == 1);
1823 CONVERT_SMI_ARG_CHECKED(size, 0);
1824 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
1825 RUNTIME_ASSERT(size > 0);
1826 RUNTIME_ASSERT(size <= Page::kMaxRegularHeapObjectSize);
1827 return *isolate->factory()->NewFillerObject(size, false, NEW_SPACE);
1828 }
1829
1830
1831 RUNTIME_FUNCTION(Runtime_AllocateInTargetSpace) {
1832 HandleScope scope(isolate);
1833 DCHECK(args.length() == 2);
1834 CONVERT_SMI_ARG_CHECKED(size, 0);
1835 CONVERT_SMI_ARG_CHECKED(flags, 1);
1836 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
1837 RUNTIME_ASSERT(size > 0);
1838 RUNTIME_ASSERT(size <= Page::kMaxRegularHeapObjectSize);
1839 bool double_align = AllocateDoubleAlignFlag::decode(flags);
1840 AllocationSpace space = AllocateTargetSpace::decode(flags);
1841 return *isolate->factory()->NewFillerObject(size, double_align, space);
1842 }
1843
1844
1845 // Push an object unto an array of objects if it is not already in the
1846 // array. Returns true if the element was pushed on the stack and
1847 // false otherwise.
1848 RUNTIME_FUNCTION(Runtime_PushIfAbsent) {
1849 HandleScope scope(isolate);
1850 DCHECK(args.length() == 2);
1851 CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0);
1852 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, element, 1);
1853 RUNTIME_ASSERT(array->HasFastSmiOrObjectElements());
1854 int length = Smi::cast(array->length())->value();
1855 FixedArray* elements = FixedArray::cast(array->elements());
1856 for (int i = 0; i < length; i++) {
1857 if (elements->get(i) == *element) return isolate->heap()->false_value();
1858 }
1859
1860 // Strict not needed. Used for cycle detection in Array join implementation.
1861 RETURN_FAILURE_ON_EXCEPTION(
1862 isolate, JSObject::SetFastElement(array, length, element, SLOPPY, true));
1863 return isolate->heap()->true_value();
1864 }
1865
1866
1867 /**
1868 * A simple visitor visits every element of Array's.
1869 * The backend storage can be a fixed array for fast elements case,
1870 * or a dictionary for sparse array. Since Dictionary is a subtype
1871 * of FixedArray, the class can be used by both fast and slow cases.
1872 * The second parameter of the constructor, fast_elements, specifies
1873 * whether the storage is a FixedArray or Dictionary.
1874 *
1875 * An index limit is used to deal with the situation that a result array
1876 * length overflows 32-bit non-negative integer.
1877 */
1878 class ArrayConcatVisitor {
1879 public:
1880 ArrayConcatVisitor(Isolate* isolate, Handle<FixedArray> storage,
1881 bool fast_elements)
1882 : isolate_(isolate),
1883 storage_(Handle<FixedArray>::cast(
1884 isolate->global_handles()->Create(*storage))),
1885 index_offset_(0u),
1886 fast_elements_(fast_elements),
1887 exceeds_array_limit_(false) {}
1888
1889 ~ArrayConcatVisitor() { clear_storage(); }
1890
1891 void visit(uint32_t i, Handle<Object> elm) {
1892 if (i > JSObject::kMaxElementCount - index_offset_) {
1893 exceeds_array_limit_ = true;
1894 return;
1895 }
1896 uint32_t index = index_offset_ + i;
1897
1898 if (fast_elements_) {
1899 if (index < static_cast<uint32_t>(storage_->length())) {
1900 storage_->set(index, *elm);
1901 return;
1902 }
1903 // Our initial estimate of length was foiled, possibly by
1904 // getters on the arrays increasing the length of later arrays
1905 // during iteration.
1906 // This shouldn't happen in anything but pathological cases.
1907 SetDictionaryMode();
1908 // Fall-through to dictionary mode.
1909 }
1910 DCHECK(!fast_elements_);
1911 Handle<SeededNumberDictionary> dict(
1912 SeededNumberDictionary::cast(*storage_));
1913 Handle<SeededNumberDictionary> result =
1914 SeededNumberDictionary::AtNumberPut(dict, index, elm);
1915 if (!result.is_identical_to(dict)) {
1916 // Dictionary needed to grow.
1917 clear_storage();
1918 set_storage(*result);
1919 }
1920 }
1921
1922 void increase_index_offset(uint32_t delta) {
1923 if (JSObject::kMaxElementCount - index_offset_ < delta) {
1924 index_offset_ = JSObject::kMaxElementCount;
1925 } else {
1926 index_offset_ += delta;
1927 }
1928 // If the initial length estimate was off (see special case in visit()),
1929 // but the array blowing the limit didn't contain elements beyond the
1930 // provided-for index range, go to dictionary mode now.
1931 if (fast_elements_ &&
1932 index_offset_ >
1933 static_cast<uint32_t>(FixedArrayBase::cast(*storage_)->length())) {
1934 SetDictionaryMode();
1935 }
1936 }
1937
1938 bool exceeds_array_limit() { return exceeds_array_limit_; }
1939
1940 Handle<JSArray> ToArray() {
1941 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
1942 Handle<Object> length =
1943 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
1944 Handle<Map> map = JSObject::GetElementsTransitionMap(
1945 array, fast_elements_ ? FAST_HOLEY_ELEMENTS : DICTIONARY_ELEMENTS);
1946 array->set_map(*map);
1947 array->set_length(*length);
1948 array->set_elements(*storage_);
1949 return array;
1950 }
1951
1952 private:
1953 // Convert storage to dictionary mode.
1954 void SetDictionaryMode() {
1955 DCHECK(fast_elements_);
1956 Handle<FixedArray> current_storage(*storage_);
1957 Handle<SeededNumberDictionary> slow_storage(
1958 SeededNumberDictionary::New(isolate_, current_storage->length()));
1959 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
1960 for (uint32_t i = 0; i < current_length; i++) {
1961 HandleScope loop_scope(isolate_);
1962 Handle<Object> element(current_storage->get(i), isolate_);
1963 if (!element->IsTheHole()) {
1964 Handle<SeededNumberDictionary> new_storage =
1965 SeededNumberDictionary::AtNumberPut(slow_storage, i, element);
1966 if (!new_storage.is_identical_to(slow_storage)) {
1967 slow_storage = loop_scope.CloseAndEscape(new_storage);
1968 }
1969 }
1970 }
1971 clear_storage();
1972 set_storage(*slow_storage);
1973 fast_elements_ = false;
1974 }
1975
1976 inline void clear_storage() {
1977 GlobalHandles::Destroy(Handle<Object>::cast(storage_).location());
1978 }
1979
1980 inline void set_storage(FixedArray* storage) {
1981 storage_ =
1982 Handle<FixedArray>::cast(isolate_->global_handles()->Create(storage));
1983 }
1984
1985 Isolate* isolate_;
1986 Handle<FixedArray> storage_; // Always a global handle.
1987 // Index after last seen index. Always less than or equal to
1988 // JSObject::kMaxElementCount.
1989 uint32_t index_offset_;
1990 bool fast_elements_ : 1;
1991 bool exceeds_array_limit_ : 1;
1992 };
1993
1994
1995 static uint32_t EstimateElementCount(Handle<JSArray> array) {
1996 uint32_t length = static_cast<uint32_t>(array->length()->Number());
1997 int element_count = 0;
1998 switch (array->GetElementsKind()) {
1999 case FAST_SMI_ELEMENTS:
2000 case FAST_HOLEY_SMI_ELEMENTS:
2001 case FAST_ELEMENTS:
2002 case FAST_HOLEY_ELEMENTS: {
2003 // Fast elements can't have lengths that are not representable by
2004 // a 32-bit signed integer.
2005 DCHECK(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
2006 int fast_length = static_cast<int>(length);
2007 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
2008 for (int i = 0; i < fast_length; i++) {
2009 if (!elements->get(i)->IsTheHole()) element_count++;
2010 }
2011 break;
2012 }
2013 case FAST_DOUBLE_ELEMENTS:
2014 case FAST_HOLEY_DOUBLE_ELEMENTS: {
2015 // Fast elements can't have lengths that are not representable by
2016 // a 32-bit signed integer.
2017 DCHECK(static_cast<int32_t>(FixedDoubleArray::kMaxLength) >= 0);
2018 int fast_length = static_cast<int>(length);
2019 if (array->elements()->IsFixedArray()) {
2020 DCHECK(FixedArray::cast(array->elements())->length() == 0);
2021 break;
2022 }
2023 Handle<FixedDoubleArray> elements(
2024 FixedDoubleArray::cast(array->elements()));
2025 for (int i = 0; i < fast_length; i++) {
2026 if (!elements->is_the_hole(i)) element_count++;
2027 }
2028 break;
2029 }
2030 case DICTIONARY_ELEMENTS: {
2031 Handle<SeededNumberDictionary> dictionary(
2032 SeededNumberDictionary::cast(array->elements()));
2033 int capacity = dictionary->Capacity();
2034 for (int i = 0; i < capacity; i++) {
2035 Handle<Object> key(dictionary->KeyAt(i), array->GetIsolate());
2036 if (dictionary->IsKey(*key)) {
2037 element_count++;
2038 }
2039 }
2040 break;
2041 }
2042 case SLOPPY_ARGUMENTS_ELEMENTS:
2043 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
2044 case EXTERNAL_##TYPE##_ELEMENTS: \
2045 case TYPE##_ELEMENTS:
2046
2047 TYPED_ARRAYS(TYPED_ARRAY_CASE)
2048 #undef TYPED_ARRAY_CASE
2049 // External arrays are always dense.
2050 return length;
2051 }
2052 // As an estimate, we assume that the prototype doesn't contain any
2053 // inherited elements.
2054 return element_count;
2055 }
2056
2057
2058 template <class ExternalArrayClass, class ElementType>
2059 static void IterateExternalArrayElements(Isolate* isolate,
2060 Handle<JSObject> receiver,
2061 bool elements_are_ints,
2062 bool elements_are_guaranteed_smis,
2063 ArrayConcatVisitor* visitor) {
2064 Handle<ExternalArrayClass> array(
2065 ExternalArrayClass::cast(receiver->elements()));
2066 uint32_t len = static_cast<uint32_t>(array->length());
2067
2068 DCHECK(visitor != NULL);
2069 if (elements_are_ints) {
2070 if (elements_are_guaranteed_smis) {
2071 for (uint32_t j = 0; j < len; j++) {
2072 HandleScope loop_scope(isolate);
2073 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))),
2074 isolate);
2075 visitor->visit(j, e);
2076 }
2077 } else {
2078 for (uint32_t j = 0; j < len; j++) {
2079 HandleScope loop_scope(isolate);
2080 int64_t val = static_cast<int64_t>(array->get_scalar(j));
2081 if (Smi::IsValid(static_cast<intptr_t>(val))) {
2082 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)), isolate);
2083 visitor->visit(j, e);
2084 } else {
2085 Handle<Object> e =
2086 isolate->factory()->NewNumber(static_cast<ElementType>(val));
2087 visitor->visit(j, e);
2088 }
2089 }
2090 }
2091 } else {
2092 for (uint32_t j = 0; j < len; j++) {
2093 HandleScope loop_scope(isolate);
2094 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j));
2095 visitor->visit(j, e);
2096 }
2097 }
2098 }
2099
2100
2101 // Used for sorting indices in a List<uint32_t>.
2102 static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
2103 uint32_t a = *ap;
2104 uint32_t b = *bp;
2105 return (a == b) ? 0 : (a < b) ? -1 : 1;
2106 }
2107
2108
2109 static void CollectElementIndices(Handle<JSObject> object, uint32_t range,
2110 List<uint32_t>* indices) {
2111 Isolate* isolate = object->GetIsolate();
2112 ElementsKind kind = object->GetElementsKind();
2113 switch (kind) {
2114 case FAST_SMI_ELEMENTS:
2115 case FAST_ELEMENTS:
2116 case FAST_HOLEY_SMI_ELEMENTS:
2117 case FAST_HOLEY_ELEMENTS: {
2118 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
2119 uint32_t length = static_cast<uint32_t>(elements->length());
2120 if (range < length) length = range;
2121 for (uint32_t i = 0; i < length; i++) {
2122 if (!elements->get(i)->IsTheHole()) {
2123 indices->Add(i);
2124 }
2125 }
2126 break;
2127 }
2128 case FAST_HOLEY_DOUBLE_ELEMENTS:
2129 case FAST_DOUBLE_ELEMENTS: {
2130 if (object->elements()->IsFixedArray()) {
2131 DCHECK(object->elements()->length() == 0);
2132 break;
2133 }
2134 Handle<FixedDoubleArray> elements(
2135 FixedDoubleArray::cast(object->elements()));
2136 uint32_t length = static_cast<uint32_t>(elements->length());
2137 if (range < length) length = range;
2138 for (uint32_t i = 0; i < length; i++) {
2139 if (!elements->is_the_hole(i)) {
2140 indices->Add(i);
2141 }
2142 }
2143 break;
2144 }
2145 case DICTIONARY_ELEMENTS: {
2146 Handle<SeededNumberDictionary> dict(
2147 SeededNumberDictionary::cast(object->elements()));
2148 uint32_t capacity = dict->Capacity();
2149 for (uint32_t j = 0; j < capacity; j++) {
2150 HandleScope loop_scope(isolate);
2151 Handle<Object> k(dict->KeyAt(j), isolate);
2152 if (dict->IsKey(*k)) {
2153 DCHECK(k->IsNumber());
2154 uint32_t index = static_cast<uint32_t>(k->Number());
2155 if (index < range) {
2156 indices->Add(index);
2157 }
2158 }
2159 }
2160 break;
2161 }
2162 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
2163 case TYPE##_ELEMENTS: \
2164 case EXTERNAL_##TYPE##_ELEMENTS:
2165
2166 TYPED_ARRAYS(TYPED_ARRAY_CASE)
2167 #undef TYPED_ARRAY_CASE
2168 {
2169 uint32_t length = static_cast<uint32_t>(
2170 FixedArrayBase::cast(object->elements())->length());
2171 if (range <= length) {
2172 length = range;
2173 // We will add all indices, so we might as well clear it first
2174 // and avoid duplicates.
2175 indices->Clear();
2176 }
2177 for (uint32_t i = 0; i < length; i++) {
2178 indices->Add(i);
2179 }
2180 if (length == range) return; // All indices accounted for already.
2181 break;
2182 }
2183 case SLOPPY_ARGUMENTS_ELEMENTS: {
2184 MaybeHandle<Object> length_obj =
2185 Object::GetProperty(object, isolate->factory()->length_string());
2186 double length_num = length_obj.ToHandleChecked()->Number();
2187 uint32_t length = static_cast<uint32_t>(DoubleToInt32(length_num));
2188 ElementsAccessor* accessor = object->GetElementsAccessor();
2189 for (uint32_t i = 0; i < length; i++) {
2190 if (accessor->HasElement(object, object, i)) {
2191 indices->Add(i);
2192 }
2193 }
2194 break;
2195 }
2196 }
2197
2198 PrototypeIterator iter(isolate, object);
2199 if (!iter.IsAtEnd()) {
2200 // The prototype will usually have no inherited element indices,
2201 // but we have to check.
2202 CollectElementIndices(
2203 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)), range,
2204 indices);
2205 }
2206 }
2207
2208
2209 /**
2210 * A helper function that visits elements of a JSArray in numerical
2211 * order.
2212 *
2213 * The visitor argument called for each existing element in the array
2214 * with the element index and the element's value.
2215 * Afterwards it increments the base-index of the visitor by the array
2216 * length.
2217 * Returns false if any access threw an exception, otherwise true.
2218 */
2219 static bool IterateElements(Isolate* isolate, Handle<JSArray> receiver,
2220 ArrayConcatVisitor* visitor) {
2221 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
2222 switch (receiver->GetElementsKind()) {
2223 case FAST_SMI_ELEMENTS:
2224 case FAST_ELEMENTS:
2225 case FAST_HOLEY_SMI_ELEMENTS:
2226 case FAST_HOLEY_ELEMENTS: {
2227 // Run through the elements FixedArray and use HasElement and GetElement
2228 // to check the prototype for missing elements.
2229 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
2230 int fast_length = static_cast<int>(length);
2231 DCHECK(fast_length <= elements->length());
2232 for (int j = 0; j < fast_length; j++) {
2233 HandleScope loop_scope(isolate);
2234 Handle<Object> element_value(elements->get(j), isolate);
2235 if (!element_value->IsTheHole()) {
2236 visitor->visit(j, element_value);
2237 } else {
2238 Maybe<bool> maybe = JSReceiver::HasElement(receiver, j);
2239 if (!maybe.has_value) return false;
2240 if (maybe.value) {
2241 // Call GetElement on receiver, not its prototype, or getters won't
2242 // have the correct receiver.
2243 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
2244 isolate, element_value,
2245 Object::GetElement(isolate, receiver, j), false);
2246 visitor->visit(j, element_value);
2247 }
2248 }
2249 }
2250 break;
2251 }
2252 case FAST_HOLEY_DOUBLE_ELEMENTS:
2253 case FAST_DOUBLE_ELEMENTS: {
2254 // Empty array is FixedArray but not FixedDoubleArray.
2255 if (length == 0) break;
2256 // Run through the elements FixedArray and use HasElement and GetElement
2257 // to check the prototype for missing elements.
2258 if (receiver->elements()->IsFixedArray()) {
2259 DCHECK(receiver->elements()->length() == 0);
2260 break;
2261 }
2262 Handle<FixedDoubleArray> elements(
2263 FixedDoubleArray::cast(receiver->elements()));
2264 int fast_length = static_cast<int>(length);
2265 DCHECK(fast_length <= elements->length());
2266 for (int j = 0; j < fast_length; j++) {
2267 HandleScope loop_scope(isolate);
2268 if (!elements->is_the_hole(j)) {
2269 double double_value = elements->get_scalar(j);
2270 Handle<Object> element_value =
2271 isolate->factory()->NewNumber(double_value);
2272 visitor->visit(j, element_value);
2273 } else {
2274 Maybe<bool> maybe = JSReceiver::HasElement(receiver, j);
2275 if (!maybe.has_value) return false;
2276 if (maybe.value) {
2277 // Call GetElement on receiver, not its prototype, or getters won't
2278 // have the correct receiver.
2279 Handle<Object> element_value;
2280 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
2281 isolate, element_value,
2282 Object::GetElement(isolate, receiver, j), false);
2283 visitor->visit(j, element_value);
2284 }
2285 }
2286 }
2287 break;
2288 }
2289 case DICTIONARY_ELEMENTS: {
2290 Handle<SeededNumberDictionary> dict(receiver->element_dictionary());
2291 List<uint32_t> indices(dict->Capacity() / 2);
2292 // Collect all indices in the object and the prototypes less
2293 // than length. This might introduce duplicates in the indices list.
2294 CollectElementIndices(receiver, length, &indices);
2295 indices.Sort(&compareUInt32);
2296 int j = 0;
2297 int n = indices.length();
2298 while (j < n) {
2299 HandleScope loop_scope(isolate);
2300 uint32_t index = indices[j];
2301 Handle<Object> element;
2302 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
2303 isolate, element, Object::GetElement(isolate, receiver, index),
2304 false);
2305 visitor->visit(index, element);
2306 // Skip to next different index (i.e., omit duplicates).
2307 do {
2308 j++;
2309 } while (j < n && indices[j] == index);
2310 }
2311 break;
2312 }
2313 case EXTERNAL_UINT8_CLAMPED_ELEMENTS: {
2314 Handle<ExternalUint8ClampedArray> pixels(
2315 ExternalUint8ClampedArray::cast(receiver->elements()));
2316 for (uint32_t j = 0; j < length; j++) {
2317 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)), isolate);
2318 visitor->visit(j, e);
2319 }
2320 break;
2321 }
2322 case EXTERNAL_INT8_ELEMENTS: {
2323 IterateExternalArrayElements<ExternalInt8Array, int8_t>(
2324 isolate, receiver, true, true, visitor);
2325 break;
2326 }
2327 case EXTERNAL_UINT8_ELEMENTS: {
2328 IterateExternalArrayElements<ExternalUint8Array, uint8_t>(
2329 isolate, receiver, true, true, visitor);
2330 break;
2331 }
2332 case EXTERNAL_INT16_ELEMENTS: {
2333 IterateExternalArrayElements<ExternalInt16Array, int16_t>(
2334 isolate, receiver, true, true, visitor);
2335 break;
2336 }
2337 case EXTERNAL_UINT16_ELEMENTS: {
2338 IterateExternalArrayElements<ExternalUint16Array, uint16_t>(
2339 isolate, receiver, true, true, visitor);
2340 break;
2341 }
2342 case EXTERNAL_INT32_ELEMENTS: {
2343 IterateExternalArrayElements<ExternalInt32Array, int32_t>(
2344 isolate, receiver, true, false, visitor);
2345 break;
2346 }
2347 case EXTERNAL_UINT32_ELEMENTS: {
2348 IterateExternalArrayElements<ExternalUint32Array, uint32_t>(
2349 isolate, receiver, true, false, visitor);
2350 break;
2351 }
2352 case EXTERNAL_FLOAT32_ELEMENTS: {
2353 IterateExternalArrayElements<ExternalFloat32Array, float>(
2354 isolate, receiver, false, false, visitor);
2355 break;
2356 }
2357 case EXTERNAL_FLOAT64_ELEMENTS: {
2358 IterateExternalArrayElements<ExternalFloat64Array, double>(
2359 isolate, receiver, false, false, visitor);
2360 break;
2361 }
2362 default:
2363 UNREACHABLE();
2364 break;
2365 }
2366 visitor->increase_index_offset(length);
2367 return true;
2368 }
2369
2370
2371 /**
2372 * Array::concat implementation.
2373 * See ECMAScript 262, 15.4.4.4.
2374 * TODO(581): Fix non-compliance for very large concatenations and update to
2375 * following the ECMAScript 5 specification.
2376 */
2377 RUNTIME_FUNCTION(Runtime_ArrayConcat) {
2378 HandleScope handle_scope(isolate);
2379 DCHECK(args.length() == 1);
2380
2381 CONVERT_ARG_HANDLE_CHECKED(JSArray, arguments, 0);
2382 int argument_count = static_cast<int>(arguments->length()->Number());
2383 RUNTIME_ASSERT(arguments->HasFastObjectElements());
2384 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
2385
2386 // Pass 1: estimate the length and number of elements of the result.
2387 // The actual length can be larger if any of the arguments have getters
2388 // that mutate other arguments (but will otherwise be precise).
2389 // The number of elements is precise if there are no inherited elements.
2390
2391 ElementsKind kind = FAST_SMI_ELEMENTS;
2392
2393 uint32_t estimate_result_length = 0;
2394 uint32_t estimate_nof_elements = 0;
2395 for (int i = 0; i < argument_count; i++) {
2396 HandleScope loop_scope(isolate);
2397 Handle<Object> obj(elements->get(i), isolate);
2398 uint32_t length_estimate;
2399 uint32_t element_estimate;
2400 if (obj->IsJSArray()) {
2401 Handle<JSArray> array(Handle<JSArray>::cast(obj));
2402 length_estimate = static_cast<uint32_t>(array->length()->Number());
2403 if (length_estimate != 0) {
2404 ElementsKind array_kind =
2405 GetPackedElementsKind(array->map()->elements_kind());
2406 if (IsMoreGeneralElementsKindTransition(kind, array_kind)) {
2407 kind = array_kind;
2408 }
2409 }
2410 element_estimate = EstimateElementCount(array);
2411 } else {
2412 if (obj->IsHeapObject()) {
2413 if (obj->IsNumber()) {
2414 if (IsMoreGeneralElementsKindTransition(kind, FAST_DOUBLE_ELEMENTS)) {
2415 kind = FAST_DOUBLE_ELEMENTS;
2416 }
2417 } else if (IsMoreGeneralElementsKindTransition(kind, FAST_ELEMENTS)) {
2418 kind = FAST_ELEMENTS;
2419 }
2420 }
2421 length_estimate = 1;
2422 element_estimate = 1;
2423 }
2424 // Avoid overflows by capping at kMaxElementCount.
2425 if (JSObject::kMaxElementCount - estimate_result_length < length_estimate) {
2426 estimate_result_length = JSObject::kMaxElementCount;
2427 } else {
2428 estimate_result_length += length_estimate;
2429 }
2430 if (JSObject::kMaxElementCount - estimate_nof_elements < element_estimate) {
2431 estimate_nof_elements = JSObject::kMaxElementCount;
2432 } else {
2433 estimate_nof_elements += element_estimate;
2434 }
2435 }
2436
2437 // If estimated number of elements is more than half of length, a
2438 // fixed array (fast case) is more time and space-efficient than a
2439 // dictionary.
2440 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
2441
2442 if (fast_case && kind == FAST_DOUBLE_ELEMENTS) {
2443 Handle<FixedArrayBase> storage =
2444 isolate->factory()->NewFixedDoubleArray(estimate_result_length);
2445 int j = 0;
2446 bool failure = false;
2447 if (estimate_result_length > 0) {
2448 Handle<FixedDoubleArray> double_storage =
2449 Handle<FixedDoubleArray>::cast(storage);
2450 for (int i = 0; i < argument_count; i++) {
2451 Handle<Object> obj(elements->get(i), isolate);
2452 if (obj->IsSmi()) {
2453 double_storage->set(j, Smi::cast(*obj)->value());
2454 j++;
2455 } else if (obj->IsNumber()) {
2456 double_storage->set(j, obj->Number());
2457 j++;
2458 } else {
2459 JSArray* array = JSArray::cast(*obj);
2460 uint32_t length = static_cast<uint32_t>(array->length()->Number());
2461 switch (array->map()->elements_kind()) {
2462 case FAST_HOLEY_DOUBLE_ELEMENTS:
2463 case FAST_DOUBLE_ELEMENTS: {
2464 // Empty array is FixedArray but not FixedDoubleArray.
2465 if (length == 0) break;
2466 FixedDoubleArray* elements =
2467 FixedDoubleArray::cast(array->elements());
2468 for (uint32_t i = 0; i < length; i++) {
2469 if (elements->is_the_hole(i)) {
2470 // TODO(jkummerow/verwaest): We could be a bit more clever
2471 // here: Check if there are no elements/getters on the
2472 // prototype chain, and if so, allow creation of a holey
2473 // result array.
2474 // Same thing below (holey smi case).
2475 failure = true;
2476 break;
2477 }
2478 double double_value = elements->get_scalar(i);
2479 double_storage->set(j, double_value);
2480 j++;
2481 }
2482 break;
2483 }
2484 case FAST_HOLEY_SMI_ELEMENTS:
2485 case FAST_SMI_ELEMENTS: {
2486 FixedArray* elements(FixedArray::cast(array->elements()));
2487 for (uint32_t i = 0; i < length; i++) {
2488 Object* element = elements->get(i);
2489 if (element->IsTheHole()) {
2490 failure = true;
2491 break;
2492 }
2493 int32_t int_value = Smi::cast(element)->value();
2494 double_storage->set(j, int_value);
2495 j++;
2496 }
2497 break;
2498 }
2499 case FAST_HOLEY_ELEMENTS:
2500 case FAST_ELEMENTS:
2501 DCHECK_EQ(0, length);
2502 break;
2503 default:
2504 UNREACHABLE();
2505 }
2506 }
2507 if (failure) break;
2508 }
2509 }
2510 if (!failure) {
2511 Handle<JSArray> array = isolate->factory()->NewJSArray(0);
2512 Smi* length = Smi::FromInt(j);
2513 Handle<Map> map;
2514 map = JSObject::GetElementsTransitionMap(array, kind);
2515 array->set_map(*map);
2516 array->set_length(length);
2517 array->set_elements(*storage);
2518 return *array;
2519 }
2520 // In case of failure, fall through.
2521 }
2522
2523 Handle<FixedArray> storage;
2524 if (fast_case) {
2525 // The backing storage array must have non-existing elements to preserve
2526 // holes across concat operations.
2527 storage =
2528 isolate->factory()->NewFixedArrayWithHoles(estimate_result_length);
2529 } else {
2530 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
2531 uint32_t at_least_space_for =
2532 estimate_nof_elements + (estimate_nof_elements >> 2);
2533 storage = Handle<FixedArray>::cast(
2534 SeededNumberDictionary::New(isolate, at_least_space_for));
2535 }
2536
2537 ArrayConcatVisitor visitor(isolate, storage, fast_case);
2538
2539 for (int i = 0; i < argument_count; i++) {
2540 Handle<Object> obj(elements->get(i), isolate);
2541 if (obj->IsJSArray()) {
2542 Handle<JSArray> array = Handle<JSArray>::cast(obj);
2543 if (!IterateElements(isolate, array, &visitor)) {
2544 return isolate->heap()->exception();
2545 }
2546 } else {
2547 visitor.visit(0, obj);
2548 visitor.increase_index_offset(1);
2549 }
2550 }
2551
2552 if (visitor.exceeds_array_limit()) {
2553 THROW_NEW_ERROR_RETURN_FAILURE(
2554 isolate,
2555 NewRangeError("invalid_array_length", HandleVector<Object>(NULL, 0)));
2556 }
2557 return *visitor.ToArray();
2558 }
2559
2560
2561 // Moves all own elements of an object, that are below a limit, to positions
2562 // starting at zero. All undefined values are placed after non-undefined values,
2563 // and are followed by non-existing element. Does not change the length
2564 // property.
2565 // Returns the number of non-undefined elements collected.
2566 // Returns -1 if hole removal is not supported by this method.
2567 RUNTIME_FUNCTION(Runtime_RemoveArrayHoles) {
2568 HandleScope scope(isolate);
2569 DCHECK(args.length() == 2);
2570 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
2571 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
2572 return *JSObject::PrepareElementsForSort(object, limit);
2573 }
2574
2575
2576 // Move contents of argument 0 (an array) to argument 1 (an array)
2577 RUNTIME_FUNCTION(Runtime_MoveArrayContents) {
2578 HandleScope scope(isolate);
2579 DCHECK(args.length() == 2);
2580 CONVERT_ARG_HANDLE_CHECKED(JSArray, from, 0);
2581 CONVERT_ARG_HANDLE_CHECKED(JSArray, to, 1);
2582 JSObject::ValidateElements(from);
2583 JSObject::ValidateElements(to);
2584
2585 Handle<FixedArrayBase> new_elements(from->elements());
2586 ElementsKind from_kind = from->GetElementsKind();
2587 Handle<Map> new_map = JSObject::GetElementsTransitionMap(to, from_kind);
2588 JSObject::SetMapAndElements(to, new_map, new_elements);
2589 to->set_length(from->length());
2590
2591 JSObject::ResetElements(from);
2592 from->set_length(Smi::FromInt(0));
2593
2594 JSObject::ValidateElements(to);
2595 return *to;
2596 }
2597
2598
2599 // How many elements does this object/array have?
2600 RUNTIME_FUNCTION(Runtime_EstimateNumberOfElements) {
2601 HandleScope scope(isolate);
2602 DCHECK(args.length() == 1);
2603 CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0);
2604 Handle<FixedArrayBase> elements(array->elements(), isolate);
2605 SealHandleScope shs(isolate);
2606 if (elements->IsDictionary()) {
2607 int result =
2608 Handle<SeededNumberDictionary>::cast(elements)->NumberOfElements();
2609 return Smi::FromInt(result);
2610 } else {
2611 DCHECK(array->length()->IsSmi());
2612 // For packed elements, we know the exact number of elements
2613 int length = elements->length();
2614 ElementsKind kind = array->GetElementsKind();
2615 if (IsFastPackedElementsKind(kind)) {
2616 return Smi::FromInt(length);
2617 }
2618 // For holey elements, take samples from the buffer checking for holes
2619 // to generate the estimate.
2620 const int kNumberOfHoleCheckSamples = 97;
2621 int increment = (length < kNumberOfHoleCheckSamples)
2622 ? 1
2623 : static_cast<int>(length / kNumberOfHoleCheckSamples);
2624 ElementsAccessor* accessor = array->GetElementsAccessor();
2625 int holes = 0;
2626 for (int i = 0; i < length; i += increment) {
2627 if (!accessor->HasElement(array, array, i, elements)) {
2628 ++holes;
2629 }
2630 }
2631 int estimate = static_cast<int>((kNumberOfHoleCheckSamples - holes) /
2632 kNumberOfHoleCheckSamples * length);
2633 return Smi::FromInt(estimate);
2634 }
2635 }
2636
2637
2638 // Returns an array that tells you where in the [0, length) interval an array
2639 // might have elements. Can either return an array of keys (positive integers
2640 // or undefined) or a number representing the positive length of an interval
2641 // starting at index 0.
2642 // Intervals can span over some keys that are not in the object.
2643 RUNTIME_FUNCTION(Runtime_GetArrayKeys) {
2644 HandleScope scope(isolate);
2645 DCHECK(args.length() == 2);
2646 CONVERT_ARG_HANDLE_CHECKED(JSObject, array, 0);
2647 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
2648 if (array->elements()->IsDictionary()) {
2649 Handle<FixedArray> keys = isolate->factory()->empty_fixed_array();
2650 for (PrototypeIterator iter(isolate, array,
2651 PrototypeIterator::START_AT_RECEIVER);
2652 !iter.IsAtEnd(); iter.Advance()) {
2653 if (PrototypeIterator::GetCurrent(iter)->IsJSProxy() ||
2654 JSObject::cast(*PrototypeIterator::GetCurrent(iter))
2655 ->HasIndexedInterceptor()) {
2656 // Bail out if we find a proxy or interceptor, likely not worth
2657 // collecting keys in that case.
2658 return *isolate->factory()->NewNumberFromUint(length);
2659 }
2660 Handle<JSObject> current =
2661 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
2662 Handle<FixedArray> current_keys =
2663 isolate->factory()->NewFixedArray(current->NumberOfOwnElements(NONE));
2664 current->GetOwnElementKeys(*current_keys, NONE);
2665 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2666 isolate, keys, FixedArray::UnionOfKeys(keys, current_keys));
2667 }
2668 // Erase any keys >= length.
2669 // TODO(adamk): Remove this step when the contract of %GetArrayKeys
2670 // is changed to let this happen on the JS side.
2671 for (int i = 0; i < keys->length(); i++) {
2672 if (NumberToUint32(keys->get(i)) >= length) keys->set_undefined(i);
2673 }
2674 return *isolate->factory()->NewJSArrayWithElements(keys);
2675 } else {
2676 RUNTIME_ASSERT(array->HasFastSmiOrObjectElements() ||
2677 array->HasFastDoubleElements());
2678 uint32_t actual_length = static_cast<uint32_t>(array->elements()->length());
2679 return *isolate->factory()->NewNumberFromUint(Min(actual_length, length));
2680 }
2681 }
2682
2683
2684 RUNTIME_FUNCTION(Runtime_LookupAccessor) {
2685 HandleScope scope(isolate);
2686 DCHECK(args.length() == 3);
2687 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0);
2688 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
2689 CONVERT_SMI_ARG_CHECKED(flag, 2);
2690 AccessorComponent component = flag == 0 ? ACCESSOR_GETTER : ACCESSOR_SETTER;
2691 if (!receiver->IsJSObject()) return isolate->heap()->undefined_value();
2692 Handle<Object> result;
2693 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2694 isolate, result,
2695 JSObject::GetAccessor(Handle<JSObject>::cast(receiver), name, component));
2696 return *result;
2697 }
2698
2699
2700 // Collect the raw data for a stack trace. Returns an array of 4
2701 // element segments each containing a receiver, function, code and
2702 // native code offset.
2703 RUNTIME_FUNCTION(Runtime_CollectStackTrace) {
2704 HandleScope scope(isolate);
2705 DCHECK(args.length() == 2);
2706 CONVERT_ARG_HANDLE_CHECKED(JSObject, error_object, 0);
2707 CONVERT_ARG_HANDLE_CHECKED(Object, caller, 1);
2708
2709 if (!isolate->bootstrapper()->IsActive()) {
2710 // Optionally capture a more detailed stack trace for the message.
2711 isolate->CaptureAndSetDetailedStackTrace(error_object);
2712 // Capture a simple stack trace for the stack property.
2713 isolate->CaptureAndSetSimpleStackTrace(error_object, caller);
2714 }
2715 return isolate->heap()->undefined_value();
2716 }
2717
2718
2719 RUNTIME_FUNCTION(Runtime_LoadMutableDouble) {
2720 HandleScope scope(isolate);
2721 DCHECK(args.length() == 2);
2722 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
2723 CONVERT_ARG_HANDLE_CHECKED(Smi, index, 1);
2724 RUNTIME_ASSERT((index->value() & 1) == 1);
2725 FieldIndex field_index =
2726 FieldIndex::ForLoadByFieldIndex(object->map(), index->value());
2727 if (field_index.is_inobject()) {
2728 RUNTIME_ASSERT(field_index.property_index() <
2729 object->map()->inobject_properties());
2730 } else {
2731 RUNTIME_ASSERT(field_index.outobject_array_index() <
2732 object->properties()->length());
2733 }
2734 Handle<Object> raw_value(object->RawFastPropertyAt(field_index), isolate);
2735 RUNTIME_ASSERT(raw_value->IsMutableHeapNumber());
2736 return *Object::WrapForRead(isolate, raw_value, Representation::Double());
2737 }
2738
2739
2740 RUNTIME_FUNCTION(Runtime_TryMigrateInstance) {
2741 HandleScope scope(isolate);
2742 DCHECK(args.length() == 1);
2743 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
2744 if (!object->IsJSObject()) return Smi::FromInt(0);
2745 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
2746 if (!js_object->map()->is_deprecated()) return Smi::FromInt(0);
2747 // This call must not cause lazy deopts, because it's called from deferred
2748 // code where we can't handle lazy deopts for lack of a suitable bailout
2749 // ID. So we just try migration and signal failure if necessary,
2750 // which will also trigger a deopt.
2751 if (!JSObject::TryMigrateInstance(js_object)) return Smi::FromInt(0);
2752 return *object;
2753 }
2754
2755
2756 RUNTIME_FUNCTION(Runtime_GetFromCache) {
2757 SealHandleScope shs(isolate);
2758 // This is only called from codegen, so checks might be more lax.
2759 CONVERT_ARG_CHECKED(JSFunctionResultCache, cache, 0);
2760 CONVERT_ARG_CHECKED(Object, key, 1);
2761
2762 {
2763 DisallowHeapAllocation no_alloc;
2764
2765 int finger_index = cache->finger_index();
2766 Object* o = cache->get(finger_index);
2767 if (o == key) {
2768 // The fastest case: hit the same place again.
2769 return cache->get(finger_index + 1);
2770 }
2771
2772 for (int i = finger_index - 2; i >= JSFunctionResultCache::kEntriesIndex;
2773 i -= 2) {
2774 o = cache->get(i);
2775 if (o == key) {
2776 cache->set_finger_index(i);
2777 return cache->get(i + 1);
2778 }
2779 }
2780
2781 int size = cache->size();
2782 DCHECK(size <= cache->length());
2783
2784 for (int i = size - 2; i > finger_index; i -= 2) {
2785 o = cache->get(i);
2786 if (o == key) {
2787 cache->set_finger_index(i);
2788 return cache->get(i + 1);
2789 }
2790 }
2791 }
2792
2793 // There is no value in the cache. Invoke the function and cache result.
2794 HandleScope scope(isolate);
2795
2796 Handle<JSFunctionResultCache> cache_handle(cache);
2797 Handle<Object> key_handle(key, isolate);
2798 Handle<Object> value;
2799 {
2800 Handle<JSFunction> factory(JSFunction::cast(
2801 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
2802 // TODO(antonm): consider passing a receiver when constructing a cache.
2803 Handle<JSObject> receiver(isolate->global_proxy());
2804 // This handle is nor shared, nor used later, so it's safe.
2805 Handle<Object> argv[] = {key_handle};
2806 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
2807 isolate, value,
2808 Execution::Call(isolate, factory, receiver, arraysize(argv), argv));
2809 }
2810
2811 #ifdef VERIFY_HEAP
2812 if (FLAG_verify_heap) {
2813 cache_handle->JSFunctionResultCacheVerify();
2814 }
2815 #endif
2816
2817 // Function invocation may have cleared the cache. Reread all the data.
2818 int finger_index = cache_handle->finger_index();
2819 int size = cache_handle->size();
2820
2821 // If we have spare room, put new data into it, otherwise evict post finger
2822 // entry which is likely to be the least recently used.
2823 int index = -1;
2824 if (size < cache_handle->length()) {
2825 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
2826 index = size;
2827 } else {
2828 index = finger_index + JSFunctionResultCache::kEntrySize;
2829 if (index == cache_handle->length()) {
2830 index = JSFunctionResultCache::kEntriesIndex;
2831 }
2832 }
2833
2834 DCHECK(index % 2 == 0);
2835 DCHECK(index >= JSFunctionResultCache::kEntriesIndex);
2836 DCHECK(index < cache_handle->length());
2837
2838 cache_handle->set(index, *key_handle);
2839 cache_handle->set(index + 1, *value);
2840 cache_handle->set_finger_index(index);
2841
2842 #ifdef VERIFY_HEAP
2843 if (FLAG_verify_heap) {
2844 cache_handle->JSFunctionResultCacheVerify();
2845 }
2846 #endif
2847
2848 return *value;
2849 }
2850
2851
2852 RUNTIME_FUNCTION(Runtime_MessageGetStartPosition) {
2853 SealHandleScope shs(isolate);
2854 DCHECK(args.length() == 1);
2855 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
2856 return Smi::FromInt(message->start_position());
2857 }
2858
2859
2860 RUNTIME_FUNCTION(Runtime_MessageGetScript) {
2861 SealHandleScope shs(isolate);
2862 DCHECK(args.length() == 1);
2863 CONVERT_ARG_CHECKED(JSMessageObject, message, 0);
2864 return message->script();
2865 }
2866
2867
2868 RUNTIME_FUNCTION(Runtime_IS_VAR) {
2869 UNREACHABLE(); // implemented as macro in the parser
2870 return NULL;
2871 }
2872
2873
2874 RUNTIME_FUNCTION(Runtime_IsJSGlobalProxy) {
2875 SealHandleScope shs(isolate);
2876 DCHECK(args.length() == 1);
2877 CONVERT_ARG_CHECKED(Object, obj, 0);
2878 return isolate->heap()->ToBoolean(obj->IsJSGlobalProxy());
2879 }
2880
2881
2882 static Object* ArrayConstructorCommon(Isolate* isolate,
2883 Handle<JSFunction> constructor,
2884 Handle<AllocationSite> site,
2885 Arguments* caller_args) {
2886 Factory* factory = isolate->factory();
2887
2888 bool holey = false;
2889 bool can_use_type_feedback = true;
2890 if (caller_args->length() == 1) {
2891 Handle<Object> argument_one = caller_args->at<Object>(0);
2892 if (argument_one->IsSmi()) {
2893 int value = Handle<Smi>::cast(argument_one)->value();
2894 if (value < 0 || value >= JSObject::kInitialMaxFastElementArray) {
2895 // the array is a dictionary in this case.
2896 can_use_type_feedback = false;
2897 } else if (value != 0) {
2898 holey = true;
2899 }
2900 } else {
2901 // Non-smi length argument produces a dictionary
2902 can_use_type_feedback = false;
2903 }
2904 }
2905
2906 Handle<JSArray> array;
2907 if (!site.is_null() && can_use_type_feedback) {
2908 ElementsKind to_kind = site->GetElementsKind();
2909 if (holey && !IsFastHoleyElementsKind(to_kind)) {
2910 to_kind = GetHoleyElementsKind(to_kind);
2911 // Update the allocation site info to reflect the advice alteration.
2912 site->SetElementsKind(to_kind);
2913 }
2914
2915 // We should allocate with an initial map that reflects the allocation site
2916 // advice. Therefore we use AllocateJSObjectFromMap instead of passing
2917 // the constructor.
2918 Handle<Map> initial_map(constructor->initial_map(), isolate);
2919 if (to_kind != initial_map->elements_kind()) {
2920 initial_map = Map::AsElementsKind(initial_map, to_kind);
2921 }
2922
2923 // If we don't care to track arrays of to_kind ElementsKind, then
2924 // don't emit a memento for them.
2925 Handle<AllocationSite> allocation_site;
2926 if (AllocationSite::GetMode(to_kind) == TRACK_ALLOCATION_SITE) {
2927 allocation_site = site;
2928 }
2929
2930 array = Handle<JSArray>::cast(factory->NewJSObjectFromMap(
2931 initial_map, NOT_TENURED, true, allocation_site));
2932 } else {
2933 array = Handle<JSArray>::cast(factory->NewJSObject(constructor));
2934
2935 // We might need to transition to holey
2936 ElementsKind kind = constructor->initial_map()->elements_kind();
2937 if (holey && !IsFastHoleyElementsKind(kind)) {
2938 kind = GetHoleyElementsKind(kind);
2939 JSObject::TransitionElementsKind(array, kind);
2940 }
2941 }
2942
2943 factory->NewJSArrayStorage(array, 0, 0, DONT_INITIALIZE_ARRAY_ELEMENTS);
2944
2945 ElementsKind old_kind = array->GetElementsKind();
2946 RETURN_FAILURE_ON_EXCEPTION(
2947 isolate, ArrayConstructInitializeElements(array, caller_args));
2948 if (!site.is_null() &&
2949 (old_kind != array->GetElementsKind() || !can_use_type_feedback)) {
2950 // The arguments passed in caused a transition. This kind of complexity
2951 // can't be dealt with in the inlined hydrogen array constructor case.
2952 // We must mark the allocationsite as un-inlinable.
2953 site->SetDoNotInlineCall();
2954 }
2955 return *array;
2956 }
2957
2958
2959 RUNTIME_FUNCTION(Runtime_ArrayConstructor) {
2960 HandleScope scope(isolate);
2961 // If we get 2 arguments then they are the stub parameters (constructor, type
2962 // info). If we get 4, then the first one is a pointer to the arguments
2963 // passed by the caller, and the last one is the length of the arguments
2964 // passed to the caller (redundant, but useful to check on the deoptimizer
2965 // with an assert).
2966 Arguments empty_args(0, NULL);
2967 bool no_caller_args = args.length() == 2;
2968 DCHECK(no_caller_args || args.length() == 4);
2969 int parameters_start = no_caller_args ? 0 : 1;
2970 Arguments* caller_args =
2971 no_caller_args ? &empty_args : reinterpret_cast<Arguments*>(args[0]);
2972 CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, parameters_start);
2973 CONVERT_ARG_HANDLE_CHECKED(Object, type_info, parameters_start + 1);
2974 #ifdef DEBUG
2975 if (!no_caller_args) {
2976 CONVERT_SMI_ARG_CHECKED(arg_count, parameters_start + 2);
2977 DCHECK(arg_count == caller_args->length());
2978 }
2979 #endif
2980
2981 Handle<AllocationSite> site;
2982 if (!type_info.is_null() &&
2983 *type_info != isolate->heap()->undefined_value()) {
2984 site = Handle<AllocationSite>::cast(type_info);
2985 DCHECK(!site->SitePointsToLiteral());
2986 }
2987
2988 return ArrayConstructorCommon(isolate, constructor, site, caller_args);
2989 }
2990
2991
2992 RUNTIME_FUNCTION(Runtime_InternalArrayConstructor) {
2993 HandleScope scope(isolate);
2994 Arguments empty_args(0, NULL);
2995 bool no_caller_args = args.length() == 1;
2996 DCHECK(no_caller_args || args.length() == 3);
2997 int parameters_start = no_caller_args ? 0 : 1;
2998 Arguments* caller_args =
2999 no_caller_args ? &empty_args : reinterpret_cast<Arguments*>(args[0]);
3000 CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, parameters_start);
3001 #ifdef DEBUG
3002 if (!no_caller_args) {
3003 CONVERT_SMI_ARG_CHECKED(arg_count, parameters_start + 1);
3004 DCHECK(arg_count == caller_args->length());
3005 }
3006 #endif
3007 return ArrayConstructorCommon(isolate, constructor,
3008 Handle<AllocationSite>::null(), caller_args);
3009 }
3010
3011
3012 RUNTIME_FUNCTION(Runtime_NormalizeElements) {
3013 HandleScope scope(isolate);
3014 DCHECK(args.length() == 1);
3015 CONVERT_ARG_HANDLE_CHECKED(JSObject, array, 0);
3016 RUNTIME_ASSERT(!array->HasExternalArrayElements() &&
3017 !array->HasFixedTypedArrayElements());
3018 JSObject::NormalizeElements(array);
3019 return *array;
3020 }
3021
3022
3023 RUNTIME_FUNCTION(Runtime_MaxSmi) {
3024 SealHandleScope shs(isolate);
3025 DCHECK(args.length() == 0);
3026 return Smi::FromInt(Smi::kMaxValue);
3027 }
3028
3029
3030 // TODO(dcarney): remove this function when TurboFan supports it.
3031 // Takes the object to be iterated over and the result of GetPropertyNamesFast
3032 // Returns pair (cache_array, cache_type).
3033 RUNTIME_FUNCTION_RETURN_PAIR(Runtime_ForInInit) {
3034 SealHandleScope scope(isolate);
3035 DCHECK(args.length() == 2);
3036 // This simulates CONVERT_ARG_HANDLE_CHECKED for calls returning pairs.
3037 // Not worth creating a macro atm as this function should be removed.
3038 if (!args[0]->IsJSReceiver() || !args[1]->IsObject()) {
3039 Object* error = isolate->ThrowIllegalOperation();
3040 return MakePair(error, isolate->heap()->undefined_value());
3041 }
3042 Handle<JSReceiver> object = args.at<JSReceiver>(0);
3043 Handle<Object> cache_type = args.at<Object>(1);
3044 if (cache_type->IsMap()) {
3045 // Enum cache case.
3046 if (Map::EnumLengthBits::decode(Map::cast(*cache_type)->bit_field3()) ==
3047 0) {
3048 // 0 length enum.
3049 // Can't handle this case in the graph builder,
3050 // so transform it into the empty fixed array case.
3051 return MakePair(isolate->heap()->empty_fixed_array(), Smi::FromInt(1));
3052 }
3053 return MakePair(object->map()->instance_descriptors()->GetEnumCache(),
3054 *cache_type);
3055 } else {
3056 // FixedArray case.
3057 Smi* new_cache_type = Smi::FromInt(object->IsJSProxy() ? 0 : 1);
3058 return MakePair(*Handle<FixedArray>::cast(cache_type), new_cache_type);
3059 }
3060 }
3061
3062
3063 // TODO(dcarney): remove this function when TurboFan supports it.
3064 RUNTIME_FUNCTION(Runtime_ForInCacheArrayLength) {
3065 SealHandleScope shs(isolate);
3066 DCHECK(args.length() == 2);
3067 CONVERT_ARG_HANDLE_CHECKED(Object, cache_type, 0);
3068 CONVERT_ARG_HANDLE_CHECKED(FixedArray, array, 1);
3069 int length = 0;
3070 if (cache_type->IsMap()) {
3071 length = Map::cast(*cache_type)->EnumLength();
3072 } else {
3073 DCHECK(cache_type->IsSmi());
3074 length = array->length();
3075 }
3076 return Smi::FromInt(length);
3077 }
3078
3079
3080 // TODO(dcarney): remove this function when TurboFan supports it.
3081 // Takes (the object to be iterated over,
3082 // cache_array from ForInInit,
3083 // cache_type from ForInInit,
3084 // the current index)
3085 // Returns pair (array[index], needs_filtering).
3086 RUNTIME_FUNCTION_RETURN_PAIR(Runtime_ForInNext) {
3087 SealHandleScope scope(isolate);
3088 DCHECK(args.length() == 4);
3089 int32_t index;
3090 // This simulates CONVERT_ARG_HANDLE_CHECKED for calls returning pairs.
3091 // Not worth creating a macro atm as this function should be removed.
3092 if (!args[0]->IsJSReceiver() || !args[1]->IsFixedArray() ||
3093 !args[2]->IsObject() || !args[3]->ToInt32(&index)) {
3094 Object* error = isolate->ThrowIllegalOperation();
3095 return MakePair(error, isolate->heap()->undefined_value());
3096 }
3097 Handle<JSReceiver> object = args.at<JSReceiver>(0);
3098 Handle<FixedArray> array = args.at<FixedArray>(1);
3099 Handle<Object> cache_type = args.at<Object>(2);
3100 // Figure out first if a slow check is needed for this object.
3101 bool slow_check_needed = false;
3102 if (cache_type->IsMap()) {
3103 if (object->map() != Map::cast(*cache_type)) {
3104 // Object transitioned. Need slow check.
3105 slow_check_needed = true;
3106 }
3107 } else {
3108 // No slow check needed for proxies.
3109 slow_check_needed = Smi::cast(*cache_type)->value() == 1;
3110 }
3111 return MakePair(array->get(index),
3112 isolate->heap()->ToBoolean(slow_check_needed));
3113 }
3114
3115
3116 // ----------------------------------------------------------------------------
3117 // Reference implementation for inlined runtime functions. Only used when the
3118 // compiler does not support a certain intrinsic. Don't optimize these, but
3119 // implement the intrinsic in the respective compiler instead.
3120
3121 // TODO(mstarzinger): These are place-holder stubs for TurboFan and will
3122 // eventually all have a C++ implementation and this macro will be gone.
3123 #define U(name) \
3124 RUNTIME_FUNCTION(RuntimeReference_##name) { \
3125 UNIMPLEMENTED(); \
3126 return NULL; \
3127 }
3128
3129 U(IsStringWrapperSafeForDefaultValueOf)
3130 U(DebugBreakInOptimizedCode)
3131
3132 #undef U
3133
3134
3135 RUNTIME_FUNCTION(RuntimeReference_IsArray) {
3136 SealHandleScope shs(isolate);
3137 DCHECK(args.length() == 1);
3138 CONVERT_ARG_CHECKED(Object, obj, 0);
3139 return isolate->heap()->ToBoolean(obj->IsJSArray());
3140 }
3141
3142
3143
3144 RUNTIME_FUNCTION(RuntimeReference_ValueOf) {
3145 SealHandleScope shs(isolate);
3146 DCHECK(args.length() == 1);
3147 CONVERT_ARG_CHECKED(Object, obj, 0);
3148 if (!obj->IsJSValue()) return obj;
3149 return JSValue::cast(obj)->value();
3150 }
3151
3152
3153 RUNTIME_FUNCTION(RuntimeReference_SetValueOf) {
3154 SealHandleScope shs(isolate);
3155 DCHECK(args.length() == 2);
3156 CONVERT_ARG_CHECKED(Object, obj, 0);
3157 CONVERT_ARG_CHECKED(Object, value, 1);
3158 if (!obj->IsJSValue()) return value;
3159 JSValue::cast(obj)->set_value(value);
3160 return value;
3161 }
3162
3163
3164 RUNTIME_FUNCTION(RuntimeReference_ObjectEquals) {
3165 SealHandleScope shs(isolate);
3166 DCHECK(args.length() == 2);
3167 CONVERT_ARG_CHECKED(Object, obj1, 0);
3168 CONVERT_ARG_CHECKED(Object, obj2, 1);
3169 return isolate->heap()->ToBoolean(obj1 == obj2);
3170 }
3171
3172
3173 RUNTIME_FUNCTION(RuntimeReference_IsObject) {
3174 SealHandleScope shs(isolate);
3175 DCHECK(args.length() == 1);
3176 CONVERT_ARG_CHECKED(Object, obj, 0);
3177 if (!obj->IsHeapObject()) return isolate->heap()->false_value();
3178 if (obj->IsNull()) return isolate->heap()->true_value();
3179 if (obj->IsUndetectableObject()) return isolate->heap()->false_value();
3180 Map* map = HeapObject::cast(obj)->map();
3181 bool is_non_callable_spec_object =
3182 map->instance_type() >= FIRST_NONCALLABLE_SPEC_OBJECT_TYPE &&
3183 map->instance_type() <= LAST_NONCALLABLE_SPEC_OBJECT_TYPE;
3184 return isolate->heap()->ToBoolean(is_non_callable_spec_object);
3185 }
3186
3187
3188 RUNTIME_FUNCTION(RuntimeReference_IsUndetectableObject) {
3189 SealHandleScope shs(isolate);
3190 DCHECK(args.length() == 1);
3191 CONVERT_ARG_CHECKED(Object, obj, 0);
3192 return isolate->heap()->ToBoolean(obj->IsUndetectableObject());
3193 }
3194
3195
3196 RUNTIME_FUNCTION(RuntimeReference_IsSpecObject) {
3197 SealHandleScope shs(isolate);
3198 DCHECK(args.length() == 1);
3199 CONVERT_ARG_CHECKED(Object, obj, 0);
3200 return isolate->heap()->ToBoolean(obj->IsSpecObject());
3201 }
3202
3203
3204 RUNTIME_FUNCTION(RuntimeReference_HasCachedArrayIndex) {
3205 SealHandleScope shs(isolate);
3206 DCHECK(args.length() == 1);
3207 return isolate->heap()->false_value();
3208 }
3209
3210
3211 RUNTIME_FUNCTION(RuntimeReference_GetCachedArrayIndex) {
3212 SealHandleScope shs(isolate);
3213 DCHECK(args.length() == 1);
3214 return isolate->heap()->undefined_value();
3215 }
3216
3217
3218 RUNTIME_FUNCTION(RuntimeReference_FastOneByteArrayJoin) {
3219 SealHandleScope shs(isolate);
3220 DCHECK(args.length() == 2);
3221 return isolate->heap()->undefined_value();
3222 }
3223
3224
3225 RUNTIME_FUNCTION(RuntimeReference_ClassOf) {
3226 SealHandleScope shs(isolate);
3227 DCHECK(args.length() == 1);
3228 CONVERT_ARG_CHECKED(Object, obj, 0);
3229 if (!obj->IsJSReceiver()) return isolate->heap()->null_value();
3230 return JSReceiver::cast(obj)->class_name();
3231 }
3232
3233
3234 RUNTIME_FUNCTION(RuntimeReference_GetFromCache) {
3235 HandleScope scope(isolate);
3236 DCHECK(args.length() == 2);
3237 CONVERT_SMI_ARG_CHECKED(id, 0);
3238 args[0] = isolate->native_context()->jsfunction_result_caches()->get(id);
3239 return __RT_impl_Runtime_GetFromCache(args, isolate);
3240 }
3241
3242
3243 // ----------------------------------------------------------------------------
3244 // Implementation of Runtime
3245
3246 #define F(name, number_of_args, result_size) \ 41 #define F(name, number_of_args, result_size) \
3247 { \ 42 { \
3248 Runtime::k##name, Runtime::RUNTIME, #name, FUNCTION_ADDR(Runtime_##name), \ 43 Runtime::k##name, Runtime::RUNTIME, #name, FUNCTION_ADDR(Runtime_##name), \
3249 number_of_args, result_size \ 44 number_of_args, result_size \
3250 } \ 45 } \
3251 , 46 ,
3252 47
3253 48
3254 #define I(name, number_of_args, result_size) \ 49 #define I(name, number_of_args, result_size) \
3255 { \ 50 { \
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
3319 return &(kIntrinsicFunctions[static_cast<int>(id)]); 114 return &(kIntrinsicFunctions[static_cast<int>(id)]);
3320 } 115 }
3321 116
3322 117
3323 std::ostream& operator<<(std::ostream& os, Runtime::FunctionId id) { 118 std::ostream& operator<<(std::ostream& os, Runtime::FunctionId id) {
3324 return os << Runtime::FunctionForId(id)->name; 119 return os << Runtime::FunctionForId(id)->name;
3325 } 120 }
3326 121
3327 } // namespace internal 122 } // namespace internal
3328 } // namespace v8 123 } // namespace v8
OLDNEW
« no previous file with comments | « src/macros.py ('k') | src/runtime/runtime-api.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698