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