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