blob: 24f306aa685daed27039a39c464a140b2a18e958 [file] [log] [blame]
// Copyright 2017 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/objects/template-objects.h"
#include "src/factory.h"
#include "src/isolate.h"
#include "src/objects-inl.h"
#include "src/property-descriptor.h"
namespace v8 {
namespace internal {
bool TemplateObjectDescription::Equals(
TemplateObjectDescription const* that) const {
if (this->raw_strings()->length() == that->raw_strings()->length()) {
for (int i = this->raw_strings()->length(); --i >= 0;) {
if (this->raw_strings()->get(i) != that->raw_strings()->get(i)) {
return false;
}
}
return true;
}
return false;
}
// static
Handle<JSArray> TemplateObjectDescription::GetTemplateObject(
Handle<TemplateObjectDescription> description,
Handle<Context> native_context) {
DCHECK(native_context->IsNativeContext());
Isolate* const isolate = native_context->GetIsolate();
// Check if we already have a [[TemplateMap]] for the {native_context},
// and if not, just allocate one on the fly (which will be set below).
Handle<TemplateMap> template_map =
native_context->template_map()->IsUndefined(isolate)
? TemplateMap::New(isolate)
: handle(TemplateMap::cast(native_context->template_map()), isolate);
// Check if we already have an appropriate entry.
Handle<JSArray> template_object;
if (!TemplateMap::Lookup(template_map, description)
.ToHandle(&template_object)) {
// Create the raw object from the {raw_strings}.
Handle<FixedArray> raw_strings(description->raw_strings(), isolate);
Handle<JSArray> raw_object = isolate->factory()->NewJSArrayWithElements(
raw_strings, PACKED_ELEMENTS, raw_strings->length(), TENURED);
// Create the template object from the {cooked_strings}.
Handle<FixedArray> cooked_strings(description->cooked_strings(), isolate);
template_object = isolate->factory()->NewJSArrayWithElements(
cooked_strings, PACKED_ELEMENTS, cooked_strings->length(), TENURED);
// Freeze the {raw_object}.
JSObject::SetIntegrityLevel(raw_object, FROZEN, kThrowOnError).ToChecked();
// Install a "raw" data property for {raw_object} on {template_object}.
PropertyDescriptor raw_desc;
raw_desc.set_value(raw_object);
raw_desc.set_configurable(false);
raw_desc.set_enumerable(false);
raw_desc.set_writable(false);
JSArray::DefineOwnProperty(isolate, template_object,
isolate->factory()->raw_string(), &raw_desc,
kThrowOnError)
.ToChecked();
// Freeze the {template_object} as well.
JSObject::SetIntegrityLevel(template_object, FROZEN, kThrowOnError)
.ToChecked();
// Remember the {template_object} in the {template_map}.
template_map = TemplateMap::Add(template_map, description, template_object);
native_context->set_template_map(*template_map);
}
return template_object;
}
// static
bool TemplateMapShape::IsMatch(TemplateObjectDescription* key, Object* value) {
return key->Equals(TemplateObjectDescription::cast(value));
}
// static
uint32_t TemplateMapShape::Hash(Isolate* isolate,
TemplateObjectDescription* key) {
return key->hash();
}
// static
uint32_t TemplateMapShape::HashForObject(Isolate* isolate, Object* object) {
return Hash(isolate, TemplateObjectDescription::cast(object));
}
// static
Handle<TemplateMap> TemplateMap::New(Isolate* isolate) {
return HashTable::New(isolate, 0);
}
// static
MaybeHandle<JSArray> TemplateMap::Lookup(
Handle<TemplateMap> template_map, Handle<TemplateObjectDescription> key) {
int const entry = template_map->FindEntry(*key);
if (entry == kNotFound) return MaybeHandle<JSArray>();
int const index = EntryToIndex(entry);
return handle(JSArray::cast(template_map->get(index + 1)));
}
// static
Handle<TemplateMap> TemplateMap::Add(Handle<TemplateMap> template_map,
Handle<TemplateObjectDescription> key,
Handle<JSArray> value) {
DCHECK_EQ(kNotFound, template_map->FindEntry(*key));
template_map = EnsureCapacity(template_map, 1);
uint32_t const hash = ShapeT::Hash(key->GetIsolate(), *key);
int const entry = template_map->FindInsertionEntry(hash);
int const index = EntryToIndex(entry);
template_map->set(index + 0, *key);
template_map->set(index + 1, *value);
template_map->ElementAdded();
return template_map;
}
} // namespace internal
} // namespace v8