• 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/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 
84 
DefineClass(Isolate * isolate,Handle<Object> name,Handle<Object> super_class,Handle<JSFunction> constructor,int start_position,int end_position)85 static MaybeHandle<Object> DefineClass(Isolate* isolate, Handle<Object> name,
86                                        Handle<Object> super_class,
87                                        Handle<JSFunction> constructor,
88                                        int start_position, int end_position) {
89   Handle<Object> prototype_parent;
90   Handle<Object> constructor_parent;
91 
92   if (super_class->IsTheHole()) {
93     prototype_parent = isolate->initial_object_prototype();
94   } else {
95     if (super_class->IsNull()) {
96       prototype_parent = isolate->factory()->null_value();
97     } else if (super_class->IsConstructor()) {
98       if (super_class->IsJSFunction() &&
99           Handle<JSFunction>::cast(super_class)->shared()->is_generator()) {
100         THROW_NEW_ERROR(
101             isolate,
102             NewTypeError(MessageTemplate::kExtendsValueGenerator, super_class),
103             Object);
104       }
105       ASSIGN_RETURN_ON_EXCEPTION(
106           isolate, prototype_parent,
107           Runtime::GetObjectProperty(isolate, super_class,
108                                      isolate->factory()->prototype_string(),
109                                      SLOPPY),
110           Object);
111       if (!prototype_parent->IsNull() && !prototype_parent->IsJSReceiver()) {
112         THROW_NEW_ERROR(
113             isolate, NewTypeError(MessageTemplate::kPrototypeParentNotAnObject,
114                                   prototype_parent),
115             Object);
116       }
117       constructor_parent = super_class;
118     } else {
119       THROW_NEW_ERROR(
120           isolate,
121           NewTypeError(MessageTemplate::kExtendsValueNotFunction, super_class),
122           Object);
123     }
124   }
125 
126   Handle<Map> map =
127       isolate->factory()->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
128   map->set_is_prototype_map(true);
129   if (constructor->map()->is_strong()) {
130     map->set_is_strong();
131     if (super_class->IsNull()) {
132       // Strong class is not permitted to extend null.
133       THROW_NEW_ERROR(isolate, NewTypeError(MessageTemplate::kStrongExtendNull),
134                       Object);
135     }
136   }
137   Map::SetPrototype(map, prototype_parent);
138   map->SetConstructor(*constructor);
139   Handle<JSObject> prototype = isolate->factory()->NewJSObjectFromMap(map);
140 
141   Handle<String> name_string = name->IsString()
142                                    ? Handle<String>::cast(name)
143                                    : isolate->factory()->empty_string();
144   constructor->shared()->set_name(*name_string);
145 
146   if (!super_class->IsTheHole()) {
147     // Derived classes, just like builtins, don't create implicit receivers in
148     // [[construct]]. Instead they just set up new.target and call into the
149     // constructor. Hence we can reuse the builtins construct stub for derived
150     // classes.
151     Handle<Code> stub(isolate->builtins()->JSBuiltinsConstructStub());
152     constructor->shared()->set_construct_stub(*stub);
153   }
154 
155   JSFunction::SetPrototype(constructor, prototype);
156   PropertyAttributes attribs =
157       static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY);
158   RETURN_ON_EXCEPTION(isolate,
159                       JSObject::SetOwnPropertyIgnoreAttributes(
160                           constructor, isolate->factory()->prototype_string(),
161                           prototype, attribs),
162                       Object);
163 
164   // TODO(arv): Only do this conditionally.
165   Handle<Symbol> home_object_symbol(isolate->heap()->home_object_symbol());
166   RETURN_ON_EXCEPTION(
167       isolate, JSObject::SetOwnPropertyIgnoreAttributes(
168                    constructor, home_object_symbol, prototype, DONT_ENUM),
169       Object);
170 
171   if (!constructor_parent.is_null()) {
172     MAYBE_RETURN_NULL(JSObject::SetPrototype(constructor, constructor_parent,
173                                              false, Object::THROW_ON_ERROR));
174   }
175 
176   JSObject::AddProperty(prototype, isolate->factory()->constructor_string(),
177                         constructor, DONT_ENUM);
178 
179   // Install private properties that are used to construct the FunctionToString.
180   RETURN_ON_EXCEPTION(
181       isolate,
182       Object::SetProperty(
183           constructor, isolate->factory()->class_start_position_symbol(),
184           handle(Smi::FromInt(start_position), isolate), STRICT),
185       Object);
186   RETURN_ON_EXCEPTION(
187       isolate, Object::SetProperty(
188                    constructor, isolate->factory()->class_end_position_symbol(),
189                    handle(Smi::FromInt(end_position), isolate), STRICT),
190       Object);
191 
192   return constructor;
193 }
194 
195 
RUNTIME_FUNCTION(Runtime_DefineClass)196 RUNTIME_FUNCTION(Runtime_DefineClass) {
197   HandleScope scope(isolate);
198   DCHECK(args.length() == 5);
199   CONVERT_ARG_HANDLE_CHECKED(Object, name, 0);
200   CONVERT_ARG_HANDLE_CHECKED(Object, super_class, 1);
201   CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, 2);
202   CONVERT_SMI_ARG_CHECKED(start_position, 3);
203   CONVERT_SMI_ARG_CHECKED(end_position, 4);
204 
205   Handle<Object> result;
206   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
207       isolate, result, DefineClass(isolate, name, super_class, constructor,
208                                    start_position, end_position));
209   return *result;
210 }
211 
212 
RUNTIME_FUNCTION(Runtime_DefineClassMethod)213 RUNTIME_FUNCTION(Runtime_DefineClassMethod) {
214   HandleScope scope(isolate);
215   DCHECK(args.length() == 3);
216   CONVERT_ARG_HANDLE_CHECKED(JSObject, object, 0);
217   CONVERT_ARG_HANDLE_CHECKED(Name, name, 1);
218   CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 2);
219 
220   RETURN_FAILURE_ON_EXCEPTION(isolate,
221                               JSObject::DefinePropertyOrElementIgnoreAttributes(
222                                   object, name, function, DONT_ENUM));
223   return isolate->heap()->undefined_value();
224 }
225 
226 
RUNTIME_FUNCTION(Runtime_FinalizeClassDefinition)227 RUNTIME_FUNCTION(Runtime_FinalizeClassDefinition) {
228   HandleScope scope(isolate);
229   DCHECK(args.length() == 2);
230   CONVERT_ARG_HANDLE_CHECKED(JSObject, constructor, 0);
231   CONVERT_ARG_HANDLE_CHECKED(JSObject, prototype, 1);
232 
233   JSObject::MigrateSlowToFast(constructor, 0, "RuntimeToFastProperties");
234 
235   if (constructor->map()->is_strong()) {
236     DCHECK(prototype->map()->is_strong());
237     MAYBE_RETURN(JSReceiver::SetIntegrityLevel(prototype, FROZEN,
238                                                Object::THROW_ON_ERROR),
239                  isolate->heap()->exception());
240     MAYBE_RETURN(JSReceiver::SetIntegrityLevel(constructor, FROZEN,
241                                                Object::THROW_ON_ERROR),
242                  isolate->heap()->exception());
243   }
244   return *constructor;
245 }
246 
247 
LoadFromSuper(Isolate * isolate,Handle<Object> receiver,Handle<JSObject> home_object,Handle<Name> name,LanguageMode language_mode)248 static MaybeHandle<Object> LoadFromSuper(Isolate* isolate,
249                                          Handle<Object> receiver,
250                                          Handle<JSObject> home_object,
251                                          Handle<Name> name,
252                                          LanguageMode language_mode) {
253   if (home_object->IsAccessCheckNeeded() &&
254       !isolate->MayAccess(handle(isolate->context()), home_object)) {
255     isolate->ReportFailedAccessCheck(home_object);
256     RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
257   }
258 
259   PrototypeIterator iter(isolate, home_object);
260   Handle<Object> proto = PrototypeIterator::GetCurrent(iter);
261   if (!proto->IsJSReceiver()) {
262     return Object::ReadAbsentProperty(isolate, proto, name, language_mode);
263   }
264 
265   LookupIterator it(receiver, name, Handle<JSReceiver>::cast(proto));
266   Handle<Object> result;
267   ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
268                              Object::GetProperty(&it, language_mode), Object);
269   return result;
270 }
271 
272 
LoadElementFromSuper(Isolate * isolate,Handle<Object> receiver,Handle<JSObject> home_object,uint32_t index,LanguageMode language_mode)273 static MaybeHandle<Object> LoadElementFromSuper(Isolate* isolate,
274                                                 Handle<Object> receiver,
275                                                 Handle<JSObject> home_object,
276                                                 uint32_t index,
277                                                 LanguageMode language_mode) {
278   if (home_object->IsAccessCheckNeeded() &&
279       !isolate->MayAccess(handle(isolate->context()), home_object)) {
280     isolate->ReportFailedAccessCheck(home_object);
281     RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
282   }
283 
284   PrototypeIterator iter(isolate, home_object);
285   Handle<Object> proto = PrototypeIterator::GetCurrent(iter);
286   if (!proto->IsJSReceiver()) {
287     Handle<Object> name = isolate->factory()->NewNumberFromUint(index);
288     return Object::ReadAbsentProperty(isolate, proto, name, language_mode);
289   }
290 
291   LookupIterator it(isolate, receiver, index, Handle<JSReceiver>::cast(proto));
292   Handle<Object> result;
293   ASSIGN_RETURN_ON_EXCEPTION(isolate, result,
294                              Object::GetProperty(&it, language_mode), Object);
295   return result;
296 }
297 
298 
299 // TODO(conradw): It would be more efficient to have a separate runtime function
300 // for strong mode.
RUNTIME_FUNCTION(Runtime_LoadFromSuper)301 RUNTIME_FUNCTION(Runtime_LoadFromSuper) {
302   HandleScope scope(isolate);
303   DCHECK(args.length() == 4);
304   CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 0);
305   CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 1);
306   CONVERT_ARG_HANDLE_CHECKED(Name, name, 2);
307   CONVERT_LANGUAGE_MODE_ARG_CHECKED(language_mode, 3);
308 
309   Handle<Object> result;
310   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
311       isolate, result,
312       LoadFromSuper(isolate, receiver, home_object, name, language_mode));
313   return *result;
314 }
315 
316 
RUNTIME_FUNCTION(Runtime_LoadKeyedFromSuper)317 RUNTIME_FUNCTION(Runtime_LoadKeyedFromSuper) {
318   HandleScope scope(isolate);
319   DCHECK(args.length() == 4);
320   CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 0);
321   CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 1);
322   CONVERT_ARG_HANDLE_CHECKED(Object, key, 2);
323   CONVERT_LANGUAGE_MODE_ARG_CHECKED(language_mode, 3);
324 
325   uint32_t index = 0;
326   Handle<Object> result;
327 
328   if (key->ToArrayIndex(&index)) {
329     ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
330         isolate, result, LoadElementFromSuper(isolate, receiver, home_object,
331                                               index, language_mode));
332     return *result;
333   }
334 
335   Handle<Name> name;
336   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name,
337                                      Object::ToName(isolate, key));
338   // TODO(verwaest): Unify using LookupIterator.
339   if (name->AsArrayIndex(&index)) {
340     ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
341         isolate, result, LoadElementFromSuper(isolate, receiver, home_object,
342                                               index, language_mode));
343     return *result;
344   }
345   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
346       isolate, result,
347       LoadFromSuper(isolate, receiver, home_object, name, language_mode));
348   return *result;
349 }
350 
351 
StoreToSuper(Isolate * isolate,Handle<JSObject> home_object,Handle<Object> receiver,Handle<Name> name,Handle<Object> value,LanguageMode language_mode)352 static Object* StoreToSuper(Isolate* isolate, Handle<JSObject> home_object,
353                             Handle<Object> receiver, Handle<Name> name,
354                             Handle<Object> value, LanguageMode language_mode) {
355   if (home_object->IsAccessCheckNeeded() &&
356       !isolate->MayAccess(handle(isolate->context()), home_object)) {
357     isolate->ReportFailedAccessCheck(home_object);
358     RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
359   }
360 
361   PrototypeIterator iter(isolate, home_object);
362   Handle<Object> proto = PrototypeIterator::GetCurrent(iter);
363   if (!proto->IsJSReceiver()) return isolate->heap()->undefined_value();
364 
365   LookupIterator it(receiver, name, Handle<JSReceiver>::cast(proto));
366   MAYBE_RETURN(Object::SetSuperProperty(&it, value, language_mode,
367                                         Object::CERTAINLY_NOT_STORE_FROM_KEYED),
368                isolate->heap()->exception());
369   return *value;
370 }
371 
372 
StoreElementToSuper(Isolate * isolate,Handle<JSObject> home_object,Handle<Object> receiver,uint32_t index,Handle<Object> value,LanguageMode language_mode)373 static Object* StoreElementToSuper(Isolate* isolate,
374                                    Handle<JSObject> home_object,
375                                    Handle<Object> receiver, uint32_t index,
376                                    Handle<Object> value,
377                                    LanguageMode language_mode) {
378   if (home_object->IsAccessCheckNeeded() &&
379       !isolate->MayAccess(handle(isolate->context()), home_object)) {
380     isolate->ReportFailedAccessCheck(home_object);
381     RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
382   }
383 
384   PrototypeIterator iter(isolate, home_object);
385   Handle<Object> proto = PrototypeIterator::GetCurrent(iter);
386   if (!proto->IsJSReceiver()) return isolate->heap()->undefined_value();
387 
388   LookupIterator it(isolate, receiver, index, Handle<JSReceiver>::cast(proto));
389   MAYBE_RETURN(Object::SetSuperProperty(&it, value, language_mode,
390                                         Object::MAY_BE_STORE_FROM_KEYED),
391                isolate->heap()->exception());
392   return *value;
393 }
394 
395 
RUNTIME_FUNCTION(Runtime_StoreToSuper_Strict)396 RUNTIME_FUNCTION(Runtime_StoreToSuper_Strict) {
397   HandleScope scope(isolate);
398   DCHECK(args.length() == 4);
399   CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 0);
400   CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 1);
401   CONVERT_ARG_HANDLE_CHECKED(Name, name, 2);
402   CONVERT_ARG_HANDLE_CHECKED(Object, value, 3);
403 
404   return StoreToSuper(isolate, home_object, receiver, name, value, STRICT);
405 }
406 
407 
RUNTIME_FUNCTION(Runtime_StoreToSuper_Sloppy)408 RUNTIME_FUNCTION(Runtime_StoreToSuper_Sloppy) {
409   HandleScope scope(isolate);
410   DCHECK(args.length() == 4);
411   CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 0);
412   CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 1);
413   CONVERT_ARG_HANDLE_CHECKED(Name, name, 2);
414   CONVERT_ARG_HANDLE_CHECKED(Object, value, 3);
415 
416   return StoreToSuper(isolate, home_object, receiver, name, value, SLOPPY);
417 }
418 
419 
StoreKeyedToSuper(Isolate * isolate,Handle<JSObject> home_object,Handle<Object> receiver,Handle<Object> key,Handle<Object> value,LanguageMode language_mode)420 static Object* StoreKeyedToSuper(Isolate* isolate, Handle<JSObject> home_object,
421                                  Handle<Object> receiver, Handle<Object> key,
422                                  Handle<Object> value,
423                                  LanguageMode language_mode) {
424   uint32_t index = 0;
425 
426   if (key->ToArrayIndex(&index)) {
427     return StoreElementToSuper(isolate, home_object, receiver, index, value,
428                                language_mode);
429   }
430   Handle<Name> name;
431   ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name,
432                                      Object::ToName(isolate, key));
433   // TODO(verwaest): Unify using LookupIterator.
434   if (name->AsArrayIndex(&index)) {
435     return StoreElementToSuper(isolate, home_object, receiver, index, value,
436                                language_mode);
437   }
438   return StoreToSuper(isolate, home_object, receiver, name, value,
439                       language_mode);
440 }
441 
442 
RUNTIME_FUNCTION(Runtime_StoreKeyedToSuper_Strict)443 RUNTIME_FUNCTION(Runtime_StoreKeyedToSuper_Strict) {
444   HandleScope scope(isolate);
445   DCHECK(args.length() == 4);
446   CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 0);
447   CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 1);
448   CONVERT_ARG_HANDLE_CHECKED(Object, key, 2);
449   CONVERT_ARG_HANDLE_CHECKED(Object, value, 3);
450 
451   return StoreKeyedToSuper(isolate, home_object, receiver, key, value, STRICT);
452 }
453 
454 
RUNTIME_FUNCTION(Runtime_StoreKeyedToSuper_Sloppy)455 RUNTIME_FUNCTION(Runtime_StoreKeyedToSuper_Sloppy) {
456   HandleScope scope(isolate);
457   DCHECK(args.length() == 4);
458   CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 0);
459   CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 1);
460   CONVERT_ARG_HANDLE_CHECKED(Object, key, 2);
461   CONVERT_ARG_HANDLE_CHECKED(Object, value, 3);
462 
463   return StoreKeyedToSuper(isolate, home_object, receiver, key, value, SLOPPY);
464 }
465 
466 
RUNTIME_FUNCTION(Runtime_GetSuperConstructor)467 RUNTIME_FUNCTION(Runtime_GetSuperConstructor) {
468   SealHandleScope shs(isolate);
469   DCHECK_EQ(1, args.length());
470   CONVERT_ARG_CHECKED(JSFunction, active_function, 0);
471   return active_function->map()->prototype();
472 }
473 
474 }  // namespace internal
475 }  // namespace v8
476