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

Side by Side Diff: src/runtime/runtime-object.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/runtime/runtime-numbers.cc ('k') | src/runtime/runtime-strings.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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/v8.h"
6
7 #include "src/arguments.h"
8 #include "src/bootstrapper.h"
9 #include "src/debug.h"
10 #include "src/runtime/runtime.h"
11 #include "src/runtime/runtime-utils.h"
12
13 namespace v8 {
14 namespace internal {
15
16 // Returns a single character string where first character equals
17 // string->Get(index).
18 static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
19 if (index < static_cast<uint32_t>(string->length())) {
20 Factory* factory = string->GetIsolate()->factory();
21 return factory->LookupSingleCharacterStringFromCode(
22 String::Flatten(string)->Get(index));
23 }
24 return Execution::CharAt(string, index);
25 }
26
27
28 MaybeHandle<Object> Runtime::GetElementOrCharAt(Isolate* isolate,
29 Handle<Object> object,
30 uint32_t index) {
31 // Handle [] indexing on Strings
32 if (object->IsString()) {
33 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
34 if (!result->IsUndefined()) return result;
35 }
36
37 // Handle [] indexing on String objects
38 if (object->IsStringObjectWithCharacterAt(index)) {
39 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
40 Handle<Object> result =
41 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
42 if (!result->IsUndefined()) return result;
43 }
44
45 Handle<Object> result;
46 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
47 PrototypeIterator iter(isolate, object);
48 return Object::GetElement(isolate, PrototypeIterator::GetCurrent(iter),
49 index);
50 } else {
51 return Object::GetElement(isolate, object, index);
52 }
53 }
54
55
56 MaybeHandle<Name> Runtime::ToName(Isolate* isolate, Handle<Object> key) {
57 if (key->IsName()) {
58 return Handle<Name>::cast(key);
59 } else {
60 Handle<Object> converted;
61 ASSIGN_RETURN_ON_EXCEPTION(isolate, converted,
62 Execution::ToString(isolate, key), Name);
63 return Handle<Name>::cast(converted);
64 }
65 }
66
67
68 MaybeHandle<Object> Runtime::HasObjectProperty(Isolate* isolate,
69 Handle<JSReceiver> object,
70 Handle<Object> key) {
71 Maybe<bool> maybe;
72 // Check if the given key is an array index.
73 uint32_t index;
74 if (key->ToArrayIndex(&index)) {
75 maybe = JSReceiver::HasElement(object, index);
76 } else {
77 // Convert the key to a name - possibly by calling back into JavaScript.
78 Handle<Name> name;
79 ASSIGN_RETURN_ON_EXCEPTION(isolate, name, ToName(isolate, key), Object);
80
81 maybe = JSReceiver::HasProperty(object, name);
82 }
83
84 if (!maybe.has_value) return MaybeHandle<Object>();
85 return isolate->factory()->ToBoolean(maybe.value);
86 }
87
88
89 MaybeHandle<Object> Runtime::GetObjectProperty(Isolate* isolate,
90 Handle<Object> object,
91 Handle<Object> key) {
92 if (object->IsUndefined() || object->IsNull()) {
93 Handle<Object> args[2] = {key, object};
94 THROW_NEW_ERROR(isolate, NewTypeError("non_object_property_load",
95 HandleVector(args, 2)),
96 Object);
97 }
98
99 // Check if the given key is an array index.
100 uint32_t index;
101 if (key->ToArrayIndex(&index)) {
102 return GetElementOrCharAt(isolate, object, index);
103 }
104
105 // Convert the key to a name - possibly by calling back into JavaScript.
106 Handle<Name> name;
107 ASSIGN_RETURN_ON_EXCEPTION(isolate, name, ToName(isolate, key), Object);
108
109 // Check if the name is trivially convertible to an index and get
110 // the element if so.
111 if (name->AsArrayIndex(&index)) {
112 return GetElementOrCharAt(isolate, object, index);
113 } else {
114 return Object::GetProperty(object, name);
115 }
116 }
117
118
119 MaybeHandle<Object> Runtime::SetObjectProperty(Isolate* isolate,
120 Handle<Object> object,
121 Handle<Object> key,
122 Handle<Object> value,
123 StrictMode strict_mode) {
124 if (object->IsUndefined() || object->IsNull()) {
125 Handle<Object> args[2] = {key, object};
126 THROW_NEW_ERROR(isolate, NewTypeError("non_object_property_store",
127 HandleVector(args, 2)),
128 Object);
129 }
130
131 if (object->IsJSProxy()) {
132 Handle<Object> name_object;
133 if (key->IsSymbol()) {
134 name_object = key;
135 } else {
136 ASSIGN_RETURN_ON_EXCEPTION(isolate, name_object,
137 Execution::ToString(isolate, key), Object);
138 }
139 Handle<Name> name = Handle<Name>::cast(name_object);
140 return Object::SetProperty(Handle<JSProxy>::cast(object), name, value,
141 strict_mode);
142 }
143
144 // Check if the given key is an array index.
145 uint32_t index;
146 if (key->ToArrayIndex(&index)) {
147 // TODO(verwaest): Support non-JSObject receivers.
148 if (!object->IsJSObject()) return value;
149 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
150
151 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
152 // of a string using [] notation. We need to support this too in
153 // JavaScript.
154 // In the case of a String object we just need to redirect the assignment to
155 // the underlying string if the index is in range. Since the underlying
156 // string does nothing with the assignment then we can ignore such
157 // assignments.
158 if (js_object->IsStringObjectWithCharacterAt(index)) {
159 return value;
160 }
161
162 JSObject::ValidateElements(js_object);
163 if (js_object->HasExternalArrayElements() ||
164 js_object->HasFixedTypedArrayElements()) {
165 if (!value->IsNumber() && !value->IsUndefined()) {
166 ASSIGN_RETURN_ON_EXCEPTION(isolate, value,
167 Execution::ToNumber(isolate, value), Object);
168 }
169 }
170
171 MaybeHandle<Object> result = JSObject::SetElement(
172 js_object, index, value, NONE, strict_mode, true, SET_PROPERTY);
173 JSObject::ValidateElements(js_object);
174
175 return result.is_null() ? result : value;
176 }
177
178 if (key->IsName()) {
179 Handle<Name> name = Handle<Name>::cast(key);
180 if (name->AsArrayIndex(&index)) {
181 // TODO(verwaest): Support non-JSObject receivers.
182 if (!object->IsJSObject()) return value;
183 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
184 if (js_object->HasExternalArrayElements()) {
185 if (!value->IsNumber() && !value->IsUndefined()) {
186 ASSIGN_RETURN_ON_EXCEPTION(
187 isolate, value, Execution::ToNumber(isolate, value), Object);
188 }
189 }
190 return JSObject::SetElement(js_object, index, value, NONE, strict_mode,
191 true, SET_PROPERTY);
192 } else {
193 if (name->IsString()) name = String::Flatten(Handle<String>::cast(name));
194 return Object::SetProperty(object, name, value, strict_mode);
195 }
196 }
197
198 // Call-back into JavaScript to convert the key to a string.
199 Handle<Object> converted;
200 ASSIGN_RETURN_ON_EXCEPTION(isolate, converted,
201 Execution::ToString(isolate, key), Object);
202 Handle<String> name = Handle<String>::cast(converted);
203
204 if (name->AsArrayIndex(&index)) {
205 // TODO(verwaest): Support non-JSObject receivers.
206 if (!object->IsJSObject()) return value;
207 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
208 return JSObject::SetElement(js_object, index, value, NONE, strict_mode,
209 true, SET_PROPERTY);
210 }
211 return Object::SetProperty(object, name, value, strict_mode);
212 }
213
214
215 MaybeHandle<Object> Runtime::DefineObjectProperty(Handle<JSObject> js_object,
216 Handle<Object> key,
217 Handle<Object> value,
218 PropertyAttributes attr) {
219 Isolate* isolate = js_object->GetIsolate();
220 // Check if the given key is an array index.
221 uint32_t index;
222 if (key->ToArrayIndex(&index)) {
223 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
224 // of a string using [] notation. We need to support this too in
225 // JavaScript.
226 // In the case of a String object we just need to redirect the assignment to
227 // the underlying string if the index is in range. Since the underlying
228 // string does nothing with the assignment then we can ignore such
229 // assignments.
230 if (js_object->IsStringObjectWithCharacterAt(index)) {
231 return value;
232 }
233
234 return JSObject::SetElement(js_object, index, value, attr, SLOPPY, false,
235 DEFINE_PROPERTY);
236 }
237
238 if (key->IsName()) {
239 Handle<Name> name = Handle<Name>::cast(key);
240 if (name->AsArrayIndex(&index)) {
241 return JSObject::SetElement(js_object, index, value, attr, SLOPPY, false,
242 DEFINE_PROPERTY);
243 } else {
244 if (name->IsString()) name = String::Flatten(Handle<String>::cast(name));
245 return JSObject::SetOwnPropertyIgnoreAttributes(js_object, name, value,
246 attr);
247 }
248 }
249
250 // Call-back into JavaScript to convert the key to a string.
251 Handle<Object> converted;
252 ASSIGN_RETURN_ON_EXCEPTION(isolate, converted,
253 Execution::ToString(isolate, key), Object);
254 Handle<String> name = Handle<String>::cast(converted);
255
256 if (name->AsArrayIndex(&index)) {
257 return JSObject::SetElement(js_object, index, value, attr, SLOPPY, false,
258 DEFINE_PROPERTY);
259 } else {
260 return JSObject::SetOwnPropertyIgnoreAttributes(js_object, name, value,
261 attr);
262 }
263 }
264
265
266 MaybeHandle<Object> Runtime::DeleteObjectProperty(Isolate* isolate,
267 Handle<JSReceiver> receiver,
268 Handle<Object> key,
269 JSReceiver::DeleteMode mode) {
270 // Check if the given key is an array index.
271 uint32_t index;
272 if (key->ToArrayIndex(&index)) {
273 // In Firefox/SpiderMonkey, Safari and Opera you can access the
274 // characters of a string using [] notation. In the case of a
275 // String object we just need to redirect the deletion to the
276 // underlying string if the index is in range. Since the
277 // underlying string does nothing with the deletion, we can ignore
278 // such deletions.
279 if (receiver->IsStringObjectWithCharacterAt(index)) {
280 return isolate->factory()->true_value();
281 }
282
283 return JSReceiver::DeleteElement(receiver, index, mode);
284 }
285
286 Handle<Name> name;
287 if (key->IsName()) {
288 name = Handle<Name>::cast(key);
289 } else {
290 // Call-back into JavaScript to convert the key to a string.
291 Handle<Object> converted;
292 ASSIGN_RETURN_ON_EXCEPTION(isolate, converted,
293 Execution::ToString(isolate, key), Object);
294 name = Handle<String>::cast(converted);
295 }
296
297 if (name->IsString()) name = String::Flatten(Handle<String>::cast(name));
298 return JSReceiver::DeleteProperty(receiver, name, mode);
299 }
300
301
302 RUNTIME_FUNCTION(Runtime_GetPrototype) {
303 HandleScope scope(isolate);
304 DCHECK(args.length() == 1);
305 CONVERT_ARG_HANDLE_CHECKED(Object, obj, 0);
306 // We don't expect access checks to be needed on JSProxy objects.
307 DCHECK(!obj->IsAccessCheckNeeded() || obj->IsJSObject());
308 PrototypeIterator iter(isolate, obj, PrototypeIterator::START_AT_RECEIVER);
309 do {
310 if (PrototypeIterator::GetCurrent(iter)->IsAccessCheckNeeded() &&
311 !isolate->MayNamedAccess(
312 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)),
313 isolate->factory()->proto_string(), v8::ACCESS_GET)) {
314 isolate->ReportFailedAccessCheck(
315 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)),
316 v8::ACCESS_GET);
317 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
318 return isolate->heap()->undefined_value();
319 }
320 iter.AdvanceIgnoringProxies();
321 if (PrototypeIterator::GetCurrent(iter)->IsJSProxy()) {
322 return *PrototypeIterator::GetCurrent(iter);
323 }
324 } while (!iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN));
325 return *PrototypeIterator::GetCurrent(iter);
326 }
327
328
329 RUNTIME_FUNCTION(Runtime_InternalSetPrototype) {
330 HandleScope scope(isolate);
331 DCHECK(args.length() == 2);
332 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
333 CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1);
334 DCHECK(!obj->IsAccessCheckNeeded());
335 DCHECK(!obj->map()->is_observed());
336 Handle<Object> result;
337 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
338 isolate, result, JSObject::SetPrototype(obj, prototype, false));
339 return *result;
340 }
341
342
343 RUNTIME_FUNCTION(Runtime_SetPrototype) {
344 HandleScope scope(isolate);
345 DCHECK(args.length() == 2);
346 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
347 CONVERT_ARG_HANDLE_CHECKED(Object, prototype, 1);
348 if (obj->IsAccessCheckNeeded() &&
349 !isolate->MayNamedAccess(obj, isolate->factory()->proto_string(),
350 v8::ACCESS_SET)) {
351 isolate->ReportFailedAccessCheck(obj, v8::ACCESS_SET);
352 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
353 return isolate->heap()->undefined_value();
354 }
355 if (obj->map()->is_observed()) {
356 Handle<Object> old_value =
357 Object::GetPrototypeSkipHiddenPrototypes(isolate, obj);
358 Handle<Object> result;
359 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
360 isolate, result, JSObject::SetPrototype(obj, prototype, true));
361
362 Handle<Object> new_value =
363 Object::GetPrototypeSkipHiddenPrototypes(isolate, obj);
364 if (!new_value->SameValue(*old_value)) {
365 JSObject::EnqueueChangeRecord(
366 obj, "setPrototype", isolate->factory()->proto_string(), old_value);
367 }
368 return *result;
369 }
370 Handle<Object> result;
371 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
372 isolate, result, JSObject::SetPrototype(obj, prototype, true));
373 return *result;
374 }
375
376
377 RUNTIME_FUNCTION(Runtime_IsInPrototypeChain) {
378 HandleScope shs(isolate);
379 DCHECK(args.length() == 2);
380 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
381 CONVERT_ARG_HANDLE_CHECKED(Object, O, 0);
382 CONVERT_ARG_HANDLE_CHECKED(Object, V, 1);
383 PrototypeIterator iter(isolate, V, PrototypeIterator::START_AT_RECEIVER);
384 while (true) {
385 iter.AdvanceIgnoringProxies();
386 if (iter.IsAtEnd()) return isolate->heap()->false_value();
387 if (iter.IsAtEnd(O)) return isolate->heap()->true_value();
388 }
389 }
390
391
392 // Enumerator used as indices into the array returned from GetOwnProperty
393 enum PropertyDescriptorIndices {
394 IS_ACCESSOR_INDEX,
395 VALUE_INDEX,
396 GETTER_INDEX,
397 SETTER_INDEX,
398 WRITABLE_INDEX,
399 ENUMERABLE_INDEX,
400 CONFIGURABLE_INDEX,
401 DESCRIPTOR_SIZE
402 };
403
404
405 MUST_USE_RESULT static MaybeHandle<Object> GetOwnProperty(Isolate* isolate,
406 Handle<JSObject> obj,
407 Handle<Name> name) {
408 Heap* heap = isolate->heap();
409 Factory* factory = isolate->factory();
410
411 PropertyAttributes attrs;
412 uint32_t index = 0;
413 Handle<Object> value;
414 MaybeHandle<AccessorPair> maybe_accessors;
415 // TODO(verwaest): Unify once indexed properties can be handled by the
416 // LookupIterator.
417 if (name->AsArrayIndex(&index)) {
418 // Get attributes.
419 Maybe<PropertyAttributes> maybe =
420 JSReceiver::GetOwnElementAttribute(obj, index);
421 if (!maybe.has_value) return MaybeHandle<Object>();
422 attrs = maybe.value;
423 if (attrs == ABSENT) return factory->undefined_value();
424
425 // Get AccessorPair if present.
426 maybe_accessors = JSObject::GetOwnElementAccessorPair(obj, index);
427
428 // Get value if not an AccessorPair.
429 if (maybe_accessors.is_null()) {
430 ASSIGN_RETURN_ON_EXCEPTION(
431 isolate, value, Runtime::GetElementOrCharAt(isolate, obj, index),
432 Object);
433 }
434 } else {
435 // Get attributes.
436 LookupIterator it(obj, name, LookupIterator::HIDDEN);
437 Maybe<PropertyAttributes> maybe = JSObject::GetPropertyAttributes(&it);
438 if (!maybe.has_value) return MaybeHandle<Object>();
439 attrs = maybe.value;
440 if (attrs == ABSENT) return factory->undefined_value();
441
442 // Get AccessorPair if present.
443 if (it.state() == LookupIterator::ACCESSOR &&
444 it.GetAccessors()->IsAccessorPair()) {
445 maybe_accessors = Handle<AccessorPair>::cast(it.GetAccessors());
446 }
447
448 // Get value if not an AccessorPair.
449 if (maybe_accessors.is_null()) {
450 ASSIGN_RETURN_ON_EXCEPTION(isolate, value, Object::GetProperty(&it),
451 Object);
452 }
453 }
454 DCHECK(!isolate->has_pending_exception());
455 Handle<FixedArray> elms = factory->NewFixedArray(DESCRIPTOR_SIZE);
456 elms->set(ENUMERABLE_INDEX, heap->ToBoolean((attrs & DONT_ENUM) == 0));
457 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean((attrs & DONT_DELETE) == 0));
458 elms->set(IS_ACCESSOR_INDEX, heap->ToBoolean(!maybe_accessors.is_null()));
459
460 Handle<AccessorPair> accessors;
461 if (maybe_accessors.ToHandle(&accessors)) {
462 Handle<Object> getter(accessors->GetComponent(ACCESSOR_GETTER), isolate);
463 Handle<Object> setter(accessors->GetComponent(ACCESSOR_SETTER), isolate);
464 elms->set(GETTER_INDEX, *getter);
465 elms->set(SETTER_INDEX, *setter);
466 } else {
467 elms->set(WRITABLE_INDEX, heap->ToBoolean((attrs & READ_ONLY) == 0));
468 elms->set(VALUE_INDEX, *value);
469 }
470
471 return factory->NewJSArrayWithElements(elms);
472 }
473
474
475 // Returns an array with the property description:
476 // if args[1] is not a property on args[0]
477 // returns undefined
478 // if args[1] is a data property on args[0]
479 // [false, value, Writeable, Enumerable, Configurable]
480 // if args[1] is an accessor on args[0]
481 // [true, GetFunction, SetFunction, Enumerable, Configurable]
482 RUNTIME_FUNCTION(Runtime_GetOwnProperty) {
483 HandleScope scope(isolate);
484 DCHECK(args.length() == 2);
485 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
486 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
487 Handle<Object> result;
488 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
489 GetOwnProperty(isolate, obj, name));
490 return *result;
491 }
492
493
494 RUNTIME_FUNCTION(Runtime_PreventExtensions) {
495 HandleScope scope(isolate);
496 DCHECK(args.length() == 1);
497 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
498 Handle<Object> result;
499 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result,
500 JSObject::PreventExtensions(obj));
501 return *result;
502 }
503
504
505 RUNTIME_FUNCTION(Runtime_IsExtensible) {
506 SealHandleScope shs(isolate);
507 DCHECK(args.length() == 1);
508 CONVERT_ARG_CHECKED(JSObject, obj, 0);
509 if (obj->IsJSGlobalProxy()) {
510 PrototypeIterator iter(isolate, obj);
511 if (iter.IsAtEnd()) return isolate->heap()->false_value();
512 DCHECK(iter.GetCurrent()->IsJSGlobalObject());
513 obj = JSObject::cast(iter.GetCurrent());
514 }
515 return isolate->heap()->ToBoolean(obj->map()->is_extensible());
516 }
517
518
519 RUNTIME_FUNCTION(Runtime_DisableAccessChecks) {
520 HandleScope scope(isolate);
521 DCHECK(args.length() == 1);
522 CONVERT_ARG_HANDLE_CHECKED(HeapObject, object, 0);
523 Handle<Map> old_map(object->map());
524 bool needs_access_checks = old_map->is_access_check_needed();
525 if (needs_access_checks) {
526 // Copy map so it won't interfere constructor's initial map.
527 Handle<Map> new_map = Map::Copy(old_map);
528 new_map->set_is_access_check_needed(false);
529 JSObject::MigrateToMap(Handle<JSObject>::cast(object), new_map);
530 }
531 return isolate->heap()->ToBoolean(needs_access_checks);
532 }
533
534
535 RUNTIME_FUNCTION(Runtime_EnableAccessChecks) {
536 HandleScope scope(isolate);
537 DCHECK(args.length() == 1);
538 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
539 Handle<Map> old_map(object->map());
540 RUNTIME_ASSERT(!old_map->is_access_check_needed());
541 // Copy map so it won't interfere constructor's initial map.
542 Handle<Map> new_map = Map::Copy(old_map);
543 new_map->set_is_access_check_needed(true);
544 JSObject::MigrateToMap(object, new_map);
545 return isolate->heap()->undefined_value();
546 }
547
548
549 RUNTIME_FUNCTION(Runtime_OptimizeObjectForAddingMultipleProperties) {
550 HandleScope scope(isolate);
551 DCHECK(args.length() == 2);
552 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
553 CONVERT_SMI_ARG_CHECKED(properties, 1);
554 // Conservative upper limit to prevent fuzz tests from going OOM.
555 RUNTIME_ASSERT(properties <= 100000);
556 if (object->HasFastProperties() && !object->IsJSGlobalProxy()) {
557 JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
558 }
559 return *object;
560 }
561
562
563 RUNTIME_FUNCTION(Runtime_ObjectFreeze) {
564 HandleScope scope(isolate);
565 DCHECK(args.length() == 1);
566 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
567
568 // %ObjectFreeze is a fast path and these cases are handled elsewhere.
569 RUNTIME_ASSERT(!object->HasSloppyArgumentsElements() &&
570 !object->map()->is_observed() && !object->IsJSProxy());
571
572 Handle<Object> result;
573 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, JSObject::Freeze(object));
574 return *result;
575 }
576
577
578 RUNTIME_FUNCTION(Runtime_GetProperty) {
579 HandleScope scope(isolate);
580 DCHECK(args.length() == 2);
581
582 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
583 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
584 Handle<Object> result;
585 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
586 isolate, result, Runtime::GetObjectProperty(isolate, object, key));
587 return *result;
588 }
589
590
591 MUST_USE_RESULT static MaybeHandle<Object> TransitionElements(
592 Handle<Object> object, ElementsKind to_kind, Isolate* isolate) {
593 HandleScope scope(isolate);
594 if (!object->IsJSObject()) {
595 isolate->ThrowIllegalOperation();
596 return MaybeHandle<Object>();
597 }
598 ElementsKind from_kind =
599 Handle<JSObject>::cast(object)->map()->elements_kind();
600 if (Map::IsValidElementsTransition(from_kind, to_kind)) {
601 JSObject::TransitionElementsKind(Handle<JSObject>::cast(object), to_kind);
602 return object;
603 }
604 isolate->ThrowIllegalOperation();
605 return MaybeHandle<Object>();
606 }
607
608
609 // KeyedGetProperty is called from KeyedLoadIC::GenerateGeneric.
610 RUNTIME_FUNCTION(Runtime_KeyedGetProperty) {
611 HandleScope scope(isolate);
612 DCHECK(args.length() == 2);
613
614 CONVERT_ARG_HANDLE_CHECKED(Object, receiver_obj, 0);
615 CONVERT_ARG_HANDLE_CHECKED(Object, key_obj, 1);
616
617 // Fast cases for getting named properties of the receiver JSObject
618 // itself.
619 //
620 // The global proxy objects has to be excluded since LookupOwn on
621 // the global proxy object can return a valid result even though the
622 // global proxy object never has properties. This is the case
623 // because the global proxy object forwards everything to its hidden
624 // prototype including own lookups.
625 //
626 // Additionally, we need to make sure that we do not cache results
627 // for objects that require access checks.
628 if (receiver_obj->IsJSObject()) {
629 if (!receiver_obj->IsJSGlobalProxy() &&
630 !receiver_obj->IsAccessCheckNeeded() && key_obj->IsName()) {
631 DisallowHeapAllocation no_allocation;
632 Handle<JSObject> receiver = Handle<JSObject>::cast(receiver_obj);
633 Handle<Name> key = Handle<Name>::cast(key_obj);
634 if (receiver->HasFastProperties()) {
635 // Attempt to use lookup cache.
636 Handle<Map> receiver_map(receiver->map(), isolate);
637 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
638 int index = keyed_lookup_cache->Lookup(receiver_map, key);
639 if (index != -1) {
640 // Doubles are not cached, so raw read the value.
641 return receiver->RawFastPropertyAt(
642 FieldIndex::ForKeyedLookupCacheIndex(*receiver_map, index));
643 }
644 // Lookup cache miss. Perform lookup and update the cache if
645 // appropriate.
646 LookupIterator it(receiver, key, LookupIterator::OWN);
647 if (it.state() == LookupIterator::DATA &&
648 it.property_details().type() == FIELD) {
649 FieldIndex field_index = it.GetFieldIndex();
650 // Do not track double fields in the keyed lookup cache. Reading
651 // double values requires boxing.
652 if (!it.representation().IsDouble()) {
653 keyed_lookup_cache->Update(receiver_map, key,
654 field_index.GetKeyedLookupCacheIndex());
655 }
656 AllowHeapAllocation allow_allocation;
657 return *JSObject::FastPropertyAt(receiver, it.representation(),
658 field_index);
659 }
660 } else {
661 // Attempt dictionary lookup.
662 NameDictionary* dictionary = receiver->property_dictionary();
663 int entry = dictionary->FindEntry(key);
664 if ((entry != NameDictionary::kNotFound) &&
665 (dictionary->DetailsAt(entry).type() == NORMAL)) {
666 Object* value = dictionary->ValueAt(entry);
667 if (!receiver->IsGlobalObject()) return value;
668 value = PropertyCell::cast(value)->value();
669 if (!value->IsTheHole()) return value;
670 // If value is the hole (meaning, absent) do the general lookup.
671 }
672 }
673 } else if (key_obj->IsSmi()) {
674 // JSObject without a name key. If the key is a Smi, check for a
675 // definite out-of-bounds access to elements, which is a strong indicator
676 // that subsequent accesses will also call the runtime. Proactively
677 // transition elements to FAST_*_ELEMENTS to avoid excessive boxing of
678 // doubles for those future calls in the case that the elements would
679 // become FAST_DOUBLE_ELEMENTS.
680 Handle<JSObject> js_object = Handle<JSObject>::cast(receiver_obj);
681 ElementsKind elements_kind = js_object->GetElementsKind();
682 if (IsFastDoubleElementsKind(elements_kind)) {
683 Handle<Smi> key = Handle<Smi>::cast(key_obj);
684 if (key->value() >= js_object->elements()->length()) {
685 if (IsFastHoleyElementsKind(elements_kind)) {
686 elements_kind = FAST_HOLEY_ELEMENTS;
687 } else {
688 elements_kind = FAST_ELEMENTS;
689 }
690 RETURN_FAILURE_ON_EXCEPTION(
691 isolate, TransitionElements(js_object, elements_kind, isolate));
692 }
693 } else {
694 DCHECK(IsFastSmiOrObjectElementsKind(elements_kind) ||
695 !IsFastElementsKind(elements_kind));
696 }
697 }
698 } else if (receiver_obj->IsString() && key_obj->IsSmi()) {
699 // Fast case for string indexing using [] with a smi index.
700 Handle<String> str = Handle<String>::cast(receiver_obj);
701 int index = args.smi_at(1);
702 if (index >= 0 && index < str->length()) {
703 return *GetCharAt(str, index);
704 }
705 }
706
707 // Fall back to GetObjectProperty.
708 Handle<Object> result;
709 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
710 isolate, result,
711 Runtime::GetObjectProperty(isolate, receiver_obj, key_obj));
712 return *result;
713 }
714
715
716 RUNTIME_FUNCTION(Runtime_AddNamedProperty) {
717 HandleScope scope(isolate);
718 RUNTIME_ASSERT(args.length() == 4);
719
720 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
721 CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
722 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
723 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
724 RUNTIME_ASSERT(
725 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
726 // Compute attributes.
727 PropertyAttributes attributes =
728 static_cast<PropertyAttributes>(unchecked_attributes);
729
730 #ifdef DEBUG
731 uint32_t index = 0;
732 DCHECK(!key->ToArrayIndex(&index));
733 LookupIterator it(object, key, LookupIterator::OWN_SKIP_INTERCEPTOR);
734 Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
735 if (!maybe.has_value) return isolate->heap()->exception();
736 RUNTIME_ASSERT(!it.IsFound());
737 #endif
738
739 Handle<Object> result;
740 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
741 isolate, result,
742 JSObject::SetOwnPropertyIgnoreAttributes(object, key, value, attributes));
743 return *result;
744 }
745
746
747 RUNTIME_FUNCTION(Runtime_SetProperty) {
748 HandleScope scope(isolate);
749 RUNTIME_ASSERT(args.length() == 4);
750
751 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
752 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
753 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
754 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode_arg, 3);
755 StrictMode strict_mode = strict_mode_arg;
756
757 Handle<Object> result;
758 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
759 isolate, result,
760 Runtime::SetObjectProperty(isolate, object, key, value, strict_mode));
761 return *result;
762 }
763
764
765 // Adds an element to an array.
766 // This is used to create an indexed data property into an array.
767 RUNTIME_FUNCTION(Runtime_AddElement) {
768 HandleScope scope(isolate);
769 RUNTIME_ASSERT(args.length() == 4);
770
771 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
772 CONVERT_ARG_HANDLE_CHECKED(Object, key, 1);
773 CONVERT_ARG_HANDLE_CHECKED(Object, value, 2);
774 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
775 RUNTIME_ASSERT(
776 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
777 // Compute attributes.
778 PropertyAttributes attributes =
779 static_cast<PropertyAttributes>(unchecked_attributes);
780
781 uint32_t index = 0;
782 key->ToArrayIndex(&index);
783
784 Handle<Object> result;
785 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
786 isolate, result, JSObject::SetElement(object, index, value, attributes,
787 SLOPPY, false, DEFINE_PROPERTY));
788 return *result;
789 }
790
791
792 RUNTIME_FUNCTION(Runtime_DeleteProperty) {
793 HandleScope scope(isolate);
794 DCHECK(args.length() == 3);
795 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0);
796 CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
797 CONVERT_STRICT_MODE_ARG_CHECKED(strict_mode, 2);
798 JSReceiver::DeleteMode delete_mode = strict_mode == STRICT
799 ? JSReceiver::STRICT_DELETION
800 : JSReceiver::NORMAL_DELETION;
801 Handle<Object> result;
802 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
803 isolate, result, JSReceiver::DeleteProperty(object, key, delete_mode));
804 return *result;
805 }
806
807
808 static Object* HasOwnPropertyImplementation(Isolate* isolate,
809 Handle<JSObject> object,
810 Handle<Name> key) {
811 Maybe<bool> maybe = JSReceiver::HasOwnProperty(object, key);
812 if (!maybe.has_value) return isolate->heap()->exception();
813 if (maybe.value) return isolate->heap()->true_value();
814 // Handle hidden prototypes. If there's a hidden prototype above this thing
815 // then we have to check it for properties, because they are supposed to
816 // look like they are on this object.
817 PrototypeIterator iter(isolate, object);
818 if (!iter.IsAtEnd() &&
819 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter))
820 ->map()
821 ->is_hidden_prototype()) {
822 // TODO(verwaest): The recursion is not necessary for keys that are array
823 // indices. Removing this.
824 return HasOwnPropertyImplementation(
825 isolate, Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter)),
826 key);
827 }
828 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
829 return isolate->heap()->false_value();
830 }
831
832
833 RUNTIME_FUNCTION(Runtime_HasOwnProperty) {
834 HandleScope scope(isolate);
835 DCHECK(args.length() == 2);
836 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0)
837 CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
838
839 uint32_t index;
840 const bool key_is_array_index = key->AsArrayIndex(&index);
841
842 // Only JS objects can have properties.
843 if (object->IsJSObject()) {
844 Handle<JSObject> js_obj = Handle<JSObject>::cast(object);
845 // Fast case: either the key is a real named property or it is not
846 // an array index and there are no interceptors or hidden
847 // prototypes.
848 Maybe<bool> maybe = JSObject::HasRealNamedProperty(js_obj, key);
849 if (!maybe.has_value) return isolate->heap()->exception();
850 DCHECK(!isolate->has_pending_exception());
851 if (maybe.value) {
852 return isolate->heap()->true_value();
853 }
854 Map* map = js_obj->map();
855 if (!key_is_array_index && !map->has_named_interceptor() &&
856 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
857 return isolate->heap()->false_value();
858 }
859 // Slow case.
860 return HasOwnPropertyImplementation(isolate, Handle<JSObject>(js_obj),
861 Handle<Name>(key));
862 } else if (object->IsString() && key_is_array_index) {
863 // Well, there is one exception: Handle [] on strings.
864 Handle<String> string = Handle<String>::cast(object);
865 if (index < static_cast<uint32_t>(string->length())) {
866 return isolate->heap()->true_value();
867 }
868 }
869 return isolate->heap()->false_value();
870 }
871
872
873 RUNTIME_FUNCTION(Runtime_HasProperty) {
874 HandleScope scope(isolate);
875 DCHECK(args.length() == 2);
876 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0);
877 CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
878
879 Maybe<bool> maybe = JSReceiver::HasProperty(receiver, key);
880 if (!maybe.has_value) return isolate->heap()->exception();
881 return isolate->heap()->ToBoolean(maybe.value);
882 }
883
884
885 RUNTIME_FUNCTION(Runtime_HasElement) {
886 HandleScope scope(isolate);
887 DCHECK(args.length() == 2);
888 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0);
889 CONVERT_SMI_ARG_CHECKED(index, 1);
890
891 Maybe<bool> maybe = JSReceiver::HasElement(receiver, index);
892 if (!maybe.has_value) return isolate->heap()->exception();
893 return isolate->heap()->ToBoolean(maybe.value);
894 }
895
896
897 RUNTIME_FUNCTION(Runtime_IsPropertyEnumerable) {
898 HandleScope scope(isolate);
899 DCHECK(args.length() == 2);
900
901 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
902 CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
903
904 Maybe<PropertyAttributes> maybe =
905 JSReceiver::GetOwnPropertyAttributes(object, key);
906 if (!maybe.has_value) return isolate->heap()->exception();
907 if (maybe.value == ABSENT) maybe.value = DONT_ENUM;
908 return isolate->heap()->ToBoolean((maybe.value & DONT_ENUM) == 0);
909 }
910
911
912 RUNTIME_FUNCTION(Runtime_GetPropertyNames) {
913 HandleScope scope(isolate);
914 DCHECK(args.length() == 1);
915 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, object, 0);
916 Handle<JSArray> result;
917
918 isolate->counters()->for_in()->Increment();
919 Handle<FixedArray> elements;
920 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
921 isolate, elements,
922 JSReceiver::GetKeys(object, JSReceiver::INCLUDE_PROTOS));
923 return *isolate->factory()->NewJSArrayWithElements(elements);
924 }
925
926
927 // Returns either a FixedArray as Runtime_GetPropertyNames,
928 // or, if the given object has an enum cache that contains
929 // all enumerable properties of the object and its prototypes
930 // have none, the map of the object. This is used to speed up
931 // the check for deletions during a for-in.
932 RUNTIME_FUNCTION(Runtime_GetPropertyNamesFast) {
933 SealHandleScope shs(isolate);
934 DCHECK(args.length() == 1);
935
936 CONVERT_ARG_CHECKED(JSReceiver, raw_object, 0);
937
938 if (raw_object->IsSimpleEnum()) return raw_object->map();
939
940 HandleScope scope(isolate);
941 Handle<JSReceiver> object(raw_object);
942 Handle<FixedArray> content;
943 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
944 isolate, content,
945 JSReceiver::GetKeys(object, JSReceiver::INCLUDE_PROTOS));
946
947 // Test again, since cache may have been built by preceding call.
948 if (object->IsSimpleEnum()) return object->map();
949
950 return *content;
951 }
952
953
954 // Find the length of the prototype chain that is to be handled as one. If a
955 // prototype object is hidden it is to be viewed as part of the the object it
956 // is prototype for.
957 static int OwnPrototypeChainLength(JSObject* obj) {
958 int count = 1;
959 for (PrototypeIterator iter(obj->GetIsolate(), obj);
960 !iter.IsAtEnd(PrototypeIterator::END_AT_NON_HIDDEN); iter.Advance()) {
961 count++;
962 }
963 return count;
964 }
965
966
967 // Return the names of the own named properties.
968 // args[0]: object
969 // args[1]: PropertyAttributes as int
970 RUNTIME_FUNCTION(Runtime_GetOwnPropertyNames) {
971 HandleScope scope(isolate);
972 DCHECK(args.length() == 2);
973 if (!args[0]->IsJSObject()) {
974 return isolate->heap()->undefined_value();
975 }
976 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
977 CONVERT_SMI_ARG_CHECKED(filter_value, 1);
978 PropertyAttributes filter = static_cast<PropertyAttributes>(filter_value);
979
980 // Skip the global proxy as it has no properties and always delegates to the
981 // real global object.
982 if (obj->IsJSGlobalProxy()) {
983 // Only collect names if access is permitted.
984 if (obj->IsAccessCheckNeeded() &&
985 !isolate->MayNamedAccess(obj, isolate->factory()->undefined_value(),
986 v8::ACCESS_KEYS)) {
987 isolate->ReportFailedAccessCheck(obj, v8::ACCESS_KEYS);
988 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
989 return *isolate->factory()->NewJSArray(0);
990 }
991 PrototypeIterator iter(isolate, obj);
992 obj = Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
993 }
994
995 // Find the number of objects making up this.
996 int length = OwnPrototypeChainLength(*obj);
997
998 // Find the number of own properties for each of the objects.
999 ScopedVector<int> own_property_count(length);
1000 int total_property_count = 0;
1001 {
1002 PrototypeIterator iter(isolate, obj, PrototypeIterator::START_AT_RECEIVER);
1003 for (int i = 0; i < length; i++) {
1004 DCHECK(!iter.IsAtEnd());
1005 Handle<JSObject> jsproto =
1006 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
1007 // Only collect names if access is permitted.
1008 if (jsproto->IsAccessCheckNeeded() &&
1009 !isolate->MayNamedAccess(jsproto,
1010 isolate->factory()->undefined_value(),
1011 v8::ACCESS_KEYS)) {
1012 isolate->ReportFailedAccessCheck(jsproto, v8::ACCESS_KEYS);
1013 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
1014 return *isolate->factory()->NewJSArray(0);
1015 }
1016 int n;
1017 n = jsproto->NumberOfOwnProperties(filter);
1018 own_property_count[i] = n;
1019 total_property_count += n;
1020 iter.Advance();
1021 }
1022 }
1023
1024 // Allocate an array with storage for all the property names.
1025 Handle<FixedArray> names =
1026 isolate->factory()->NewFixedArray(total_property_count);
1027
1028 // Get the property names.
1029 int next_copy_index = 0;
1030 int hidden_strings = 0;
1031 {
1032 PrototypeIterator iter(isolate, obj, PrototypeIterator::START_AT_RECEIVER);
1033 for (int i = 0; i < length; i++) {
1034 DCHECK(!iter.IsAtEnd());
1035 Handle<JSObject> jsproto =
1036 Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
1037 jsproto->GetOwnPropertyNames(*names, next_copy_index, filter);
1038 if (i > 0) {
1039 // Names from hidden prototypes may already have been added
1040 // for inherited function template instances. Count the duplicates
1041 // and stub them out; the final copy pass at the end ignores holes.
1042 for (int j = next_copy_index;
1043 j < next_copy_index + own_property_count[i]; j++) {
1044 Object* name_from_hidden_proto = names->get(j);
1045 for (int k = 0; k < next_copy_index; k++) {
1046 if (names->get(k) != isolate->heap()->hidden_string()) {
1047 Object* name = names->get(k);
1048 if (name_from_hidden_proto == name) {
1049 names->set(j, isolate->heap()->hidden_string());
1050 hidden_strings++;
1051 break;
1052 }
1053 }
1054 }
1055 }
1056 }
1057 next_copy_index += own_property_count[i];
1058
1059 // Hidden properties only show up if the filter does not skip strings.
1060 if ((filter & STRING) == 0 && JSObject::HasHiddenProperties(jsproto)) {
1061 hidden_strings++;
1062 }
1063 iter.Advance();
1064 }
1065 }
1066
1067 // Filter out name of hidden properties object and
1068 // hidden prototype duplicates.
1069 if (hidden_strings > 0) {
1070 Handle<FixedArray> old_names = names;
1071 names = isolate->factory()->NewFixedArray(names->length() - hidden_strings);
1072 int dest_pos = 0;
1073 for (int i = 0; i < total_property_count; i++) {
1074 Object* name = old_names->get(i);
1075 if (name == isolate->heap()->hidden_string()) {
1076 hidden_strings--;
1077 continue;
1078 }
1079 names->set(dest_pos++, name);
1080 }
1081 DCHECK_EQ(0, hidden_strings);
1082 }
1083
1084 return *isolate->factory()->NewJSArrayWithElements(names);
1085 }
1086
1087
1088 // Return the names of the own indexed properties.
1089 // args[0]: object
1090 RUNTIME_FUNCTION(Runtime_GetOwnElementNames) {
1091 HandleScope scope(isolate);
1092 DCHECK(args.length() == 1);
1093 if (!args[0]->IsJSObject()) {
1094 return isolate->heap()->undefined_value();
1095 }
1096 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
1097
1098 int n = obj->NumberOfOwnElements(static_cast<PropertyAttributes>(NONE));
1099 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
1100 obj->GetOwnElementKeys(*names, static_cast<PropertyAttributes>(NONE));
1101 return *isolate->factory()->NewJSArrayWithElements(names);
1102 }
1103
1104
1105 // Return information on whether an object has a named or indexed interceptor.
1106 // args[0]: object
1107 RUNTIME_FUNCTION(Runtime_GetInterceptorInfo) {
1108 HandleScope scope(isolate);
1109 DCHECK(args.length() == 1);
1110 if (!args[0]->IsJSObject()) {
1111 return Smi::FromInt(0);
1112 }
1113 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
1114
1115 int result = 0;
1116 if (obj->HasNamedInterceptor()) result |= 2;
1117 if (obj->HasIndexedInterceptor()) result |= 1;
1118
1119 return Smi::FromInt(result);
1120 }
1121
1122
1123 // Return property names from named interceptor.
1124 // args[0]: object
1125 RUNTIME_FUNCTION(Runtime_GetNamedInterceptorPropertyNames) {
1126 HandleScope scope(isolate);
1127 DCHECK(args.length() == 1);
1128 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
1129
1130 if (obj->HasNamedInterceptor()) {
1131 Handle<JSObject> result;
1132 if (JSObject::GetKeysForNamedInterceptor(obj, obj).ToHandle(&result)) {
1133 return *result;
1134 }
1135 }
1136 return isolate->heap()->undefined_value();
1137 }
1138
1139
1140 // Return element names from indexed interceptor.
1141 // args[0]: object
1142 RUNTIME_FUNCTION(Runtime_GetIndexedInterceptorElementNames) {
1143 HandleScope scope(isolate);
1144 DCHECK(args.length() == 1);
1145 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
1146
1147 if (obj->HasIndexedInterceptor()) {
1148 Handle<JSObject> result;
1149 if (JSObject::GetKeysForIndexedInterceptor(obj, obj).ToHandle(&result)) {
1150 return *result;
1151 }
1152 }
1153 return isolate->heap()->undefined_value();
1154 }
1155
1156
1157 RUNTIME_FUNCTION(Runtime_OwnKeys) {
1158 HandleScope scope(isolate);
1159 DCHECK(args.length() == 1);
1160 CONVERT_ARG_CHECKED(JSObject, raw_object, 0);
1161 Handle<JSObject> object(raw_object);
1162
1163 if (object->IsJSGlobalProxy()) {
1164 // Do access checks before going to the global object.
1165 if (object->IsAccessCheckNeeded() &&
1166 !isolate->MayNamedAccess(object, isolate->factory()->undefined_value(),
1167 v8::ACCESS_KEYS)) {
1168 isolate->ReportFailedAccessCheck(object, v8::ACCESS_KEYS);
1169 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
1170 return *isolate->factory()->NewJSArray(0);
1171 }
1172
1173 PrototypeIterator iter(isolate, object);
1174 // If proxy is detached we simply return an empty array.
1175 if (iter.IsAtEnd()) return *isolate->factory()->NewJSArray(0);
1176 object = Handle<JSObject>::cast(PrototypeIterator::GetCurrent(iter));
1177 }
1178
1179 Handle<FixedArray> contents;
1180 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
1181 isolate, contents, JSReceiver::GetKeys(object, JSReceiver::OWN_ONLY));
1182
1183 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
1184 // property array and since the result is mutable we have to create
1185 // a fresh clone on each invocation.
1186 int length = contents->length();
1187 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
1188 for (int i = 0; i < length; i++) {
1189 Object* entry = contents->get(i);
1190 if (entry->IsString()) {
1191 copy->set(i, entry);
1192 } else {
1193 DCHECK(entry->IsNumber());
1194 HandleScope scope(isolate);
1195 Handle<Object> entry_handle(entry, isolate);
1196 Handle<Object> entry_str =
1197 isolate->factory()->NumberToString(entry_handle);
1198 copy->set(i, *entry_str);
1199 }
1200 }
1201 return *isolate->factory()->NewJSArrayWithElements(copy);
1202 }
1203
1204
1205 RUNTIME_FUNCTION(Runtime_ToFastProperties) {
1206 HandleScope scope(isolate);
1207 DCHECK(args.length() == 1);
1208 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
1209 if (object->IsJSObject() && !object->IsGlobalObject()) {
1210 JSObject::MigrateSlowToFast(Handle<JSObject>::cast(object), 0);
1211 }
1212 return *object;
1213 }
1214
1215
1216 RUNTIME_FUNCTION(Runtime_ToBool) {
1217 SealHandleScope shs(isolate);
1218 DCHECK(args.length() == 1);
1219 CONVERT_ARG_CHECKED(Object, object, 0);
1220
1221 return isolate->heap()->ToBoolean(object->BooleanValue());
1222 }
1223
1224
1225 // Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
1226 // Possible optimizations: put the type string into the oddballs.
1227 RUNTIME_FUNCTION(Runtime_Typeof) {
1228 SealHandleScope shs(isolate);
1229 DCHECK(args.length() == 1);
1230 CONVERT_ARG_CHECKED(Object, obj, 0);
1231 if (obj->IsNumber()) return isolate->heap()->number_string();
1232 HeapObject* heap_obj = HeapObject::cast(obj);
1233
1234 // typeof an undetectable object is 'undefined'
1235 if (heap_obj->map()->is_undetectable()) {
1236 return isolate->heap()->undefined_string();
1237 }
1238
1239 InstanceType instance_type = heap_obj->map()->instance_type();
1240 if (instance_type < FIRST_NONSTRING_TYPE) {
1241 return isolate->heap()->string_string();
1242 }
1243
1244 switch (instance_type) {
1245 case ODDBALL_TYPE:
1246 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
1247 return isolate->heap()->boolean_string();
1248 }
1249 if (heap_obj->IsNull()) {
1250 return isolate->heap()->object_string();
1251 }
1252 DCHECK(heap_obj->IsUndefined());
1253 return isolate->heap()->undefined_string();
1254 case SYMBOL_TYPE:
1255 return isolate->heap()->symbol_string();
1256 case JS_FUNCTION_TYPE:
1257 case JS_FUNCTION_PROXY_TYPE:
1258 return isolate->heap()->function_string();
1259 default:
1260 // For any kind of object not handled above, the spec rule for
1261 // host objects gives that it is okay to return "object"
1262 return isolate->heap()->object_string();
1263 }
1264 }
1265
1266
1267 RUNTIME_FUNCTION(Runtime_Booleanize) {
1268 SealHandleScope shs(isolate);
1269 DCHECK(args.length() == 2);
1270 CONVERT_ARG_CHECKED(Object, value_raw, 0);
1271 CONVERT_SMI_ARG_CHECKED(token_raw, 1);
1272 intptr_t value = reinterpret_cast<intptr_t>(value_raw);
1273 Token::Value token = static_cast<Token::Value>(token_raw);
1274 switch (token) {
1275 case Token::EQ:
1276 case Token::EQ_STRICT:
1277 return isolate->heap()->ToBoolean(value == 0);
1278 case Token::NE:
1279 case Token::NE_STRICT:
1280 return isolate->heap()->ToBoolean(value != 0);
1281 case Token::LT:
1282 return isolate->heap()->ToBoolean(value < 0);
1283 case Token::GT:
1284 return isolate->heap()->ToBoolean(value > 0);
1285 case Token::LTE:
1286 return isolate->heap()->ToBoolean(value <= 0);
1287 case Token::GTE:
1288 return isolate->heap()->ToBoolean(value >= 0);
1289 default:
1290 // This should only happen during natives fuzzing.
1291 return isolate->heap()->undefined_value();
1292 }
1293 }
1294
1295
1296 RUNTIME_FUNCTION(Runtime_NewStringWrapper) {
1297 HandleScope scope(isolate);
1298 DCHECK(args.length() == 1);
1299 CONVERT_ARG_HANDLE_CHECKED(String, value, 0);
1300 return *Object::ToObject(isolate, value).ToHandleChecked();
1301 }
1302
1303
1304 RUNTIME_FUNCTION(Runtime_AllocateHeapNumber) {
1305 HandleScope scope(isolate);
1306 DCHECK(args.length() == 0);
1307 return *isolate->factory()->NewHeapNumber(0);
1308 }
1309
1310
1311 static Object* Runtime_NewObjectHelper(Isolate* isolate,
1312 Handle<Object> constructor,
1313 Handle<AllocationSite> site) {
1314 // If the constructor isn't a proper function we throw a type error.
1315 if (!constructor->IsJSFunction()) {
1316 Vector<Handle<Object> > arguments = HandleVector(&constructor, 1);
1317 THROW_NEW_ERROR_RETURN_FAILURE(isolate,
1318 NewTypeError("not_constructor", arguments));
1319 }
1320
1321 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
1322
1323 // If function should not have prototype, construction is not allowed. In this
1324 // case generated code bailouts here, since function has no initial_map.
1325 if (!function->should_have_prototype() && !function->shared()->bound()) {
1326 Vector<Handle<Object> > arguments = HandleVector(&constructor, 1);
1327 THROW_NEW_ERROR_RETURN_FAILURE(isolate,
1328 NewTypeError("not_constructor", arguments));
1329 }
1330
1331 Debug* debug = isolate->debug();
1332 // Handle stepping into constructors if step into is active.
1333 if (debug->StepInActive()) {
1334 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
1335 }
1336
1337 if (function->has_initial_map()) {
1338 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
1339 // The 'Function' function ignores the receiver object when
1340 // called using 'new' and creates a new JSFunction object that
1341 // is returned. The receiver object is only used for error
1342 // reporting if an error occurs when constructing the new
1343 // JSFunction. Factory::NewJSObject() should not be used to
1344 // allocate JSFunctions since it does not properly initialize
1345 // the shared part of the function. Since the receiver is
1346 // ignored anyway, we use the global object as the receiver
1347 // instead of a new JSFunction object. This way, errors are
1348 // reported the same way whether or not 'Function' is called
1349 // using 'new'.
1350 return isolate->global_proxy();
1351 }
1352 }
1353
1354 // The function should be compiled for the optimization hints to be
1355 // available.
1356 Compiler::EnsureCompiled(function, CLEAR_EXCEPTION);
1357
1358 Handle<JSObject> result;
1359 if (site.is_null()) {
1360 result = isolate->factory()->NewJSObject(function);
1361 } else {
1362 result = isolate->factory()->NewJSObjectWithMemento(function, site);
1363 }
1364
1365 isolate->counters()->constructed_objects()->Increment();
1366 isolate->counters()->constructed_objects_runtime()->Increment();
1367
1368 return *result;
1369 }
1370
1371
1372 RUNTIME_FUNCTION(Runtime_NewObject) {
1373 HandleScope scope(isolate);
1374 DCHECK(args.length() == 1);
1375 CONVERT_ARG_HANDLE_CHECKED(Object, constructor, 0);
1376 return Runtime_NewObjectHelper(isolate, constructor,
1377 Handle<AllocationSite>::null());
1378 }
1379
1380
1381 RUNTIME_FUNCTION(Runtime_NewObjectWithAllocationSite) {
1382 HandleScope scope(isolate);
1383 DCHECK(args.length() == 2);
1384 CONVERT_ARG_HANDLE_CHECKED(Object, constructor, 1);
1385 CONVERT_ARG_HANDLE_CHECKED(Object, feedback, 0);
1386 Handle<AllocationSite> site;
1387 if (feedback->IsAllocationSite()) {
1388 // The feedback can be an AllocationSite or undefined.
1389 site = Handle<AllocationSite>::cast(feedback);
1390 }
1391 return Runtime_NewObjectHelper(isolate, constructor, site);
1392 }
1393
1394
1395 RUNTIME_FUNCTION(Runtime_FinalizeInstanceSize) {
1396 HandleScope scope(isolate);
1397 DCHECK(args.length() == 1);
1398
1399 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
1400 function->CompleteInobjectSlackTracking();
1401
1402 return isolate->heap()->undefined_value();
1403 }
1404
1405
1406 RUNTIME_FUNCTION(Runtime_GlobalProxy) {
1407 SealHandleScope shs(isolate);
1408 DCHECK(args.length() == 1);
1409 CONVERT_ARG_CHECKED(Object, global, 0);
1410 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
1411 return JSGlobalObject::cast(global)->global_proxy();
1412 }
1413
1414
1415 RUNTIME_FUNCTION(Runtime_IsAttachedGlobal) {
1416 SealHandleScope shs(isolate);
1417 DCHECK(args.length() == 1);
1418 CONVERT_ARG_CHECKED(Object, global, 0);
1419 if (!global->IsJSGlobalObject()) return isolate->heap()->false_value();
1420 return isolate->heap()->ToBoolean(
1421 !JSGlobalObject::cast(global)->IsDetached());
1422 }
1423
1424
1425 RUNTIME_FUNCTION(Runtime_LookupAccessor) {
1426 HandleScope scope(isolate);
1427 DCHECK(args.length() == 3);
1428 CONVERT_ARG_HANDLE_CHECKED(JSReceiver, receiver, 0);
1429 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
1430 CONVERT_SMI_ARG_CHECKED(flag, 2);
1431 AccessorComponent component = flag == 0 ? ACCESSOR_GETTER : ACCESSOR_SETTER;
1432 if (!receiver->IsJSObject()) return isolate->heap()->undefined_value();
1433 Handle<Object> result;
1434 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
1435 isolate, result,
1436 JSObject::GetAccessor(Handle<JSObject>::cast(receiver), name, component));
1437 return *result;
1438 }
1439
1440
1441 RUNTIME_FUNCTION(Runtime_LoadMutableDouble) {
1442 HandleScope scope(isolate);
1443 DCHECK(args.length() == 2);
1444 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
1445 CONVERT_ARG_HANDLE_CHECKED(Smi, index, 1);
1446 RUNTIME_ASSERT((index->value() & 1) == 1);
1447 FieldIndex field_index =
1448 FieldIndex::ForLoadByFieldIndex(object->map(), index->value());
1449 if (field_index.is_inobject()) {
1450 RUNTIME_ASSERT(field_index.property_index() <
1451 object->map()->inobject_properties());
1452 } else {
1453 RUNTIME_ASSERT(field_index.outobject_array_index() <
1454 object->properties()->length());
1455 }
1456 Handle<Object> raw_value(object->RawFastPropertyAt(field_index), isolate);
1457 RUNTIME_ASSERT(raw_value->IsMutableHeapNumber());
1458 return *Object::WrapForRead(isolate, raw_value, Representation::Double());
1459 }
1460
1461
1462 RUNTIME_FUNCTION(Runtime_TryMigrateInstance) {
1463 HandleScope scope(isolate);
1464 DCHECK(args.length() == 1);
1465 CONVERT_ARG_HANDLE_CHECKED(Object, object, 0);
1466 if (!object->IsJSObject()) return Smi::FromInt(0);
1467 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
1468 if (!js_object->map()->is_deprecated()) return Smi::FromInt(0);
1469 // This call must not cause lazy deopts, because it's called from deferred
1470 // code where we can't handle lazy deopts for lack of a suitable bailout
1471 // ID. So we just try migration and signal failure if necessary,
1472 // which will also trigger a deopt.
1473 if (!JSObject::TryMigrateInstance(js_object)) return Smi::FromInt(0);
1474 return *object;
1475 }
1476
1477
1478 RUNTIME_FUNCTION(Runtime_IsJSGlobalProxy) {
1479 SealHandleScope shs(isolate);
1480 DCHECK(args.length() == 1);
1481 CONVERT_ARG_CHECKED(Object, obj, 0);
1482 return isolate->heap()->ToBoolean(obj->IsJSGlobalProxy());
1483 }
1484
1485
1486 static bool IsValidAccessor(Handle<Object> obj) {
1487 return obj->IsUndefined() || obj->IsSpecFunction() || obj->IsNull();
1488 }
1489
1490
1491 // Implements part of 8.12.9 DefineOwnProperty.
1492 // There are 3 cases that lead here:
1493 // Step 4b - define a new accessor property.
1494 // Steps 9c & 12 - replace an existing data property with an accessor property.
1495 // Step 12 - update an existing accessor property with an accessor or generic
1496 // descriptor.
1497 RUNTIME_FUNCTION(Runtime_DefineAccessorPropertyUnchecked) {
1498 HandleScope scope(isolate);
1499 DCHECK(args.length() == 5);
1500 CONVERT_ARG_HANDLE_CHECKED(JSObject, obj, 0);
1501 RUNTIME_ASSERT(!obj->IsNull());
1502 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
1503 CONVERT_ARG_HANDLE_CHECKED(Object, getter, 2);
1504 RUNTIME_ASSERT(IsValidAccessor(getter));
1505 CONVERT_ARG_HANDLE_CHECKED(Object, setter, 3);
1506 RUNTIME_ASSERT(IsValidAccessor(setter));
1507 CONVERT_SMI_ARG_CHECKED(unchecked, 4);
1508 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
1509 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
1510
1511 bool fast = obj->HasFastProperties();
1512 RETURN_FAILURE_ON_EXCEPTION(
1513 isolate, JSObject::DefineAccessor(obj, name, getter, setter, attr));
1514 if (fast) JSObject::MigrateSlowToFast(obj, 0);
1515 return isolate->heap()->undefined_value();
1516 }
1517
1518
1519 // Implements part of 8.12.9 DefineOwnProperty.
1520 // There are 3 cases that lead here:
1521 // Step 4a - define a new data property.
1522 // Steps 9b & 12 - replace an existing accessor property with a data property.
1523 // Step 12 - update an existing data property with a data or generic
1524 // descriptor.
1525 RUNTIME_FUNCTION(Runtime_DefineDataPropertyUnchecked) {
1526 HandleScope scope(isolate);
1527 DCHECK(args.length() == 4);
1528 CONVERT_ARG_HANDLE_CHECKED(JSObject, js_object, 0);
1529 CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
1530 CONVERT_ARG_HANDLE_CHECKED(Object, obj_value, 2);
1531 CONVERT_SMI_ARG_CHECKED(unchecked, 3);
1532 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
1533 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
1534
1535 LookupIterator it(js_object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
1536 if (it.IsFound() && it.state() == LookupIterator::ACCESS_CHECK) {
1537 if (!isolate->MayNamedAccess(js_object, name, v8::ACCESS_SET)) {
1538 return isolate->heap()->undefined_value();
1539 }
1540 it.Next();
1541 }
1542
1543 // Take special care when attributes are different and there is already
1544 // a property.
1545 if (it.state() == LookupIterator::ACCESSOR) {
1546 // Use IgnoreAttributes version since a readonly property may be
1547 // overridden and SetProperty does not allow this.
1548 Handle<Object> result;
1549 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
1550 isolate, result,
1551 JSObject::SetOwnPropertyIgnoreAttributes(
1552 js_object, name, obj_value, attr, JSObject::DONT_FORCE_FIELD));
1553 return *result;
1554 }
1555
1556 Handle<Object> result;
1557 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
1558 isolate, result,
1559 Runtime::DefineObjectProperty(js_object, name, obj_value, attr));
1560 return *result;
1561 }
1562
1563
1564 // Return property without being observable by accessors or interceptors.
1565 RUNTIME_FUNCTION(Runtime_GetDataProperty) {
1566 HandleScope scope(isolate);
1567 DCHECK(args.length() == 2);
1568 CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
1569 CONVERT_ARG_HANDLE_CHECKED(Name, key, 1);
1570 return *JSObject::GetDataProperty(object, key);
1571 }
1572
1573
1574 RUNTIME_FUNCTION(RuntimeReference_ValueOf) {
1575 SealHandleScope shs(isolate);
1576 DCHECK(args.length() == 1);
1577 CONVERT_ARG_CHECKED(Object, obj, 0);
1578 if (!obj->IsJSValue()) return obj;
1579 return JSValue::cast(obj)->value();
1580 }
1581
1582
1583 RUNTIME_FUNCTION(RuntimeReference_SetValueOf) {
1584 SealHandleScope shs(isolate);
1585 DCHECK(args.length() == 2);
1586 CONVERT_ARG_CHECKED(Object, obj, 0);
1587 CONVERT_ARG_CHECKED(Object, value, 1);
1588 if (!obj->IsJSValue()) return value;
1589 JSValue::cast(obj)->set_value(value);
1590 return value;
1591 }
1592
1593
1594 RUNTIME_FUNCTION(RuntimeReference_ObjectEquals) {
1595 SealHandleScope shs(isolate);
1596 DCHECK(args.length() == 2);
1597 CONVERT_ARG_CHECKED(Object, obj1, 0);
1598 CONVERT_ARG_CHECKED(Object, obj2, 1);
1599 return isolate->heap()->ToBoolean(obj1 == obj2);
1600 }
1601
1602
1603 RUNTIME_FUNCTION(RuntimeReference_IsObject) {
1604 SealHandleScope shs(isolate);
1605 DCHECK(args.length() == 1);
1606 CONVERT_ARG_CHECKED(Object, obj, 0);
1607 if (!obj->IsHeapObject()) return isolate->heap()->false_value();
1608 if (obj->IsNull()) return isolate->heap()->true_value();
1609 if (obj->IsUndetectableObject()) return isolate->heap()->false_value();
1610 Map* map = HeapObject::cast(obj)->map();
1611 bool is_non_callable_spec_object =
1612 map->instance_type() >= FIRST_NONCALLABLE_SPEC_OBJECT_TYPE &&
1613 map->instance_type() <= LAST_NONCALLABLE_SPEC_OBJECT_TYPE;
1614 return isolate->heap()->ToBoolean(is_non_callable_spec_object);
1615 }
1616
1617
1618 RUNTIME_FUNCTION(RuntimeReference_IsUndetectableObject) {
1619 SealHandleScope shs(isolate);
1620 DCHECK(args.length() == 1);
1621 CONVERT_ARG_CHECKED(Object, obj, 0);
1622 return isolate->heap()->ToBoolean(obj->IsUndetectableObject());
1623 }
1624
1625
1626 RUNTIME_FUNCTION(RuntimeReference_IsSpecObject) {
1627 SealHandleScope shs(isolate);
1628 DCHECK(args.length() == 1);
1629 CONVERT_ARG_CHECKED(Object, obj, 0);
1630 return isolate->heap()->ToBoolean(obj->IsSpecObject());
1631 }
1632
1633
1634 RUNTIME_FUNCTION(RuntimeReference_ClassOf) {
1635 SealHandleScope shs(isolate);
1636 DCHECK(args.length() == 1);
1637 CONVERT_ARG_CHECKED(Object, obj, 0);
1638 if (!obj->IsJSReceiver()) return isolate->heap()->null_value();
1639 return JSReceiver::cast(obj)->class_name();
1640 }
1641 }
1642 } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/runtime/runtime-numbers.cc ('k') | src/runtime/runtime-strings.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698