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