Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(227)

Side by Side Diff: src/api-natives.cc

Issue 895053002: Move the contents of api-natives.js to c++ (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/api-natives.h ('k') | src/apinatives.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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 #include "src/isolate-inl.h"
7
8 namespace v8 {
9 namespace internal {
10
11 namespace {
12
13 // Transform getter or setter into something DefineAccessor can handle.
14 Handle<Object> InstantiateAccessorComponent(Isolate* isolate,
15 Handle<Object> component) {
16 if (component->IsUndefined()) return isolate->factory()->undefined_value();
17 Handle<FunctionTemplateInfo> info =
18 Handle<FunctionTemplateInfo>::cast(component);
19 // TODO(dcarney): instantiate directly.
20 return Utils::OpenHandle(*Utils::ToLocal(info)->GetFunction());
21 }
22
23
24 Object* DefineApiAccessorProperty(Isolate* isolate, Handle<JSObject> object,
25 Handle<Name> name, Handle<Object> getter,
26 Handle<Object> setter, Smi* attribute) {
27 DCHECK(PropertyDetails::AttributesField::is_valid(
28 static_cast<PropertyAttributes>(attribute->value())));
29 RETURN_FAILURE_ON_EXCEPTION(
30 isolate, JSObject::DefineAccessor(
31 object, name, InstantiateAccessorComponent(isolate, getter),
32 InstantiateAccessorComponent(isolate, setter),
33 static_cast<PropertyAttributes>(attribute->value())));
34 return *object;
35 }
36
37
38 Object* AddPropertyForTemplate(Isolate* isolate, Handle<JSObject> object,
39 Handle<Object> key, Handle<Object> value,
40 Smi* unchecked_attributes) {
41 DCHECK((unchecked_attributes->value() &
42 ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
43 // Compute attributes.
44 PropertyAttributes attributes =
45 static_cast<PropertyAttributes>(unchecked_attributes->value());
46
47 #ifdef DEBUG
48 bool duplicate;
49 if (key->IsName()) {
50 LookupIterator it(object, Handle<Name>::cast(key),
51 LookupIterator::OWN_SKIP_INTERCEPTOR);
52 Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
53 DCHECK(maybe.has_value);
54 duplicate = it.IsFound();
55 } else {
56 uint32_t index = 0;
57 key->ToArrayIndex(&index);
58 Maybe<bool> maybe = JSReceiver::HasOwnElement(object, index);
59 if (!maybe.has_value) return isolate->heap()->exception();
60 duplicate = maybe.value;
61 }
62 if (duplicate) {
63 Handle<Object> args[1] = {key};
64 THROW_NEW_ERROR_RETURN_FAILURE(
65 isolate,
66 NewTypeError("duplicate_template_property", HandleVector(args, 1)));
67 }
68 #endif
69
70 Handle<Object> result;
71 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
72 isolate, result,
73 Runtime::DefineObjectProperty(object, key, value, attributes));
74 return *result;
75 }
76
77
78 void DisableAccessChecks(Isolate* isolate, Handle<JSObject> object) {
79 Handle<Map> old_map(object->map());
80 // Copy map so it won't interfere constructor's initial map.
81 Handle<Map> new_map = Map::Copy(old_map, "DisableAccessChecks");
82 new_map->set_is_access_check_needed(false);
83 JSObject::MigrateToMap(Handle<JSObject>::cast(object), new_map);
84 }
85
86
87 void EnableAccessChecks(Isolate* isolate, Handle<JSObject> object) {
88 Handle<Map> old_map(object->map());
89 // Copy map so it won't interfere constructor's initial map.
90 Handle<Map> new_map = Map::Copy(old_map, "EnableAccessChecks");
91 new_map->set_is_access_check_needed(true);
92 JSObject::MigrateToMap(object, new_map);
93 }
94
95
96 MaybeHandle<JSObject> InstantiateObject(Isolate* isolate,
97 Handle<ObjectTemplateInfo> data);
98
99
100 MaybeHandle<JSFunction> InstantiateFunction(Isolate* isolate,
101 Handle<FunctionTemplateInfo> data,
102 Handle<Name> name = Handle<Name>());
103
104
105 MaybeHandle<Object> Instantiate(Isolate* isolate, Handle<Object> data,
106 Handle<Name> name = Handle<Name>()) {
107 if (data->IsFunctionTemplateInfo()) {
108 return InstantiateFunction(isolate,
109 Handle<FunctionTemplateInfo>::cast(data), name);
110 } else if (data->IsObjectTemplateInfo()) {
111 return InstantiateObject(isolate, Handle<ObjectTemplateInfo>::cast(data));
112 } else {
113 // TODO(dcarney): CHECK data is JSObject or Primitive.
114 return data;
115 }
116 }
117
118
119 MaybeHandle<JSObject> ConfigureInstance(Isolate* isolate, Handle<JSObject> obj,
120 Handle<TemplateInfo> data) {
121 auto property_list = handle(data->property_list(), isolate);
122 if (property_list->IsUndefined()) return obj;
123 // TODO(dcarney): just use a FixedArray here.
124 NeanderArray properties(property_list);
125 if (properties.length() == 0) return obj;
126 HandleScope scope(isolate);
127 // // Disable access checks while instantiating the object.
128 bool requires_access_checks = obj->map()->is_access_check_needed();
129 if (requires_access_checks) {
130 DisableAccessChecks(isolate, obj);
131 }
132 // TODO(dcarney): put iteration in own function so exception checking is more
133 // standard.
Toon Verwaest 2015/02/04 12:04:04 Would indeed be nice if you'd just move the Disabl
134 MaybeHandle<JSObject> result = obj;
135 for (int i = 0; i < properties.length();) {
136 int length = Smi::cast(properties.get(i))->value();
137 if (length == 3) {
138 auto name = handle(Name::cast(properties.get(i + 1)), isolate);
139 auto prop_data = handle(properties.get(i + 2), isolate);
140 auto attributes = Smi::cast(properties.get(i + 3));
141 auto instantiate_result = Instantiate(isolate, prop_data, name);
142 Handle<Object> value;
143 if (!instantiate_result.ToHandle(&value)) {
144 result = MaybeHandle<JSObject>();
145 break;
146 }
147 auto add_result =
148 AddPropertyForTemplate(isolate, obj, name, value, attributes);
Toon Verwaest 2015/02/04 12:04:04 Can you change this to return a MaybeHandle<> rath
149 if (add_result->IsException()) {
150 result = MaybeHandle<JSObject>();
151 break;
152 }
153 } else {
154 DCHECK(length == 4 || length == 5);
155 // TODO(verwaest): The 5th value used to be access_control. Remove once
156 // the bindings are updated.
157 auto name = handle(Name::cast(properties.get(i + 1)), isolate);
158 auto getter = handle(properties.get(i + 2), isolate);
159 auto setter = handle(properties.get(i + 3), isolate);
160 auto attributes = Smi::cast(properties.get(i + 4));
161 auto define_result = DefineApiAccessorProperty(isolate, obj, name, getter,
162 setter, attributes);
Toon Verwaest 2015/02/04 12:04:04 Same here
163 if (define_result->IsException()) {
164 result = MaybeHandle<JSObject>();
165 break;
166 }
167 }
168 i += length + 1;
169 }
170 if (requires_access_checks) {
171 EnableAccessChecks(isolate, obj);
172 }
173 // TODO(dcarney): return a Object* here?
174 return result;
175 }
176
177
178 MaybeHandle<JSObject> InstantiateObject(Isolate* isolate,
179 Handle<ObjectTemplateInfo> data) {
180 // Enter a new scope. Recursion could otherwise create a lot of handles.
181 HandleScope scope(isolate);
182 // Fast path.
183 Handle<JSObject> result;
184 auto info = Handle<ObjectTemplateInfo>::cast(data);
185 auto constructor = handle(info->constructor(), isolate);
186 Handle<JSFunction> cons;
187 if (constructor->IsUndefined()) {
188 cons = isolate->object_function();
189 } else {
190 auto cons_templ = Handle<FunctionTemplateInfo>::cast(constructor);
191 ASSIGN_RETURN_ON_EXCEPTION(
192 isolate, cons, InstantiateFunction(isolate, cons_templ), JSFunction);
193 }
194 auto object = isolate->factory()->NewJSObject(cons);
195 ASSIGN_RETURN_ON_EXCEPTION(
196 isolate, result, ConfigureInstance(isolate, object, info), JSFunction);
197 // TODO(dcarney): is this necessary?
198 JSObject::MigrateSlowToFast(result, 0, "ApiNatives::InstantiateObject");
199 return scope.CloseAndEscape(result);
200 }
201
202
203 void InstallInCache(Isolate* isolate, int serial_number,
204 Handle<JSFunction> function) {
205 Handle<FixedArray> cache(isolate->native_context()->function_cache());
Toon Verwaest 2015/02/04 12:04:04 auto cache = isolate->function_cache();
206 if (isolate->native_context()->function_cache()->length() <= serial_number) {
Toon Verwaest 2015/02/04 12:04:04 cache->length()
207 int new_size;
208 if (isolate->next_serial_number() < 50) {
209 new_size = 100;
210 } else {
211 new_size = 3 * isolate->next_serial_number() / 2;
212 }
213 cache = FixedArray::CopySize(cache, new_size);
214 isolate->native_context()->set_function_cache(*cache);
215 }
216 cache->set(serial_number, *function);
217 }
218
219
220 MaybeHandle<JSFunction> InstantiateFunction(Isolate* isolate,
221 Handle<FunctionTemplateInfo> data,
222 Handle<Name> name) {
223 int serial_number = Smi::cast(data->serial_number())->value();
224 // Probe cache.
225 if (!data->do_not_cache()) {
226 Handle<FixedArray> cache(isolate->native_context()->function_cache());
Toon Verwaest 2015/02/04 12:04:04 auto cache = isolate->function_cache()
227 // Fast case: see if the function has already been instantiated
228 if (serial_number < cache->length()) {
229 Handle<Object> element = FixedArray::get(cache, serial_number);
230 if (element->IsJSFunction()) {
231 return Handle<JSFunction>::cast(element);
232 }
233 }
234 }
235 // Enter a new scope. Recursion could otherwise create a lot of handles.
236 HandleScope scope(isolate);
237 Handle<JSObject> prototype;
238 if (!data->remove_prototype()) {
239 auto prototype_templ = handle(data->prototype_template(), isolate);
240 if (prototype_templ->IsUndefined()) {
241 prototype = isolate->factory()->NewJSObject(isolate->object_function());
242 } else {
243 ASSIGN_RETURN_ON_EXCEPTION(
244 isolate, prototype,
245 InstantiateObject(isolate,
246 Handle<ObjectTemplateInfo>::cast(prototype_templ)),
247 JSFunction);
248 }
249 auto parent = handle(data->parent_template(), isolate);
250 if (!parent->IsUndefined()) {
251 Handle<JSFunction> parent_instance;
252 ASSIGN_RETURN_ON_EXCEPTION(
253 isolate, parent_instance,
254 InstantiateFunction(isolate,
255 Handle<FunctionTemplateInfo>::cast(parent)),
256 JSFunction);
257 // TODO(dcarney): decide what to do here.
258 Handle<Object> parent_prototype;
259 ASSIGN_RETURN_ON_EXCEPTION(
260 isolate, parent_prototype,
261 JSObject::GetProperty(parent_instance,
262 isolate->factory()->prototype_string()),
263 JSFunction);
264 RETURN_ON_EXCEPTION(
265 isolate, JSObject::SetPrototype(prototype, parent_prototype, false),
266 JSFunction);
267 }
268 }
269 auto function = ApiNatives::CreateApiFunction(
270 isolate, data, prototype, ApiNatives::JavaScriptObjectType);
271 if (!name.is_null() && name->IsString()) {
272 function->shared()->set_name(*name);
273 }
274 if (!data->do_not_cache()) {
275 // Cache the function to limit recursion.
276 InstallInCache(isolate, serial_number, function);
277 }
278 auto result = ConfigureInstance(isolate, function, data);
279 if (result.is_null()) {
280 // uncache on error.
281 if (!data->do_not_cache()) {
282 Handle<FixedArray> cache(isolate->native_context()->function_cache());
283 cache->set(serial_number, isolate->heap()->undefined_value());
284 }
285 return MaybeHandle<JSFunction>();
286 }
287 return scope.CloseAndEscape(function);
288 }
289
290
291 class InvokeScope {
292 public:
293 explicit InvokeScope(Isolate* isolate)
294 : isolate_(isolate), save_context_(isolate) {}
295 ~InvokeScope() {
296 bool has_exception = isolate_->has_pending_exception();
297 if (has_exception) {
298 isolate_->ReportPendingMessages();
299 } else {
300 isolate_->clear_pending_message();
301 }
302 }
303
304 private:
305 Isolate* isolate_;
306 SaveContext save_context_;
307 };
308
309 } // namespace
310
311
312 MaybeHandle<JSFunction> ApiNatives::InstantiateFunction(
313 Handle<FunctionTemplateInfo> data) {
314 Isolate* isolate = data->GetIsolate();
315 InvokeScope invoke_scope(isolate);
316 return ::v8::internal::InstantiateFunction(isolate, data);
317 }
318
319
320 MaybeHandle<JSObject> ApiNatives::InstantiateObject(
321 Handle<ObjectTemplateInfo> data) {
322 Isolate* isolate = data->GetIsolate();
323 InvokeScope invoke_scope(isolate);
324 return ::v8::internal::InstantiateObject(isolate, data);
325 }
326
327
328 MaybeHandle<FunctionTemplateInfo> ApiNatives::ConfigureInstance(
329 Isolate* isolate, Handle<FunctionTemplateInfo> desc,
330 Handle<JSObject> instance) {
331 // Configure the instance by adding the properties specified by the
332 // instance template.
333 if (desc->instance_template()->IsUndefined()) return desc;
334 InvokeScope invoke_scope(isolate);
335 Handle<ObjectTemplateInfo> instance_template(
336 ObjectTemplateInfo::cast(desc->instance_template()), isolate);
337 RETURN_ON_EXCEPTION(isolate, ::v8::internal::ConfigureInstance(
338 isolate, instance, instance_template),
339 FunctionTemplateInfo);
340 return desc;
341 }
342
343
344 Handle<JSFunction> ApiNatives::CreateApiFunction(
345 Isolate* isolate, Handle<FunctionTemplateInfo> obj,
346 Handle<Object> prototype, ApiInstanceType instance_type) {
347 Handle<Code> code = isolate->builtins()->HandleApiCall();
348 Handle<Code> construct_stub = isolate->builtins()->JSConstructStubApi();
349
350 obj->set_instantiated(true);
351 Handle<JSFunction> result;
352 if (obj->remove_prototype()) {
353 result = isolate->factory()->NewFunctionWithoutPrototype(
354 isolate->factory()->empty_string(), code);
355 } else {
356 int internal_field_count = 0;
357 if (!obj->instance_template()->IsUndefined()) {
358 Handle<ObjectTemplateInfo> instance_template = Handle<ObjectTemplateInfo>(
359 ObjectTemplateInfo::cast(obj->instance_template()));
360 internal_field_count =
361 Smi::cast(instance_template->internal_field_count())->value();
362 }
363
364 // TODO(svenpanne) Kill ApiInstanceType and refactor things by generalizing
365 // JSObject::GetHeaderSize.
366 int instance_size = kPointerSize * internal_field_count;
367 InstanceType type;
368 switch (instance_type) {
369 case JavaScriptObjectType:
370 type = JS_OBJECT_TYPE;
371 instance_size += JSObject::kHeaderSize;
372 break;
373 case GlobalObjectType:
374 type = JS_GLOBAL_OBJECT_TYPE;
375 instance_size += JSGlobalObject::kSize;
376 break;
377 case GlobalProxyType:
378 type = JS_GLOBAL_PROXY_TYPE;
379 instance_size += JSGlobalProxy::kSize;
380 break;
381 default:
382 UNREACHABLE();
383 type = JS_OBJECT_TYPE; // Keep the compiler happy.
384 break;
385 }
386
387 result = isolate->factory()->NewFunction(
388 isolate->factory()->empty_string(), code, prototype, type,
389 instance_size, obj->read_only_prototype(), true);
390 }
391
392 result->shared()->set_length(obj->length());
393 Handle<Object> class_name(obj->class_name(), isolate);
394 if (class_name->IsString()) {
395 result->shared()->set_instance_class_name(*class_name);
396 result->shared()->set_name(*class_name);
397 }
398 result->shared()->set_function_data(*obj);
399 result->shared()->set_construct_stub(*construct_stub);
400 result->shared()->DontAdaptArguments();
401
402 if (obj->remove_prototype()) {
403 DCHECK(result->shared()->IsApiFunction());
404 DCHECK(!result->has_initial_map());
405 DCHECK(!result->has_prototype());
406 return result;
407 }
408
409 #ifdef DEBUG
410 LookupIterator it(handle(JSObject::cast(result->prototype())),
411 isolate->factory()->constructor_string(),
412 LookupIterator::OWN_SKIP_INTERCEPTOR);
413 MaybeHandle<Object> maybe_prop = Object::GetProperty(&it);
414 DCHECK(it.IsFound());
415 DCHECK(maybe_prop.ToHandleChecked().is_identical_to(result));
416 #endif
417
418 // Down from here is only valid for API functions that can be used as a
419 // constructor (don't set the "remove prototype" flag).
420
421 Handle<Map> map(result->initial_map());
422
423 // Mark as undetectable if needed.
424 if (obj->undetectable()) {
425 map->set_is_undetectable();
426 }
427
428 // Mark as hidden for the __proto__ accessor if needed.
429 if (obj->hidden_prototype()) {
430 map->set_is_hidden_prototype();
431 }
432
433 // Mark as needs_access_check if needed.
434 if (obj->needs_access_check()) {
435 map->set_is_access_check_needed(true);
436 }
437
438 // Set interceptor information in the map.
439 if (!obj->named_property_handler()->IsUndefined()) {
440 map->set_has_named_interceptor();
441 }
442 if (!obj->indexed_property_handler()->IsUndefined()) {
443 map->set_has_indexed_interceptor();
444 }
445
446 // Set instance call-as-function information in the map.
447 if (!obj->instance_call_handler()->IsUndefined()) {
448 map->set_has_instance_call_handler();
449 }
450
451 // Recursively copy parent instance templates' accessors,
452 // 'data' may be modified.
453 int max_number_of_additional_properties = 0;
454 int max_number_of_static_properties = 0;
455 FunctionTemplateInfo* info = *obj;
456 while (true) {
457 if (!info->instance_template()->IsUndefined()) {
458 Object* props = ObjectTemplateInfo::cast(info->instance_template())
459 ->property_accessors();
460 if (!props->IsUndefined()) {
461 Handle<Object> props_handle(props, isolate);
462 NeanderArray props_array(props_handle);
463 max_number_of_additional_properties += props_array.length();
464 }
465 }
466 if (!info->property_accessors()->IsUndefined()) {
467 Object* props = info->property_accessors();
468 if (!props->IsUndefined()) {
469 Handle<Object> props_handle(props, isolate);
470 NeanderArray props_array(props_handle);
471 max_number_of_static_properties += props_array.length();
472 }
473 }
474 Object* parent = info->parent_template();
475 if (parent->IsUndefined()) break;
476 info = FunctionTemplateInfo::cast(parent);
477 }
478
479 Map::EnsureDescriptorSlack(map, max_number_of_additional_properties);
480
481 // Use a temporary FixedArray to acculumate static accessors
482 int valid_descriptors = 0;
483 Handle<FixedArray> array;
484 if (max_number_of_static_properties > 0) {
485 array = isolate->factory()->NewFixedArray(max_number_of_static_properties);
486 }
487
488 while (true) {
489 // Install instance descriptors
490 if (!obj->instance_template()->IsUndefined()) {
491 Handle<ObjectTemplateInfo> instance = Handle<ObjectTemplateInfo>(
492 ObjectTemplateInfo::cast(obj->instance_template()), isolate);
493 Handle<Object> props =
494 Handle<Object>(instance->property_accessors(), isolate);
495 if (!props->IsUndefined()) {
496 Map::AppendCallbackDescriptors(map, props);
497 }
498 }
499 // Accumulate static accessors
500 if (!obj->property_accessors()->IsUndefined()) {
501 Handle<Object> props = Handle<Object>(obj->property_accessors(), isolate);
502 valid_descriptors =
503 AccessorInfo::AppendUnique(props, array, valid_descriptors);
504 }
505 // Climb parent chain
506 Handle<Object> parent = Handle<Object>(obj->parent_template(), isolate);
507 if (parent->IsUndefined()) break;
508 obj = Handle<FunctionTemplateInfo>::cast(parent);
509 }
510
511 // Install accumulated static accessors
512 for (int i = 0; i < valid_descriptors; i++) {
513 Handle<AccessorInfo> accessor(AccessorInfo::cast(array->get(i)));
514 JSObject::SetAccessor(result, accessor).Assert();
515 }
516
517 DCHECK(result->shared()->IsApiFunction());
518 return result;
519 }
520
521 } // namespace internal
522 } // namespace v8
OLDNEW
« no previous file with comments | « src/api-natives.h ('k') | src/apinatives.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698