blob: fcd19ccadad7b364599d830ac72f90c0a40c5ace [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// 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
12namespace v8 {
13namespace internal {
14
15
16namespace {
17
18MaybeHandle<JSObject> InstantiateObject(Isolate* isolate,
Ben Murdoch097c5b22016-05-18 11:27:45 +010019 Handle<ObjectTemplateInfo> data,
Ben Murdochc5610432016-08-08 18:44:38 +010020 Handle<JSReceiver> new_target,
Ben Murdoch097c5b22016-05-18 11:27:45 +010021 bool is_hidden_prototype);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000022
23MaybeHandle<JSFunction> InstantiateFunction(Isolate* isolate,
24 Handle<FunctionTemplateInfo> data,
25 Handle<Name> name = Handle<Name>());
26
27
28MaybeHandle<Object> Instantiate(Isolate* isolate, Handle<Object> data,
29 Handle<Name> name = Handle<Name>()) {
30 if (data->IsFunctionTemplateInfo()) {
31 return InstantiateFunction(isolate,
32 Handle<FunctionTemplateInfo>::cast(data), name);
33 } else if (data->IsObjectTemplateInfo()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +010034 return InstantiateObject(isolate, Handle<ObjectTemplateInfo>::cast(data),
Ben Murdochc5610432016-08-08 18:44:38 +010035 Handle<JSReceiver>(), false);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000036 } else {
37 return data;
38 }
39}
40
Ben Murdoch097c5b22016-05-18 11:27:45 +010041MaybeHandle<Object> DefineAccessorProperty(
42 Isolate* isolate, Handle<JSObject> object, Handle<Name> name,
43 Handle<Object> getter, Handle<Object> setter, PropertyAttributes attributes,
44 bool force_instantiate) {
45 DCHECK(!getter->IsFunctionTemplateInfo() ||
46 !FunctionTemplateInfo::cast(*getter)->do_not_cache());
47 DCHECK(!setter->IsFunctionTemplateInfo() ||
48 !FunctionTemplateInfo::cast(*setter)->do_not_cache());
49 if (force_instantiate) {
50 if (getter->IsFunctionTemplateInfo()) {
51 ASSIGN_RETURN_ON_EXCEPTION(
52 isolate, getter,
53 InstantiateFunction(isolate,
54 Handle<FunctionTemplateInfo>::cast(getter)),
55 Object);
56 }
57 if (setter->IsFunctionTemplateInfo()) {
58 ASSIGN_RETURN_ON_EXCEPTION(
59 isolate, setter,
60 InstantiateFunction(isolate,
61 Handle<FunctionTemplateInfo>::cast(setter)),
62 Object);
63 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000064 }
65 RETURN_ON_EXCEPTION(isolate, JSObject::DefineAccessor(object, name, getter,
66 setter, attributes),
67 Object);
68 return object;
69}
70
71
72MaybeHandle<Object> DefineDataProperty(Isolate* isolate,
73 Handle<JSObject> object,
74 Handle<Name> name,
75 Handle<Object> prop_data,
76 PropertyAttributes attributes) {
77 Handle<Object> value;
78 ASSIGN_RETURN_ON_EXCEPTION(isolate, value,
79 Instantiate(isolate, prop_data, name), Object);
80
81 LookupIterator it = LookupIterator::PropertyOrElement(
82 isolate, object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
83
84#ifdef DEBUG
85 Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
86 DCHECK(maybe.IsJust());
87 if (it.IsFound()) {
88 THROW_NEW_ERROR(
89 isolate,
90 NewTypeError(MessageTemplate::kDuplicateTemplateProperty, name),
91 Object);
92 }
93#endif
94
95 MAYBE_RETURN_NULL(
96 Object::AddDataProperty(&it, value, attributes, Object::THROW_ON_ERROR,
97 Object::CERTAINLY_NOT_STORE_FROM_KEYED));
98 return value;
99}
100
101
102void DisableAccessChecks(Isolate* isolate, Handle<JSObject> object) {
103 Handle<Map> old_map(object->map());
104 // Copy map so it won't interfere constructor's initial map.
105 Handle<Map> new_map = Map::Copy(old_map, "DisableAccessChecks");
106 new_map->set_is_access_check_needed(false);
107 JSObject::MigrateToMap(Handle<JSObject>::cast(object), new_map);
108}
109
110
111void EnableAccessChecks(Isolate* isolate, Handle<JSObject> object) {
112 Handle<Map> old_map(object->map());
113 // Copy map so it won't interfere constructor's initial map.
114 Handle<Map> new_map = Map::Copy(old_map, "EnableAccessChecks");
115 new_map->set_is_access_check_needed(true);
116 JSObject::MigrateToMap(object, new_map);
117}
118
119
120class AccessCheckDisableScope {
121 public:
122 AccessCheckDisableScope(Isolate* isolate, Handle<JSObject> obj)
123 : isolate_(isolate),
124 disabled_(obj->map()->is_access_check_needed()),
125 obj_(obj) {
126 if (disabled_) {
127 DisableAccessChecks(isolate_, obj_);
128 }
129 }
130 ~AccessCheckDisableScope() {
131 if (disabled_) {
132 EnableAccessChecks(isolate_, obj_);
133 }
134 }
135
136 private:
137 Isolate* isolate_;
138 const bool disabled_;
139 Handle<JSObject> obj_;
140};
141
142
143Object* GetIntrinsic(Isolate* isolate, v8::Intrinsic intrinsic) {
144 Handle<Context> native_context = isolate->native_context();
145 DCHECK(!native_context.is_null());
146 switch (intrinsic) {
147#define GET_INTRINSIC_VALUE(name, iname) \
148 case v8::k##name: \
149 return native_context->iname();
150 V8_INTRINSICS_LIST(GET_INTRINSIC_VALUE)
151#undef GET_INTRINSIC_VALUE
152 }
153 return nullptr;
154}
155
Ben Murdoch097c5b22016-05-18 11:27:45 +0100156// Returns parent function template or null.
157FunctionTemplateInfo* GetParent(FunctionTemplateInfo* data) {
158 Object* parent = data->parent_template();
159 return parent->IsUndefined() ? nullptr : FunctionTemplateInfo::cast(parent);
160}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000161
Ben Murdoch097c5b22016-05-18 11:27:45 +0100162// Starting from given object template's constructor walk up the inheritance
163// chain till a function template that has an instance template is found.
164ObjectTemplateInfo* GetParent(ObjectTemplateInfo* data) {
165 Object* maybe_ctor = data->constructor();
166 if (maybe_ctor->IsUndefined()) return nullptr;
167 FunctionTemplateInfo* ctor = FunctionTemplateInfo::cast(maybe_ctor);
168 while (true) {
169 ctor = GetParent(ctor);
170 if (ctor == nullptr) return nullptr;
171 Object* maybe_obj = ctor->instance_template();
172 if (!maybe_obj->IsUndefined()) return ObjectTemplateInfo::cast(maybe_obj);
173 }
174}
175
176template <typename TemplateInfoT>
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000177MaybeHandle<JSObject> ConfigureInstance(Isolate* isolate, Handle<JSObject> obj,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100178 Handle<TemplateInfoT> data,
179 bool is_hidden_prototype) {
180 HandleScope scope(isolate);
181 // Disable access checks while instantiating the object.
182 AccessCheckDisableScope access_check_scope(isolate, obj);
183
184 // Walk the inheritance chain and copy all accessors to current object.
185 int max_number_of_properties = 0;
186 TemplateInfoT* info = *data;
187 while (info != nullptr) {
188 if (!info->property_accessors()->IsUndefined()) {
189 Object* props = info->property_accessors();
190 if (!props->IsUndefined()) {
191 Handle<Object> props_handle(props, isolate);
192 NeanderArray props_array(props_handle);
193 max_number_of_properties += props_array.length();
194 }
195 }
196 info = GetParent(info);
197 }
198
199 if (max_number_of_properties > 0) {
200 int valid_descriptors = 0;
201 // Use a temporary FixedArray to accumulate unique accessors.
202 Handle<FixedArray> array =
203 isolate->factory()->NewFixedArray(max_number_of_properties);
204
205 info = *data;
206 while (info != nullptr) {
207 // Accumulate accessors.
208 if (!info->property_accessors()->IsUndefined()) {
209 Handle<Object> props(info->property_accessors(), isolate);
210 valid_descriptors =
211 AccessorInfo::AppendUnique(props, array, valid_descriptors);
212 }
213 info = GetParent(info);
214 }
215
216 // Install accumulated accessors.
217 for (int i = 0; i < valid_descriptors; i++) {
218 Handle<AccessorInfo> accessor(AccessorInfo::cast(array->get(i)));
219 JSObject::SetAccessor(obj, accessor).Assert();
220 }
221 }
222
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000223 auto property_list = handle(data->property_list(), isolate);
224 if (property_list->IsUndefined()) return obj;
225 // TODO(dcarney): just use a FixedArray here.
226 NeanderArray properties(property_list);
227 if (properties.length() == 0) return obj;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000228
229 int i = 0;
230 for (int c = 0; c < data->number_of_properties(); c++) {
231 auto name = handle(Name::cast(properties.get(i++)), isolate);
232 auto bit = handle(properties.get(i++), isolate);
233 if (bit->IsSmi()) {
234 PropertyDetails details(Smi::cast(*bit));
235 PropertyAttributes attributes = details.attributes();
236 PropertyKind kind = details.kind();
237
238 if (kind == kData) {
239 auto prop_data = handle(properties.get(i++), isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000240 RETURN_ON_EXCEPTION(isolate, DefineDataProperty(isolate, obj, name,
241 prop_data, attributes),
242 JSObject);
243 } else {
244 auto getter = handle(properties.get(i++), isolate);
245 auto setter = handle(properties.get(i++), isolate);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100246 RETURN_ON_EXCEPTION(
247 isolate, DefineAccessorProperty(isolate, obj, name, getter, setter,
248 attributes, is_hidden_prototype),
249 JSObject);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000250 }
251 } else {
252 // Intrinsic data property --- Get appropriate value from the current
253 // context.
254 PropertyDetails details(Smi::cast(properties.get(i++)));
255 PropertyAttributes attributes = details.attributes();
256 DCHECK_EQ(kData, details.kind());
257
258 v8::Intrinsic intrinsic =
259 static_cast<v8::Intrinsic>(Smi::cast(properties.get(i++))->value());
260 auto prop_data = handle(GetIntrinsic(isolate, intrinsic), isolate);
261
262 RETURN_ON_EXCEPTION(isolate, DefineDataProperty(isolate, obj, name,
263 prop_data, attributes),
264 JSObject);
265 }
266 }
267 return obj;
268}
269
Ben Murdochda12d292016-06-02 14:46:10 +0100270void CacheTemplateInstantiation(Isolate* isolate, uint32_t serial_number,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100271 Handle<JSObject> object) {
272 auto cache = isolate->template_instantiations_cache();
Ben Murdochda12d292016-06-02 14:46:10 +0100273 auto new_cache =
274 UnseededNumberDictionary::AtNumberPut(cache, serial_number, object);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100275 isolate->native_context()->set_template_instantiations_cache(*new_cache);
276}
277
Ben Murdochda12d292016-06-02 14:46:10 +0100278void UncacheTemplateInstantiation(Isolate* isolate, uint32_t serial_number) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100279 auto cache = isolate->template_instantiations_cache();
Ben Murdochda12d292016-06-02 14:46:10 +0100280 int entry = cache->FindEntry(serial_number);
281 DCHECK(entry != UnseededNumberDictionary::kNotFound);
282 Handle<Object> result =
283 UnseededNumberDictionary::DeleteProperty(cache, entry);
284 USE(result);
285 DCHECK(result->IsTrue());
286 auto new_cache = UnseededNumberDictionary::Shrink(cache, entry);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100287 isolate->native_context()->set_template_instantiations_cache(*new_cache);
288}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000289
290MaybeHandle<JSObject> InstantiateObject(Isolate* isolate,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100291 Handle<ObjectTemplateInfo> info,
Ben Murdochc5610432016-08-08 18:44:38 +0100292 Handle<JSReceiver> new_target,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100293 bool is_hidden_prototype) {
Ben Murdochc5610432016-08-08 18:44:38 +0100294 Handle<JSFunction> constructor;
Ben Murdochda12d292016-06-02 14:46:10 +0100295 uint32_t serial_number =
296 static_cast<uint32_t>(Smi::cast(info->serial_number())->value());
Ben Murdochc5610432016-08-08 18:44:38 +0100297 if (!new_target.is_null()) {
298 if (new_target->IsJSFunction() &&
299 JSFunction::cast(*new_target)->shared()->function_data() ==
300 info->constructor() &&
301 JSFunction::cast(*new_target)->context()->native_context() ==
302 isolate->context()->native_context()) {
303 constructor = Handle<JSFunction>::cast(new_target);
304 } else {
305 // Disable caching for subclass instantiation.
306 serial_number = 0;
307 }
308 }
309 // Fast path.
310 Handle<JSObject> result;
Ben Murdochda12d292016-06-02 14:46:10 +0100311 if (serial_number) {
312 // Probe cache.
313 auto cache = isolate->template_instantiations_cache();
314 int entry = cache->FindEntry(serial_number);
315 if (entry != UnseededNumberDictionary::kNotFound) {
316 Object* boilerplate = cache->ValueAt(entry);
317 result = handle(JSObject::cast(boilerplate), isolate);
318 return isolate->factory()->CopyJSObject(result);
319 }
320 }
321 // Enter a new scope. Recursion could otherwise create a lot of handles.
322 HandleScope scope(isolate);
Ben Murdochc5610432016-08-08 18:44:38 +0100323
324 if (constructor.is_null()) {
325 Handle<Object> cons(info->constructor(), isolate);
326 if (cons->IsUndefined()) {
327 constructor = isolate->object_function();
328 } else {
329 auto cons_templ = Handle<FunctionTemplateInfo>::cast(cons);
330 ASSIGN_RETURN_ON_EXCEPTION(isolate, constructor,
331 InstantiateFunction(isolate, cons_templ),
332 JSObject);
333 }
334
335 if (new_target.is_null()) new_target = constructor;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000336 }
Ben Murdochc5610432016-08-08 18:44:38 +0100337
338 Handle<JSObject> object;
339 ASSIGN_RETURN_ON_EXCEPTION(isolate, object,
340 JSObject::New(constructor, new_target), JSObject);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000341 ASSIGN_RETURN_ON_EXCEPTION(
Ben Murdoch097c5b22016-05-18 11:27:45 +0100342 isolate, result,
Ben Murdochc5610432016-08-08 18:44:38 +0100343 ConfigureInstance(isolate, object, info, is_hidden_prototype), JSObject);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000344 // TODO(dcarney): is this necessary?
345 JSObject::MigrateSlowToFast(result, 0, "ApiNatives::InstantiateObject");
Ben Murdoch097c5b22016-05-18 11:27:45 +0100346
Ben Murdochda12d292016-06-02 14:46:10 +0100347 if (serial_number) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100348 CacheTemplateInstantiation(isolate, serial_number, result);
Ben Murdochda12d292016-06-02 14:46:10 +0100349 result = isolate->factory()->CopyJSObject(result);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100350 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000351 return scope.CloseAndEscape(result);
352}
353
354
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000355MaybeHandle<JSFunction> InstantiateFunction(Isolate* isolate,
356 Handle<FunctionTemplateInfo> data,
357 Handle<Name> name) {
Ben Murdochda12d292016-06-02 14:46:10 +0100358 uint32_t serial_number =
359 static_cast<uint32_t>(Smi::cast(data->serial_number())->value());
360 if (serial_number) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100361 // Probe cache.
362 auto cache = isolate->template_instantiations_cache();
Ben Murdochda12d292016-06-02 14:46:10 +0100363 int entry = cache->FindEntry(serial_number);
364 if (entry != UnseededNumberDictionary::kNotFound) {
365 Object* element = cache->ValueAt(entry);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000366 return handle(JSFunction::cast(element), isolate);
367 }
368 }
369 // Enter a new scope. Recursion could otherwise create a lot of handles.
370 HandleScope scope(isolate);
371 Handle<JSObject> prototype;
372 if (!data->remove_prototype()) {
373 auto prototype_templ = handle(data->prototype_template(), isolate);
374 if (prototype_templ->IsUndefined()) {
375 prototype = isolate->factory()->NewJSObject(isolate->object_function());
376 } else {
377 ASSIGN_RETURN_ON_EXCEPTION(
378 isolate, prototype,
379 InstantiateObject(isolate,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100380 Handle<ObjectTemplateInfo>::cast(prototype_templ),
Ben Murdochc5610432016-08-08 18:44:38 +0100381 Handle<JSReceiver>(), data->hidden_prototype()),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000382 JSFunction);
383 }
384 auto parent = handle(data->parent_template(), isolate);
385 if (!parent->IsUndefined()) {
386 Handle<JSFunction> parent_instance;
387 ASSIGN_RETURN_ON_EXCEPTION(
388 isolate, parent_instance,
389 InstantiateFunction(isolate,
390 Handle<FunctionTemplateInfo>::cast(parent)),
391 JSFunction);
392 // TODO(dcarney): decide what to do here.
393 Handle<Object> parent_prototype;
394 ASSIGN_RETURN_ON_EXCEPTION(
395 isolate, parent_prototype,
396 JSObject::GetProperty(parent_instance,
397 isolate->factory()->prototype_string()),
398 JSFunction);
399 MAYBE_RETURN(JSObject::SetPrototype(prototype, parent_prototype, false,
400 Object::THROW_ON_ERROR),
401 MaybeHandle<JSFunction>());
402 }
403 }
404 auto function = ApiNatives::CreateApiFunction(
405 isolate, data, prototype, ApiNatives::JavaScriptObjectType);
406 if (!name.is_null() && name->IsString()) {
407 function->shared()->set_name(*name);
408 }
Ben Murdochda12d292016-06-02 14:46:10 +0100409 if (serial_number) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000410 // Cache the function.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100411 CacheTemplateInstantiation(isolate, serial_number, function);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000412 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100413 auto result =
414 ConfigureInstance(isolate, function, data, data->hidden_prototype());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000415 if (result.is_null()) {
416 // Uncache on error.
Ben Murdochda12d292016-06-02 14:46:10 +0100417 if (serial_number) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100418 UncacheTemplateInstantiation(isolate, serial_number);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000419 }
420 return MaybeHandle<JSFunction>();
421 }
422 return scope.CloseAndEscape(function);
423}
424
425
426class InvokeScope {
427 public:
428 explicit InvokeScope(Isolate* isolate)
429 : isolate_(isolate), save_context_(isolate) {}
430 ~InvokeScope() {
431 bool has_exception = isolate_->has_pending_exception();
432 if (has_exception) {
433 isolate_->ReportPendingMessages();
434 } else {
435 isolate_->clear_pending_message();
436 }
437 }
438
439 private:
440 Isolate* isolate_;
441 SaveContext save_context_;
442};
443
444
445void AddPropertyToPropertyList(Isolate* isolate, Handle<TemplateInfo> templ,
446 int length, Handle<Object>* data) {
447 auto list = handle(templ->property_list(), isolate);
448 if (list->IsUndefined()) {
449 list = NeanderArray(isolate).value();
450 templ->set_property_list(*list);
451 }
452 templ->set_number_of_properties(templ->number_of_properties() + 1);
453 NeanderArray array(list);
454 for (int i = 0; i < length; i++) {
455 Handle<Object> value =
456 data[i].is_null()
457 ? Handle<Object>::cast(isolate->factory()->undefined_value())
458 : data[i];
459 array.add(isolate, value);
460 }
461}
462
463} // namespace
464
465
466MaybeHandle<JSFunction> ApiNatives::InstantiateFunction(
467 Handle<FunctionTemplateInfo> data) {
468 Isolate* isolate = data->GetIsolate();
469 InvokeScope invoke_scope(isolate);
470 return ::v8::internal::InstantiateFunction(isolate, data);
471}
472
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000473MaybeHandle<JSObject> ApiNatives::InstantiateObject(
Ben Murdochc5610432016-08-08 18:44:38 +0100474 Handle<ObjectTemplateInfo> data, Handle<JSReceiver> new_target) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000475 Isolate* isolate = data->GetIsolate();
476 InvokeScope invoke_scope(isolate);
Ben Murdochc5610432016-08-08 18:44:38 +0100477 return ::v8::internal::InstantiateObject(isolate, data, new_target, false);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000478}
479
480
481void ApiNatives::AddDataProperty(Isolate* isolate, Handle<TemplateInfo> info,
482 Handle<Name> name, Handle<Object> value,
483 PropertyAttributes attributes) {
484 const int kSize = 3;
485 PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell);
486 auto details_handle = handle(details.AsSmi(), isolate);
487 Handle<Object> data[kSize] = {name, details_handle, value};
488 AddPropertyToPropertyList(isolate, info, kSize, data);
489}
490
491
492void ApiNatives::AddDataProperty(Isolate* isolate, Handle<TemplateInfo> info,
493 Handle<Name> name, v8::Intrinsic intrinsic,
494 PropertyAttributes attributes) {
495 const int kSize = 4;
496 auto value = handle(Smi::FromInt(intrinsic), isolate);
497 auto intrinsic_marker = isolate->factory()->true_value();
498 PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell);
499 auto details_handle = handle(details.AsSmi(), isolate);
500 Handle<Object> data[kSize] = {name, intrinsic_marker, details_handle, value};
501 AddPropertyToPropertyList(isolate, info, kSize, data);
502}
503
504
505void ApiNatives::AddAccessorProperty(Isolate* isolate,
506 Handle<TemplateInfo> info,
507 Handle<Name> name,
508 Handle<FunctionTemplateInfo> getter,
509 Handle<FunctionTemplateInfo> setter,
510 PropertyAttributes attributes) {
511 const int kSize = 4;
512 PropertyDetails details(attributes, ACCESSOR, 0, PropertyCellType::kNoCell);
513 auto details_handle = handle(details.AsSmi(), isolate);
514 Handle<Object> data[kSize] = {name, details_handle, getter, setter};
515 AddPropertyToPropertyList(isolate, info, kSize, data);
516}
517
518
519void ApiNatives::AddNativeDataProperty(Isolate* isolate,
520 Handle<TemplateInfo> info,
521 Handle<AccessorInfo> property) {
522 auto list = handle(info->property_accessors(), isolate);
523 if (list->IsUndefined()) {
524 list = NeanderArray(isolate).value();
525 info->set_property_accessors(*list);
526 }
527 NeanderArray array(list);
528 array.add(isolate, property);
529}
530
531
532Handle<JSFunction> ApiNatives::CreateApiFunction(
533 Isolate* isolate, Handle<FunctionTemplateInfo> obj,
534 Handle<Object> prototype, ApiInstanceType instance_type) {
535 Handle<Code> code;
536 if (obj->call_code()->IsCallHandlerInfo() &&
537 CallHandlerInfo::cast(obj->call_code())->fast_handler()->IsCode()) {
538 code = isolate->builtins()->HandleFastApiCall();
539 } else {
540 code = isolate->builtins()->HandleApiCall();
541 }
542 Handle<Code> construct_stub =
543 prototype.is_null() ? isolate->builtins()->ConstructedNonConstructable()
544 : isolate->builtins()->JSConstructStubApi();
545
546 obj->set_instantiated(true);
547 Handle<JSFunction> result;
548 if (obj->remove_prototype()) {
549 result = isolate->factory()->NewFunctionWithoutPrototype(
550 isolate->factory()->empty_string(), code);
551 } else {
552 int internal_field_count = 0;
553 if (!obj->instance_template()->IsUndefined()) {
554 Handle<ObjectTemplateInfo> instance_template = Handle<ObjectTemplateInfo>(
555 ObjectTemplateInfo::cast(obj->instance_template()));
556 internal_field_count =
557 Smi::cast(instance_template->internal_field_count())->value();
558 }
559
560 // TODO(svenpanne) Kill ApiInstanceType and refactor things by generalizing
561 // JSObject::GetHeaderSize.
562 int instance_size = kPointerSize * internal_field_count;
563 InstanceType type;
564 switch (instance_type) {
565 case JavaScriptObjectType:
Ben Murdochda12d292016-06-02 14:46:10 +0100566 if (!obj->needs_access_check() &&
567 obj->named_property_handler()->IsUndefined() &&
568 obj->indexed_property_handler()->IsUndefined()) {
Ben Murdochc5610432016-08-08 18:44:38 +0100569 type = JS_API_OBJECT_TYPE;
Ben Murdochda12d292016-06-02 14:46:10 +0100570 } else {
571 type = JS_SPECIAL_API_OBJECT_TYPE;
572 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000573 instance_size += JSObject::kHeaderSize;
574 break;
575 case GlobalObjectType:
576 type = JS_GLOBAL_OBJECT_TYPE;
577 instance_size += JSGlobalObject::kSize;
578 break;
579 case GlobalProxyType:
580 type = JS_GLOBAL_PROXY_TYPE;
581 instance_size += JSGlobalProxy::kSize;
582 break;
583 default:
584 UNREACHABLE();
585 type = JS_OBJECT_TYPE; // Keep the compiler happy.
586 break;
587 }
588
589 result = isolate->factory()->NewFunction(
590 isolate->factory()->empty_string(), code, prototype, type,
591 instance_size, obj->read_only_prototype(), true);
592 }
593
594 result->shared()->set_length(obj->length());
595 Handle<Object> class_name(obj->class_name(), isolate);
596 if (class_name->IsString()) {
597 result->shared()->set_instance_class_name(*class_name);
598 result->shared()->set_name(*class_name);
599 }
Ben Murdochda12d292016-06-02 14:46:10 +0100600 result->shared()->set_api_func_data(*obj);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000601 result->shared()->set_construct_stub(*construct_stub);
602 result->shared()->DontAdaptArguments();
603
604 if (obj->remove_prototype()) {
605 DCHECK(result->shared()->IsApiFunction());
606 DCHECK(!result->has_initial_map());
607 DCHECK(!result->has_prototype());
608 return result;
609 }
610
611#ifdef DEBUG
612 LookupIterator it(handle(JSObject::cast(result->prototype())),
613 isolate->factory()->constructor_string(),
614 LookupIterator::OWN_SKIP_INTERCEPTOR);
615 MaybeHandle<Object> maybe_prop = Object::GetProperty(&it);
616 DCHECK(it.IsFound());
617 DCHECK(maybe_prop.ToHandleChecked().is_identical_to(result));
618#endif
619
620 // Down from here is only valid for API functions that can be used as a
621 // constructor (don't set the "remove prototype" flag).
622
623 Handle<Map> map(result->initial_map());
624
625 // Mark as undetectable if needed.
626 if (obj->undetectable()) {
627 map->set_is_undetectable();
628 }
629
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000630 // Mark as needs_access_check if needed.
631 if (obj->needs_access_check()) {
632 map->set_is_access_check_needed(true);
633 }
634
635 // Set interceptor information in the map.
636 if (!obj->named_property_handler()->IsUndefined()) {
637 map->set_has_named_interceptor();
638 }
639 if (!obj->indexed_property_handler()->IsUndefined()) {
640 map->set_has_indexed_interceptor();
641 }
642
643 // Mark instance as callable in the map.
644 if (!obj->instance_call_handler()->IsUndefined()) {
645 map->set_is_callable();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100646 map->set_is_constructor(true);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000647 }
648
649 DCHECK(result->shared()->IsApiFunction());
650 return result;
651}
652
653} // namespace internal
654} // namespace v8