1 // Copyright 2015 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/api-natives.h"
6
7 #include "src/api.h"
8 #include "src/isolate-inl.h"
9 #include "src/lookup.h"
10 #include "src/messages.h"
11 #include "src/objects/api-callbacks.h"
12 #include "src/objects/hash-table-inl.h"
13 #include "src/objects/templates.h"
14
15 namespace v8 {
16 namespace internal {
17
18
19 namespace {
20
21 class InvokeScope {
22 public:
InvokeScope(Isolate * isolate)23 explicit InvokeScope(Isolate* isolate)
24 : isolate_(isolate), save_context_(isolate) {}
~InvokeScope()25 ~InvokeScope() {
26 bool has_exception = isolate_->has_pending_exception();
27 if (has_exception) {
28 isolate_->ReportPendingMessages();
29 } else {
30 isolate_->clear_pending_message();
31 }
32 }
33
34 private:
35 Isolate* isolate_;
36 SaveContext save_context_;
37 };
38
39 MaybeHandle<JSObject> InstantiateObject(Isolate* isolate,
40 Handle<ObjectTemplateInfo> data,
41 Handle<JSReceiver> new_target,
42 bool is_hidden_prototype,
43 bool is_prototype);
44
45 MaybeHandle<JSFunction> InstantiateFunction(
46 Isolate* isolate, Handle<FunctionTemplateInfo> data,
47 MaybeHandle<Name> maybe_name = MaybeHandle<Name>());
48
Instantiate(Isolate * isolate,Handle<Object> data,MaybeHandle<Name> maybe_name=MaybeHandle<Name> ())49 MaybeHandle<Object> Instantiate(
50 Isolate* isolate, Handle<Object> data,
51 MaybeHandle<Name> maybe_name = MaybeHandle<Name>()) {
52 if (data->IsFunctionTemplateInfo()) {
53 return InstantiateFunction(
54 isolate, Handle<FunctionTemplateInfo>::cast(data), maybe_name);
55 } else if (data->IsObjectTemplateInfo()) {
56 return InstantiateObject(isolate, Handle<ObjectTemplateInfo>::cast(data),
57 Handle<JSReceiver>(), false, false);
58 } else {
59 return data;
60 }
61 }
62
DefineAccessorProperty(Isolate * isolate,Handle<JSObject> object,Handle<Name> name,Handle<Object> getter,Handle<Object> setter,PropertyAttributes attributes,bool force_instantiate)63 MaybeHandle<Object> DefineAccessorProperty(
64 Isolate* isolate, Handle<JSObject> object, Handle<Name> name,
65 Handle<Object> getter, Handle<Object> setter, PropertyAttributes attributes,
66 bool force_instantiate) {
67 DCHECK(!getter->IsFunctionTemplateInfo() ||
68 !FunctionTemplateInfo::cast(*getter)->do_not_cache());
69 DCHECK(!setter->IsFunctionTemplateInfo() ||
70 !FunctionTemplateInfo::cast(*setter)->do_not_cache());
71 if (force_instantiate) {
72 if (getter->IsFunctionTemplateInfo()) {
73 ASSIGN_RETURN_ON_EXCEPTION(
74 isolate, getter,
75 InstantiateFunction(isolate,
76 Handle<FunctionTemplateInfo>::cast(getter)),
77 Object);
78 }
79 if (setter->IsFunctionTemplateInfo()) {
80 ASSIGN_RETURN_ON_EXCEPTION(
81 isolate, setter,
82 InstantiateFunction(isolate,
83 Handle<FunctionTemplateInfo>::cast(setter)),
84 Object);
85 }
86 }
87 RETURN_ON_EXCEPTION(isolate, JSObject::DefineAccessor(object, name, getter,
88 setter, attributes),
89 Object);
90 return object;
91 }
92
93
DefineDataProperty(Isolate * isolate,Handle<JSObject> object,Handle<Name> name,Handle<Object> prop_data,PropertyAttributes attributes)94 MaybeHandle<Object> DefineDataProperty(Isolate* isolate,
95 Handle<JSObject> object,
96 Handle<Name> name,
97 Handle<Object> prop_data,
98 PropertyAttributes attributes) {
99 Handle<Object> value;
100 ASSIGN_RETURN_ON_EXCEPTION(isolate, value,
101 Instantiate(isolate, prop_data, name), Object);
102
103 LookupIterator it = LookupIterator::PropertyOrElement(
104 isolate, object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
105
106 #ifdef DEBUG
107 Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
108 DCHECK(maybe.IsJust());
109 if (it.IsFound()) {
110 THROW_NEW_ERROR(
111 isolate,
112 NewTypeError(MessageTemplate::kDuplicateTemplateProperty, name),
113 Object);
114 }
115 #endif
116
117 MAYBE_RETURN_NULL(
118 Object::AddDataProperty(&it, value, attributes, kThrowOnError,
119 Object::CERTAINLY_NOT_STORE_FROM_KEYED));
120 return value;
121 }
122
123
DisableAccessChecks(Isolate * isolate,Handle<JSObject> object)124 void DisableAccessChecks(Isolate* isolate, Handle<JSObject> object) {
125 Handle<Map> old_map(object->map());
126 // Copy map so it won't interfere constructor's initial map.
127 Handle<Map> new_map = Map::Copy(old_map, "DisableAccessChecks");
128 new_map->set_is_access_check_needed(false);
129 JSObject::MigrateToMap(Handle<JSObject>::cast(object), new_map);
130 }
131
132
EnableAccessChecks(Isolate * isolate,Handle<JSObject> object)133 void EnableAccessChecks(Isolate* isolate, Handle<JSObject> object) {
134 Handle<Map> old_map(object->map());
135 // Copy map so it won't interfere constructor's initial map.
136 Handle<Map> new_map = Map::Copy(old_map, "EnableAccessChecks");
137 new_map->set_is_access_check_needed(true);
138 new_map->set_may_have_interesting_symbols(true);
139 JSObject::MigrateToMap(object, new_map);
140 }
141
142
143 class AccessCheckDisableScope {
144 public:
AccessCheckDisableScope(Isolate * isolate,Handle<JSObject> obj)145 AccessCheckDisableScope(Isolate* isolate, Handle<JSObject> obj)
146 : isolate_(isolate),
147 disabled_(obj->map()->is_access_check_needed()),
148 obj_(obj) {
149 if (disabled_) {
150 DisableAccessChecks(isolate_, obj_);
151 }
152 }
~AccessCheckDisableScope()153 ~AccessCheckDisableScope() {
154 if (disabled_) {
155 EnableAccessChecks(isolate_, obj_);
156 }
157 }
158
159 private:
160 Isolate* isolate_;
161 const bool disabled_;
162 Handle<JSObject> obj_;
163 };
164
165
GetIntrinsic(Isolate * isolate,v8::Intrinsic intrinsic)166 Object* GetIntrinsic(Isolate* isolate, v8::Intrinsic intrinsic) {
167 Handle<Context> native_context = isolate->native_context();
168 DCHECK(!native_context.is_null());
169 switch (intrinsic) {
170 #define GET_INTRINSIC_VALUE(name, iname) \
171 case v8::k##name: \
172 return native_context->iname();
173 V8_INTRINSICS_LIST(GET_INTRINSIC_VALUE)
174 #undef GET_INTRINSIC_VALUE
175 }
176 return nullptr;
177 }
178
179
180 template <typename TemplateInfoT>
ConfigureInstance(Isolate * isolate,Handle<JSObject> obj,Handle<TemplateInfoT> data,bool is_hidden_prototype)181 MaybeHandle<JSObject> ConfigureInstance(Isolate* isolate, Handle<JSObject> obj,
182 Handle<TemplateInfoT> data,
183 bool is_hidden_prototype) {
184 HandleScope scope(isolate);
185 // Disable access checks while instantiating the object.
186 AccessCheckDisableScope access_check_scope(isolate, obj);
187
188 // Walk the inheritance chain and copy all accessors to current object.
189 int max_number_of_properties = 0;
190 TemplateInfoT* info = *data;
191 while (info != nullptr) {
192 Object* props = info->property_accessors();
193 if (!props->IsUndefined(isolate)) {
194 max_number_of_properties += TemplateList::cast(props)->length();
195 }
196 info = info->GetParent(isolate);
197 }
198
199 if (max_number_of_properties > 0) {
200 int valid_descriptors = 0;
201 // Use a temporary FixedArray to accumulate unique accessors.
202 Handle<FixedArray> array =
203 isolate->factory()->NewFixedArray(max_number_of_properties);
204
205 for (Handle<TemplateInfoT> temp(*data); *temp != nullptr;
206 temp = handle(temp->GetParent(isolate), isolate)) {
207 // Accumulate accessors.
208 Object* maybe_properties = temp->property_accessors();
209 if (!maybe_properties->IsUndefined(isolate)) {
210 valid_descriptors = AccessorInfo::AppendUnique(
211 handle(maybe_properties, isolate), array, valid_descriptors);
212 }
213 }
214
215 // Install accumulated accessors.
216 for (int i = 0; i < valid_descriptors; i++) {
217 Handle<AccessorInfo> accessor(AccessorInfo::cast(array->get(i)));
218 Handle<Name> name(Name::cast(accessor->name()), isolate);
219 JSObject::SetAccessor(obj, name, accessor,
220 accessor->initial_property_attributes())
221 .Assert();
222 }
223 }
224
225 Object* maybe_property_list = data->property_list();
226 if (maybe_property_list->IsUndefined(isolate)) return obj;
227 Handle<TemplateList> properties(TemplateList::cast(maybe_property_list),
228 isolate);
229 if (properties->length() == 0) return obj;
230
231 int i = 0;
232 for (int c = 0; c < data->number_of_properties(); c++) {
233 auto name = handle(Name::cast(properties->get(i++)), isolate);
234 Object* bit = properties->get(i++);
235 if (bit->IsSmi()) {
236 PropertyDetails details(Smi::cast(bit));
237 PropertyAttributes attributes = details.attributes();
238 PropertyKind kind = details.kind();
239
240 if (kind == kData) {
241 auto prop_data = handle(properties->get(i++), isolate);
242 RETURN_ON_EXCEPTION(isolate, DefineDataProperty(isolate, obj, name,
243 prop_data, attributes),
244 JSObject);
245 } else {
246 auto getter = handle(properties->get(i++), isolate);
247 auto setter = handle(properties->get(i++), isolate);
248 RETURN_ON_EXCEPTION(
249 isolate, DefineAccessorProperty(isolate, obj, name, getter, setter,
250 attributes, is_hidden_prototype),
251 JSObject);
252 }
253 } else {
254 // Intrinsic data property --- Get appropriate value from the current
255 // context.
256 PropertyDetails details(Smi::cast(properties->get(i++)));
257 PropertyAttributes attributes = details.attributes();
258 DCHECK_EQ(kData, details.kind());
259
260 v8::Intrinsic intrinsic =
261 static_cast<v8::Intrinsic>(Smi::ToInt(properties->get(i++)));
262 auto prop_data = handle(GetIntrinsic(isolate, intrinsic), isolate);
263
264 RETURN_ON_EXCEPTION(isolate, DefineDataProperty(isolate, obj, name,
265 prop_data, attributes),
266 JSObject);
267 }
268 }
269 return obj;
270 }
271
272 // Whether or not to cache every instance: when we materialize a getter or
273 // setter from an lazy AccessorPair, we rely on this cache to be able to always
274 // return the same getter or setter. However, objects will be cloned anyways,
275 // so it's not observable if we didn't cache an instance. Furthermore, a badly
276 // behaved embedder might create an unlimited number of objects, so we limit
277 // the cache for those cases.
278 enum class CachingMode { kLimited, kUnlimited };
279
ProbeInstantiationsCache(Isolate * isolate,int serial_number,CachingMode caching_mode)280 MaybeHandle<JSObject> ProbeInstantiationsCache(Isolate* isolate,
281 int serial_number,
282 CachingMode caching_mode) {
283 DCHECK_LE(1, serial_number);
284 if (serial_number <= TemplateInfo::kFastTemplateInstantiationsCacheSize) {
285 Handle<FixedArray> fast_cache =
286 isolate->fast_template_instantiations_cache();
287 return fast_cache->GetValue<JSObject>(isolate, serial_number - 1);
288 } else if (caching_mode == CachingMode::kUnlimited ||
289 (serial_number <=
290 TemplateInfo::kSlowTemplateInstantiationsCacheSize)) {
291 Handle<SimpleNumberDictionary> slow_cache =
292 isolate->slow_template_instantiations_cache();
293 int entry = slow_cache->FindEntry(serial_number);
294 if (entry == SimpleNumberDictionary::kNotFound) {
295 return MaybeHandle<JSObject>();
296 }
297 return handle(JSObject::cast(slow_cache->ValueAt(entry)), isolate);
298 } else {
299 return MaybeHandle<JSObject>();
300 }
301 }
302
CacheTemplateInstantiation(Isolate * isolate,int serial_number,CachingMode caching_mode,Handle<JSObject> object)303 void CacheTemplateInstantiation(Isolate* isolate, int serial_number,
304 CachingMode caching_mode,
305 Handle<JSObject> object) {
306 DCHECK_LE(1, serial_number);
307 if (serial_number <= TemplateInfo::kFastTemplateInstantiationsCacheSize) {
308 Handle<FixedArray> fast_cache =
309 isolate->fast_template_instantiations_cache();
310 Handle<FixedArray> new_cache =
311 FixedArray::SetAndGrow(fast_cache, serial_number - 1, object);
312 if (*new_cache != *fast_cache) {
313 isolate->native_context()->set_fast_template_instantiations_cache(
314 *new_cache);
315 }
316 } else if (caching_mode == CachingMode::kUnlimited ||
317 (serial_number <=
318 TemplateInfo::kSlowTemplateInstantiationsCacheSize)) {
319 Handle<SimpleNumberDictionary> cache =
320 isolate->slow_template_instantiations_cache();
321 auto new_cache = SimpleNumberDictionary::Set(cache, serial_number, object);
322 if (*new_cache != *cache) {
323 isolate->native_context()->set_slow_template_instantiations_cache(
324 *new_cache);
325 }
326 }
327 }
328
UncacheTemplateInstantiation(Isolate * isolate,int serial_number,CachingMode caching_mode)329 void UncacheTemplateInstantiation(Isolate* isolate, int serial_number,
330 CachingMode caching_mode) {
331 DCHECK_LE(1, serial_number);
332 if (serial_number <= TemplateInfo::kFastTemplateInstantiationsCacheSize) {
333 Handle<FixedArray> fast_cache =
334 isolate->fast_template_instantiations_cache();
335 DCHECK(!fast_cache->get(serial_number - 1)->IsUndefined(isolate));
336 fast_cache->set_undefined(serial_number - 1);
337 } else if (caching_mode == CachingMode::kUnlimited ||
338 (serial_number <=
339 TemplateInfo::kSlowTemplateInstantiationsCacheSize)) {
340 Handle<SimpleNumberDictionary> cache =
341 isolate->slow_template_instantiations_cache();
342 int entry = cache->FindEntry(serial_number);
343 DCHECK_NE(SimpleNumberDictionary::kNotFound, entry);
344 cache = SimpleNumberDictionary::DeleteEntry(cache, entry);
345 isolate->native_context()->set_slow_template_instantiations_cache(*cache);
346 }
347 }
348
IsSimpleInstantiation(Isolate * isolate,ObjectTemplateInfo * info,JSReceiver * new_target)349 bool IsSimpleInstantiation(Isolate* isolate, ObjectTemplateInfo* info,
350 JSReceiver* new_target) {
351 DisallowHeapAllocation no_gc;
352
353 if (!new_target->IsJSFunction()) return false;
354 JSFunction* fun = JSFunction::cast(new_target);
355 if (fun->shared()->function_data() != info->constructor()) return false;
356 if (info->immutable_proto()) return false;
357 return fun->context()->native_context() == isolate->raw_native_context();
358 }
359
InstantiateObject(Isolate * isolate,Handle<ObjectTemplateInfo> info,Handle<JSReceiver> new_target,bool is_hidden_prototype,bool is_prototype)360 MaybeHandle<JSObject> InstantiateObject(Isolate* isolate,
361 Handle<ObjectTemplateInfo> info,
362 Handle<JSReceiver> new_target,
363 bool is_hidden_prototype,
364 bool is_prototype) {
365 Handle<JSFunction> constructor;
366 int serial_number = Smi::ToInt(info->serial_number());
367 if (!new_target.is_null()) {
368 if (IsSimpleInstantiation(isolate, *info, *new_target)) {
369 constructor = Handle<JSFunction>::cast(new_target);
370 } else {
371 // Disable caching for subclass instantiation.
372 serial_number = 0;
373 }
374 }
375 // Fast path.
376 Handle<JSObject> result;
377 if (serial_number) {
378 if (ProbeInstantiationsCache(isolate, serial_number, CachingMode::kLimited)
379 .ToHandle(&result)) {
380 return isolate->factory()->CopyJSObject(result);
381 }
382 }
383
384 if (constructor.is_null()) {
385 Object* maybe_constructor_info = info->constructor();
386 if (maybe_constructor_info->IsUndefined(isolate)) {
387 constructor = isolate->object_function();
388 } else {
389 // Enter a new scope. Recursion could otherwise create a lot of handles.
390 HandleScope scope(isolate);
391 Handle<FunctionTemplateInfo> cons_templ(
392 FunctionTemplateInfo::cast(maybe_constructor_info), isolate);
393 Handle<JSFunction> tmp_constructor;
394 ASSIGN_RETURN_ON_EXCEPTION(isolate, tmp_constructor,
395 InstantiateFunction(isolate, cons_templ),
396 JSObject);
397 constructor = scope.CloseAndEscape(tmp_constructor);
398 }
399
400 if (new_target.is_null()) new_target = constructor;
401 }
402
403 Handle<JSObject> object;
404 ASSIGN_RETURN_ON_EXCEPTION(isolate, object,
405 JSObject::New(constructor, new_target), JSObject);
406
407 if (is_prototype) JSObject::OptimizeAsPrototype(object);
408
409 ASSIGN_RETURN_ON_EXCEPTION(
410 isolate, result,
411 ConfigureInstance(isolate, object, info, is_hidden_prototype), JSObject);
412 if (info->immutable_proto()) {
413 JSObject::SetImmutableProto(object);
414 }
415 if (!is_prototype) {
416 // Keep prototypes in slow-mode. Let them be lazily turned fast later on.
417 // TODO(dcarney): is this necessary?
418 JSObject::MigrateSlowToFast(result, 0, "ApiNatives::InstantiateObject");
419 // Don't cache prototypes.
420 if (serial_number) {
421 CacheTemplateInstantiation(isolate, serial_number, CachingMode::kLimited,
422 result);
423 result = isolate->factory()->CopyJSObject(result);
424 }
425 }
426
427 return result;
428 }
429
430 namespace {
GetInstancePrototype(Isolate * isolate,Object * function_template)431 MaybeHandle<Object> GetInstancePrototype(Isolate* isolate,
432 Object* function_template) {
433 // Enter a new scope. Recursion could otherwise create a lot of handles.
434 HandleScope scope(isolate);
435 Handle<JSFunction> parent_instance;
436 ASSIGN_RETURN_ON_EXCEPTION(
437 isolate, parent_instance,
438 InstantiateFunction(
439 isolate,
440 handle(FunctionTemplateInfo::cast(function_template), isolate)),
441 JSFunction);
442 Handle<Object> instance_prototype;
443 // TODO(cbruni): decide what to do here.
444 ASSIGN_RETURN_ON_EXCEPTION(
445 isolate, instance_prototype,
446 JSObject::GetProperty(parent_instance,
447 isolate->factory()->prototype_string()),
448 JSFunction);
449 return scope.CloseAndEscape(instance_prototype);
450 }
451 } // namespace
452
InstantiateFunction(Isolate * isolate,Handle<FunctionTemplateInfo> data,MaybeHandle<Name> maybe_name)453 MaybeHandle<JSFunction> InstantiateFunction(Isolate* isolate,
454 Handle<FunctionTemplateInfo> data,
455 MaybeHandle<Name> maybe_name) {
456 int serial_number = Smi::ToInt(data->serial_number());
457 if (serial_number) {
458 Handle<JSObject> result;
459 if (ProbeInstantiationsCache(isolate, serial_number,
460 CachingMode::kUnlimited)
461 .ToHandle(&result)) {
462 return Handle<JSFunction>::cast(result);
463 }
464 }
465 Handle<Object> prototype;
466 if (!data->remove_prototype()) {
467 Object* prototype_templ = data->prototype_template();
468 if (prototype_templ->IsUndefined(isolate)) {
469 Object* protoype_provider_templ = data->prototype_provider_template();
470 if (protoype_provider_templ->IsUndefined(isolate)) {
471 prototype = isolate->factory()->NewJSObject(isolate->object_function());
472 } else {
473 ASSIGN_RETURN_ON_EXCEPTION(
474 isolate, prototype,
475 GetInstancePrototype(isolate, protoype_provider_templ), JSFunction);
476 }
477 } else {
478 ASSIGN_RETURN_ON_EXCEPTION(
479 isolate, prototype,
480 InstantiateObject(
481 isolate,
482 handle(ObjectTemplateInfo::cast(prototype_templ), isolate),
483 Handle<JSReceiver>(), data->hidden_prototype(), true),
484 JSFunction);
485 }
486 Object* parent = data->parent_template();
487 if (!parent->IsUndefined(isolate)) {
488 Handle<Object> parent_prototype;
489 ASSIGN_RETURN_ON_EXCEPTION(isolate, parent_prototype,
490 GetInstancePrototype(isolate, parent),
491 JSFunction);
492 JSObject::ForceSetPrototype(Handle<JSObject>::cast(prototype),
493 parent_prototype);
494 }
495 }
496 Handle<JSFunction> function = ApiNatives::CreateApiFunction(
497 isolate, data, prototype, ApiNatives::JavaScriptObjectType, maybe_name);
498 if (serial_number) {
499 // Cache the function.
500 CacheTemplateInstantiation(isolate, serial_number, CachingMode::kUnlimited,
501 function);
502 }
503 MaybeHandle<JSObject> result =
504 ConfigureInstance(isolate, function, data, data->hidden_prototype());
505 if (result.is_null()) {
506 // Uncache on error.
507 if (serial_number) {
508 UncacheTemplateInstantiation(isolate, serial_number,
509 CachingMode::kUnlimited);
510 }
511 return MaybeHandle<JSFunction>();
512 }
513 return function;
514 }
515
516
AddPropertyToPropertyList(Isolate * isolate,Handle<TemplateInfo> templ,int length,Handle<Object> * data)517 void AddPropertyToPropertyList(Isolate* isolate, Handle<TemplateInfo> templ,
518 int length, Handle<Object>* data) {
519 Object* maybe_list = templ->property_list();
520 Handle<TemplateList> list;
521 if (maybe_list->IsUndefined(isolate)) {
522 list = TemplateList::New(isolate, length);
523 } else {
524 list = handle(TemplateList::cast(maybe_list), isolate);
525 }
526 templ->set_number_of_properties(templ->number_of_properties() + 1);
527 for (int i = 0; i < length; i++) {
528 Handle<Object> value =
529 data[i].is_null()
530 ? Handle<Object>::cast(isolate->factory()->undefined_value())
531 : data[i];
532 list = TemplateList::Add(isolate, list, value);
533 }
534 templ->set_property_list(*list);
535 }
536
537 } // namespace
538
InstantiateFunction(Handle<FunctionTemplateInfo> data,MaybeHandle<Name> maybe_name)539 MaybeHandle<JSFunction> ApiNatives::InstantiateFunction(
540 Handle<FunctionTemplateInfo> data, MaybeHandle<Name> maybe_name) {
541 Isolate* isolate = data->GetIsolate();
542 InvokeScope invoke_scope(isolate);
543 return ::v8::internal::InstantiateFunction(isolate, data, maybe_name);
544 }
545
InstantiateObject(Handle<ObjectTemplateInfo> data,Handle<JSReceiver> new_target)546 MaybeHandle<JSObject> ApiNatives::InstantiateObject(
547 Handle<ObjectTemplateInfo> data, Handle<JSReceiver> new_target) {
548 Isolate* isolate = data->GetIsolate();
549 InvokeScope invoke_scope(isolate);
550 return ::v8::internal::InstantiateObject(isolate, data, new_target, false,
551 false);
552 }
553
InstantiateRemoteObject(Handle<ObjectTemplateInfo> data)554 MaybeHandle<JSObject> ApiNatives::InstantiateRemoteObject(
555 Handle<ObjectTemplateInfo> data) {
556 Isolate* isolate = data->GetIsolate();
557 InvokeScope invoke_scope(isolate);
558
559 Handle<FunctionTemplateInfo> constructor(
560 FunctionTemplateInfo::cast(data->constructor()));
561 Handle<Map> object_map = isolate->factory()->NewMap(
562 JS_SPECIAL_API_OBJECT_TYPE,
563 JSObject::kHeaderSize + data->embedder_field_count() * kPointerSize,
564 TERMINAL_FAST_ELEMENTS_KIND);
565 object_map->SetConstructor(*constructor);
566 object_map->set_is_access_check_needed(true);
567 object_map->set_may_have_interesting_symbols(true);
568
569 Handle<JSObject> object = isolate->factory()->NewJSObjectFromMap(object_map);
570 JSObject::ForceSetPrototype(object, isolate->factory()->null_value());
571
572 return object;
573 }
574
AddDataProperty(Isolate * isolate,Handle<TemplateInfo> info,Handle<Name> name,Handle<Object> value,PropertyAttributes attributes)575 void ApiNatives::AddDataProperty(Isolate* isolate, Handle<TemplateInfo> info,
576 Handle<Name> name, Handle<Object> value,
577 PropertyAttributes attributes) {
578 PropertyDetails details(kData, attributes, PropertyCellType::kNoCell);
579 auto details_handle = handle(details.AsSmi(), isolate);
580 Handle<Object> data[] = {name, details_handle, value};
581 AddPropertyToPropertyList(isolate, info, arraysize(data), data);
582 }
583
584
AddDataProperty(Isolate * isolate,Handle<TemplateInfo> info,Handle<Name> name,v8::Intrinsic intrinsic,PropertyAttributes attributes)585 void ApiNatives::AddDataProperty(Isolate* isolate, Handle<TemplateInfo> info,
586 Handle<Name> name, v8::Intrinsic intrinsic,
587 PropertyAttributes attributes) {
588 auto value = handle(Smi::FromInt(intrinsic), isolate);
589 auto intrinsic_marker = isolate->factory()->true_value();
590 PropertyDetails details(kData, attributes, PropertyCellType::kNoCell);
591 auto details_handle = handle(details.AsSmi(), isolate);
592 Handle<Object> data[] = {name, intrinsic_marker, details_handle, value};
593 AddPropertyToPropertyList(isolate, info, arraysize(data), data);
594 }
595
596
AddAccessorProperty(Isolate * isolate,Handle<TemplateInfo> info,Handle<Name> name,Handle<FunctionTemplateInfo> getter,Handle<FunctionTemplateInfo> setter,PropertyAttributes attributes)597 void ApiNatives::AddAccessorProperty(Isolate* isolate,
598 Handle<TemplateInfo> info,
599 Handle<Name> name,
600 Handle<FunctionTemplateInfo> getter,
601 Handle<FunctionTemplateInfo> setter,
602 PropertyAttributes attributes) {
603 PropertyDetails details(kAccessor, attributes, PropertyCellType::kNoCell);
604 auto details_handle = handle(details.AsSmi(), isolate);
605 Handle<Object> data[] = {name, details_handle, getter, setter};
606 AddPropertyToPropertyList(isolate, info, arraysize(data), data);
607 }
608
609
AddNativeDataProperty(Isolate * isolate,Handle<TemplateInfo> info,Handle<AccessorInfo> property)610 void ApiNatives::AddNativeDataProperty(Isolate* isolate,
611 Handle<TemplateInfo> info,
612 Handle<AccessorInfo> property) {
613 Object* maybe_list = info->property_accessors();
614 Handle<TemplateList> list;
615 if (maybe_list->IsUndefined(isolate)) {
616 list = TemplateList::New(isolate, 1);
617 } else {
618 list = handle(TemplateList::cast(maybe_list), isolate);
619 }
620 list = TemplateList::Add(isolate, list, property);
621 info->set_property_accessors(*list);
622 }
623
CreateApiFunction(Isolate * isolate,Handle<FunctionTemplateInfo> obj,Handle<Object> prototype,ApiInstanceType instance_type,MaybeHandle<Name> maybe_name)624 Handle<JSFunction> ApiNatives::CreateApiFunction(
625 Isolate* isolate, Handle<FunctionTemplateInfo> obj,
626 Handle<Object> prototype, ApiInstanceType instance_type,
627 MaybeHandle<Name> maybe_name) {
628 Handle<SharedFunctionInfo> shared =
629 FunctionTemplateInfo::GetOrCreateSharedFunctionInfo(isolate, obj,
630 maybe_name);
631 // To simplify things, API functions always have shared name.
632 DCHECK(shared->HasSharedName());
633
634 Handle<JSFunction> result =
635 isolate->factory()->NewFunctionFromSharedFunctionInfo(
636 shared, isolate->native_context());
637
638 if (obj->remove_prototype()) {
639 DCHECK(prototype.is_null());
640 DCHECK(result->shared()->IsApiFunction());
641 DCHECK(!result->IsConstructor());
642 DCHECK(!result->has_prototype_slot());
643 return result;
644 }
645
646 // Down from here is only valid for API functions that can be used as a
647 // constructor (don't set the "remove prototype" flag).
648 DCHECK(result->has_prototype_slot());
649
650 if (obj->read_only_prototype()) {
651 result->set_map(*isolate->sloppy_function_with_readonly_prototype_map());
652 }
653
654 if (prototype->IsTheHole(isolate)) {
655 prototype = isolate->factory()->NewFunctionPrototype(result);
656 } else if (obj->prototype_provider_template()->IsUndefined(isolate)) {
657 JSObject::AddProperty(Handle<JSObject>::cast(prototype),
658 isolate->factory()->constructor_string(), result,
659 DONT_ENUM);
660 }
661
662 int embedder_field_count = 0;
663 bool immutable_proto = false;
664 if (!obj->instance_template()->IsUndefined(isolate)) {
665 Handle<ObjectTemplateInfo> instance_template = Handle<ObjectTemplateInfo>(
666 ObjectTemplateInfo::cast(obj->instance_template()));
667 embedder_field_count = instance_template->embedder_field_count();
668 immutable_proto = instance_template->immutable_proto();
669 }
670
671 // TODO(svenpanne) Kill ApiInstanceType and refactor things by generalizing
672 // JSObject::GetHeaderSize.
673 int instance_size = kPointerSize * embedder_field_count;
674 InstanceType type;
675 switch (instance_type) {
676 case JavaScriptObjectType:
677 if (!obj->needs_access_check() &&
678 obj->named_property_handler()->IsUndefined(isolate) &&
679 obj->indexed_property_handler()->IsUndefined(isolate)) {
680 type = JS_API_OBJECT_TYPE;
681 } else {
682 type = JS_SPECIAL_API_OBJECT_TYPE;
683 }
684 instance_size += JSObject::kHeaderSize;
685 break;
686 case GlobalObjectType:
687 type = JS_GLOBAL_OBJECT_TYPE;
688 instance_size += JSGlobalObject::kSize;
689 break;
690 case GlobalProxyType:
691 type = JS_GLOBAL_PROXY_TYPE;
692 instance_size += JSGlobalProxy::kSize;
693 break;
694 default:
695 UNREACHABLE();
696 break;
697 }
698
699 Handle<Map> map = isolate->factory()->NewMap(type, instance_size,
700 TERMINAL_FAST_ELEMENTS_KIND);
701 JSFunction::SetInitialMap(result, map, Handle<JSObject>::cast(prototype));
702
703 // Mark as undetectable if needed.
704 if (obj->undetectable()) {
705 // We only allow callable undetectable receivers here, since this whole
706 // undetectable business is only to support document.all, which is both
707 // undetectable and callable. If we ever see the need to have an object
708 // that is undetectable but not callable, we need to update the types.h
709 // to allow encoding this.
710 CHECK(!obj->instance_call_handler()->IsUndefined(isolate));
711 map->set_is_undetectable(true);
712 }
713
714 // Mark as needs_access_check if needed.
715 if (obj->needs_access_check()) {
716 map->set_is_access_check_needed(true);
717 map->set_may_have_interesting_symbols(true);
718 }
719
720 // Set interceptor information in the map.
721 if (!obj->named_property_handler()->IsUndefined(isolate)) {
722 map->set_has_named_interceptor(true);
723 map->set_may_have_interesting_symbols(true);
724 }
725 if (!obj->indexed_property_handler()->IsUndefined(isolate)) {
726 map->set_has_indexed_interceptor(true);
727 }
728
729 // Mark instance as callable in the map.
730 if (!obj->instance_call_handler()->IsUndefined(isolate)) {
731 map->set_is_callable(true);
732 }
733
734 if (immutable_proto) map->set_is_immutable_proto(true);
735
736 return result;
737 }
738
739 } // namespace internal
740 } // namespace v8
741