Line data Source code
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 <stdlib.h>
8 : #include <limits>
9 :
10 : #include "src/accessors.h"
11 : #include "src/arguments.h"
12 : #include "src/debug/debug.h"
13 : #include "src/elements.h"
14 : #include "src/isolate-inl.h"
15 : #include "src/messages.h"
16 : #include "src/runtime/runtime.h"
17 :
18 : namespace v8 {
19 : namespace internal {
20 :
21 :
22 56 : RUNTIME_FUNCTION(Runtime_ThrowUnsupportedSuperError) {
23 28 : HandleScope scope(isolate);
24 : DCHECK_EQ(0, args.length());
25 56 : THROW_NEW_ERROR_RETURN_FAILURE(
26 28 : isolate, NewReferenceError(MessageTemplate::kUnsupportedSuper));
27 : }
28 :
29 :
30 848 : RUNTIME_FUNCTION(Runtime_ThrowConstructorNonCallableError) {
31 424 : HandleScope scope(isolate);
32 : DCHECK_EQ(1, args.length());
33 848 : CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, 0);
34 424 : Handle<String> name(constructor->shared()->name(), isolate);
35 848 : THROW_NEW_ERROR_RETURN_FAILURE(
36 424 : isolate, NewTypeError(MessageTemplate::kConstructorNonCallable, name));
37 : }
38 :
39 :
40 144 : RUNTIME_FUNCTION(Runtime_ThrowStaticPrototypeError) {
41 72 : HandleScope scope(isolate);
42 : DCHECK_EQ(0, args.length());
43 144 : THROW_NEW_ERROR_RETURN_FAILURE(
44 72 : isolate, NewTypeError(MessageTemplate::kStaticPrototype));
45 : }
46 :
47 138 : RUNTIME_FUNCTION(Runtime_ThrowSuperAlreadyCalledError) {
48 69 : HandleScope scope(isolate);
49 : DCHECK_EQ(0, args.length());
50 138 : THROW_NEW_ERROR_RETURN_FAILURE(
51 69 : isolate, NewReferenceError(MessageTemplate::kSuperAlreadyCalled));
52 : }
53 :
54 354 : RUNTIME_FUNCTION(Runtime_ThrowSuperNotCalled) {
55 177 : HandleScope scope(isolate);
56 : DCHECK_EQ(0, args.length());
57 354 : THROW_NEW_ERROR_RETURN_FAILURE(
58 177 : isolate, NewReferenceError(MessageTemplate::kSuperNotCalled));
59 : }
60 :
61 : namespace {
62 :
63 115 : Object* ThrowNotSuperConstructor(Isolate* isolate, Handle<Object> constructor,
64 : Handle<JSFunction> function) {
65 : Handle<String> super_name;
66 115 : if (constructor->IsJSFunction()) {
67 : super_name = handle(Handle<JSFunction>::cast(constructor)->shared()->name(),
68 : isolate);
69 49 : } else if (constructor->IsOddball()) {
70 : DCHECK(constructor->IsNull(isolate));
71 : super_name = isolate->factory()->null_string();
72 : } else {
73 0 : super_name = Object::NoSideEffectsToString(isolate, constructor);
74 : }
75 : // null constructor
76 115 : if (super_name->length() == 0) {
77 : super_name = isolate->factory()->null_string();
78 : }
79 : Handle<String> function_name(function->shared()->name(), isolate);
80 : // anonymous class
81 115 : if (function_name->length() == 0) {
82 72 : THROW_NEW_ERROR_RETURN_FAILURE(
83 : isolate,
84 : NewTypeError(MessageTemplate::kNotSuperConstructorAnonymousClass,
85 : super_name));
86 : }
87 158 : THROW_NEW_ERROR_RETURN_FAILURE(
88 : isolate, NewTypeError(MessageTemplate::kNotSuperConstructor, super_name,
89 : function_name));
90 : }
91 :
92 : } // namespace
93 :
94 174 : RUNTIME_FUNCTION(Runtime_ThrowNotSuperConstructor) {
95 87 : HandleScope scope(isolate);
96 : DCHECK_EQ(2, args.length());
97 87 : CONVERT_ARG_HANDLE_CHECKED(Object, constructor, 0);
98 174 : CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 1);
99 87 : return ThrowNotSuperConstructor(isolate, constructor, function);
100 : }
101 :
102 270 : RUNTIME_FUNCTION(Runtime_HomeObjectSymbol) {
103 : DCHECK_EQ(0, args.length());
104 135 : return isolate->heap()->home_object_symbol();
105 : }
106 :
107 82979 : static MaybeHandle<Object> DefineClass(Isolate* isolate,
108 : Handle<Object> super_class,
109 : Handle<JSFunction> constructor,
110 : int start_position, int end_position) {
111 : Handle<Object> prototype_parent;
112 : Handle<Object> constructor_parent;
113 :
114 82979 : if (super_class->IsTheHole(isolate)) {
115 73858 : prototype_parent = isolate->initial_object_prototype();
116 : } else {
117 9121 : if (super_class->IsNull(isolate)) {
118 : prototype_parent = isolate->factory()->null_value();
119 8860 : } else if (super_class->IsConstructor()) {
120 : DCHECK(!super_class->IsJSFunction() ||
121 : !IsResumableFunction(
122 : Handle<JSFunction>::cast(super_class)->shared()->kind()));
123 17324 : ASSIGN_RETURN_ON_EXCEPTION(
124 : isolate, prototype_parent,
125 : Runtime::GetObjectProperty(isolate, super_class,
126 : isolate->factory()->prototype_string()),
127 : Object);
128 17306 : if (!prototype_parent->IsNull(isolate) &&
129 : !prototype_parent->IsJSReceiver()) {
130 90 : THROW_NEW_ERROR(
131 : isolate, NewTypeError(MessageTemplate::kPrototypeParentNotAnObject,
132 : prototype_parent),
133 : Object);
134 : }
135 : constructor_parent = super_class;
136 : } else {
137 396 : THROW_NEW_ERROR(isolate,
138 : NewTypeError(MessageTemplate::kExtendsValueNotConstructor,
139 : super_class),
140 : Object);
141 : }
142 : }
143 :
144 : Handle<Map> map =
145 82736 : isolate->factory()->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
146 : map->set_is_prototype_map(true);
147 82736 : Map::SetPrototype(map, prototype_parent);
148 : map->SetConstructor(*constructor);
149 82736 : Handle<JSObject> prototype = isolate->factory()->NewJSObjectFromMap(map);
150 :
151 82736 : JSFunction::SetPrototype(constructor, prototype);
152 : PropertyAttributes attribs =
153 : static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY);
154 165472 : RETURN_ON_EXCEPTION(isolate,
155 : JSObject::SetOwnPropertyIgnoreAttributes(
156 : constructor, isolate->factory()->prototype_string(),
157 : prototype, attribs),
158 : Object);
159 :
160 82736 : if (!constructor_parent.is_null()) {
161 8617 : MAYBE_RETURN_NULL(JSObject::SetPrototype(constructor, constructor_parent,
162 : false, Object::THROW_ON_ERROR));
163 : }
164 :
165 : JSObject::AddProperty(prototype, isolate->factory()->constructor_string(),
166 82736 : constructor, DONT_ENUM);
167 :
168 : // Install private properties that are used to construct the FunctionToString.
169 165472 : RETURN_ON_EXCEPTION(
170 : isolate,
171 : Object::SetProperty(
172 : constructor, isolate->factory()->class_start_position_symbol(),
173 : handle(Smi::FromInt(start_position), isolate), LanguageMode::kStrict),
174 : Object);
175 165472 : RETURN_ON_EXCEPTION(
176 : isolate,
177 : Object::SetProperty(
178 : constructor, isolate->factory()->class_end_position_symbol(),
179 : handle(Smi::FromInt(end_position), isolate), LanguageMode::kStrict),
180 : Object);
181 :
182 : // Caller already has access to constructor, so return the prototype.
183 82736 : return prototype;
184 : }
185 :
186 :
187 165958 : RUNTIME_FUNCTION(Runtime_DefineClass) {
188 82979 : HandleScope scope(isolate);
189 : DCHECK_EQ(4, args.length());
190 82979 : CONVERT_ARG_HANDLE_CHECKED(Object, super_class, 0);
191 165958 : CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, 1);
192 165958 : CONVERT_SMI_ARG_CHECKED(start_position, 2);
193 165958 : CONVERT_SMI_ARG_CHECKED(end_position, 3);
194 :
195 165958 : RETURN_RESULT_OR_FAILURE(
196 : isolate, DefineClass(isolate, super_class, constructor, start_position,
197 82979 : end_position));
198 : }
199 :
200 : namespace {
201 70014 : void InstallClassNameAccessor(Isolate* isolate, Handle<JSObject> object) {
202 : PropertyAttributes attrs =
203 : static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY);
204 : // Cannot fail since this should only be called when creating an object
205 : // literal.
206 140028 : CHECK(!JSObject::SetAccessor(
207 : object, Accessors::FunctionNameInfo(object->GetIsolate(), attrs))
208 : .is_null());
209 70014 : }
210 : } // anonymous namespace
211 :
212 137292 : RUNTIME_FUNCTION(Runtime_InstallClassNameAccessor) {
213 68646 : HandleScope scope(isolate);
214 : DCHECK_EQ(1, args.length());
215 137292 : CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
216 68646 : InstallClassNameAccessor(isolate, object);
217 68646 : return *object;
218 : }
219 :
220 2772 : RUNTIME_FUNCTION(Runtime_InstallClassNameAccessorWithCheck) {
221 1386 : HandleScope scope(isolate);
222 : DCHECK_EQ(1, args.length());
223 2772 : CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
224 :
225 : // If a property named "name" is already defined, exit.
226 1386 : Handle<Name> key = isolate->factory()->name_string();
227 2772 : if (JSObject::HasRealNamedProperty(object, key).FromMaybe(false)) {
228 : return *object;
229 : }
230 :
231 : // Define the "name" accessor.
232 1368 : InstallClassNameAccessor(isolate, object);
233 1386 : return *object;
234 : }
235 :
236 : namespace {
237 :
238 : enum class SuperMode { kLoad, kStore };
239 :
240 4065 : MaybeHandle<JSReceiver> GetSuperHolder(
241 0 : Isolate* isolate, Handle<Object> receiver, Handle<JSObject> home_object,
242 : SuperMode mode, MaybeHandle<Name> maybe_name, uint32_t index) {
243 4065 : if (home_object->IsAccessCheckNeeded() &&
244 0 : !isolate->MayAccess(handle(isolate->context()), home_object)) {
245 0 : isolate->ReportFailedAccessCheck(home_object);
246 0 : RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, JSReceiver);
247 : }
248 :
249 4065 : PrototypeIterator iter(isolate, home_object);
250 : Handle<Object> proto = PrototypeIterator::GetCurrent(iter);
251 4065 : if (!proto->IsJSReceiver()) {
252 : MessageTemplate::Template message =
253 : mode == SuperMode::kLoad ? MessageTemplate::kNonObjectPropertyLoad
254 72 : : MessageTemplate::kNonObjectPropertyStore;
255 : Handle<Name> name;
256 72 : if (!maybe_name.ToHandle(&name)) {
257 36 : name = isolate->factory()->Uint32ToString(index);
258 : }
259 144 : THROW_NEW_ERROR(isolate, NewTypeError(message, name, proto), JSReceiver);
260 : }
261 3993 : return Handle<JSReceiver>::cast(proto);
262 : }
263 :
264 2136 : MaybeHandle<Object> LoadFromSuper(Isolate* isolate, Handle<Object> receiver,
265 : Handle<JSObject> home_object,
266 : Handle<Name> name) {
267 : Handle<JSReceiver> holder;
268 4272 : ASSIGN_RETURN_ON_EXCEPTION(
269 : isolate, holder,
270 : GetSuperHolder(isolate, receiver, home_object, SuperMode::kLoad, name, 0),
271 : Object);
272 2118 : LookupIterator it(receiver, name, holder);
273 : Handle<Object> result;
274 4236 : ASSIGN_RETURN_ON_EXCEPTION(isolate, result, Object::GetProperty(&it), Object);
275 2118 : return result;
276 : }
277 :
278 486 : MaybeHandle<Object> LoadElementFromSuper(Isolate* isolate,
279 : Handle<Object> receiver,
280 : Handle<JSObject> home_object,
281 : uint32_t index) {
282 : Handle<JSReceiver> holder;
283 972 : ASSIGN_RETURN_ON_EXCEPTION(
284 : isolate, holder,
285 : GetSuperHolder(isolate, receiver, home_object, SuperMode::kLoad,
286 : MaybeHandle<Name>(), index),
287 : Object);
288 : LookupIterator it(isolate, receiver, index, holder);
289 : Handle<Object> result;
290 936 : ASSIGN_RETURN_ON_EXCEPTION(isolate, result, Object::GetProperty(&it), Object);
291 468 : return result;
292 : }
293 :
294 : } // anonymous namespace
295 :
296 3210 : RUNTIME_FUNCTION(Runtime_LoadFromSuper) {
297 1605 : HandleScope scope(isolate);
298 : DCHECK_EQ(3, args.length());
299 1605 : CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 0);
300 3210 : CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 1);
301 3210 : CONVERT_ARG_HANDLE_CHECKED(Name, name, 2);
302 :
303 3210 : RETURN_RESULT_OR_FAILURE(isolate,
304 1605 : LoadFromSuper(isolate, receiver, home_object, name));
305 : }
306 :
307 :
308 2070 : RUNTIME_FUNCTION(Runtime_LoadKeyedFromSuper) {
309 1035 : HandleScope scope(isolate);
310 : DCHECK_EQ(3, args.length());
311 1035 : CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 0);
312 2070 : CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 1);
313 1035 : CONVERT_ARG_HANDLE_CHECKED(Object, key, 2);
314 :
315 1035 : uint32_t index = 0;
316 :
317 1035 : if (key->ToArrayIndex(&index)) {
318 918 : RETURN_RESULT_OR_FAILURE(
319 : isolate, LoadElementFromSuper(isolate, receiver, home_object, index));
320 : }
321 :
322 : Handle<Name> name;
323 1152 : ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name,
324 : Object::ToName(isolate, key));
325 : // TODO(verwaest): Unify using LookupIterator.
326 558 : if (name->AsArrayIndex(&index)) {
327 54 : RETURN_RESULT_OR_FAILURE(
328 : isolate, LoadElementFromSuper(isolate, receiver, home_object, index));
329 : }
330 1062 : RETURN_RESULT_OR_FAILURE(isolate,
331 1035 : LoadFromSuper(isolate, receiver, home_object, name));
332 : }
333 :
334 : namespace {
335 :
336 1002 : MaybeHandle<Object> StoreToSuper(Isolate* isolate, Handle<JSObject> home_object,
337 : Handle<Object> receiver, Handle<Name> name,
338 : Handle<Object> value,
339 : LanguageMode language_mode) {
340 : Handle<JSReceiver> holder;
341 2004 : ASSIGN_RETURN_ON_EXCEPTION(isolate, holder,
342 : GetSuperHolder(isolate, receiver, home_object,
343 : SuperMode::kStore, name, 0),
344 : Object);
345 984 : LookupIterator it(receiver, name, holder);
346 984 : MAYBE_RETURN(Object::SetSuperProperty(&it, value, language_mode,
347 : Object::CERTAINLY_NOT_STORE_FROM_KEYED),
348 : MaybeHandle<Object>());
349 799 : return value;
350 : }
351 :
352 441 : MaybeHandle<Object> StoreElementToSuper(Isolate* isolate,
353 : Handle<JSObject> home_object,
354 : Handle<Object> receiver, uint32_t index,
355 : Handle<Object> value,
356 : LanguageMode language_mode) {
357 : Handle<JSReceiver> holder;
358 882 : ASSIGN_RETURN_ON_EXCEPTION(
359 : isolate, holder,
360 : GetSuperHolder(isolate, receiver, home_object, SuperMode::kStore,
361 : MaybeHandle<Name>(), index),
362 : Object);
363 : LookupIterator it(isolate, receiver, index, holder);
364 423 : MAYBE_RETURN(Object::SetSuperProperty(&it, value, language_mode,
365 : Object::MAY_BE_STORE_FROM_KEYED),
366 : MaybeHandle<Object>());
367 333 : return value;
368 : }
369 :
370 : } // anonymous namespace
371 :
372 508 : RUNTIME_FUNCTION(Runtime_StoreToSuper_Strict) {
373 254 : HandleScope scope(isolate);
374 : DCHECK_EQ(4, args.length());
375 254 : CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 0);
376 508 : CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 1);
377 508 : CONVERT_ARG_HANDLE_CHECKED(Name, name, 2);
378 254 : CONVERT_ARG_HANDLE_CHECKED(Object, value, 3);
379 :
380 508 : RETURN_RESULT_OR_FAILURE(
381 : isolate, StoreToSuper(isolate, home_object, receiver, name, value,
382 254 : LanguageMode::kStrict));
383 : }
384 :
385 :
386 572 : RUNTIME_FUNCTION(Runtime_StoreToSuper_Sloppy) {
387 286 : HandleScope scope(isolate);
388 : DCHECK_EQ(4, args.length());
389 286 : CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 0);
390 572 : CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 1);
391 572 : CONVERT_ARG_HANDLE_CHECKED(Name, name, 2);
392 286 : CONVERT_ARG_HANDLE_CHECKED(Object, value, 3);
393 :
394 572 : RETURN_RESULT_OR_FAILURE(
395 : isolate, StoreToSuper(isolate, home_object, receiver, name, value,
396 286 : LanguageMode::kSloppy));
397 : }
398 :
399 921 : static MaybeHandle<Object> StoreKeyedToSuper(
400 : Isolate* isolate, Handle<JSObject> home_object, Handle<Object> receiver,
401 : Handle<Object> key, Handle<Object> value, LanguageMode language_mode) {
402 921 : uint32_t index = 0;
403 :
404 921 : if (key->ToArrayIndex(&index)) {
405 : return StoreElementToSuper(isolate, home_object, receiver, index, value,
406 423 : language_mode);
407 : }
408 : Handle<Name> name;
409 996 : ASSIGN_RETURN_ON_EXCEPTION(isolate, name, Object::ToName(isolate, key),
410 : Object);
411 : // TODO(verwaest): Unify using LookupIterator.
412 480 : if (name->AsArrayIndex(&index)) {
413 : return StoreElementToSuper(isolate, home_object, receiver, index, value,
414 18 : language_mode);
415 : }
416 : return StoreToSuper(isolate, home_object, receiver, name, value,
417 462 : language_mode);
418 : }
419 :
420 :
421 630 : RUNTIME_FUNCTION(Runtime_StoreKeyedToSuper_Strict) {
422 315 : HandleScope scope(isolate);
423 : DCHECK_EQ(4, args.length());
424 315 : CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 0);
425 630 : CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 1);
426 315 : CONVERT_ARG_HANDLE_CHECKED(Object, key, 2);
427 315 : CONVERT_ARG_HANDLE_CHECKED(Object, value, 3);
428 :
429 630 : RETURN_RESULT_OR_FAILURE(
430 : isolate, StoreKeyedToSuper(isolate, home_object, receiver, key, value,
431 315 : LanguageMode::kStrict));
432 : }
433 :
434 :
435 1212 : RUNTIME_FUNCTION(Runtime_StoreKeyedToSuper_Sloppy) {
436 606 : HandleScope scope(isolate);
437 : DCHECK_EQ(4, args.length());
438 606 : CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 0);
439 1212 : CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 1);
440 606 : CONVERT_ARG_HANDLE_CHECKED(Object, key, 2);
441 606 : CONVERT_ARG_HANDLE_CHECKED(Object, value, 3);
442 :
443 1212 : RETURN_RESULT_OR_FAILURE(
444 : isolate, StoreKeyedToSuper(isolate, home_object, receiver, key, value,
445 606 : LanguageMode::kSloppy));
446 : }
447 :
448 :
449 68 : RUNTIME_FUNCTION(Runtime_GetSuperConstructor) {
450 : SealHandleScope shs(isolate);
451 : DCHECK_EQ(1, args.length());
452 68 : CONVERT_ARG_CHECKED(JSFunction, active_function, 0);
453 34 : Object* prototype = active_function->map()->prototype();
454 34 : if (!prototype->IsConstructor()) {
455 28 : HandleScope scope(isolate);
456 : return ThrowNotSuperConstructor(isolate, handle(prototype, isolate),
457 28 : handle(active_function, isolate));
458 : }
459 : return prototype;
460 : }
461 :
462 : } // namespace internal
463 : } // namespace v8
|