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