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

Unified 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/api-natives.h ('k') | src/apinatives.js » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/api-natives.cc
diff --git a/src/api-natives.cc b/src/api-natives.cc
new file mode 100644
index 0000000000000000000000000000000000000000..8233b8abd1662845be33ecfea1077d22638a07aa
--- /dev/null
+++ b/src/api-natives.cc
@@ -0,0 +1,529 @@
+// Copyright 2015 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/api-natives.h"
+#include "src/isolate-inl.h"
+
+namespace v8 {
+namespace internal {
+
+namespace {
+
+// Transform getter or setter into something DefineAccessor can handle.
+Handle<Object> InstantiateAccessorComponent(Isolate* isolate,
+ Handle<Object> component) {
+ if (component->IsUndefined()) return isolate->factory()->undefined_value();
+ Handle<FunctionTemplateInfo> info =
+ Handle<FunctionTemplateInfo>::cast(component);
+ // TODO(dcarney): instantiate directly.
+ return Utils::OpenHandle(*Utils::ToLocal(info)->GetFunction());
+}
+
+
+MaybeHandle<Object> DefineApiAccessorProperty(
+ Isolate* isolate, Handle<JSObject> object, Handle<Name> name,
+ Handle<Object> getter, Handle<Object> setter, Smi* attribute) {
+ DCHECK(PropertyDetails::AttributesField::is_valid(
+ static_cast<PropertyAttributes>(attribute->value())));
+ RETURN_ON_EXCEPTION(
+ isolate, JSObject::DefineAccessor(
+ object, name, InstantiateAccessorComponent(isolate, getter),
+ InstantiateAccessorComponent(isolate, setter),
+ static_cast<PropertyAttributes>(attribute->value())),
+ Object);
+ return object;
+}
+
+
+MaybeHandle<Object> AddPropertyForTemplate(Isolate* isolate,
+ Handle<JSObject> object,
+ Handle<Object> key,
+ Handle<Object> value,
+ Smi* unchecked_attributes) {
+ DCHECK((unchecked_attributes->value() &
+ ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
+ // Compute attributes.
+ PropertyAttributes attributes =
+ static_cast<PropertyAttributes>(unchecked_attributes->value());
+
+#ifdef DEBUG
+ bool duplicate;
+ if (key->IsName()) {
+ LookupIterator it(object, Handle<Name>::cast(key),
+ LookupIterator::OWN_SKIP_INTERCEPTOR);
+ Maybe<PropertyAttributes> maybe = JSReceiver::GetPropertyAttributes(&it);
+ DCHECK(maybe.has_value);
+ duplicate = it.IsFound();
+ } else {
+ uint32_t index = 0;
+ key->ToArrayIndex(&index);
+ Maybe<bool> maybe = JSReceiver::HasOwnElement(object, index);
+ if (!maybe.has_value) return MaybeHandle<Object>();
+ duplicate = maybe.value;
+ }
+ if (duplicate) {
+ Handle<Object> args[1] = {key};
+ THROW_NEW_ERROR(isolate, NewTypeError("duplicate_template_property",
+ HandleVector(args, 1)),
+ Object);
+ }
+#endif
+
+ RETURN_ON_EXCEPTION(
+ isolate, Runtime::DefineObjectProperty(object, key, value, attributes),
+ Object);
+ return object;
+}
+
+
+void DisableAccessChecks(Isolate* isolate, Handle<JSObject> object) {
+ Handle<Map> old_map(object->map());
+ // Copy map so it won't interfere constructor's initial map.
+ Handle<Map> new_map = Map::Copy(old_map, "DisableAccessChecks");
+ new_map->set_is_access_check_needed(false);
+ JSObject::MigrateToMap(Handle<JSObject>::cast(object), new_map);
+}
+
+
+void EnableAccessChecks(Isolate* isolate, Handle<JSObject> object) {
+ Handle<Map> old_map(object->map());
+ // Copy map so it won't interfere constructor's initial map.
+ Handle<Map> new_map = Map::Copy(old_map, "EnableAccessChecks");
+ new_map->set_is_access_check_needed(true);
+ JSObject::MigrateToMap(object, new_map);
+}
+
+
+MaybeHandle<JSObject> InstantiateObject(Isolate* isolate,
+ Handle<ObjectTemplateInfo> data);
+
+
+MaybeHandle<JSFunction> InstantiateFunction(Isolate* isolate,
+ Handle<FunctionTemplateInfo> data,
+ Handle<Name> name = Handle<Name>());
+
+
+MaybeHandle<Object> Instantiate(Isolate* isolate, Handle<Object> data,
+ Handle<Name> name = Handle<Name>()) {
+ if (data->IsFunctionTemplateInfo()) {
+ return InstantiateFunction(isolate,
+ Handle<FunctionTemplateInfo>::cast(data), name);
+ } else if (data->IsObjectTemplateInfo()) {
+ return InstantiateObject(isolate, Handle<ObjectTemplateInfo>::cast(data));
+ } else {
+ // TODO(dcarney): CHECK data is JSObject or Primitive.
+ return data;
+ }
+}
+
+
+class AccessCheckDisableScope {
+ public:
+ AccessCheckDisableScope(Isolate* isolate, Handle<JSObject> obj)
+ : isolate_(isolate),
+ disabled_(obj->map()->is_access_check_needed()),
+ obj_(obj) {
+ if (disabled_) {
+ DisableAccessChecks(isolate_, obj_);
+ }
+ }
+ ~AccessCheckDisableScope() {
+ if (disabled_) {
+ EnableAccessChecks(isolate_, obj_);
+ }
+ }
+
+ private:
+ Isolate* isolate_;
+ const bool disabled_;
+ Handle<JSObject> obj_;
+};
+
+
+MaybeHandle<JSObject> ConfigureInstance(Isolate* isolate, Handle<JSObject> obj,
+ Handle<TemplateInfo> data) {
+ auto property_list = handle(data->property_list(), isolate);
+ if (property_list->IsUndefined()) return obj;
+ // TODO(dcarney): just use a FixedArray here.
+ NeanderArray properties(property_list);
+ if (properties.length() == 0) return obj;
+ HandleScope scope(isolate);
+ // Disable access checks while instantiating the object.
+ AccessCheckDisableScope access_check_scope(isolate, obj);
+ for (int i = 0; i < properties.length();) {
+ int length = Smi::cast(properties.get(i))->value();
+ if (length == 3) {
+ auto name = handle(Name::cast(properties.get(i + 1)), isolate);
+ auto prop_data = handle(properties.get(i + 2), isolate);
+ auto attributes = Smi::cast(properties.get(i + 3));
+ Handle<Object> value;
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, value, Instantiate(isolate, prop_data, name), JSObject);
+ RETURN_ON_EXCEPTION(isolate, AddPropertyForTemplate(isolate, obj, name,
+ value, attributes),
+ JSObject);
+ } else {
+ DCHECK(length == 4 || length == 5);
+ // TODO(verwaest): The 5th value used to be access_control. Remove once
+ // the bindings are updated.
+ auto name = handle(Name::cast(properties.get(i + 1)), isolate);
+ auto getter = handle(properties.get(i + 2), isolate);
+ auto setter = handle(properties.get(i + 3), isolate);
+ auto attributes = Smi::cast(properties.get(i + 4));
+ RETURN_ON_EXCEPTION(isolate,
+ DefineApiAccessorProperty(isolate, obj, name, getter,
+ setter, attributes),
+ JSObject);
+ }
+ i += length + 1;
+ }
+ return obj;
+}
+
+
+MaybeHandle<JSObject> InstantiateObject(Isolate* isolate,
+ Handle<ObjectTemplateInfo> data) {
+ // Enter a new scope. Recursion could otherwise create a lot of handles.
+ HandleScope scope(isolate);
+ // Fast path.
+ Handle<JSObject> result;
+ auto info = Handle<ObjectTemplateInfo>::cast(data);
+ auto constructor = handle(info->constructor(), isolate);
+ Handle<JSFunction> cons;
+ if (constructor->IsUndefined()) {
+ cons = isolate->object_function();
+ } else {
+ auto cons_templ = Handle<FunctionTemplateInfo>::cast(constructor);
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, cons, InstantiateFunction(isolate, cons_templ), JSFunction);
+ }
+ auto object = isolate->factory()->NewJSObject(cons);
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, result, ConfigureInstance(isolate, object, info), JSFunction);
+ // TODO(dcarney): is this necessary?
+ JSObject::MigrateSlowToFast(result, 0, "ApiNatives::InstantiateObject");
+ return scope.CloseAndEscape(result);
+}
+
+
+void InstallInCache(Isolate* isolate, int serial_number,
+ Handle<JSFunction> function) {
+ auto cache = isolate->function_cache();
+ if (cache->length() <= serial_number) {
+ int new_size;
+ if (isolate->next_serial_number() < 50) {
+ new_size = 100;
+ } else {
+ new_size = 3 * isolate->next_serial_number() / 2;
+ }
+ cache = FixedArray::CopySize(cache, new_size);
+ isolate->native_context()->set_function_cache(*cache);
+ }
+ cache->set(serial_number, *function);
+}
+
+
+MaybeHandle<JSFunction> InstantiateFunction(Isolate* isolate,
+ Handle<FunctionTemplateInfo> data,
+ Handle<Name> name) {
+ int serial_number = Smi::cast(data->serial_number())->value();
+ // Probe cache.
+ if (!data->do_not_cache()) {
+ auto cache = isolate->function_cache();
+ // Fast case: see if the function has already been instantiated
+ if (serial_number < cache->length()) {
+ Handle<Object> element = FixedArray::get(cache, serial_number);
+ if (element->IsJSFunction()) {
+ return Handle<JSFunction>::cast(element);
+ }
+ }
+ }
+ // Enter a new scope. Recursion could otherwise create a lot of handles.
+ HandleScope scope(isolate);
+ Handle<JSObject> prototype;
+ if (!data->remove_prototype()) {
+ auto prototype_templ = handle(data->prototype_template(), isolate);
+ if (prototype_templ->IsUndefined()) {
+ prototype = isolate->factory()->NewJSObject(isolate->object_function());
+ } else {
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, prototype,
+ InstantiateObject(isolate,
+ Handle<ObjectTemplateInfo>::cast(prototype_templ)),
+ JSFunction);
+ }
+ auto parent = handle(data->parent_template(), isolate);
+ if (!parent->IsUndefined()) {
+ Handle<JSFunction> parent_instance;
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, parent_instance,
+ InstantiateFunction(isolate,
+ Handle<FunctionTemplateInfo>::cast(parent)),
+ JSFunction);
+ // TODO(dcarney): decide what to do here.
+ Handle<Object> parent_prototype;
+ ASSIGN_RETURN_ON_EXCEPTION(
+ isolate, parent_prototype,
+ JSObject::GetProperty(parent_instance,
+ isolate->factory()->prototype_string()),
+ JSFunction);
+ RETURN_ON_EXCEPTION(
+ isolate, JSObject::SetPrototype(prototype, parent_prototype, false),
+ JSFunction);
+ }
+ }
+ auto function = ApiNatives::CreateApiFunction(
+ isolate, data, prototype, ApiNatives::JavaScriptObjectType);
+ if (!name.is_null() && name->IsString()) {
+ function->shared()->set_name(*name);
+ }
+ if (!data->do_not_cache()) {
+ // Cache the function to limit recursion.
+ InstallInCache(isolate, serial_number, function);
+ }
+ auto result = ConfigureInstance(isolate, function, data);
+ if (result.is_null()) {
+ // uncache on error.
+ if (!data->do_not_cache()) {
+ auto cache = isolate->function_cache();
+ cache->set(serial_number, isolate->heap()->undefined_value());
+ }
+ return MaybeHandle<JSFunction>();
+ }
+ return scope.CloseAndEscape(function);
+}
+
+
+class InvokeScope {
+ public:
+ explicit InvokeScope(Isolate* isolate)
+ : isolate_(isolate), save_context_(isolate) {}
+ ~InvokeScope() {
+ bool has_exception = isolate_->has_pending_exception();
+ if (has_exception) {
+ isolate_->ReportPendingMessages();
+ } else {
+ isolate_->clear_pending_message();
+ }
+ }
+
+ private:
+ Isolate* isolate_;
+ SaveContext save_context_;
+};
+
+} // namespace
+
+
+MaybeHandle<JSFunction> ApiNatives::InstantiateFunction(
+ Handle<FunctionTemplateInfo> data) {
+ Isolate* isolate = data->GetIsolate();
+ InvokeScope invoke_scope(isolate);
+ return ::v8::internal::InstantiateFunction(isolate, data);
+}
+
+
+MaybeHandle<JSObject> ApiNatives::InstantiateObject(
+ Handle<ObjectTemplateInfo> data) {
+ Isolate* isolate = data->GetIsolate();
+ InvokeScope invoke_scope(isolate);
+ return ::v8::internal::InstantiateObject(isolate, data);
+}
+
+
+MaybeHandle<FunctionTemplateInfo> ApiNatives::ConfigureInstance(
+ Isolate* isolate, Handle<FunctionTemplateInfo> desc,
+ Handle<JSObject> instance) {
+ // Configure the instance by adding the properties specified by the
+ // instance template.
+ if (desc->instance_template()->IsUndefined()) return desc;
+ InvokeScope invoke_scope(isolate);
+ Handle<ObjectTemplateInfo> instance_template(
+ ObjectTemplateInfo::cast(desc->instance_template()), isolate);
+ RETURN_ON_EXCEPTION(isolate, ::v8::internal::ConfigureInstance(
+ isolate, instance, instance_template),
+ FunctionTemplateInfo);
+ return desc;
+}
+
+
+Handle<JSFunction> ApiNatives::CreateApiFunction(
+ Isolate* isolate, Handle<FunctionTemplateInfo> obj,
+ Handle<Object> prototype, ApiInstanceType instance_type) {
+ Handle<Code> code = isolate->builtins()->HandleApiCall();
+ Handle<Code> construct_stub = isolate->builtins()->JSConstructStubApi();
+
+ obj->set_instantiated(true);
+ Handle<JSFunction> result;
+ if (obj->remove_prototype()) {
+ result = isolate->factory()->NewFunctionWithoutPrototype(
+ isolate->factory()->empty_string(), code);
+ } else {
+ int internal_field_count = 0;
+ if (!obj->instance_template()->IsUndefined()) {
+ Handle<ObjectTemplateInfo> instance_template = Handle<ObjectTemplateInfo>(
+ ObjectTemplateInfo::cast(obj->instance_template()));
+ internal_field_count =
+ Smi::cast(instance_template->internal_field_count())->value();
+ }
+
+ // TODO(svenpanne) Kill ApiInstanceType and refactor things by generalizing
+ // JSObject::GetHeaderSize.
+ int instance_size = kPointerSize * internal_field_count;
+ InstanceType type;
+ switch (instance_type) {
+ case JavaScriptObjectType:
+ type = JS_OBJECT_TYPE;
+ instance_size += JSObject::kHeaderSize;
+ break;
+ case GlobalObjectType:
+ type = JS_GLOBAL_OBJECT_TYPE;
+ instance_size += JSGlobalObject::kSize;
+ break;
+ case GlobalProxyType:
+ type = JS_GLOBAL_PROXY_TYPE;
+ instance_size += JSGlobalProxy::kSize;
+ break;
+ default:
+ UNREACHABLE();
+ type = JS_OBJECT_TYPE; // Keep the compiler happy.
+ break;
+ }
+
+ result = isolate->factory()->NewFunction(
+ isolate->factory()->empty_string(), code, prototype, type,
+ instance_size, obj->read_only_prototype(), true);
+ }
+
+ result->shared()->set_length(obj->length());
+ Handle<Object> class_name(obj->class_name(), isolate);
+ if (class_name->IsString()) {
+ result->shared()->set_instance_class_name(*class_name);
+ result->shared()->set_name(*class_name);
+ }
+ result->shared()->set_function_data(*obj);
+ result->shared()->set_construct_stub(*construct_stub);
+ result->shared()->DontAdaptArguments();
+
+ if (obj->remove_prototype()) {
+ DCHECK(result->shared()->IsApiFunction());
+ DCHECK(!result->has_initial_map());
+ DCHECK(!result->has_prototype());
+ return result;
+ }
+
+#ifdef DEBUG
+ LookupIterator it(handle(JSObject::cast(result->prototype())),
+ isolate->factory()->constructor_string(),
+ LookupIterator::OWN_SKIP_INTERCEPTOR);
+ MaybeHandle<Object> maybe_prop = Object::GetProperty(&it);
+ DCHECK(it.IsFound());
+ DCHECK(maybe_prop.ToHandleChecked().is_identical_to(result));
+#endif
+
+ // Down from here is only valid for API functions that can be used as a
+ // constructor (don't set the "remove prototype" flag).
+
+ Handle<Map> map(result->initial_map());
+
+ // Mark as undetectable if needed.
+ if (obj->undetectable()) {
+ map->set_is_undetectable();
+ }
+
+ // Mark as hidden for the __proto__ accessor if needed.
+ if (obj->hidden_prototype()) {
+ map->set_is_hidden_prototype();
+ }
+
+ // Mark as needs_access_check if needed.
+ if (obj->needs_access_check()) {
+ map->set_is_access_check_needed(true);
+ }
+
+ // Set interceptor information in the map.
+ if (!obj->named_property_handler()->IsUndefined()) {
+ map->set_has_named_interceptor();
+ }
+ if (!obj->indexed_property_handler()->IsUndefined()) {
+ map->set_has_indexed_interceptor();
+ }
+
+ // Set instance call-as-function information in the map.
+ if (!obj->instance_call_handler()->IsUndefined()) {
+ map->set_has_instance_call_handler();
+ }
+
+ // Recursively copy parent instance templates' accessors,
+ // 'data' may be modified.
+ int max_number_of_additional_properties = 0;
+ int max_number_of_static_properties = 0;
+ FunctionTemplateInfo* info = *obj;
+ while (true) {
+ if (!info->instance_template()->IsUndefined()) {
+ Object* props = ObjectTemplateInfo::cast(info->instance_template())
+ ->property_accessors();
+ if (!props->IsUndefined()) {
+ Handle<Object> props_handle(props, isolate);
+ NeanderArray props_array(props_handle);
+ max_number_of_additional_properties += props_array.length();
+ }
+ }
+ if (!info->property_accessors()->IsUndefined()) {
+ Object* props = info->property_accessors();
+ if (!props->IsUndefined()) {
+ Handle<Object> props_handle(props, isolate);
+ NeanderArray props_array(props_handle);
+ max_number_of_static_properties += props_array.length();
+ }
+ }
+ Object* parent = info->parent_template();
+ if (parent->IsUndefined()) break;
+ info = FunctionTemplateInfo::cast(parent);
+ }
+
+ Map::EnsureDescriptorSlack(map, max_number_of_additional_properties);
+
+ // Use a temporary FixedArray to acculumate static accessors
+ int valid_descriptors = 0;
+ Handle<FixedArray> array;
+ if (max_number_of_static_properties > 0) {
+ array = isolate->factory()->NewFixedArray(max_number_of_static_properties);
+ }
+
+ while (true) {
+ // Install instance descriptors
+ if (!obj->instance_template()->IsUndefined()) {
+ Handle<ObjectTemplateInfo> instance = Handle<ObjectTemplateInfo>(
+ ObjectTemplateInfo::cast(obj->instance_template()), isolate);
+ Handle<Object> props =
+ Handle<Object>(instance->property_accessors(), isolate);
+ if (!props->IsUndefined()) {
+ Map::AppendCallbackDescriptors(map, props);
+ }
+ }
+ // Accumulate static accessors
+ if (!obj->property_accessors()->IsUndefined()) {
+ Handle<Object> props = Handle<Object>(obj->property_accessors(), isolate);
+ valid_descriptors =
+ AccessorInfo::AppendUnique(props, array, valid_descriptors);
+ }
+ // Climb parent chain
+ Handle<Object> parent = Handle<Object>(obj->parent_template(), isolate);
+ if (parent->IsUndefined()) break;
+ obj = Handle<FunctionTemplateInfo>::cast(parent);
+ }
+
+ // Install accumulated static accessors
+ for (int i = 0; i < valid_descriptors; i++) {
+ Handle<AccessorInfo> accessor(AccessorInfo::cast(array->get(i)));
+ JSObject::SetAccessor(result, accessor).Assert();
+ }
+
+ DCHECK(result->shared()->IsApiFunction());
+ return result;
+}
+
+} // namespace internal
+} // namespace v8
« 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