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