1 // Copyright 2014 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/runtime/runtime-utils.h"
6
7 #include "src/arguments.h"
8 #include "src/bootstrapper.h"
9 #include "src/debug/debug.h"
10 #include "src/isolate-inl.h"
11 #include "src/messages.h"
12 #include "src/property-descriptor.h"
13 #include "src/runtime/runtime.h"
14
15 namespace v8 {
16 namespace internal {
17
GetObjectProperty(Isolate * isolate,Handle<Object> object,Handle<Object> key,bool * is_found_out)18 MaybeHandle<Object> Runtime::GetObjectProperty(Isolate* isolate,
19 Handle<Object> object,
20 Handle<Object> key,
21 bool* is_found_out) {
22 if (object->IsUndefined(isolate) || object->IsNull(isolate)) {
23 THROW_NEW_ERROR(
24 isolate,
25 NewTypeError(MessageTemplate::kNonObjectPropertyLoad, key, object),
26 Object);
27 }
28
29 bool success = false;
30 LookupIterator it =
31 LookupIterator::PropertyOrElement(isolate, object, key, &success);
32 if (!success) return MaybeHandle<Object>();
33
34 MaybeHandle<Object> result = Object::GetProperty(&it);
35 if (is_found_out) *is_found_out = it.IsFound();
36 return result;
37 }
38
KeyedGetObjectProperty(Isolate * isolate,Handle<Object> receiver_obj,Handle<Object> key_obj)39 static MaybeHandle<Object> KeyedGetObjectProperty(Isolate* isolate,
40 Handle<Object> receiver_obj,
41 Handle<Object> key_obj) {
42 // Fast cases for getting named properties of the receiver JSObject
43 // itself.
44 //
45 // The global proxy objects has to be excluded since LookupOwn on
46 // the global proxy object can return a valid result even though the
47 // global proxy object never has properties. This is the case
48 // because the global proxy object forwards everything to its hidden
49 // prototype including own lookups.
50 //
51 // Additionally, we need to make sure that we do not cache results
52 // for objects that require access checks.
53 if (receiver_obj->IsJSObject()) {
54 if (!receiver_obj->IsJSGlobalProxy() &&
55 !receiver_obj->IsAccessCheckNeeded() && key_obj->IsName()) {
56 DisallowHeapAllocation no_allocation;
57 Handle<JSObject> receiver = Handle<JSObject>::cast(receiver_obj);
58 Handle<Name> key = Handle<Name>::cast(key_obj);
59 if (receiver->IsJSGlobalObject()) {
60 // Attempt dictionary lookup.
61 GlobalDictionary* dictionary = receiver->global_dictionary();
62 int entry = dictionary->FindEntry(key);
63 if (entry != GlobalDictionary::kNotFound) {
64 DCHECK(dictionary->ValueAt(entry)->IsPropertyCell());
65 PropertyCell* cell = PropertyCell::cast(dictionary->ValueAt(entry));
66 if (cell->property_details().type() == DATA) {
67 Object* value = cell->value();
68 if (!value->IsTheHole(isolate)) {
69 return Handle<Object>(value, isolate);
70 }
71 // If value is the hole (meaning, absent) do the general lookup.
72 }
73 }
74 } else if (!receiver->HasFastProperties()) {
75 // Attempt dictionary lookup.
76 NameDictionary* dictionary = receiver->property_dictionary();
77 int entry = dictionary->FindEntry(key);
78 if ((entry != NameDictionary::kNotFound) &&
79 (dictionary->DetailsAt(entry).type() == DATA)) {
80 Object* value = dictionary->ValueAt(entry);
81 return Handle<Object>(value, isolate);
82 }
83 }
84 } else if (key_obj->IsSmi()) {
85 // JSObject without a name key. If the key is a Smi, check for a
86 // definite out-of-bounds access to elements, which is a strong indicator
87 // that subsequent accesses will also call the runtime. Proactively
88 // transition elements to FAST_*_ELEMENTS to avoid excessive boxing of
89 // doubles for those future calls in the case that the elements would
90 // become FAST_DOUBLE_ELEMENTS.
91 Handle<JSObject> js_object = Handle<JSObject>::cast(receiver_obj);
92 ElementsKind elements_kind = js_object->GetElementsKind();
93 if (IsFastDoubleElementsKind(elements_kind)) {
94 if (Smi::cast(*key_obj)->value() >= js_object->elements()->length()) {
95 elements_kind = IsFastHoleyElementsKind(elements_kind)
96 ? FAST_HOLEY_ELEMENTS
97 : FAST_ELEMENTS;
98 JSObject::TransitionElementsKind(js_object, elements_kind);
99 }
100 } else {
101 DCHECK(IsFastSmiOrObjectElementsKind(elements_kind) ||
102 !IsFastElementsKind(elements_kind));
103 }
104 }
105 } else if (receiver_obj->IsString() && key_obj->IsSmi()) {
106 // Fast case for string indexing using [] with a smi index.
107 Handle<String> str = Handle<String>::cast(receiver_obj);
108 int index = Handle<Smi>::cast(key_obj)->value();
109 if (index >= 0 && index < str->length()) {
110 Factory* factory = isolate->factory();
111 return factory->LookupSingleCharacterStringFromCode(
112 String::Flatten(str)->Get(index));
113 }
114 }
115
116 // Fall back to GetObjectProperty.
117 return Runtime::GetObjectProperty(isolate, receiver_obj, key_obj);
118 }
119
120
DeleteObjectProperty(Isolate * isolate,Handle<JSReceiver> receiver,Handle<Object> key,LanguageMode language_mode)121 Maybe<bool> Runtime::DeleteObjectProperty(Isolate* isolate,
122 Handle<JSReceiver> receiver,
123 Handle<Object> key,
124 LanguageMode language_mode) {
125 bool success = false;
126 LookupIterator it = LookupIterator::PropertyOrElement(
127 isolate, receiver, key, &success, LookupIterator::OWN);
128 if (!success) return Nothing<bool>();
129
130 return JSReceiver::DeleteProperty(&it, language_mode);
131 }
132
133 // ES6 19.1.3.2
RUNTIME_FUNCTION(Runtime_ObjectHasOwnProperty)134 RUNTIME_FUNCTION(Runtime_ObjectHasOwnProperty) {
135 HandleScope scope(isolate);
136 Handle<Object> property = args.at<Object>(1);
137
138 Handle<Name> key;
139 uint32_t index;
140 bool key_is_array_index = property->ToArrayIndex(&index);
141
142 if (!key_is_array_index) {
143 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, key,
144 Object::ToName(isolate, property));
145 key_is_array_index = key->AsArrayIndex(&index);
146 }
147
148 Handle<Object> object = args.at<Object>(0);
149
150 if (object->IsJSObject()) {
151 Handle<JSObject> js_obj = Handle<JSObject>::cast(object);
152 // Fast case: either the key is a real named property or it is not
153 // an array index and there are no interceptors or hidden
154 // prototypes.
155 // TODO(jkummerow): Make JSReceiver::HasOwnProperty fast enough to
156 // handle all cases directly (without this custom fast path).
157 {
158 LookupIterator::Configuration c = LookupIterator::OWN_SKIP_INTERCEPTOR;
159 LookupIterator it =
160 key_is_array_index ? LookupIterator(isolate, js_obj, index, js_obj, c)
161 : LookupIterator(js_obj, key, js_obj, c);
162 Maybe<bool> maybe = JSReceiver::HasProperty(&it);
163 if (maybe.IsNothing()) return isolate->heap()->exception();
164 DCHECK(!isolate->has_pending_exception());
165 if (maybe.FromJust()) return isolate->heap()->true_value();
166 }
167
168 Map* map = js_obj->map();
169 if (!map->has_hidden_prototype() &&
170 (key_is_array_index ? !map->has_indexed_interceptor()
171 : !map->has_named_interceptor())) {
172 return isolate->heap()->false_value();
173 }
174
175 // Slow case.
176 LookupIterator::Configuration c = LookupIterator::OWN;
177 LookupIterator it = key_is_array_index
178 ? LookupIterator(isolate, js_obj, index, js_obj, c)
179 : LookupIterator(js_obj, key, js_obj, c);
180
181 Maybe<bool> maybe = JSReceiver::HasProperty(&it);
182 if (maybe.IsNothing()) return isolate->heap()->exception();
183 DCHECK(!isolate->has_pending_exception());
184 return isolate->heap()->ToBoolean(maybe.FromJust());
185
186 } else if (object->IsJSProxy()) {
187 if (key.is_null()) {
188 DCHECK(key_is_array_index);
189 key = isolate->factory()->Uint32ToString(index);
190 }
191
192 Maybe<bool> result =
193 JSReceiver::HasOwnProperty(Handle<JSProxy>::cast(object), key);
194 if (!result.IsJust()) return isolate->heap()->exception();
195 return isolate->heap()->ToBoolean(result.FromJust());
196
197 } else if (object->IsString()) {
198 return isolate->heap()->ToBoolean(
199 key_is_array_index
200 ? index < static_cast<uint32_t>(String::cast(*object)->length())
201 : key->Equals(isolate->heap()->length_string()));
202 } else if (object->IsNull(isolate) || object->IsUndefined(isolate)) {
203 THROW_NEW_ERROR_RETURN_FAILURE(
204 isolate, NewTypeError(MessageTemplate::kUndefinedOrNullToObject));
205 }
206
207 return isolate->heap()->false_value();
208 }
209
SetObjectProperty(Isolate * isolate,Handle<Object> object,Handle<Object> key,Handle<Object> value,LanguageMode language_mode)210 MaybeHandle<Object> Runtime::SetObjectProperty(Isolate* isolate,
211 Handle<Object> object,
212 Handle<Object> key,
213 Handle<Object> value,
214 LanguageMode language_mode) {
215 if (object->IsUndefined(isolate) || object->IsNull(isolate)) {
216 THROW_NEW_ERROR(
217 isolate,
218 NewTypeError(MessageTemplate::kNonObjectPropertyStore, key, object),
219 Object);
220 }
221
222 // Check if the given key is an array index.
223 bool success = false;
224 LookupIterator it =
225 LookupIterator::PropertyOrElement(isolate, object, key, &success);
226 if (!success) return MaybeHandle<Object>();
227
228 MAYBE_RETURN_NULL(Object::SetProperty(&it, value, language_mode,
229 Object::MAY_BE_STORE_FROM_KEYED));
230 return value;
231 }
232
233
RUNTIME_FUNCTION(Runtime_GetPrototype)234 RUNTIME_FUNCTION(Runtime_GetPrototype) {
235 HandleScope scope(isolate);
236 DCHECK(args.length() == 1);
237 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, obj, 0);
238 RETURN_RESULT_OR_FAILURE(isolate, JSReceiver::GetPrototype(isolate, obj));
239 }
240
241
RUNTIME_FUNCTION(Runtime_InternalSetPrototype)242 RUNTIME_FUNCTION(Runtime_InternalSetPrototype) {
243 HandleScope scope(isolate);
244 DCHECK(args.length() == 2);
245 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, obj, 0);
246 CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1);
247 MAYBE_RETURN(
248 JSReceiver::SetPrototype(obj, prototype, false, Object::THROW_ON_ERROR),
249 isolate->heap()->exception());
250 return *obj;
251 }
252
253
RUNTIME_FUNCTION(Runtime_SetPrototype)254 RUNTIME_FUNCTION(Runtime_SetPrototype) {
255 HandleScope scope(isolate);
256 DCHECK(args.length() == 2);
257 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, obj, 0);
258 CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1);
259 MAYBE_RETURN(
260 JSReceiver::SetPrototype(obj, prototype, true, Object::THROW_ON_ERROR),
261 isolate->heap()->exception());
262 return *obj;
263 }
264
RUNTIME_FUNCTION(Runtime_OptimizeObjectForAddingMultipleProperties)265 RUNTIME_FUNCTION(Runtime_OptimizeObjectForAddingMultipleProperties) {
266 HandleScope scope(isolate);
267 DCHECK(args.length() == 2);
268 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
269 CONVERT_SMI_ARG_CHECKED(properties, 1);
270 // Conservative upper limit to prevent fuzz tests from going OOM.
271 RUNTIME_ASSERT(properties <= 100000);
272 if (object->HasFastProperties() && !object->IsJSGlobalProxy()) {
273 JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties,
274 "OptimizeForAdding");
275 }
276 return *object;
277 }
278
279
280 namespace {
281
StoreGlobalViaContext(Isolate * isolate,int slot,Handle<Object> value,LanguageMode language_mode)282 Object* StoreGlobalViaContext(Isolate* isolate, int slot, Handle<Object> value,
283 LanguageMode language_mode) {
284 // Go up context chain to the script context.
285 Handle<Context> script_context(isolate->context()->script_context(), isolate);
286 DCHECK(script_context->IsScriptContext());
287 DCHECK(script_context->get(slot)->IsPropertyCell());
288
289 // Lookup the named property on the global object.
290 Handle<ScopeInfo> scope_info(script_context->scope_info(), isolate);
291 Handle<Name> name(scope_info->ContextSlotName(slot), isolate);
292 Handle<JSGlobalObject> global_object(script_context->global_object(),
293 isolate);
294 LookupIterator it(global_object, name, global_object, LookupIterator::OWN);
295
296 // Switch to fast mode only if there is a data property and it's not on
297 // a hidden prototype.
298 if (it.state() == LookupIterator::DATA &&
299 it.GetHolder<Object>().is_identical_to(global_object)) {
300 // Now update cell in the script context.
301 Handle<PropertyCell> cell = it.GetPropertyCell();
302 script_context->set(slot, *cell);
303 } else {
304 // This is not a fast case, so keep this access in a slow mode.
305 // Store empty_property_cell here to release the outdated property cell.
306 script_context->set(slot, isolate->heap()->empty_property_cell());
307 }
308
309 MAYBE_RETURN(Object::SetProperty(&it, value, language_mode,
310 Object::CERTAINLY_NOT_STORE_FROM_KEYED),
311 isolate->heap()->exception());
312 return *value;
313 }
314
315 } // namespace
316
317
RUNTIME_FUNCTION(Runtime_StoreGlobalViaContext_Sloppy)318 RUNTIME_FUNCTION(Runtime_StoreGlobalViaContext_Sloppy) {
319 HandleScope scope(isolate);
320 DCHECK_EQ(2, args.length());
321 CONVERT_SMI_ARG_CHECKED(slot, 0);
322 CONVERT_ARG_HANDLE_CHECKED(Object, value, 1);
323
324 return StoreGlobalViaContext(isolate, slot, value, SLOPPY);
325 }
326
327
RUNTIME_FUNCTION(Runtime_StoreGlobalViaContext_Strict)328 RUNTIME_FUNCTION(Runtime_StoreGlobalViaContext_Strict) {
329 HandleScope scope(isolate);
330 DCHECK_EQ(2, args.length());
331 CONVERT_SMI_ARG_CHECKED(slot, 0);
332 CONVERT_ARG_HANDLE_CHECKED(Object, value, 1);
333
334 return StoreGlobalViaContext(isolate, slot, value, STRICT);
335 }
336
337
RUNTIME_FUNCTION(Runtime_GetProperty)338 RUNTIME_FUNCTION(Runtime_GetProperty) {
339 HandleScope scope(isolate);
340 DCHECK(args.length() == 2);
341
342 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
343 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
344
345 RETURN_RESULT_OR_FAILURE(isolate,
346 Runtime::GetObjectProperty(isolate, object, key));
347 }
348
349 // KeyedGetProperty is called from KeyedLoadIC::GenerateGeneric.
RUNTIME_FUNCTION(Runtime_KeyedGetProperty)350 RUNTIME_FUNCTION(Runtime_KeyedGetProperty) {
351 HandleScope scope(isolate);
352 DCHECK(args.length() == 2);
353
354 CONVERT_ARG_HANDLE_CHECKED(Object, receiver_obj, 0);
355 CONVERT_ARG_HANDLE_CHECKED(Object, key_obj, 1);
356
357 RETURN_RESULT_OR_FAILURE(
358 isolate, KeyedGetObjectProperty(isolate, receiver_obj, key_obj));
359 }
360
361
RUNTIME_FUNCTION(Runtime_AddNamedProperty)362 RUNTIME_FUNCTION(Runtime_AddNamedProperty) {
363 HandleScope scope(isolate);
364 DCHECK_EQ(4, args.length());
365
366 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
367 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
368 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
369 CONVERT_PROPERTY_ATTRIBUTES_CHECKED(attrs, 3);
370
371 #ifdef DEBUG
372 uint32_t index = 0;
373 DCHECK(!name->ToArrayIndex(&index));
374 LookupIterator it(object, name, object, LookupIterator::OWN_SKIP_INTERCEPTOR);
375 Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
376 if (!maybe.IsJust()) return isolate->heap()->exception();
377 CHECK(!it.IsFound());
378 #endif
379
380 RETURN_RESULT_OR_FAILURE(isolate, JSObject::SetOwnPropertyIgnoreAttributes(
381 object, name, value, attrs));
382 }
383
384
385 // Adds an element to an array.
386 // This is used to create an indexed data property into an array.
RUNTIME_FUNCTION(Runtime_AddElement)387 RUNTIME_FUNCTION(Runtime_AddElement) {
388 HandleScope scope(isolate);
389 DCHECK_EQ(3, args.length());
390
391 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
392 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
393 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
394
395 uint32_t index = 0;
396 CHECK(key->ToArrayIndex(&index));
397
398 #ifdef DEBUG
399 LookupIterator it(isolate, object, index, object,
400 LookupIterator::OWN_SKIP_INTERCEPTOR);
401 Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
402 if (!maybe.IsJust()) return isolate->heap()->exception();
403 CHECK(!it.IsFound());
404
405 if (object->IsJSArray()) {
406 Handle<JSArray> array = Handle<JSArray>::cast(object);
407 CHECK(!JSArray::WouldChangeReadOnlyLength(array, index));
408 }
409 #endif
410
411 RETURN_RESULT_OR_FAILURE(isolate, JSObject::SetOwnElementIgnoreAttributes(
412 object, index, value, NONE));
413 }
414
415
RUNTIME_FUNCTION(Runtime_AppendElement)416 RUNTIME_FUNCTION(Runtime_AppendElement) {
417 HandleScope scope(isolate);
418 DCHECK_EQ(2, args.length());
419
420 CONVERT_ARG_HANDLE_CHECKED(JSArray, array, 0);
421 CONVERT_ARG_HANDLE_CHECKED(Object, value, 1);
422
423 uint32_t index;
424 CHECK(array->length()->ToArrayIndex(&index));
425
426 RETURN_FAILURE_ON_EXCEPTION(
427 isolate, JSObject::AddDataElement(array, index, value, NONE));
428 JSObject::ValidateElements(array);
429 return *array;
430 }
431
432
RUNTIME_FUNCTION(Runtime_SetProperty)433 RUNTIME_FUNCTION(Runtime_SetProperty) {
434 HandleScope scope(isolate);
435 DCHECK_EQ(4, args.length());
436
437 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
438 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
439 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
440 CONVERT_LANGUAGE_MODE_ARG_CHECKED(language_mode_arg, 3);
441 LanguageMode language_mode = language_mode_arg;
442
443 RETURN_RESULT_OR_FAILURE(
444 isolate,
445 Runtime::SetObjectProperty(isolate, object, key, value, language_mode));
446 }
447
448
449 namespace {
450
451 // ES6 section 12.5.4.
DeleteProperty(Isolate * isolate,Handle<Object> object,Handle<Object> key,LanguageMode language_mode)452 Object* DeleteProperty(Isolate* isolate, Handle<Object> object,
453 Handle<Object> key, LanguageMode language_mode) {
454 Handle<JSReceiver> receiver;
455 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver,
456 Object::ToObject(isolate, object));
457 Maybe<bool> result =
458 Runtime::DeleteObjectProperty(isolate, receiver, key, language_mode);
459 MAYBE_RETURN(result, isolate->heap()->exception());
460 return isolate->heap()->ToBoolean(result.FromJust());
461 }
462
463 } // namespace
464
465
RUNTIME_FUNCTION(Runtime_DeleteProperty_Sloppy)466 RUNTIME_FUNCTION(Runtime_DeleteProperty_Sloppy) {
467 HandleScope scope(isolate);
468 DCHECK_EQ(2, args.length());
469 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
470 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
471 return DeleteProperty(isolate, object, key, SLOPPY);
472 }
473
474
RUNTIME_FUNCTION(Runtime_DeleteProperty_Strict)475 RUNTIME_FUNCTION(Runtime_DeleteProperty_Strict) {
476 HandleScope scope(isolate);
477 DCHECK_EQ(2, args.length());
478 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
479 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
480 return DeleteProperty(isolate, object, key, STRICT);
481 }
482
483
484 // ES6 section 12.9.3, operator in.
RUNTIME_FUNCTION(Runtime_HasProperty)485 RUNTIME_FUNCTION(Runtime_HasProperty) {
486 HandleScope scope(isolate);
487 DCHECK_EQ(2, args.length());
488 CONVERT_ARG_HANDLE_CHECKED(Object, key, 0);
489 CONVERT_ARG_HANDLE_CHECKED(Object, object, 1);
490
491 // Check that {object} is actually a receiver.
492 if (!object->IsJSReceiver()) {
493 THROW_NEW_ERROR_RETURN_FAILURE(
494 isolate,
495 NewTypeError(MessageTemplate::kInvalidInOperatorUse, key, object));
496 }
497 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(object);
498
499 // Convert the {key} to a name.
500 Handle<Name> name;
501 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name,
502 Object::ToName(isolate, key));
503
504 // Lookup the {name} on {receiver}.
505 Maybe<bool> maybe = JSReceiver::HasProperty(receiver, name);
506 if (!maybe.IsJust()) return isolate->heap()->exception();
507 return isolate->heap()->ToBoolean(maybe.FromJust());
508 }
509
510
RUNTIME_FUNCTION(Runtime_PropertyIsEnumerable)511 RUNTIME_FUNCTION(Runtime_PropertyIsEnumerable) {
512 HandleScope scope(isolate);
513 DCHECK(args.length() == 2);
514
515 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0);
516 CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
517
518 Maybe<PropertyAttributes> maybe =
519 JSReceiver::GetOwnPropertyAttributes(object, key);
520 if (!maybe.IsJust()) return isolate->heap()->exception();
521 if (maybe.FromJust() == ABSENT) return isolate->heap()->false_value();
522 return isolate->heap()->ToBoolean((maybe.FromJust() & DONT_ENUM) == 0);
523 }
524
525
RUNTIME_FUNCTION(Runtime_GetOwnPropertyKeys)526 RUNTIME_FUNCTION(Runtime_GetOwnPropertyKeys) {
527 HandleScope scope(isolate);
528 DCHECK(args.length() == 2);
529 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0);
530 CONVERT_SMI_ARG_CHECKED(filter_value, 1);
531 PropertyFilter filter = static_cast<PropertyFilter>(filter_value);
532
533 Handle<FixedArray> keys;
534 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
535 isolate, keys,
536 KeyAccumulator::GetKeys(object, KeyCollectionMode::kOwnOnly, filter,
537 GetKeysConversion::kConvertToString));
538
539 return *isolate->factory()->NewJSArrayWithElements(keys);
540 }
541
542
543 // Return information on whether an object has a named or indexed interceptor.
544 // args[0]: object
RUNTIME_FUNCTION(Runtime_GetInterceptorInfo)545 RUNTIME_FUNCTION(Runtime_GetInterceptorInfo) {
546 HandleScope scope(isolate);
547 DCHECK(args.length() == 1);
548 if (!args[0]->IsJSObject()) {
549 return Smi::FromInt(0);
550 }
551 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
552
553 int result = 0;
554 if (obj->HasNamedInterceptor()) result |= 2;
555 if (obj->HasIndexedInterceptor()) result |= 1;
556
557 return Smi::FromInt(result);
558 }
559
560
RUNTIME_FUNCTION(Runtime_ToFastProperties)561 RUNTIME_FUNCTION(Runtime_ToFastProperties) {
562 HandleScope scope(isolate);
563 DCHECK(args.length() == 1);
564 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
565 if (object->IsJSObject() && !object->IsJSGlobalObject()) {
566 JSObject::MigrateSlowToFast(Handle<JSObject>::cast(object), 0,
567 "RuntimeToFastProperties");
568 }
569 return *object;
570 }
571
572
RUNTIME_FUNCTION(Runtime_AllocateHeapNumber)573 RUNTIME_FUNCTION(Runtime_AllocateHeapNumber) {
574 HandleScope scope(isolate);
575 DCHECK(args.length() == 0);
576 return *isolate->factory()->NewHeapNumber(0);
577 }
578
579
RUNTIME_FUNCTION(Runtime_NewObject)580 RUNTIME_FUNCTION(Runtime_NewObject) {
581 HandleScope scope(isolate);
582 DCHECK_EQ(2, args.length());
583 CONVERT_ARG_HANDLE_CHECKED(JSFunction, target, 0);
584 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, new_target, 1);
585 RETURN_RESULT_OR_FAILURE(isolate, JSObject::New(target, new_target));
586 }
587
588
RUNTIME_FUNCTION(Runtime_FinalizeInstanceSize)589 RUNTIME_FUNCTION(Runtime_FinalizeInstanceSize) {
590 HandleScope scope(isolate);
591 DCHECK(args.length() == 1);
592
593 CONVERT_ARG_HANDLE_CHECKED(Map, initial_map, 0);
594 initial_map->CompleteInobjectSlackTracking();
595
596 return isolate->heap()->undefined_value();
597 }
598
599
RUNTIME_FUNCTION(Runtime_LoadMutableDouble)600 RUNTIME_FUNCTION(Runtime_LoadMutableDouble) {
601 HandleScope scope(isolate);
602 DCHECK(args.length() == 2);
603 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
604 CONVERT_ARG_HANDLE_CHECKED(Smi, index, 1);
605 CHECK((index->value() & 1) == 1);
606 FieldIndex field_index =
607 FieldIndex::ForLoadByFieldIndex(object->map(), index->value());
608 if (field_index.is_inobject()) {
609 CHECK(field_index.property_index() <
610 object->map()->GetInObjectProperties());
611 } else {
612 CHECK(field_index.outobject_array_index() < object->properties()->length());
613 }
614 return *JSObject::FastPropertyAt(object, Representation::Double(),
615 field_index);
616 }
617
618
RUNTIME_FUNCTION(Runtime_TryMigrateInstance)619 RUNTIME_FUNCTION(Runtime_TryMigrateInstance) {
620 HandleScope scope(isolate);
621 DCHECK(args.length() == 1);
622 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
623 if (!object->IsJSObject()) return Smi::FromInt(0);
624 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
625 if (!js_object->map()->is_deprecated()) return Smi::FromInt(0);
626 // This call must not cause lazy deopts, because it's called from deferred
627 // code where we can't handle lazy deopts for lack of a suitable bailout
628 // ID. So we just try migration and signal failure if necessary,
629 // which will also trigger a deopt.
630 if (!JSObject::TryMigrateInstance(js_object)) return Smi::FromInt(0);
631 return *object;
632 }
633
634
RUNTIME_FUNCTION(Runtime_IsJSGlobalProxy)635 RUNTIME_FUNCTION(Runtime_IsJSGlobalProxy) {
636 SealHandleScope shs(isolate);
637 DCHECK(args.length() == 1);
638 CONVERT_ARG_CHECKED(Object, obj, 0);
639 return isolate->heap()->ToBoolean(obj->IsJSGlobalProxy());
640 }
641
IsValidAccessor(Isolate * isolate,Handle<Object> obj)642 static bool IsValidAccessor(Isolate* isolate, Handle<Object> obj) {
643 return obj->IsUndefined(isolate) || obj->IsCallable() || obj->IsNull(isolate);
644 }
645
646
647 // Implements part of 8.12.9 DefineOwnProperty.
648 // There are 3 cases that lead here:
649 // Step 4b - define a new accessor property.
650 // Steps 9c & 12 - replace an existing data property with an accessor property.
651 // Step 12 - update an existing accessor property with an accessor or generic
652 // descriptor.
RUNTIME_FUNCTION(Runtime_DefineAccessorPropertyUnchecked)653 RUNTIME_FUNCTION(Runtime_DefineAccessorPropertyUnchecked) {
654 HandleScope scope(isolate);
655 DCHECK(args.length() == 5);
656 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
657 CHECK(!obj->IsNull(isolate));
658 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
659 CONVERT_ARG_HANDLE_CHECKED(Object, getter, 2);
660 CHECK(IsValidAccessor(isolate, getter));
661 CONVERT_ARG_HANDLE_CHECKED(Object, setter, 3);
662 CHECK(IsValidAccessor(isolate, setter));
663 CONVERT_PROPERTY_ATTRIBUTES_CHECKED(attrs, 4);
664
665 RETURN_FAILURE_ON_EXCEPTION(
666 isolate, JSObject::DefineAccessor(obj, name, getter, setter, attrs));
667 return isolate->heap()->undefined_value();
668 }
669
670
RUNTIME_FUNCTION(Runtime_DefineDataPropertyInLiteral)671 RUNTIME_FUNCTION(Runtime_DefineDataPropertyInLiteral) {
672 HandleScope scope(isolate);
673 DCHECK(args.length() == 5);
674 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
675 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
676 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
677 CONVERT_PROPERTY_ATTRIBUTES_CHECKED(attrs, 3);
678 CONVERT_SMI_ARG_CHECKED(set_function_name, 4);
679
680 if (set_function_name) {
681 DCHECK(value->IsJSFunction());
682 JSFunction::SetName(Handle<JSFunction>::cast(value), name,
683 isolate->factory()->empty_string());
684 }
685
686 LookupIterator it = LookupIterator::PropertyOrElement(
687 isolate, object, name, object, LookupIterator::OWN);
688 // Cannot fail since this should only be called when
689 // creating an object literal.
690 CHECK(JSObject::DefineOwnPropertyIgnoreAttributes(&it, value, attrs,
691 Object::DONT_THROW)
692 .IsJust());
693 return *object;
694 }
695
696 // Return property without being observable by accessors or interceptors.
RUNTIME_FUNCTION(Runtime_GetDataProperty)697 RUNTIME_FUNCTION(Runtime_GetDataProperty) {
698 HandleScope scope(isolate);
699 DCHECK(args.length() == 2);
700 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0);
701 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
702 return *JSReceiver::GetDataProperty(object, name);
703 }
704
705
RUNTIME_FUNCTION(Runtime_HasFastPackedElements)706 RUNTIME_FUNCTION(Runtime_HasFastPackedElements) {
707 SealHandleScope shs(isolate);
708 DCHECK(args.length() == 1);
709 CONVERT_ARG_CHECKED(HeapObject, obj, 0);
710 return isolate->heap()->ToBoolean(
711 IsFastPackedElementsKind(obj->map()->elements_kind()));
712 }
713
714
RUNTIME_FUNCTION(Runtime_ValueOf)715 RUNTIME_FUNCTION(Runtime_ValueOf) {
716 SealHandleScope shs(isolate);
717 DCHECK(args.length() == 1);
718 CONVERT_ARG_CHECKED(Object, obj, 0);
719 if (!obj->IsJSValue()) return obj;
720 return JSValue::cast(obj)->value();
721 }
722
723
RUNTIME_FUNCTION(Runtime_IsJSReceiver)724 RUNTIME_FUNCTION(Runtime_IsJSReceiver) {
725 SealHandleScope shs(isolate);
726 DCHECK(args.length() == 1);
727 CONVERT_ARG_CHECKED(Object, obj, 0);
728 return isolate->heap()->ToBoolean(obj->IsJSReceiver());
729 }
730
731
RUNTIME_FUNCTION(Runtime_ClassOf)732 RUNTIME_FUNCTION(Runtime_ClassOf) {
733 SealHandleScope shs(isolate);
734 DCHECK(args.length() == 1);
735 CONVERT_ARG_CHECKED(Object, obj, 0);
736 if (!obj->IsJSReceiver()) return isolate->heap()->null_value();
737 return JSReceiver::cast(obj)->class_name();
738 }
739
740
RUNTIME_FUNCTION(Runtime_DefineGetterPropertyUnchecked)741 RUNTIME_FUNCTION(Runtime_DefineGetterPropertyUnchecked) {
742 HandleScope scope(isolate);
743 DCHECK(args.length() == 4);
744 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
745 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
746 CONVERT_ARG_HANDLE_CHECKED(JSFunction, getter, 2);
747 CONVERT_PROPERTY_ATTRIBUTES_CHECKED(attrs, 3);
748
749 if (String::cast(getter->shared()->name())->length() == 0) {
750 JSFunction::SetName(getter, name, isolate->factory()->get_string());
751 }
752
753 RETURN_FAILURE_ON_EXCEPTION(
754 isolate,
755 JSObject::DefineAccessor(object, name, getter,
756 isolate->factory()->null_value(), attrs));
757 return isolate->heap()->undefined_value();
758 }
759
760
RUNTIME_FUNCTION(Runtime_DefineSetterPropertyUnchecked)761 RUNTIME_FUNCTION(Runtime_DefineSetterPropertyUnchecked) {
762 HandleScope scope(isolate);
763 DCHECK(args.length() == 4);
764 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
765 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
766 CONVERT_ARG_HANDLE_CHECKED(JSFunction, setter, 2);
767 CONVERT_PROPERTY_ATTRIBUTES_CHECKED(attrs, 3);
768
769 if (String::cast(setter->shared()->name())->length() == 0) {
770 JSFunction::SetName(setter, name, isolate->factory()->set_string());
771 }
772
773 RETURN_FAILURE_ON_EXCEPTION(
774 isolate,
775 JSObject::DefineAccessor(object, name, isolate->factory()->null_value(),
776 setter, attrs));
777 return isolate->heap()->undefined_value();
778 }
779
780
RUNTIME_FUNCTION(Runtime_ToObject)781 RUNTIME_FUNCTION(Runtime_ToObject) {
782 HandleScope scope(isolate);
783 DCHECK_EQ(1, args.length());
784 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
785 RETURN_RESULT_OR_FAILURE(isolate, Object::ToObject(isolate, object));
786 }
787
788
RUNTIME_FUNCTION(Runtime_ToPrimitive)789 RUNTIME_FUNCTION(Runtime_ToPrimitive) {
790 HandleScope scope(isolate);
791 DCHECK_EQ(1, args.length());
792 CONVERT_ARG_HANDLE_CHECKED(Object, input, 0);
793 RETURN_RESULT_OR_FAILURE(isolate, Object::ToPrimitive(input));
794 }
795
796
RUNTIME_FUNCTION(Runtime_ToPrimitive_Number)797 RUNTIME_FUNCTION(Runtime_ToPrimitive_Number) {
798 HandleScope scope(isolate);
799 DCHECK_EQ(1, args.length());
800 CONVERT_ARG_HANDLE_CHECKED(Object, input, 0);
801 RETURN_RESULT_OR_FAILURE(
802 isolate, Object::ToPrimitive(input, ToPrimitiveHint::kNumber));
803 }
804
805
RUNTIME_FUNCTION(Runtime_ToPrimitive_String)806 RUNTIME_FUNCTION(Runtime_ToPrimitive_String) {
807 HandleScope scope(isolate);
808 DCHECK_EQ(1, args.length());
809 CONVERT_ARG_HANDLE_CHECKED(Object, input, 0);
810 RETURN_RESULT_OR_FAILURE(
811 isolate, Object::ToPrimitive(input, ToPrimitiveHint::kString));
812 }
813
814
RUNTIME_FUNCTION(Runtime_ToNumber)815 RUNTIME_FUNCTION(Runtime_ToNumber) {
816 HandleScope scope(isolate);
817 DCHECK_EQ(1, args.length());
818 CONVERT_ARG_HANDLE_CHECKED(Object, input, 0);
819 RETURN_RESULT_OR_FAILURE(isolate, Object::ToNumber(input));
820 }
821
822
RUNTIME_FUNCTION(Runtime_ToInteger)823 RUNTIME_FUNCTION(Runtime_ToInteger) {
824 HandleScope scope(isolate);
825 DCHECK_EQ(1, args.length());
826 CONVERT_ARG_HANDLE_CHECKED(Object, input, 0);
827 RETURN_RESULT_OR_FAILURE(isolate, Object::ToInteger(isolate, input));
828 }
829
830
RUNTIME_FUNCTION(Runtime_ToLength)831 RUNTIME_FUNCTION(Runtime_ToLength) {
832 HandleScope scope(isolate);
833 DCHECK_EQ(1, args.length());
834 CONVERT_ARG_HANDLE_CHECKED(Object, input, 0);
835 RETURN_RESULT_OR_FAILURE(isolate, Object::ToLength(isolate, input));
836 }
837
838
RUNTIME_FUNCTION(Runtime_ToString)839 RUNTIME_FUNCTION(Runtime_ToString) {
840 HandleScope scope(isolate);
841 DCHECK_EQ(1, args.length());
842 CONVERT_ARG_HANDLE_CHECKED(Object, input, 0);
843 RETURN_RESULT_OR_FAILURE(isolate, Object::ToString(isolate, input));
844 }
845
846
RUNTIME_FUNCTION(Runtime_ToName)847 RUNTIME_FUNCTION(Runtime_ToName) {
848 HandleScope scope(isolate);
849 DCHECK_EQ(1, args.length());
850 CONVERT_ARG_HANDLE_CHECKED(Object, input, 0);
851 RETURN_RESULT_OR_FAILURE(isolate, Object::ToName(isolate, input));
852 }
853
854
RUNTIME_FUNCTION(Runtime_SameValue)855 RUNTIME_FUNCTION(Runtime_SameValue) {
856 SealHandleScope scope(isolate);
857 DCHECK_EQ(2, args.length());
858 CONVERT_ARG_CHECKED(Object, x, 0);
859 CONVERT_ARG_CHECKED(Object, y, 1);
860 return isolate->heap()->ToBoolean(x->SameValue(y));
861 }
862
863
RUNTIME_FUNCTION(Runtime_SameValueZero)864 RUNTIME_FUNCTION(Runtime_SameValueZero) {
865 SealHandleScope scope(isolate);
866 DCHECK_EQ(2, args.length());
867 CONVERT_ARG_CHECKED(Object, x, 0);
868 CONVERT_ARG_CHECKED(Object, y, 1);
869 return isolate->heap()->ToBoolean(x->SameValueZero(y));
870 }
871
872
873 // TODO(bmeurer): Kill this special wrapper and use TF compatible LessThan,
874 // GreaterThan, etc. which return true or false.
RUNTIME_FUNCTION(Runtime_Compare)875 RUNTIME_FUNCTION(Runtime_Compare) {
876 HandleScope scope(isolate);
877 DCHECK_EQ(3, args.length());
878 CONVERT_ARG_HANDLE_CHECKED(Object, x, 0);
879 CONVERT_ARG_HANDLE_CHECKED(Object, y, 1);
880 CONVERT_ARG_HANDLE_CHECKED(Object, ncr, 2);
881 Maybe<ComparisonResult> result = Object::Compare(x, y);
882 if (result.IsJust()) {
883 switch (result.FromJust()) {
884 case ComparisonResult::kLessThan:
885 return Smi::FromInt(LESS);
886 case ComparisonResult::kEqual:
887 return Smi::FromInt(EQUAL);
888 case ComparisonResult::kGreaterThan:
889 return Smi::FromInt(GREATER);
890 case ComparisonResult::kUndefined:
891 return *ncr;
892 }
893 UNREACHABLE();
894 }
895 return isolate->heap()->exception();
896 }
897
RUNTIME_FUNCTION(Runtime_HasInPrototypeChain)898 RUNTIME_FUNCTION(Runtime_HasInPrototypeChain) {
899 HandleScope scope(isolate);
900 DCHECK_EQ(2, args.length());
901 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0);
902 CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1);
903 Maybe<bool> result =
904 JSReceiver::HasInPrototypeChain(isolate, object, prototype);
905 MAYBE_RETURN(result, isolate->heap()->exception());
906 return isolate->heap()->ToBoolean(result.FromJust());
907 }
908
909
910 // ES6 section 7.4.7 CreateIterResultObject ( value, done )
RUNTIME_FUNCTION(Runtime_CreateIterResultObject)911 RUNTIME_FUNCTION(Runtime_CreateIterResultObject) {
912 HandleScope scope(isolate);
913 DCHECK_EQ(2, args.length());
914 CONVERT_ARG_HANDLE_CHECKED(Object, value, 0);
915 CONVERT_ARG_HANDLE_CHECKED(Object, done, 1);
916 Handle<JSObject> result =
917 isolate->factory()->NewJSObjectFromMap(isolate->iterator_result_map());
918 result->InObjectPropertyAtPut(JSIteratorResult::kValueIndex, *value);
919 result->InObjectPropertyAtPut(JSIteratorResult::kDoneIndex, *done);
920 return *result;
921 }
922
923
RUNTIME_FUNCTION(Runtime_IsAccessCheckNeeded)924 RUNTIME_FUNCTION(Runtime_IsAccessCheckNeeded) {
925 SealHandleScope shs(isolate);
926 DCHECK_EQ(1, args.length());
927 CONVERT_ARG_CHECKED(Object, object, 0);
928 return isolate->heap()->ToBoolean(object->IsAccessCheckNeeded());
929 }
930
931
RUNTIME_FUNCTION(Runtime_CreateDataProperty)932 RUNTIME_FUNCTION(Runtime_CreateDataProperty) {
933 HandleScope scope(isolate);
934 DCHECK(args.length() == 3);
935 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, o, 0);
936 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
937 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
938 bool success;
939 LookupIterator it = LookupIterator::PropertyOrElement(
940 isolate, o, key, &success, LookupIterator::OWN);
941 if (!success) return isolate->heap()->exception();
942 MAYBE_RETURN(
943 JSReceiver::CreateDataProperty(&it, value, Object::THROW_ON_ERROR),
944 isolate->heap()->exception());
945 return *value;
946 }
947
948 } // namespace internal
949 } // namespace v8
950