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 2098748 : : isolate_(isolate), save_context_(isolate) {}
26 4197496 : ~InvokeScope() {
27 2098748 : bool has_exception = isolate_->has_pending_exception();
28 2098748 : if (has_exception) {
29 0 : isolate_->ReportPendingMessages();
30 : } else {
31 2098748 : isolate_->clear_pending_message();
32 : }
33 2098747 : }
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 2829614 : MaybeHandle<Object> Instantiate(
51 : Isolate* isolate, Handle<Object> data,
52 : MaybeHandle<Name> maybe_name = MaybeHandle<Name>()) {
53 5659228 : if (data->IsFunctionTemplateInfo()) {
54 : return InstantiateFunction(
55 2289101 : isolate, Handle<FunctionTemplateInfo>::cast(data), maybe_name);
56 1081026 : } else if (data->IsObjectTemplateInfo()) {
57 : return InstantiateObject(isolate, Handle<ObjectTemplateInfo>::cast(data),
58 422454 : Handle<JSReceiver>(), false, false);
59 : } else {
60 118059 : return data;
61 : }
62 : }
63 :
64 144 : 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 144 : if (force_instantiate) {
73 0 : if (getter->IsFunctionTemplateInfo()) {
74 0 : ASSIGN_RETURN_ON_EXCEPTION(
75 : isolate, getter,
76 : InstantiateFunction(isolate,
77 : Handle<FunctionTemplateInfo>::cast(getter)),
78 : Object);
79 : }
80 0 : if (setter->IsFunctionTemplateInfo()) {
81 0 : ASSIGN_RETURN_ON_EXCEPTION(
82 : isolate, setter,
83 : InstantiateFunction(isolate,
84 : Handle<FunctionTemplateInfo>::cast(setter)),
85 : Object);
86 : }
87 : }
88 288 : RETURN_ON_EXCEPTION(isolate, JSObject::DefineAccessor(object, name, getter,
89 : setter, attributes),
90 : Object);
91 144 : return object;
92 : }
93 :
94 :
95 2829614 : MaybeHandle<Object> DefineDataProperty(Isolate* isolate,
96 : Handle<JSObject> object,
97 : Handle<Name> name,
98 : Handle<Object> prop_data,
99 : PropertyAttributes attributes) {
100 : Handle<Object> value;
101 5659228 : ASSIGN_RETURN_ON_EXCEPTION(isolate, value,
102 : Instantiate(isolate, prop_data, name), Object);
103 :
104 : LookupIterator it = LookupIterator::PropertyOrElement(
105 2829614 : isolate, object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
106 :
107 : #ifdef DEBUG
108 : Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
109 : DCHECK(maybe.IsJust());
110 : if (it.IsFound()) {
111 : THROW_NEW_ERROR(
112 : isolate,
113 : NewTypeError(MessageTemplate::kDuplicateTemplateProperty, name),
114 : Object);
115 : }
116 : #endif
117 :
118 2829614 : MAYBE_RETURN_NULL(Object::AddDataProperty(&it, value, attributes,
119 : Just(ShouldThrow::kThrowOnError),
120 : StoreOrigin::kNamed));
121 2829614 : return value;
122 : }
123 :
124 :
125 226 : void DisableAccessChecks(Isolate* isolate, Handle<JSObject> object) {
126 : Handle<Map> old_map(object->map(), isolate);
127 : // Copy map so it won't interfere constructor's initial map.
128 226 : Handle<Map> new_map = Map::Copy(isolate, old_map, "DisableAccessChecks");
129 : new_map->set_is_access_check_needed(false);
130 226 : JSObject::MigrateToMap(Handle<JSObject>::cast(object), new_map);
131 226 : }
132 :
133 :
134 226 : void EnableAccessChecks(Isolate* isolate, Handle<JSObject> object) {
135 : Handle<Map> old_map(object->map(), isolate);
136 : // Copy map so it won't interfere constructor's initial map.
137 226 : Handle<Map> new_map = Map::Copy(isolate, old_map, "EnableAccessChecks");
138 : new_map->set_is_access_check_needed(true);
139 226 : new_map->set_may_have_interesting_symbols(true);
140 226 : JSObject::MigrateToMap(object, new_map);
141 226 : }
142 :
143 :
144 : class AccessCheckDisableScope {
145 : public:
146 4239395 : AccessCheckDisableScope(Isolate* isolate, Handle<JSObject> obj)
147 : : isolate_(isolate),
148 : disabled_(obj->map()->is_access_check_needed()),
149 8478790 : obj_(obj) {
150 4239395 : if (disabled_) {
151 226 : DisableAccessChecks(isolate_, obj_);
152 : }
153 4239395 : }
154 : ~AccessCheckDisableScope() {
155 4239394 : if (disabled_) {
156 226 : EnableAccessChecks(isolate_, obj_);
157 : }
158 : }
159 :
160 : private:
161 : Isolate* isolate_;
162 : const bool disabled_;
163 : Handle<JSObject> obj_;
164 : };
165 :
166 60 : Object GetIntrinsic(Isolate* isolate, v8::Intrinsic intrinsic) {
167 60 : Handle<Context> native_context = isolate->native_context();
168 : DCHECK(!native_context.is_null());
169 60 : switch (intrinsic) {
170 : #define GET_INTRINSIC_VALUE(name, iname) \
171 : case v8::k##name: \
172 : return native_context->iname();
173 60 : V8_INTRINSICS_LIST(GET_INTRINSIC_VALUE)
174 : #undef GET_INTRINSIC_VALUE
175 : }
176 0 : return Object();
177 : }
178 :
179 : template <typename TemplateInfoT>
180 4239396 : MaybeHandle<JSObject> ConfigureInstance(Isolate* isolate, Handle<JSObject> obj,
181 : Handle<TemplateInfoT> data,
182 : bool is_hidden_prototype) {
183 : HandleScope scope(isolate);
184 : // Disable access checks while instantiating the object.
185 4239396 : AccessCheckDisableScope access_check_scope(isolate, obj);
186 :
187 : // Walk the inheritance chain and copy all accessors to current object.
188 : int max_number_of_properties = 0;
189 4239395 : TemplateInfoT info = *data;
190 12718598 : while (!info.is_null()) {
191 4239807 : Object props = info->property_accessors();
192 4239808 : if (!props->IsUndefined(isolate)) {
193 52926 : max_number_of_properties += TemplateList::cast(props)->length();
194 : }
195 4239808 : info = info->GetParent(isolate);
196 : }
197 :
198 4239396 : if (max_number_of_properties > 0) {
199 : int valid_descriptors = 0;
200 : // Use a temporary FixedArray to accumulate unique accessors.
201 : Handle<FixedArray> array =
202 52908 : isolate->factory()->NewFixedArray(max_number_of_properties);
203 :
204 105882 : for (Handle<TemplateInfoT> temp(*data, isolate); !temp->is_null();
205 105948 : temp = handle(temp->GetParent(isolate), isolate)) {
206 : // Accumulate accessors.
207 52974 : Object maybe_properties = temp->property_accessors();
208 52974 : if (!maybe_properties->IsUndefined(isolate)) {
209 52926 : valid_descriptors = AccessorInfo::AppendUnique(
210 : isolate, handle(maybe_properties, isolate), array,
211 : valid_descriptors);
212 : }
213 : }
214 :
215 : // Install accumulated accessors.
216 53175 : for (int i = 0; i < valid_descriptors; i++) {
217 : Handle<AccessorInfo> accessor(AccessorInfo::cast(array->get(i)), isolate);
218 106350 : Handle<Name> name(Name::cast(accessor->name()), isolate);
219 : JSObject::SetAccessor(obj, name, accessor,
220 106350 : accessor->initial_property_attributes())
221 53175 : .Assert();
222 : }
223 : }
224 :
225 4239391 : Object maybe_property_list = data->property_list();
226 4239394 : if (maybe_property_list->IsUndefined(isolate)) return obj;
227 : Handle<TemplateList> properties(TemplateList::cast(maybe_property_list),
228 : isolate);
229 373951 : if (properties->length() == 0) return obj;
230 :
231 : int i = 0;
232 6033467 : for (int c = 0; c < data->number_of_properties(); c++) {
233 8489274 : auto name = handle(Name::cast(properties->get(i++)), isolate);
234 5659516 : Object bit = properties->get(i++);
235 2829758 : if (bit->IsSmi()) {
236 : PropertyDetails details(Smi::cast(bit));
237 : PropertyAttributes attributes = details.attributes();
238 : PropertyKind kind = details.kind();
239 :
240 2829698 : if (kind == kData) {
241 8488662 : auto prop_data = handle(properties->get(i++), isolate);
242 5659108 : RETURN_ON_EXCEPTION(isolate, DefineDataProperty(isolate, obj, name,
243 : prop_data, attributes),
244 : JSObject);
245 : } else {
246 432 : auto getter = handle(properties->get(i++), isolate);
247 432 : auto setter = handle(properties->get(i++), isolate);
248 288 : 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 180 : PropertyDetails details(Smi::cast(properties->get(i++)));
257 : PropertyAttributes attributes = details.attributes();
258 : DCHECK_EQ(kData, details.kind());
259 :
260 : v8::Intrinsic intrinsic =
261 120 : static_cast<v8::Intrinsic>(Smi::ToInt(properties->get(i++)));
262 120 : auto prop_data = handle(GetIntrinsic(isolate, intrinsic), isolate);
263 :
264 120 : RETURN_ON_EXCEPTION(isolate, DefineDataProperty(isolate, obj, name,
265 : prop_data, attributes),
266 : JSObject);
267 : }
268 : }
269 373951 : 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 :
280 4625876 : MaybeHandle<JSObject> ProbeInstantiationsCache(Isolate* isolate,
281 : int serial_number,
282 : CachingMode caching_mode) {
283 : DCHECK_LE(1, serial_number);
284 4625876 : if (serial_number <= TemplateInfo::kFastTemplateInstantiationsCacheSize) {
285 : Handle<FixedArray> fast_cache =
286 4560062 : isolate->fast_template_instantiations_cache();
287 9120124 : return fast_cache->GetValue<JSObject>(isolate, serial_number - 1);
288 131628 : } else if (caching_mode == CachingMode::kUnlimited ||
289 65814 : (serial_number <=
290 : TemplateInfo::kSlowTemplateInstantiationsCacheSize)) {
291 : Handle<SimpleNumberDictionary> slow_cache =
292 65814 : isolate->slow_template_instantiations_cache();
293 131628 : int entry = slow_cache->FindEntry(isolate, serial_number);
294 65814 : if (entry == SimpleNumberDictionary::kNotFound) {
295 62835 : return MaybeHandle<JSObject>();
296 : }
297 5958 : return handle(JSObject::cast(slow_cache->ValueAt(entry)), isolate);
298 : } else {
299 0 : return MaybeHandle<JSObject>();
300 : }
301 : }
302 :
303 3777031 : void CacheTemplateInstantiation(Isolate* isolate, int serial_number,
304 : CachingMode caching_mode,
305 : Handle<JSObject> object) {
306 : DCHECK_LE(1, serial_number);
307 3777031 : if (serial_number <= TemplateInfo::kFastTemplateInstantiationsCacheSize) {
308 : Handle<FixedArray> fast_cache =
309 3714214 : isolate->fast_template_instantiations_cache();
310 : Handle<FixedArray> new_cache =
311 3714213 : FixedArray::SetAndGrow(isolate, fast_cache, serial_number - 1, object);
312 3714214 : if (*new_cache != *fast_cache) {
313 0 : isolate->native_context()->set_fast_template_instantiations_cache(
314 0 : *new_cache);
315 : }
316 125634 : } else if (caching_mode == CachingMode::kUnlimited ||
317 62817 : (serial_number <=
318 : TemplateInfo::kSlowTemplateInstantiationsCacheSize)) {
319 : Handle<SimpleNumberDictionary> cache =
320 62817 : isolate->slow_template_instantiations_cache();
321 : auto new_cache =
322 62817 : SimpleNumberDictionary::Set(isolate, cache, serial_number, object);
323 62817 : if (*new_cache != *cache) {
324 0 : isolate->native_context()->set_slow_template_instantiations_cache(
325 0 : *new_cache);
326 : }
327 : }
328 3777031 : }
329 :
330 0 : void UncacheTemplateInstantiation(Isolate* isolate, int serial_number,
331 : CachingMode caching_mode) {
332 : DCHECK_LE(1, serial_number);
333 0 : if (serial_number <= TemplateInfo::kFastTemplateInstantiationsCacheSize) {
334 : Handle<FixedArray> fast_cache =
335 0 : isolate->fast_template_instantiations_cache();
336 : DCHECK(!fast_cache->get(serial_number - 1)->IsUndefined(isolate));
337 0 : fast_cache->set_undefined(serial_number - 1);
338 0 : } else if (caching_mode == CachingMode::kUnlimited ||
339 0 : (serial_number <=
340 : TemplateInfo::kSlowTemplateInstantiationsCacheSize)) {
341 : Handle<SimpleNumberDictionary> cache =
342 0 : isolate->slow_template_instantiations_cache();
343 0 : int entry = cache->FindEntry(isolate, serial_number);
344 : DCHECK_NE(SimpleNumberDictionary::kNotFound, entry);
345 0 : cache = SimpleNumberDictionary::DeleteEntry(isolate, cache, entry);
346 0 : isolate->native_context()->set_slow_template_instantiations_cache(*cache);
347 : }
348 0 : }
349 :
350 297746 : bool IsSimpleInstantiation(Isolate* isolate, ObjectTemplateInfo info,
351 : JSReceiver new_target) {
352 : DisallowHeapAllocation no_gc;
353 :
354 297745 : if (!new_target->IsJSFunction()) return false;
355 297742 : JSFunction fun = JSFunction::cast(new_target);
356 595489 : if (fun->shared()->function_data() != info->constructor()) return false;
357 2718 : if (info->immutable_proto()) return false;
358 5424 : return fun->context()->native_context() == isolate->raw_native_context();
359 : }
360 :
361 940743 : MaybeHandle<JSObject> InstantiateObject(Isolate* isolate,
362 : Handle<ObjectTemplateInfo> info,
363 : Handle<JSReceiver> new_target,
364 : bool is_hidden_prototype,
365 : bool is_prototype) {
366 : Handle<JSFunction> constructor;
367 940746 : int serial_number = Smi::ToInt(info->serial_number());
368 940749 : if (!new_target.is_null()) {
369 297746 : if (IsSimpleInstantiation(isolate, *info, *new_target)) {
370 2712 : constructor = Handle<JSFunction>::cast(new_target);
371 : } else {
372 : // Disable caching for subclass instantiation.
373 : serial_number = 0;
374 : }
375 : }
376 : // Fast path.
377 : Handle<JSObject> result;
378 940750 : if (serial_number) {
379 484252 : if (ProbeInstantiationsCache(isolate, serial_number, CachingMode::kLimited)
380 968504 : .ToHandle(&result)) {
381 213328 : return isolate->factory()->CopyJSObject(result);
382 : }
383 : }
384 :
385 727422 : if (constructor.is_null()) {
386 726024 : Object maybe_constructor_info = info->constructor();
387 726024 : if (maybe_constructor_info->IsUndefined(isolate)) {
388 556682 : constructor = isolate->object_function();
389 : } else {
390 : // Enter a new scope. Recursion could otherwise create a lot of handles.
391 : HandleScope scope(isolate);
392 : Handle<FunctionTemplateInfo> cons_templ(
393 : FunctionTemplateInfo::cast(maybe_constructor_info), isolate);
394 : Handle<JSFunction> tmp_constructor;
395 338684 : ASSIGN_RETURN_ON_EXCEPTION(isolate, tmp_constructor,
396 : InstantiateFunction(isolate, cons_templ),
397 : JSObject);
398 169342 : constructor = scope.CloseAndEscape(tmp_constructor);
399 : }
400 :
401 726022 : if (new_target.is_null()) new_target = constructor;
402 : }
403 :
404 : Handle<JSObject> object;
405 1454841 : ASSIGN_RETURN_ON_EXCEPTION(
406 : isolate, object,
407 : JSObject::New(constructor, new_target, Handle<AllocationSite>::null()),
408 : JSObject);
409 :
410 727421 : if (is_prototype) JSObject::OptimizeAsPrototype(object);
411 :
412 1454837 : ASSIGN_RETURN_ON_EXCEPTION(
413 : isolate, result,
414 : ConfigureInstance(isolate, object, info, is_hidden_prototype), JSObject);
415 727417 : if (info->immutable_proto()) {
416 24 : JSObject::SetImmutableProto(object);
417 : }
418 727417 : if (!is_prototype) {
419 : // Keep prototypes in slow-mode. Let them be lazily turned fast later on.
420 : // TODO(dcarney): is this necessary?
421 619766 : JSObject::MigrateSlowToFast(result, 0, "ApiNatives::InstantiateObject");
422 : // Don't cache prototypes.
423 619767 : if (serial_number) {
424 : CacheTemplateInstantiation(isolate, serial_number, CachingMode::kLimited,
425 270198 : result);
426 270198 : result = isolate->factory()->CopyJSObject(result);
427 : }
428 : }
429 :
430 727418 : return result;
431 : }
432 :
433 : namespace {
434 243 : MaybeHandle<Object> GetInstancePrototype(Isolate* isolate,
435 : Object function_template) {
436 : // Enter a new scope. Recursion could otherwise create a lot of handles.
437 : HandleScope scope(isolate);
438 : Handle<JSFunction> parent_instance;
439 729 : ASSIGN_RETURN_ON_EXCEPTION(
440 : isolate, parent_instance,
441 : InstantiateFunction(
442 : isolate,
443 : handle(FunctionTemplateInfo::cast(function_template), isolate)),
444 : JSFunction);
445 : Handle<Object> instance_prototype;
446 : // TODO(cbruni): decide what to do here.
447 486 : ASSIGN_RETURN_ON_EXCEPTION(
448 : isolate, instance_prototype,
449 : JSObject::GetProperty(isolate, parent_instance,
450 : isolate->factory()->prototype_string()),
451 : JSFunction);
452 243 : return scope.CloseAndEscape(instance_prototype);
453 : }
454 : } // namespace
455 :
456 4146767 : MaybeHandle<JSFunction> InstantiateFunction(Isolate* isolate,
457 : Handle<FunctionTemplateInfo> data,
458 : MaybeHandle<Name> maybe_name) {
459 4146767 : int serial_number = Smi::ToInt(data->serial_number());
460 4146767 : if (serial_number) {
461 : Handle<JSObject> result;
462 4141623 : if (ProbeInstantiationsCache(isolate, serial_number,
463 : CachingMode::kUnlimited)
464 8283247 : .ToHandle(&result)) {
465 634792 : return Handle<JSFunction>::cast(result);
466 : }
467 : }
468 : Handle<Object> prototype;
469 3511975 : if (!data->remove_prototype()) {
470 3507158 : Object prototype_templ = data->GetPrototypeTemplate();
471 3507157 : if (prototype_templ->IsUndefined(isolate)) {
472 3399506 : Object protoype_provider_templ = data->GetPrototypeProviderTemplate();
473 3399506 : if (protoype_provider_templ->IsUndefined(isolate)) {
474 3399501 : prototype = isolate->factory()->NewJSObject(isolate->object_function());
475 : } else {
476 10 : ASSIGN_RETURN_ON_EXCEPTION(
477 : isolate, prototype,
478 : GetInstancePrototype(isolate, protoype_provider_templ), JSFunction);
479 : }
480 : } else {
481 322953 : ASSIGN_RETURN_ON_EXCEPTION(
482 : isolate, prototype,
483 : InstantiateObject(
484 : isolate,
485 : handle(ObjectTemplateInfo::cast(prototype_templ), isolate),
486 : Handle<JSReceiver>(), data->hidden_prototype(), true),
487 : JSFunction);
488 : }
489 3507159 : Object parent = data->GetParentTemplate();
490 3507160 : if (!parent->IsUndefined(isolate)) {
491 : Handle<Object> parent_prototype;
492 476 : ASSIGN_RETURN_ON_EXCEPTION(isolate, parent_prototype,
493 : GetInstancePrototype(isolate, parent),
494 : JSFunction);
495 : JSObject::ForceSetPrototype(Handle<JSObject>::cast(prototype),
496 238 : parent_prototype);
497 : }
498 : }
499 : InstanceType function_type =
500 10535702 : (!data->needs_access_check() &&
501 10534560 : data->GetNamedPropertyHandler()->IsUndefined(isolate) &&
502 7022810 : data->GetIndexedPropertyHandler()->IsUndefined(isolate))
503 : ? JS_API_OBJECT_TYPE
504 3511976 : : JS_SPECIAL_API_OBJECT_TYPE;
505 :
506 : Handle<JSFunction> function = ApiNatives::CreateApiFunction(
507 3511976 : isolate, data, prototype, function_type, maybe_name);
508 3511976 : if (serial_number) {
509 : // Cache the function.
510 : CacheTemplateInstantiation(isolate, serial_number, CachingMode::kUnlimited,
511 3506833 : function);
512 : }
513 : MaybeHandle<JSObject> result =
514 7023952 : ConfigureInstance(isolate, function, data, data->hidden_prototype());
515 3511975 : if (result.is_null()) {
516 : // Uncache on error.
517 0 : if (serial_number) {
518 : UncacheTemplateInstantiation(isolate, serial_number,
519 0 : CachingMode::kUnlimited);
520 : }
521 0 : return MaybeHandle<JSFunction>();
522 : }
523 3511975 : return function;
524 : }
525 :
526 :
527 1989670 : void AddPropertyToPropertyList(Isolate* isolate, Handle<TemplateInfo> templ,
528 : int length, Handle<Object>* data) {
529 1989670 : Object maybe_list = templ->property_list();
530 : Handle<TemplateList> list;
531 1989670 : if (maybe_list->IsUndefined(isolate)) {
532 318999 : list = TemplateList::New(isolate, length);
533 : } else {
534 : list = handle(TemplateList::cast(maybe_list), isolate);
535 : }
536 1989670 : templ->set_number_of_properties(templ->number_of_properties() + 1);
537 7958844 : for (int i = 0; i < length; i++) {
538 : Handle<Object> value =
539 5969174 : data[i].is_null()
540 : ? Handle<Object>::cast(isolate->factory()->undefined_value())
541 5969233 : : data[i];
542 5969174 : list = TemplateList::Add(isolate, list, value);
543 : }
544 3979340 : templ->set_property_list(*list);
545 1989670 : }
546 :
547 : } // namespace
548 :
549 1688081 : MaybeHandle<JSFunction> ApiNatives::InstantiateFunction(
550 : Handle<FunctionTemplateInfo> data, MaybeHandle<Name> maybe_name) {
551 : Isolate* isolate = data->GetIsolate();
552 : InvokeScope invoke_scope(isolate);
553 1688081 : return ::v8::internal::InstantiateFunction(isolate, data, maybe_name);
554 : }
555 :
556 410641 : MaybeHandle<JSObject> ApiNatives::InstantiateObject(
557 : Isolate* isolate, Handle<ObjectTemplateInfo> data,
558 : Handle<JSReceiver> new_target) {
559 : InvokeScope invoke_scope(isolate);
560 : return ::v8::internal::InstantiateObject(isolate, data, new_target, false,
561 410643 : false);
562 : }
563 :
564 26 : MaybeHandle<JSObject> ApiNatives::InstantiateRemoteObject(
565 : Handle<ObjectTemplateInfo> data) {
566 : Isolate* isolate = data->GetIsolate();
567 : InvokeScope invoke_scope(isolate);
568 :
569 : Handle<FunctionTemplateInfo> constructor(
570 : FunctionTemplateInfo::cast(data->constructor()), isolate);
571 : Handle<Map> object_map = isolate->factory()->NewMap(
572 : JS_SPECIAL_API_OBJECT_TYPE,
573 : JSObject::kHeaderSize +
574 52 : data->embedder_field_count() * kEmbedderDataSlotSize,
575 26 : TERMINAL_FAST_ELEMENTS_KIND);
576 52 : object_map->SetConstructor(*constructor);
577 : object_map->set_is_access_check_needed(true);
578 26 : object_map->set_may_have_interesting_symbols(true);
579 :
580 26 : Handle<JSObject> object = isolate->factory()->NewJSObjectFromMap(object_map);
581 26 : JSObject::ForceSetPrototype(object, isolate->factory()->null_value());
582 :
583 26 : return object;
584 : }
585 :
586 1989506 : void ApiNatives::AddDataProperty(Isolate* isolate, Handle<TemplateInfo> info,
587 : Handle<Name> name, Handle<Object> value,
588 : PropertyAttributes attributes) {
589 : PropertyDetails details(kData, attributes, PropertyCellType::kNoCell);
590 : auto details_handle = handle(details.AsSmi(), isolate);
591 1989506 : Handle<Object> data[] = {name, details_handle, value};
592 1989506 : AddPropertyToPropertyList(isolate, info, arraysize(data), data);
593 1989506 : }
594 :
595 :
596 55 : void ApiNatives::AddDataProperty(Isolate* isolate, Handle<TemplateInfo> info,
597 : Handle<Name> name, v8::Intrinsic intrinsic,
598 : PropertyAttributes attributes) {
599 55 : auto value = handle(Smi::FromInt(intrinsic), isolate);
600 : auto intrinsic_marker = isolate->factory()->true_value();
601 : PropertyDetails details(kData, attributes, PropertyCellType::kNoCell);
602 : auto details_handle = handle(details.AsSmi(), isolate);
603 : Handle<Object> data[] = {name, intrinsic_marker, details_handle, value};
604 55 : AddPropertyToPropertyList(isolate, info, arraysize(data), data);
605 55 : }
606 :
607 :
608 109 : void ApiNatives::AddAccessorProperty(Isolate* isolate,
609 : Handle<TemplateInfo> info,
610 : Handle<Name> name,
611 : Handle<FunctionTemplateInfo> getter,
612 : Handle<FunctionTemplateInfo> setter,
613 : PropertyAttributes attributes) {
614 : PropertyDetails details(kAccessor, attributes, PropertyCellType::kNoCell);
615 : auto details_handle = handle(details.AsSmi(), isolate);
616 : Handle<Object> data[] = {name, details_handle, getter, setter};
617 109 : AddPropertyToPropertyList(isolate, info, arraysize(data), data);
618 109 : }
619 :
620 :
621 53104 : void ApiNatives::AddNativeDataProperty(Isolate* isolate,
622 : Handle<TemplateInfo> info,
623 : Handle<AccessorInfo> property) {
624 53104 : Object maybe_list = info->property_accessors();
625 : Handle<TemplateList> list;
626 53104 : if (maybe_list->IsUndefined(isolate)) {
627 52867 : list = TemplateList::New(isolate, 1);
628 : } else {
629 : list = handle(TemplateList::cast(maybe_list), isolate);
630 : }
631 53104 : list = TemplateList::Add(isolate, list, property);
632 106208 : info->set_property_accessors(*list);
633 53104 : }
634 :
635 3622376 : Handle<JSFunction> ApiNatives::CreateApiFunction(
636 : Isolate* isolate, Handle<FunctionTemplateInfo> obj,
637 : Handle<Object> prototype, InstanceType type, MaybeHandle<Name> maybe_name) {
638 : Handle<SharedFunctionInfo> shared =
639 : FunctionTemplateInfo::GetOrCreateSharedFunctionInfo(isolate, obj,
640 3622376 : maybe_name);
641 : // To simplify things, API functions always have shared name.
642 : DCHECK(shared->HasSharedName());
643 :
644 : Handle<JSFunction> result =
645 : isolate->factory()->NewFunctionFromSharedFunctionInfo(
646 7244748 : shared, isolate->native_context());
647 :
648 3622374 : if (obj->remove_prototype()) {
649 : DCHECK(prototype.is_null());
650 : DCHECK(result->shared()->IsApiFunction());
651 : DCHECK(!result->IsConstructor());
652 : DCHECK(!result->has_prototype_slot());
653 4816 : return result;
654 : }
655 :
656 : // Down from here is only valid for API functions that can be used as a
657 : // constructor (don't set the "remove prototype" flag).
658 : DCHECK(result->has_prototype_slot());
659 :
660 3617558 : if (obj->read_only_prototype()) {
661 3458682 : result->set_map(*isolate->sloppy_function_with_readonly_prototype_map());
662 : }
663 :
664 7235114 : if (prototype->IsTheHole(isolate)) {
665 110400 : prototype = isolate->factory()->NewFunctionPrototype(result);
666 7014314 : } else if (obj->GetPrototypeProviderTemplate()->IsUndefined(isolate)) {
667 : JSObject::AddProperty(isolate, Handle<JSObject>::cast(prototype),
668 : isolate->factory()->constructor_string(), result,
669 3507152 : DONT_ENUM);
670 : }
671 :
672 : int embedder_field_count = 0;
673 : bool immutable_proto = false;
674 7235115 : if (!obj->GetInstanceTemplate()->IsUndefined(isolate)) {
675 : Handle<ObjectTemplateInfo> GetInstanceTemplate = Handle<ObjectTemplateInfo>(
676 549772 : ObjectTemplateInfo::cast(obj->GetInstanceTemplate()), isolate);
677 274886 : embedder_field_count = GetInstanceTemplate->embedder_field_count();
678 274886 : immutable_proto = GetInstanceTemplate->immutable_proto();
679 : }
680 :
681 : // JS_FUNCTION_TYPE requires information about the prototype slot.
682 : DCHECK_NE(JS_FUNCTION_TYPE, type);
683 3617557 : int instance_size = JSObject::GetHeaderSize(type) +
684 3617556 : kEmbedderDataSlotSize * embedder_field_count;
685 :
686 : Handle<Map> map = isolate->factory()->NewMap(type, instance_size,
687 3617556 : TERMINAL_FAST_ELEMENTS_KIND);
688 7235109 : JSFunction::SetInitialMap(result, map, Handle<JSObject>::cast(prototype));
689 :
690 : // Mark as undetectable if needed.
691 3617558 : if (obj->undetectable()) {
692 : // We only allow callable undetectable receivers here, since this whole
693 : // undetectable business is only to support document.all, which is both
694 : // undetectable and callable. If we ever see the need to have an object
695 : // that is undetectable but not callable, we need to update the types.h
696 : // to allow encoding this.
697 298 : CHECK(!obj->GetInstanceCallHandler()->IsUndefined(isolate));
698 : map->set_is_undetectable(true);
699 : }
700 :
701 : // Mark as needs_access_check if needed.
702 3617558 : if (obj->needs_access_check()) {
703 : map->set_is_access_check_needed(true);
704 349 : map->set_may_have_interesting_symbols(true);
705 : }
706 :
707 : // Set interceptor information in the map.
708 7235118 : if (!obj->GetNamedPropertyHandler()->IsUndefined(isolate)) {
709 : map->set_has_named_interceptor(true);
710 1060 : map->set_may_have_interesting_symbols(true);
711 : }
712 7235119 : if (!obj->GetIndexedPropertyHandler()->IsUndefined(isolate)) {
713 : map->set_has_indexed_interceptor(true);
714 : }
715 :
716 : // Mark instance as callable in the map.
717 7235119 : if (!obj->GetInstanceCallHandler()->IsUndefined(isolate)) {
718 : map->set_is_callable(true);
719 394 : map->set_is_constructor(!obj->undetectable());
720 : }
721 :
722 3617577 : if (immutable_proto) map->set_is_immutable_proto(true);
723 :
724 3617559 : return result;
725 : }
726 :
727 : } // namespace internal
728 178779 : } // namespace v8
|