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