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