blob: adf4b6af576431d8d2d7c078a3fcbaffcaca8c1b [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,
20 bool is_hidden_prototype);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000021
22MaybeHandle<JSFunction> InstantiateFunction(Isolate* isolate,
23 Handle<FunctionTemplateInfo> data,
24 Handle<Name> name = Handle<Name>());
25
26
27MaybeHandle<Object> Instantiate(Isolate* isolate, Handle<Object> data,
28 Handle<Name> name = Handle<Name>()) {
29 if (data->IsFunctionTemplateInfo()) {
30 return InstantiateFunction(isolate,
31 Handle<FunctionTemplateInfo>::cast(data), name);
32 } else if (data->IsObjectTemplateInfo()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +010033 return InstantiateObject(isolate, Handle<ObjectTemplateInfo>::cast(data),
34 false);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000035 } else {
36 return data;
37 }
38}
39
Ben Murdoch097c5b22016-05-18 11:27:45 +010040MaybeHandle<Object> DefineAccessorProperty(
41 Isolate* isolate, Handle<JSObject> object, Handle<Name> name,
42 Handle<Object> getter, Handle<Object> setter, PropertyAttributes attributes,
43 bool force_instantiate) {
44 DCHECK(!getter->IsFunctionTemplateInfo() ||
45 !FunctionTemplateInfo::cast(*getter)->do_not_cache());
46 DCHECK(!setter->IsFunctionTemplateInfo() ||
47 !FunctionTemplateInfo::cast(*setter)->do_not_cache());
48 if (force_instantiate) {
49 if (getter->IsFunctionTemplateInfo()) {
50 ASSIGN_RETURN_ON_EXCEPTION(
51 isolate, getter,
52 InstantiateFunction(isolate,
53 Handle<FunctionTemplateInfo>::cast(getter)),
54 Object);
55 }
56 if (setter->IsFunctionTemplateInfo()) {
57 ASSIGN_RETURN_ON_EXCEPTION(
58 isolate, setter,
59 InstantiateFunction(isolate,
60 Handle<FunctionTemplateInfo>::cast(setter)),
61 Object);
62 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000063 }
64 RETURN_ON_EXCEPTION(isolate, JSObject::DefineAccessor(object, name, getter,
65 setter, attributes),
66 Object);
67 return object;
68}
69
70
71MaybeHandle<Object> DefineDataProperty(Isolate* isolate,
72 Handle<JSObject> object,
73 Handle<Name> name,
74 Handle<Object> prop_data,
75 PropertyAttributes attributes) {
76 Handle<Object> value;
77 ASSIGN_RETURN_ON_EXCEPTION(isolate, value,
78 Instantiate(isolate, prop_data, name), Object);
79
80 LookupIterator it = LookupIterator::PropertyOrElement(
81 isolate, object, name, LookupIterator::OWN_SKIP_INTERCEPTOR);
82
83#ifdef DEBUG
84 Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
85 DCHECK(maybe.IsJust());
86 if (it.IsFound()) {
87 THROW_NEW_ERROR(
88 isolate,
89 NewTypeError(MessageTemplate::kDuplicateTemplateProperty, name),
90 Object);
91 }
92#endif
93
94 MAYBE_RETURN_NULL(
95 Object::AddDataProperty(&it, value, attributes, Object::THROW_ON_ERROR,
96 Object::CERTAINLY_NOT_STORE_FROM_KEYED));
97 return value;
98}
99
100
101void DisableAccessChecks(Isolate* isolate, Handle<JSObject> object) {
102 Handle<Map> old_map(object->map());
103 // Copy map so it won't interfere constructor's initial map.
104 Handle<Map> new_map = Map::Copy(old_map, "DisableAccessChecks");
105 new_map->set_is_access_check_needed(false);
106 JSObject::MigrateToMap(Handle<JSObject>::cast(object), new_map);
107}
108
109
110void EnableAccessChecks(Isolate* isolate, Handle<JSObject> object) {
111 Handle<Map> old_map(object->map());
112 // Copy map so it won't interfere constructor's initial map.
113 Handle<Map> new_map = Map::Copy(old_map, "EnableAccessChecks");
114 new_map->set_is_access_check_needed(true);
115 JSObject::MigrateToMap(object, new_map);
116}
117
118
119class AccessCheckDisableScope {
120 public:
121 AccessCheckDisableScope(Isolate* isolate, Handle<JSObject> obj)
122 : isolate_(isolate),
123 disabled_(obj->map()->is_access_check_needed()),
124 obj_(obj) {
125 if (disabled_) {
126 DisableAccessChecks(isolate_, obj_);
127 }
128 }
129 ~AccessCheckDisableScope() {
130 if (disabled_) {
131 EnableAccessChecks(isolate_, obj_);
132 }
133 }
134
135 private:
136 Isolate* isolate_;
137 const bool disabled_;
138 Handle<JSObject> obj_;
139};
140
141
142Object* GetIntrinsic(Isolate* isolate, v8::Intrinsic intrinsic) {
143 Handle<Context> native_context = isolate->native_context();
144 DCHECK(!native_context.is_null());
145 switch (intrinsic) {
146#define GET_INTRINSIC_VALUE(name, iname) \
147 case v8::k##name: \
148 return native_context->iname();
149 V8_INTRINSICS_LIST(GET_INTRINSIC_VALUE)
150#undef GET_INTRINSIC_VALUE
151 }
152 return nullptr;
153}
154
Ben Murdoch097c5b22016-05-18 11:27:45 +0100155// Returns parent function template or null.
156FunctionTemplateInfo* GetParent(FunctionTemplateInfo* data) {
157 Object* parent = data->parent_template();
158 return parent->IsUndefined() ? nullptr : FunctionTemplateInfo::cast(parent);
159}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000160
Ben Murdoch097c5b22016-05-18 11:27:45 +0100161// Starting from given object template's constructor walk up the inheritance
162// chain till a function template that has an instance template is found.
163ObjectTemplateInfo* GetParent(ObjectTemplateInfo* data) {
164 Object* maybe_ctor = data->constructor();
165 if (maybe_ctor->IsUndefined()) return nullptr;
166 FunctionTemplateInfo* ctor = FunctionTemplateInfo::cast(maybe_ctor);
167 while (true) {
168 ctor = GetParent(ctor);
169 if (ctor == nullptr) return nullptr;
170 Object* maybe_obj = ctor->instance_template();
171 if (!maybe_obj->IsUndefined()) return ObjectTemplateInfo::cast(maybe_obj);
172 }
173}
174
175template <typename TemplateInfoT>
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000176MaybeHandle<JSObject> ConfigureInstance(Isolate* isolate, Handle<JSObject> obj,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100177 Handle<TemplateInfoT> data,
178 bool is_hidden_prototype) {
179 HandleScope scope(isolate);
180 // Disable access checks while instantiating the object.
181 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 while (info != nullptr) {
187 if (!info->property_accessors()->IsUndefined()) {
188 Object* props = info->property_accessors();
189 if (!props->IsUndefined()) {
190 Handle<Object> props_handle(props, isolate);
191 NeanderArray props_array(props_handle);
192 max_number_of_properties += props_array.length();
193 }
194 }
195 info = GetParent(info);
196 }
197
198 if (max_number_of_properties > 0) {
199 int valid_descriptors = 0;
200 // Use a temporary FixedArray to accumulate unique accessors.
201 Handle<FixedArray> array =
202 isolate->factory()->NewFixedArray(max_number_of_properties);
203
204 info = *data;
205 while (info != nullptr) {
206 // Accumulate accessors.
207 if (!info->property_accessors()->IsUndefined()) {
208 Handle<Object> props(info->property_accessors(), isolate);
209 valid_descriptors =
210 AccessorInfo::AppendUnique(props, array, valid_descriptors);
211 }
212 info = GetParent(info);
213 }
214
215 // Install accumulated accessors.
216 for (int i = 0; i < valid_descriptors; i++) {
217 Handle<AccessorInfo> accessor(AccessorInfo::cast(array->get(i)));
218 JSObject::SetAccessor(obj, accessor).Assert();
219 }
220 }
221
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000222 auto property_list = handle(data->property_list(), isolate);
223 if (property_list->IsUndefined()) return obj;
224 // TODO(dcarney): just use a FixedArray here.
225 NeanderArray properties(property_list);
226 if (properties.length() == 0) return obj;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000227
228 int i = 0;
229 for (int c = 0; c < data->number_of_properties(); c++) {
230 auto name = handle(Name::cast(properties.get(i++)), isolate);
231 auto bit = handle(properties.get(i++), isolate);
232 if (bit->IsSmi()) {
233 PropertyDetails details(Smi::cast(*bit));
234 PropertyAttributes attributes = details.attributes();
235 PropertyKind kind = details.kind();
236
237 if (kind == kData) {
238 auto prop_data = handle(properties.get(i++), isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000239 RETURN_ON_EXCEPTION(isolate, DefineDataProperty(isolate, obj, name,
240 prop_data, attributes),
241 JSObject);
242 } else {
243 auto getter = handle(properties.get(i++), isolate);
244 auto setter = handle(properties.get(i++), isolate);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100245 RETURN_ON_EXCEPTION(
246 isolate, DefineAccessorProperty(isolate, obj, name, getter, setter,
247 attributes, is_hidden_prototype),
248 JSObject);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000249 }
250 } else {
251 // Intrinsic data property --- Get appropriate value from the current
252 // context.
253 PropertyDetails details(Smi::cast(properties.get(i++)));
254 PropertyAttributes attributes = details.attributes();
255 DCHECK_EQ(kData, details.kind());
256
257 v8::Intrinsic intrinsic =
258 static_cast<v8::Intrinsic>(Smi::cast(properties.get(i++))->value());
259 auto prop_data = handle(GetIntrinsic(isolate, intrinsic), isolate);
260
261 RETURN_ON_EXCEPTION(isolate, DefineDataProperty(isolate, obj, name,
262 prop_data, attributes),
263 JSObject);
264 }
265 }
266 return obj;
267}
268
Ben Murdochda12d292016-06-02 14:46:10 +0100269void CacheTemplateInstantiation(Isolate* isolate, uint32_t serial_number,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100270 Handle<JSObject> object) {
271 auto cache = isolate->template_instantiations_cache();
Ben Murdochda12d292016-06-02 14:46:10 +0100272 auto new_cache =
273 UnseededNumberDictionary::AtNumberPut(cache, serial_number, object);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100274 isolate->native_context()->set_template_instantiations_cache(*new_cache);
275}
276
Ben Murdochda12d292016-06-02 14:46:10 +0100277void UncacheTemplateInstantiation(Isolate* isolate, uint32_t serial_number) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100278 auto cache = isolate->template_instantiations_cache();
Ben Murdochda12d292016-06-02 14:46:10 +0100279 int entry = cache->FindEntry(serial_number);
280 DCHECK(entry != UnseededNumberDictionary::kNotFound);
281 Handle<Object> result =
282 UnseededNumberDictionary::DeleteProperty(cache, entry);
283 USE(result);
284 DCHECK(result->IsTrue());
285 auto new_cache = UnseededNumberDictionary::Shrink(cache, entry);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100286 isolate->native_context()->set_template_instantiations_cache(*new_cache);
287}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000288
289MaybeHandle<JSObject> InstantiateObject(Isolate* isolate,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100290 Handle<ObjectTemplateInfo> info,
291 bool is_hidden_prototype) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000292 // Fast path.
293 Handle<JSObject> result;
Ben Murdochda12d292016-06-02 14:46:10 +0100294 uint32_t serial_number =
295 static_cast<uint32_t>(Smi::cast(info->serial_number())->value());
296 if (serial_number) {
297 // Probe cache.
298 auto cache = isolate->template_instantiations_cache();
299 int entry = cache->FindEntry(serial_number);
300 if (entry != UnseededNumberDictionary::kNotFound) {
301 Object* boilerplate = cache->ValueAt(entry);
302 result = handle(JSObject::cast(boilerplate), isolate);
303 return isolate->factory()->CopyJSObject(result);
304 }
305 }
306 // Enter a new scope. Recursion could otherwise create a lot of handles.
307 HandleScope scope(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000308 auto constructor = handle(info->constructor(), isolate);
309 Handle<JSFunction> cons;
310 if (constructor->IsUndefined()) {
311 cons = isolate->object_function();
312 } else {
313 auto cons_templ = Handle<FunctionTemplateInfo>::cast(constructor);
314 ASSIGN_RETURN_ON_EXCEPTION(
315 isolate, cons, InstantiateFunction(isolate, cons_templ), JSFunction);
316 }
317 auto object = isolate->factory()->NewJSObject(cons);
318 ASSIGN_RETURN_ON_EXCEPTION(
Ben Murdoch097c5b22016-05-18 11:27:45 +0100319 isolate, result,
320 ConfigureInstance(isolate, object, info, is_hidden_prototype),
321 JSFunction);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000322 // TODO(dcarney): is this necessary?
323 JSObject::MigrateSlowToFast(result, 0, "ApiNatives::InstantiateObject");
Ben Murdoch097c5b22016-05-18 11:27:45 +0100324
Ben Murdochda12d292016-06-02 14:46:10 +0100325 if (serial_number) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100326 CacheTemplateInstantiation(isolate, serial_number, result);
Ben Murdochda12d292016-06-02 14:46:10 +0100327 result = isolate->factory()->CopyJSObject(result);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100328 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000329 return scope.CloseAndEscape(result);
330}
331
332
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000333MaybeHandle<JSFunction> InstantiateFunction(Isolate* isolate,
334 Handle<FunctionTemplateInfo> data,
335 Handle<Name> name) {
Ben Murdochda12d292016-06-02 14:46:10 +0100336 uint32_t serial_number =
337 static_cast<uint32_t>(Smi::cast(data->serial_number())->value());
338 if (serial_number) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100339 // Probe cache.
340 auto cache = isolate->template_instantiations_cache();
Ben Murdochda12d292016-06-02 14:46:10 +0100341 int entry = cache->FindEntry(serial_number);
342 if (entry != UnseededNumberDictionary::kNotFound) {
343 Object* element = cache->ValueAt(entry);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000344 return handle(JSFunction::cast(element), isolate);
345 }
346 }
347 // Enter a new scope. Recursion could otherwise create a lot of handles.
348 HandleScope scope(isolate);
349 Handle<JSObject> prototype;
350 if (!data->remove_prototype()) {
351 auto prototype_templ = handle(data->prototype_template(), isolate);
352 if (prototype_templ->IsUndefined()) {
353 prototype = isolate->factory()->NewJSObject(isolate->object_function());
354 } else {
355 ASSIGN_RETURN_ON_EXCEPTION(
356 isolate, prototype,
357 InstantiateObject(isolate,
Ben Murdoch097c5b22016-05-18 11:27:45 +0100358 Handle<ObjectTemplateInfo>::cast(prototype_templ),
359 data->hidden_prototype()),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000360 JSFunction);
361 }
362 auto parent = handle(data->parent_template(), isolate);
363 if (!parent->IsUndefined()) {
364 Handle<JSFunction> parent_instance;
365 ASSIGN_RETURN_ON_EXCEPTION(
366 isolate, parent_instance,
367 InstantiateFunction(isolate,
368 Handle<FunctionTemplateInfo>::cast(parent)),
369 JSFunction);
370 // TODO(dcarney): decide what to do here.
371 Handle<Object> parent_prototype;
372 ASSIGN_RETURN_ON_EXCEPTION(
373 isolate, parent_prototype,
374 JSObject::GetProperty(parent_instance,
375 isolate->factory()->prototype_string()),
376 JSFunction);
377 MAYBE_RETURN(JSObject::SetPrototype(prototype, parent_prototype, false,
378 Object::THROW_ON_ERROR),
379 MaybeHandle<JSFunction>());
380 }
381 }
382 auto function = ApiNatives::CreateApiFunction(
383 isolate, data, prototype, ApiNatives::JavaScriptObjectType);
384 if (!name.is_null() && name->IsString()) {
385 function->shared()->set_name(*name);
386 }
Ben Murdochda12d292016-06-02 14:46:10 +0100387 if (serial_number) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000388 // Cache the function.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100389 CacheTemplateInstantiation(isolate, serial_number, function);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000390 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100391 auto result =
392 ConfigureInstance(isolate, function, data, data->hidden_prototype());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000393 if (result.is_null()) {
394 // Uncache on error.
Ben Murdochda12d292016-06-02 14:46:10 +0100395 if (serial_number) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100396 UncacheTemplateInstantiation(isolate, serial_number);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000397 }
398 return MaybeHandle<JSFunction>();
399 }
400 return scope.CloseAndEscape(function);
401}
402
403
404class InvokeScope {
405 public:
406 explicit InvokeScope(Isolate* isolate)
407 : isolate_(isolate), save_context_(isolate) {}
408 ~InvokeScope() {
409 bool has_exception = isolate_->has_pending_exception();
410 if (has_exception) {
411 isolate_->ReportPendingMessages();
412 } else {
413 isolate_->clear_pending_message();
414 }
415 }
416
417 private:
418 Isolate* isolate_;
419 SaveContext save_context_;
420};
421
422
423void AddPropertyToPropertyList(Isolate* isolate, Handle<TemplateInfo> templ,
424 int length, Handle<Object>* data) {
425 auto list = handle(templ->property_list(), isolate);
426 if (list->IsUndefined()) {
427 list = NeanderArray(isolate).value();
428 templ->set_property_list(*list);
429 }
430 templ->set_number_of_properties(templ->number_of_properties() + 1);
431 NeanderArray array(list);
432 for (int i = 0; i < length; i++) {
433 Handle<Object> value =
434 data[i].is_null()
435 ? Handle<Object>::cast(isolate->factory()->undefined_value())
436 : data[i];
437 array.add(isolate, value);
438 }
439}
440
441} // namespace
442
443
444MaybeHandle<JSFunction> ApiNatives::InstantiateFunction(
445 Handle<FunctionTemplateInfo> data) {
446 Isolate* isolate = data->GetIsolate();
447 InvokeScope invoke_scope(isolate);
448 return ::v8::internal::InstantiateFunction(isolate, data);
449}
450
451
452MaybeHandle<JSObject> ApiNatives::InstantiateObject(
453 Handle<ObjectTemplateInfo> data) {
454 Isolate* isolate = data->GetIsolate();
455 InvokeScope invoke_scope(isolate);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100456 return ::v8::internal::InstantiateObject(isolate, data, false);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000457}
458
459
460void ApiNatives::AddDataProperty(Isolate* isolate, Handle<TemplateInfo> info,
461 Handle<Name> name, Handle<Object> value,
462 PropertyAttributes attributes) {
463 const int kSize = 3;
464 PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell);
465 auto details_handle = handle(details.AsSmi(), isolate);
466 Handle<Object> data[kSize] = {name, details_handle, value};
467 AddPropertyToPropertyList(isolate, info, kSize, data);
468}
469
470
471void ApiNatives::AddDataProperty(Isolate* isolate, Handle<TemplateInfo> info,
472 Handle<Name> name, v8::Intrinsic intrinsic,
473 PropertyAttributes attributes) {
474 const int kSize = 4;
475 auto value = handle(Smi::FromInt(intrinsic), isolate);
476 auto intrinsic_marker = isolate->factory()->true_value();
477 PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell);
478 auto details_handle = handle(details.AsSmi(), isolate);
479 Handle<Object> data[kSize] = {name, intrinsic_marker, details_handle, value};
480 AddPropertyToPropertyList(isolate, info, kSize, data);
481}
482
483
484void ApiNatives::AddAccessorProperty(Isolate* isolate,
485 Handle<TemplateInfo> info,
486 Handle<Name> name,
487 Handle<FunctionTemplateInfo> getter,
488 Handle<FunctionTemplateInfo> setter,
489 PropertyAttributes attributes) {
490 const int kSize = 4;
491 PropertyDetails details(attributes, ACCESSOR, 0, PropertyCellType::kNoCell);
492 auto details_handle = handle(details.AsSmi(), isolate);
493 Handle<Object> data[kSize] = {name, details_handle, getter, setter};
494 AddPropertyToPropertyList(isolate, info, kSize, data);
495}
496
497
498void ApiNatives::AddNativeDataProperty(Isolate* isolate,
499 Handle<TemplateInfo> info,
500 Handle<AccessorInfo> property) {
501 auto list = handle(info->property_accessors(), isolate);
502 if (list->IsUndefined()) {
503 list = NeanderArray(isolate).value();
504 info->set_property_accessors(*list);
505 }
506 NeanderArray array(list);
507 array.add(isolate, property);
508}
509
510
511Handle<JSFunction> ApiNatives::CreateApiFunction(
512 Isolate* isolate, Handle<FunctionTemplateInfo> obj,
513 Handle<Object> prototype, ApiInstanceType instance_type) {
514 Handle<Code> code;
515 if (obj->call_code()->IsCallHandlerInfo() &&
516 CallHandlerInfo::cast(obj->call_code())->fast_handler()->IsCode()) {
517 code = isolate->builtins()->HandleFastApiCall();
518 } else {
519 code = isolate->builtins()->HandleApiCall();
520 }
521 Handle<Code> construct_stub =
522 prototype.is_null() ? isolate->builtins()->ConstructedNonConstructable()
523 : isolate->builtins()->JSConstructStubApi();
524
525 obj->set_instantiated(true);
526 Handle<JSFunction> result;
527 if (obj->remove_prototype()) {
528 result = isolate->factory()->NewFunctionWithoutPrototype(
529 isolate->factory()->empty_string(), code);
530 } else {
531 int internal_field_count = 0;
532 if (!obj->instance_template()->IsUndefined()) {
533 Handle<ObjectTemplateInfo> instance_template = Handle<ObjectTemplateInfo>(
534 ObjectTemplateInfo::cast(obj->instance_template()));
535 internal_field_count =
536 Smi::cast(instance_template->internal_field_count())->value();
537 }
538
539 // TODO(svenpanne) Kill ApiInstanceType and refactor things by generalizing
540 // JSObject::GetHeaderSize.
541 int instance_size = kPointerSize * internal_field_count;
542 InstanceType type;
543 switch (instance_type) {
544 case JavaScriptObjectType:
Ben Murdochda12d292016-06-02 14:46:10 +0100545 if (!obj->needs_access_check() &&
546 obj->named_property_handler()->IsUndefined() &&
547 obj->indexed_property_handler()->IsUndefined()) {
548 type = JS_OBJECT_TYPE;
549 } else {
550 type = JS_SPECIAL_API_OBJECT_TYPE;
551 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000552 instance_size += JSObject::kHeaderSize;
553 break;
554 case GlobalObjectType:
555 type = JS_GLOBAL_OBJECT_TYPE;
556 instance_size += JSGlobalObject::kSize;
557 break;
558 case GlobalProxyType:
559 type = JS_GLOBAL_PROXY_TYPE;
560 instance_size += JSGlobalProxy::kSize;
561 break;
562 default:
563 UNREACHABLE();
564 type = JS_OBJECT_TYPE; // Keep the compiler happy.
565 break;
566 }
567
568 result = isolate->factory()->NewFunction(
569 isolate->factory()->empty_string(), code, prototype, type,
570 instance_size, obj->read_only_prototype(), true);
571 }
572
573 result->shared()->set_length(obj->length());
574 Handle<Object> class_name(obj->class_name(), isolate);
575 if (class_name->IsString()) {
576 result->shared()->set_instance_class_name(*class_name);
577 result->shared()->set_name(*class_name);
578 }
Ben Murdochda12d292016-06-02 14:46:10 +0100579 result->shared()->set_api_func_data(*obj);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000580 result->shared()->set_construct_stub(*construct_stub);
581 result->shared()->DontAdaptArguments();
582
583 if (obj->remove_prototype()) {
584 DCHECK(result->shared()->IsApiFunction());
585 DCHECK(!result->has_initial_map());
586 DCHECK(!result->has_prototype());
587 return result;
588 }
589
590#ifdef DEBUG
591 LookupIterator it(handle(JSObject::cast(result->prototype())),
592 isolate->factory()->constructor_string(),
593 LookupIterator::OWN_SKIP_INTERCEPTOR);
594 MaybeHandle<Object> maybe_prop = Object::GetProperty(&it);
595 DCHECK(it.IsFound());
596 DCHECK(maybe_prop.ToHandleChecked().is_identical_to(result));
597#endif
598
599 // Down from here is only valid for API functions that can be used as a
600 // constructor (don't set the "remove prototype" flag).
601
602 Handle<Map> map(result->initial_map());
603
604 // Mark as undetectable if needed.
605 if (obj->undetectable()) {
606 map->set_is_undetectable();
607 }
608
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000609 // Mark as needs_access_check if needed.
610 if (obj->needs_access_check()) {
611 map->set_is_access_check_needed(true);
612 }
613
614 // Set interceptor information in the map.
615 if (!obj->named_property_handler()->IsUndefined()) {
616 map->set_has_named_interceptor();
617 }
618 if (!obj->indexed_property_handler()->IsUndefined()) {
619 map->set_has_indexed_interceptor();
620 }
621
622 // Mark instance as callable in the map.
623 if (!obj->instance_call_handler()->IsUndefined()) {
624 map->set_is_callable();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100625 map->set_is_constructor(true);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000626 }
627
628 DCHECK(result->shared()->IsApiFunction());
629 return result;
630}
631
632} // namespace internal
633} // namespace v8