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