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 !Handle<JSFunction>::cast(super_class)->shared()->is_resumable());
99 ASSIGN_RETURN_ON_EXCEPTION(
100 isolate, prototype_parent,
101 Runtime::GetObjectProperty(isolate, super_class,
102 isolate->factory()->prototype_string()),
103 Object);
104 if (!prototype_parent->IsNull(isolate) &&
105 !prototype_parent->IsJSReceiver()) {
106 THROW_NEW_ERROR(
107 isolate, NewTypeError(MessageTemplate::kPrototypeParentNotAnObject,
108 prototype_parent),
109 Object);
110 }
111 constructor_parent = super_class;
112 } else {
113 THROW_NEW_ERROR(isolate,
114 NewTypeError(MessageTemplate::kExtendsValueNotConstructor,
115 super_class),
116 Object);
117 }
118 }
119
120 Handle<Map> map =
121 isolate->factory()->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
122 map->set_is_prototype_map(true);
123 Map::SetPrototype(map, prototype_parent);
124 map->SetConstructor(*constructor);
125 Handle<JSObject> prototype = isolate->factory()->NewJSObjectFromMap(map);
126
127 if (!super_class->IsTheHole(isolate)) {
128 // Derived classes, just like builtins, don't create implicit receivers in
129 // [[construct]]. Instead they just set up new.target and call into the
130 // constructor. Hence we can reuse the builtins construct stub for derived
131 // classes.
132 Handle<Code> stub(isolate->builtins()->JSBuiltinsConstructStubForDerived());
133 constructor->shared()->set_construct_stub(*stub);
134 }
135
136 JSFunction::SetPrototype(constructor, prototype);
137 PropertyAttributes attribs =
138 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE | READ_ONLY);
139 RETURN_ON_EXCEPTION(isolate,
140 JSObject::SetOwnPropertyIgnoreAttributes(
141 constructor, isolate->factory()->prototype_string(),
142 prototype, attribs),
143 Object);
144
145 // TODO(arv): Only do this conditionally.
146 Handle<Symbol> home_object_symbol(isolate->heap()->home_object_symbol());
147 RETURN_ON_EXCEPTION(
148 isolate, JSObject::SetOwnPropertyIgnoreAttributes(
149 constructor, home_object_symbol, prototype, DONT_ENUM),
150 Object);
151
152 if (!constructor_parent.is_null()) {
153 MAYBE_RETURN_NULL(JSObject::SetPrototype(constructor, constructor_parent,
154 false, Object::THROW_ON_ERROR));
155 }
156
157 JSObject::AddProperty(prototype, isolate->factory()->constructor_string(),
158 constructor, DONT_ENUM);
159
160 // Install private properties that are used to construct the FunctionToString.
161 RETURN_ON_EXCEPTION(
162 isolate,
163 Object::SetProperty(
164 constructor, isolate->factory()->class_start_position_symbol(),
165 handle(Smi::FromInt(start_position), isolate), STRICT),
166 Object);
167 RETURN_ON_EXCEPTION(
168 isolate, Object::SetProperty(
169 constructor, isolate->factory()->class_end_position_symbol(),
170 handle(Smi::FromInt(end_position), isolate), STRICT),
171 Object);
172
173 return constructor;
174 }
175
176
RUNTIME_FUNCTION(Runtime_DefineClass)177 RUNTIME_FUNCTION(Runtime_DefineClass) {
178 HandleScope scope(isolate);
179 DCHECK(args.length() == 4);
180 CONVERT_ARG_HANDLE_CHECKED(Object, super_class, 0);
181 CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, 1);
182 CONVERT_SMI_ARG_CHECKED(start_position, 2);
183 CONVERT_SMI_ARG_CHECKED(end_position, 3);
184
185 RETURN_RESULT_OR_FAILURE(
186 isolate, DefineClass(isolate, super_class, constructor, start_position,
187 end_position));
188 }
189
190
LoadFromSuper(Isolate * isolate,Handle<Object> receiver,Handle<JSObject> home_object,Handle<Name> name)191 static MaybeHandle<Object> LoadFromSuper(Isolate* isolate,
192 Handle<Object> receiver,
193 Handle<JSObject> home_object,
194 Handle<Name> name) {
195 if (home_object->IsAccessCheckNeeded() &&
196 !isolate->MayAccess(handle(isolate->context()), home_object)) {
197 isolate->ReportFailedAccessCheck(home_object);
198 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
199 }
200
201 PrototypeIterator iter(isolate, home_object);
202 Handle<Object> proto = PrototypeIterator::GetCurrent(iter);
203 if (!proto->IsJSReceiver()) {
204 return Object::ReadAbsentProperty(isolate, proto, name);
205 }
206
207 LookupIterator it(receiver, name, Handle<JSReceiver>::cast(proto));
208 Handle<Object> result;
209 ASSIGN_RETURN_ON_EXCEPTION(isolate, result, Object::GetProperty(&it), Object);
210 return result;
211 }
212
LoadElementFromSuper(Isolate * isolate,Handle<Object> receiver,Handle<JSObject> home_object,uint32_t index)213 static MaybeHandle<Object> LoadElementFromSuper(Isolate* isolate,
214 Handle<Object> receiver,
215 Handle<JSObject> home_object,
216 uint32_t index) {
217 if (home_object->IsAccessCheckNeeded() &&
218 !isolate->MayAccess(handle(isolate->context()), home_object)) {
219 isolate->ReportFailedAccessCheck(home_object);
220 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object);
221 }
222
223 PrototypeIterator iter(isolate, home_object);
224 Handle<Object> proto = PrototypeIterator::GetCurrent(iter);
225 if (!proto->IsJSReceiver()) {
226 Handle<Object> name = isolate->factory()->NewNumberFromUint(index);
227 return Object::ReadAbsentProperty(isolate, proto, name);
228 }
229
230 LookupIterator it(isolate, receiver, index, Handle<JSReceiver>::cast(proto));
231 Handle<Object> result;
232 ASSIGN_RETURN_ON_EXCEPTION(isolate, result, Object::GetProperty(&it), Object);
233 return result;
234 }
235
236
RUNTIME_FUNCTION(Runtime_LoadFromSuper)237 RUNTIME_FUNCTION(Runtime_LoadFromSuper) {
238 HandleScope scope(isolate);
239 DCHECK_EQ(3, args.length());
240 CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 0);
241 CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 1);
242 CONVERT_ARG_HANDLE_CHECKED(Name, name, 2);
243
244 RETURN_RESULT_OR_FAILURE(isolate,
245 LoadFromSuper(isolate, receiver, home_object, name));
246 }
247
248
RUNTIME_FUNCTION(Runtime_LoadKeyedFromSuper)249 RUNTIME_FUNCTION(Runtime_LoadKeyedFromSuper) {
250 HandleScope scope(isolate);
251 DCHECK_EQ(3, args.length());
252 CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 0);
253 CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 1);
254 CONVERT_ARG_HANDLE_CHECKED(Object, key, 2);
255
256 uint32_t index = 0;
257
258 if (key->ToArrayIndex(&index)) {
259 RETURN_RESULT_OR_FAILURE(
260 isolate, LoadElementFromSuper(isolate, receiver, home_object, index));
261 }
262
263 Handle<Name> name;
264 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name,
265 Object::ToName(isolate, key));
266 // TODO(verwaest): Unify using LookupIterator.
267 if (name->AsArrayIndex(&index)) {
268 RETURN_RESULT_OR_FAILURE(
269 isolate, LoadElementFromSuper(isolate, receiver, home_object, index));
270 }
271 RETURN_RESULT_OR_FAILURE(isolate,
272 LoadFromSuper(isolate, receiver, home_object, name));
273 }
274
275
StoreToSuper(Isolate * isolate,Handle<JSObject> home_object,Handle<Object> receiver,Handle<Name> name,Handle<Object> value,LanguageMode language_mode)276 static Object* StoreToSuper(Isolate* isolate, Handle<JSObject> home_object,
277 Handle<Object> receiver, Handle<Name> name,
278 Handle<Object> value, LanguageMode language_mode) {
279 if (home_object->IsAccessCheckNeeded() &&
280 !isolate->MayAccess(handle(isolate->context()), home_object)) {
281 isolate->ReportFailedAccessCheck(home_object);
282 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
283 }
284
285 PrototypeIterator iter(isolate, home_object);
286 Handle<Object> proto = PrototypeIterator::GetCurrent(iter);
287 if (!proto->IsJSReceiver()) return isolate->heap()->undefined_value();
288
289 LookupIterator it(receiver, name, Handle<JSReceiver>::cast(proto));
290 MAYBE_RETURN(Object::SetSuperProperty(&it, value, language_mode,
291 Object::CERTAINLY_NOT_STORE_FROM_KEYED),
292 isolate->heap()->exception());
293 return *value;
294 }
295
296
StoreElementToSuper(Isolate * isolate,Handle<JSObject> home_object,Handle<Object> receiver,uint32_t index,Handle<Object> value,LanguageMode language_mode)297 static Object* StoreElementToSuper(Isolate* isolate,
298 Handle<JSObject> home_object,
299 Handle<Object> receiver, uint32_t index,
300 Handle<Object> value,
301 LanguageMode language_mode) {
302 if (home_object->IsAccessCheckNeeded() &&
303 !isolate->MayAccess(handle(isolate->context()), home_object)) {
304 isolate->ReportFailedAccessCheck(home_object);
305 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate);
306 }
307
308 PrototypeIterator iter(isolate, home_object);
309 Handle<Object> proto = PrototypeIterator::GetCurrent(iter);
310 if (!proto->IsJSReceiver()) return isolate->heap()->undefined_value();
311
312 LookupIterator it(isolate, receiver, index, Handle<JSReceiver>::cast(proto));
313 MAYBE_RETURN(Object::SetSuperProperty(&it, value, language_mode,
314 Object::MAY_BE_STORE_FROM_KEYED),
315 isolate->heap()->exception());
316 return *value;
317 }
318
319
RUNTIME_FUNCTION(Runtime_StoreToSuper_Strict)320 RUNTIME_FUNCTION(Runtime_StoreToSuper_Strict) {
321 HandleScope scope(isolate);
322 DCHECK(args.length() == 4);
323 CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 0);
324 CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 1);
325 CONVERT_ARG_HANDLE_CHECKED(Name, name, 2);
326 CONVERT_ARG_HANDLE_CHECKED(Object, value, 3);
327
328 return StoreToSuper(isolate, home_object, receiver, name, value, STRICT);
329 }
330
331
RUNTIME_FUNCTION(Runtime_StoreToSuper_Sloppy)332 RUNTIME_FUNCTION(Runtime_StoreToSuper_Sloppy) {
333 HandleScope scope(isolate);
334 DCHECK(args.length() == 4);
335 CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 0);
336 CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 1);
337 CONVERT_ARG_HANDLE_CHECKED(Name, name, 2);
338 CONVERT_ARG_HANDLE_CHECKED(Object, value, 3);
339
340 return StoreToSuper(isolate, home_object, receiver, name, value, SLOPPY);
341 }
342
343
StoreKeyedToSuper(Isolate * isolate,Handle<JSObject> home_object,Handle<Object> receiver,Handle<Object> key,Handle<Object> value,LanguageMode language_mode)344 static Object* StoreKeyedToSuper(Isolate* isolate, Handle<JSObject> home_object,
345 Handle<Object> receiver, Handle<Object> key,
346 Handle<Object> value,
347 LanguageMode language_mode) {
348 uint32_t index = 0;
349
350 if (key->ToArrayIndex(&index)) {
351 return StoreElementToSuper(isolate, home_object, receiver, index, value,
352 language_mode);
353 }
354 Handle<Name> name;
355 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name,
356 Object::ToName(isolate, key));
357 // TODO(verwaest): Unify using LookupIterator.
358 if (name->AsArrayIndex(&index)) {
359 return StoreElementToSuper(isolate, home_object, receiver, index, value,
360 language_mode);
361 }
362 return StoreToSuper(isolate, home_object, receiver, name, value,
363 language_mode);
364 }
365
366
RUNTIME_FUNCTION(Runtime_StoreKeyedToSuper_Strict)367 RUNTIME_FUNCTION(Runtime_StoreKeyedToSuper_Strict) {
368 HandleScope scope(isolate);
369 DCHECK(args.length() == 4);
370 CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 0);
371 CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 1);
372 CONVERT_ARG_HANDLE_CHECKED(Object, key, 2);
373 CONVERT_ARG_HANDLE_CHECKED(Object, value, 3);
374
375 return StoreKeyedToSuper(isolate, home_object, receiver, key, value, STRICT);
376 }
377
378
RUNTIME_FUNCTION(Runtime_StoreKeyedToSuper_Sloppy)379 RUNTIME_FUNCTION(Runtime_StoreKeyedToSuper_Sloppy) {
380 HandleScope scope(isolate);
381 DCHECK(args.length() == 4);
382 CONVERT_ARG_HANDLE_CHECKED(Object, receiver, 0);
383 CONVERT_ARG_HANDLE_CHECKED(JSObject, home_object, 1);
384 CONVERT_ARG_HANDLE_CHECKED(Object, key, 2);
385 CONVERT_ARG_HANDLE_CHECKED(Object, value, 3);
386
387 return StoreKeyedToSuper(isolate, home_object, receiver, key, value, SLOPPY);
388 }
389
390
RUNTIME_FUNCTION(Runtime_GetSuperConstructor)391 RUNTIME_FUNCTION(Runtime_GetSuperConstructor) {
392 SealHandleScope shs(isolate);
393 DCHECK_EQ(1, args.length());
394 CONVERT_ARG_CHECKED(JSFunction, active_function, 0);
395 return active_function->map()->prototype();
396 }
397
398 } // namespace internal
399 } // namespace v8
400