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