OLD | NEW |
1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/type-feedback-vector.h" | 5 #include "src/type-feedback-vector.h" |
6 | 6 |
7 #include "src/code-stubs.h" | 7 #include "src/code-stubs.h" |
8 #include "src/ic/ic-inl.h" | 8 #include "src/ic/ic-inl.h" |
9 #include "src/ic/ic-state.h" | 9 #include "src/ic/ic-state.h" |
10 #include "src/objects.h" | 10 #include "src/objects.h" |
(...skipping 19 matching lines...) Expand all Loading... |
30 } | 30 } |
31 | 31 |
32 | 32 |
33 FeedbackVectorSlotKind TypeFeedbackMetadata::GetKind( | 33 FeedbackVectorSlotKind TypeFeedbackMetadata::GetKind( |
34 FeedbackVectorSlot slot) const { | 34 FeedbackVectorSlot slot) const { |
35 int index = VectorICComputer::index(kReservedIndexCount, slot.ToInt()); | 35 int index = VectorICComputer::index(kReservedIndexCount, slot.ToInt()); |
36 int data = Smi::cast(get(index))->value(); | 36 int data = Smi::cast(get(index))->value(); |
37 return VectorICComputer::decode(data, slot.ToInt()); | 37 return VectorICComputer::decode(data, slot.ToInt()); |
38 } | 38 } |
39 | 39 |
| 40 int TypeFeedbackMetadata::GetParameter(int parameter_index) const { |
| 41 FixedArray* parameters = FixedArray::cast(get(kParametersTableIndex)); |
| 42 return Smi::cast(parameters->get(parameter_index))->value(); |
| 43 } |
| 44 |
40 void TypeFeedbackMetadata::SetKind(FeedbackVectorSlot slot, | 45 void TypeFeedbackMetadata::SetKind(FeedbackVectorSlot slot, |
41 FeedbackVectorSlotKind kind) { | 46 FeedbackVectorSlotKind kind) { |
42 int index = VectorICComputer::index(kReservedIndexCount, slot.ToInt()); | 47 int index = VectorICComputer::index(kReservedIndexCount, slot.ToInt()); |
43 int data = Smi::cast(get(index))->value(); | 48 int data = Smi::cast(get(index))->value(); |
44 int new_data = VectorICComputer::encode(data, slot.ToInt(), kind); | 49 int new_data = VectorICComputer::encode(data, slot.ToInt(), kind); |
45 set(index, Smi::FromInt(new_data)); | 50 set(index, Smi::FromInt(new_data)); |
46 } | 51 } |
47 | 52 |
48 | 53 |
49 template Handle<TypeFeedbackMetadata> TypeFeedbackMetadata::New( | 54 template Handle<TypeFeedbackMetadata> TypeFeedbackMetadata::New( |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
84 } | 89 } |
85 | 90 |
86 Handle<TypeFeedbackMetadata> metadata = | 91 Handle<TypeFeedbackMetadata> metadata = |
87 Handle<TypeFeedbackMetadata>::cast(array); | 92 Handle<TypeFeedbackMetadata>::cast(array); |
88 | 93 |
89 for (int i = 0; i < slot_count; i++) { | 94 for (int i = 0; i < slot_count; i++) { |
90 FeedbackVectorSlotKind kind = spec->GetKind(i); | 95 FeedbackVectorSlotKind kind = spec->GetKind(i); |
91 metadata->SetKind(FeedbackVectorSlot(i), kind); | 96 metadata->SetKind(FeedbackVectorSlot(i), kind); |
92 } | 97 } |
93 | 98 |
| 99 if (spec->parameters_count() > 0) { |
| 100 const int parameters_count = spec->parameters_count(); |
| 101 Handle<FixedArray> params_array = |
| 102 factory->NewFixedArray(parameters_count, TENURED); |
| 103 for (int i = 0; i < parameters_count; i++) { |
| 104 params_array->set(i, Smi::FromInt(spec->GetParameter(i))); |
| 105 } |
| 106 metadata->set(kParametersTableIndex, *params_array); |
| 107 } else { |
| 108 metadata->set(kParametersTableIndex, *factory->empty_fixed_array()); |
| 109 } |
| 110 |
94 // It's important that the TypeFeedbackMetadata have a COW map, since it's | 111 // It's important that the TypeFeedbackMetadata have a COW map, since it's |
95 // pointed to by both a SharedFunctionInfo and indirectly by closures through | 112 // pointed to by both a SharedFunctionInfo and indirectly by closures through |
96 // the TypeFeedbackVector. The serializer uses the COW map type to decide | 113 // the TypeFeedbackVector. The serializer uses the COW map type to decide |
97 // this object belongs in the startup snapshot and not the partial | 114 // this object belongs in the startup snapshot and not the partial |
98 // snapshot(s). | 115 // snapshot(s). |
99 metadata->set_map(isolate->heap()->fixed_cow_array_map()); | 116 metadata->set_map(isolate->heap()->fixed_cow_array_map()); |
100 | 117 |
101 return metadata; | 118 return metadata; |
102 } | 119 } |
103 | 120 |
104 | 121 |
105 bool TypeFeedbackMetadata::SpecDiffersFrom( | 122 bool TypeFeedbackMetadata::SpecDiffersFrom( |
106 const FeedbackVectorSpec* other_spec) const { | 123 const FeedbackVectorSpec* other_spec) const { |
107 if (other_spec->slots() != slot_count()) { | 124 if (other_spec->slots() != slot_count()) { |
108 return true; | 125 return true; |
109 } | 126 } |
110 | 127 |
111 int slots = slot_count(); | 128 int slots = slot_count(); |
| 129 int parameter_index = 0; |
112 for (int i = 0; i < slots;) { | 130 for (int i = 0; i < slots;) { |
113 FeedbackVectorSlot slot(i); | 131 FeedbackVectorSlot slot(i); |
114 FeedbackVectorSlotKind kind = GetKind(slot); | 132 FeedbackVectorSlotKind kind = GetKind(slot); |
115 int entry_size = TypeFeedbackMetadata::GetSlotSize(kind); | 133 int entry_size = TypeFeedbackMetadata::GetSlotSize(kind); |
116 | 134 |
117 if (kind != other_spec->GetKind(i)) { | 135 if (kind != other_spec->GetKind(i)) { |
118 return true; | 136 return true; |
119 } | 137 } |
| 138 if (SlotRequiresParameter(kind)) { |
| 139 int parameter = GetParameter(parameter_index); |
| 140 int other_parameter = other_spec->GetParameter(parameter_index); |
| 141 if (parameter != other_parameter) { |
| 142 return true; |
| 143 } |
| 144 parameter_index++; |
| 145 } |
120 i += entry_size; | 146 i += entry_size; |
121 } | 147 } |
122 return false; | 148 return false; |
123 } | 149 } |
124 | 150 |
125 bool TypeFeedbackMetadata::DiffersFrom( | 151 bool TypeFeedbackMetadata::DiffersFrom( |
126 const TypeFeedbackMetadata* other_metadata) const { | 152 const TypeFeedbackMetadata* other_metadata) const { |
127 if (other_metadata->slot_count() != slot_count()) { | 153 if (other_metadata->slot_count() != slot_count()) { |
128 return true; | 154 return true; |
129 } | 155 } |
130 | 156 |
131 int slots = slot_count(); | 157 int slots = slot_count(); |
| 158 int parameter_index = 0; |
132 for (int i = 0; i < slots;) { | 159 for (int i = 0; i < slots;) { |
133 FeedbackVectorSlot slot(i); | 160 FeedbackVectorSlot slot(i); |
134 FeedbackVectorSlotKind kind = GetKind(slot); | 161 FeedbackVectorSlotKind kind = GetKind(slot); |
135 int entry_size = TypeFeedbackMetadata::GetSlotSize(kind); | 162 int entry_size = TypeFeedbackMetadata::GetSlotSize(kind); |
136 if (GetKind(slot) != other_metadata->GetKind(slot)) { | 163 if (GetKind(slot) != other_metadata->GetKind(slot)) { |
137 return true; | 164 return true; |
138 } | 165 } |
| 166 if (SlotRequiresParameter(kind)) { |
| 167 if (GetParameter(parameter_index) != |
| 168 other_metadata->GetParameter(parameter_index)) { |
| 169 return true; |
| 170 } |
| 171 parameter_index++; |
| 172 } |
139 i += entry_size; | 173 i += entry_size; |
140 } | 174 } |
141 return false; | 175 return false; |
142 } | 176 } |
143 | 177 |
144 const char* TypeFeedbackMetadata::Kind2String(FeedbackVectorSlotKind kind) { | 178 const char* TypeFeedbackMetadata::Kind2String(FeedbackVectorSlotKind kind) { |
145 switch (kind) { | 179 switch (kind) { |
146 case FeedbackVectorSlotKind::INVALID: | 180 case FeedbackVectorSlotKind::INVALID: |
147 return "INVALID"; | 181 return "INVALID"; |
148 case FeedbackVectorSlotKind::CALL_IC: | 182 case FeedbackVectorSlotKind::CALL_IC: |
149 return "CALL_IC"; | 183 return "CALL_IC"; |
150 case FeedbackVectorSlotKind::LOAD_IC: | 184 case FeedbackVectorSlotKind::LOAD_IC: |
151 return "LOAD_IC"; | 185 return "LOAD_IC"; |
152 case FeedbackVectorSlotKind::LOAD_GLOBAL_IC: | 186 case FeedbackVectorSlotKind::LOAD_GLOBAL_IC: |
153 return "LOAD_GLOBAL_IC"; | 187 return "LOAD_GLOBAL_IC"; |
154 case FeedbackVectorSlotKind::KEYED_LOAD_IC: | 188 case FeedbackVectorSlotKind::KEYED_LOAD_IC: |
155 return "KEYED_LOAD_IC"; | 189 return "KEYED_LOAD_IC"; |
156 case FeedbackVectorSlotKind::STORE_IC: | 190 case FeedbackVectorSlotKind::STORE_IC: |
157 return "STORE_IC"; | 191 return "STORE_IC"; |
158 case FeedbackVectorSlotKind::KEYED_STORE_IC: | 192 case FeedbackVectorSlotKind::KEYED_STORE_IC: |
159 return "KEYED_STORE_IC"; | 193 return "KEYED_STORE_IC"; |
160 case FeedbackVectorSlotKind::INTERPRETER_BINARYOP_IC: | 194 case FeedbackVectorSlotKind::INTERPRETER_BINARYOP_IC: |
161 return "INTERPRETER_BINARYOP_IC"; | 195 return "INTERPRETER_BINARYOP_IC"; |
162 case FeedbackVectorSlotKind::INTERPRETER_COMPARE_IC: | 196 case FeedbackVectorSlotKind::INTERPRETER_COMPARE_IC: |
163 return "INTERPRETER_COMPARE_IC"; | 197 return "INTERPRETER_COMPARE_IC"; |
164 case FeedbackVectorSlotKind::STORE_DATA_PROPERTY_IN_LITERAL_IC: | 198 case FeedbackVectorSlotKind::STORE_DATA_PROPERTY_IN_LITERAL_IC: |
165 return "STORE_DATA_PROPERTY_IN_LITERAL_IC"; | 199 return "STORE_DATA_PROPERTY_IN_LITERAL_IC"; |
| 200 case FeedbackVectorSlotKind::CREATE_CLOSURE: |
| 201 return "CREATE_CLOSURE"; |
166 case FeedbackVectorSlotKind::GENERAL: | 202 case FeedbackVectorSlotKind::GENERAL: |
167 return "STUB"; | 203 return "STUB"; |
168 case FeedbackVectorSlotKind::KINDS_NUMBER: | 204 case FeedbackVectorSlotKind::KINDS_NUMBER: |
169 break; | 205 break; |
170 } | 206 } |
171 UNREACHABLE(); | 207 UNREACHABLE(); |
172 return "?"; | 208 return "?"; |
173 } | 209 } |
174 | 210 |
175 FeedbackVectorSlotKind TypeFeedbackVector::GetKind( | 211 FeedbackVectorSlotKind TypeFeedbackVector::GetKind( |
176 FeedbackVectorSlot slot) const { | 212 FeedbackVectorSlot slot) const { |
177 DCHECK(!is_empty()); | 213 DCHECK(!is_empty()); |
178 return metadata()->GetKind(slot); | 214 return metadata()->GetKind(slot); |
179 } | 215 } |
180 | 216 |
| 217 int TypeFeedbackVector::GetParameter(FeedbackVectorSlot slot) const { |
| 218 DCHECK(!is_empty()); |
| 219 DCHECK( |
| 220 TypeFeedbackMetadata::SlotRequiresParameter(metadata()->GetKind(slot))); |
| 221 return FixedArray::cast(Get(slot))->length(); |
| 222 } |
| 223 |
181 // static | 224 // static |
182 Handle<TypeFeedbackVector> TypeFeedbackVector::New( | 225 Handle<TypeFeedbackVector> TypeFeedbackVector::New( |
183 Isolate* isolate, Handle<TypeFeedbackMetadata> metadata) { | 226 Isolate* isolate, Handle<TypeFeedbackMetadata> metadata) { |
184 Factory* factory = isolate->factory(); | 227 Factory* factory = isolate->factory(); |
185 | 228 |
186 const int slot_count = metadata->slot_count(); | 229 const int slot_count = metadata->slot_count(); |
187 const int length = slot_count + kReservedIndexCount; | 230 const int length = slot_count + kReservedIndexCount; |
188 if (length == kReservedIndexCount) { | 231 if (length == kReservedIndexCount) { |
189 return Handle<TypeFeedbackVector>::cast( | 232 return Handle<TypeFeedbackVector>::cast( |
190 factory->empty_type_feedback_vector()); | 233 factory->empty_type_feedback_vector()); |
191 } | 234 } |
192 | 235 |
193 Handle<FixedArray> array = factory->NewFixedArray(length, TENURED); | 236 Handle<FixedArray> array = factory->NewFixedArray(length, TENURED); |
194 array->set_map_no_write_barrier(isolate->heap()->type_feedback_vector_map()); | 237 array->set_map_no_write_barrier(isolate->heap()->type_feedback_vector_map()); |
195 array->set(kMetadataIndex, *metadata); | 238 array->set(kMetadataIndex, *metadata); |
196 array->set(kInvocationCountIndex, Smi::kZero); | 239 array->set(kInvocationCountIndex, Smi::kZero); |
| 240 int parameter_index = 0; |
| 241 for (int i = 0; i < slot_count;) { |
| 242 FeedbackVectorSlot slot(i); |
| 243 FeedbackVectorSlotKind kind = metadata->GetKind(slot); |
| 244 int index = TypeFeedbackVector::GetIndex(slot); |
| 245 int entry_size = TypeFeedbackMetadata::GetSlotSize(kind); |
| 246 |
| 247 if (kind == FeedbackVectorSlotKind::CREATE_CLOSURE) { |
| 248 // This fixed array is filled with undefined. |
| 249 int length = metadata->GetParameter(parameter_index++); |
| 250 if (length == 0) { |
| 251 // This is a native function literal. We can always point to |
| 252 // the empty literals array here. |
| 253 array->set(index, *factory->empty_literals_array(), SKIP_WRITE_BARRIER); |
| 254 } else { |
| 255 // TODO(mvstanton): Create the array. |
| 256 // Handle<FixedArray> value = factory->NewFixedArray(length); |
| 257 // array->set(index, *value); |
| 258 array->set(index, *factory->empty_literals_array(), SKIP_WRITE_BARRIER); |
| 259 } |
| 260 } |
| 261 i += entry_size; |
| 262 } |
197 | 263 |
198 DisallowHeapAllocation no_gc; | 264 DisallowHeapAllocation no_gc; |
199 | 265 |
200 // Ensure we can skip the write barrier | 266 // Ensure we can skip the write barrier |
201 Handle<Object> uninitialized_sentinel = UninitializedSentinel(isolate); | 267 Handle<Object> uninitialized_sentinel = UninitializedSentinel(isolate); |
202 DCHECK_EQ(isolate->heap()->uninitialized_symbol(), *uninitialized_sentinel); | 268 DCHECK_EQ(isolate->heap()->uninitialized_symbol(), *uninitialized_sentinel); |
203 for (int i = 0; i < slot_count;) { | 269 for (int i = 0; i < slot_count;) { |
204 FeedbackVectorSlot slot(i); | 270 FeedbackVectorSlot slot(i); |
205 FeedbackVectorSlotKind kind = metadata->GetKind(slot); | 271 FeedbackVectorSlotKind kind = metadata->GetKind(slot); |
206 int index = TypeFeedbackVector::GetIndex(slot); | 272 int index = TypeFeedbackVector::GetIndex(slot); |
207 int entry_size = TypeFeedbackMetadata::GetSlotSize(kind); | 273 int entry_size = TypeFeedbackMetadata::GetSlotSize(kind); |
208 | 274 |
209 Object* value; | 275 Object* value; |
210 if (kind == FeedbackVectorSlotKind::LOAD_GLOBAL_IC) { | 276 if (kind == FeedbackVectorSlotKind::LOAD_GLOBAL_IC) { |
211 value = isolate->heap()->empty_weak_cell(); | 277 value = isolate->heap()->empty_weak_cell(); |
212 } else if (kind == FeedbackVectorSlotKind::INTERPRETER_COMPARE_IC || | 278 } else if (kind == FeedbackVectorSlotKind::INTERPRETER_COMPARE_IC || |
213 kind == FeedbackVectorSlotKind::INTERPRETER_BINARYOP_IC) { | 279 kind == FeedbackVectorSlotKind::INTERPRETER_BINARYOP_IC) { |
214 value = Smi::kZero; | 280 value = Smi::kZero; |
215 } else { | 281 } else { |
216 value = *uninitialized_sentinel; | 282 value = *uninitialized_sentinel; |
217 } | 283 } |
218 array->set(index, value, SKIP_WRITE_BARRIER); | |
219 | 284 |
220 value = kind == FeedbackVectorSlotKind::CALL_IC ? Smi::kZero | 285 if (kind != FeedbackVectorSlotKind::CREATE_CLOSURE) { |
221 : *uninitialized_sentinel; | 286 array->set(index, value, SKIP_WRITE_BARRIER); |
222 for (int j = 1; j < entry_size; j++) { | 287 value = kind == FeedbackVectorSlotKind::CALL_IC ? Smi::kZero |
223 array->set(index + j, value, SKIP_WRITE_BARRIER); | 288 : *uninitialized_sentinel; |
| 289 for (int j = 1; j < entry_size; j++) { |
| 290 array->set(index + j, value, SKIP_WRITE_BARRIER); |
| 291 } |
224 } | 292 } |
225 i += entry_size; | 293 i += entry_size; |
226 } | 294 } |
227 return Handle<TypeFeedbackVector>::cast(array); | 295 return Handle<TypeFeedbackVector>::cast(array); |
228 } | 296 } |
229 | 297 |
230 | 298 |
231 // static | 299 // static |
232 int TypeFeedbackVector::GetIndexFromSpec(const FeedbackVectorSpec* spec, | 300 int TypeFeedbackVector::GetIndexFromSpec(const FeedbackVectorSpec* spec, |
233 FeedbackVectorSlot slot) { | 301 FeedbackVectorSlot slot) { |
(...skipping 14 matching lines...) Expand all Loading... |
248 // This logic is copied from | 316 // This logic is copied from |
249 // StaticMarkingVisitor<StaticVisitor>::VisitCodeTarget. | 317 // StaticMarkingVisitor<StaticVisitor>::VisitCodeTarget. |
250 static bool ClearLogic(Isolate* isolate) { | 318 static bool ClearLogic(Isolate* isolate) { |
251 return FLAG_cleanup_code_caches_at_gc && isolate->serializer_enabled(); | 319 return FLAG_cleanup_code_caches_at_gc && isolate->serializer_enabled(); |
252 } | 320 } |
253 | 321 |
254 | 322 |
255 void TypeFeedbackVector::ClearSlotsImpl(SharedFunctionInfo* shared, | 323 void TypeFeedbackVector::ClearSlotsImpl(SharedFunctionInfo* shared, |
256 bool force_clear) { | 324 bool force_clear) { |
257 Isolate* isolate = GetIsolate(); | 325 Isolate* isolate = GetIsolate(); |
| 326 if (!force_clear && !ClearLogic(isolate)) return; |
258 | 327 |
259 if (!force_clear && !ClearLogic(isolate)) return; | 328 if (this == isolate->heap()->empty_type_feedback_vector()) return; |
260 | 329 |
261 Object* uninitialized_sentinel = | 330 Object* uninitialized_sentinel = |
262 TypeFeedbackVector::RawUninitializedSentinel(isolate); | 331 TypeFeedbackVector::RawUninitializedSentinel(isolate); |
263 | 332 |
264 TypeFeedbackMetadataIterator iter(metadata()); | 333 TypeFeedbackMetadataIterator iter(metadata()); |
265 while (iter.HasNext()) { | 334 while (iter.HasNext()) { |
266 FeedbackVectorSlot slot = iter.Next(); | 335 FeedbackVectorSlot slot = iter.Next(); |
267 FeedbackVectorSlotKind kind = iter.kind(); | 336 FeedbackVectorSlotKind kind = iter.kind(); |
268 | 337 |
269 Object* obj = Get(slot); | 338 Object* obj = Get(slot); |
(...skipping 29 matching lines...) Expand all Loading... |
299 nexus.Clear(shared->code()); | 368 nexus.Clear(shared->code()); |
300 break; | 369 break; |
301 } | 370 } |
302 case FeedbackVectorSlotKind::INTERPRETER_BINARYOP_IC: | 371 case FeedbackVectorSlotKind::INTERPRETER_BINARYOP_IC: |
303 case FeedbackVectorSlotKind::INTERPRETER_COMPARE_IC: { | 372 case FeedbackVectorSlotKind::INTERPRETER_COMPARE_IC: { |
304 DCHECK(Get(slot)->IsSmi()); | 373 DCHECK(Get(slot)->IsSmi()); |
305 // don't clear these smi slots. | 374 // don't clear these smi slots. |
306 // Set(slot, Smi::kZero); | 375 // Set(slot, Smi::kZero); |
307 break; | 376 break; |
308 } | 377 } |
| 378 case FeedbackVectorSlotKind::CREATE_CLOSURE: { |
| 379 // Fill the array with undefined. |
| 380 FixedArray* array = FixedArray::cast(Get(slot)); |
| 381 for (int i = 1; i < array->length(); i++) { |
| 382 array->set_undefined(i); |
| 383 } |
| 384 break; |
| 385 } |
309 case FeedbackVectorSlotKind::GENERAL: { | 386 case FeedbackVectorSlotKind::GENERAL: { |
310 if (obj->IsHeapObject()) { | 387 if (obj->IsHeapObject()) { |
311 InstanceType instance_type = | 388 InstanceType instance_type = |
312 HeapObject::cast(obj)->map()->instance_type(); | 389 HeapObject::cast(obj)->map()->instance_type(); |
313 // AllocationSites are exempt from clearing. They don't store Maps | 390 // AllocationSites are exempt from clearing. They don't store Maps |
314 // or Code pointers which can cause memory leaks if not cleared | 391 // or Code pointers which can cause memory leaks if not cleared |
315 // regularly. | 392 // regularly. |
316 if (instance_type != ALLOCATION_SITE_TYPE) { | 393 if (instance_type != ALLOCATION_SITE_TYPE) { |
317 Set(slot, uninitialized_sentinel, SKIP_WRITE_BARRIER); | 394 Set(slot, uninitialized_sentinel, SKIP_WRITE_BARRIER); |
318 } | 395 } |
(...skipping 693 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1012 void StoreDataPropertyInLiteralICNexus::ConfigureMonomorphic( | 1089 void StoreDataPropertyInLiteralICNexus::ConfigureMonomorphic( |
1013 Handle<Name> name, Handle<Map> receiver_map) { | 1090 Handle<Name> name, Handle<Map> receiver_map) { |
1014 Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map); | 1091 Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map); |
1015 | 1092 |
1016 SetFeedback(*cell); | 1093 SetFeedback(*cell); |
1017 SetFeedbackExtra(*name); | 1094 SetFeedbackExtra(*name); |
1018 } | 1095 } |
1019 | 1096 |
1020 } // namespace internal | 1097 } // namespace internal |
1021 } // namespace v8 | 1098 } // namespace v8 |
OLD | NEW |