summaryrefslogtreecommitdiff
path: root/deps/v8/src/objects/template-objects.cc
blob: 5e374b47229ea34162b15f2940c28331d38a3e2f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
// 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, Object::THROW_ON_ERROR)
        .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,
                               Object::THROW_ON_ERROR)
        .ToChecked();

    // Freeze the {template_object} as well.
    JSObject::SetIntegrityLevel(template_object, FROZEN, Object::THROW_ON_ERROR)
        .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