Chromium Code Reviews| 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/runtime/runtime-utils.h" | 5 #include "src/runtime/runtime-utils.h" |
| 6 | 6 |
| 7 #include "src/allocation-site-scopes.h" | 7 #include "src/allocation-site-scopes.h" |
| 8 #include "src/arguments.h" | 8 #include "src/arguments.h" |
| 9 #include "src/ast/ast.h" | 9 #include "src/ast/ast.h" |
| 10 #include "src/ast/compile-time-value.h" | 10 #include "src/ast/compile-time-value.h" |
| 11 #include "src/isolate-inl.h" | 11 #include "src/isolate-inl.h" |
| 12 #include "src/runtime/runtime.h" | 12 #include "src/runtime/runtime.h" |
| 13 | 13 |
| 14 namespace v8 { | 14 namespace v8 { |
| 15 namespace internal { | 15 namespace internal { |
| 16 | 16 |
| 17 static Handle<Map> ComputeObjectLiteralMap( | |
| 18 Handle<Context> context, | |
| 19 Handle<BoilerplateDescription> boilerplate_description, | |
| 20 bool* is_result_from_cache) { | |
| 21 int number_of_properties = boilerplate_description->backing_store_size(); | |
| 22 Isolate* isolate = context->GetIsolate(); | |
| 23 return isolate->factory()->ObjectLiteralMapFromCache( | |
| 24 context, number_of_properties, is_result_from_cache); | |
| 25 } | |
| 26 | |
| 27 MUST_USE_RESULT static MaybeHandle<Object> CreateLiteralBoilerplate( | 17 MUST_USE_RESULT static MaybeHandle<Object> CreateLiteralBoilerplate( |
| 28 Isolate* isolate, Handle<FeedbackVector> vector, | 18 Isolate* isolate, Handle<FeedbackVector> vector, |
| 29 Handle<BoilerplateDescription> boilerplate_description); | 19 Handle<FixedArray> compile_time_value); |
| 30 | 20 |
| 31 MUST_USE_RESULT static MaybeHandle<Object> CreateObjectLiteralBoilerplate( | 21 MUST_USE_RESULT static MaybeHandle<Object> CreateObjectLiteralBoilerplate( |
| 32 Isolate* isolate, Handle<FeedbackVector> vector, | 22 Isolate* isolate, Handle<FeedbackVector> vector, |
| 33 Handle<BoilerplateDescription> boilerplate_description, | 23 Handle<BoilerplateDescription> boilerplate_description, |
| 34 bool should_have_fast_elements) { | 24 bool use_fast_elements, bool has_null_prototype) { |
| 35 Handle<Context> context = isolate->native_context(); | 25 Handle<Context> native_context = isolate->native_context(); |
| 36 | 26 |
| 37 // In case we have function literals, we want the object to be in | 27 // In case we have function literals, we want the object to be in |
| 38 // slow properties mode for now. We don't go in the map cache because | 28 // slow properties mode for now. We don't go in the map cache because |
| 39 // maps with constant functions can't be shared if the functions are | 29 // maps with constant functions can't be shared if the functions are |
| 40 // not the same (which is the common case). | 30 // not the same (which is the common case). |
| 41 bool is_result_from_cache = false; | 31 int number_of_properties = boilerplate_description->backing_store_size(); |
| 42 Handle<Map> map = ComputeObjectLiteralMap(context, boilerplate_description, | 32 |
| 43 &is_result_from_cache); | 33 Handle<Map> map; |
| 34 // Ignoring number_of_properties for force dictionary map with __proto__:null. | |
| 35 if (has_null_prototype) { | |
| 36 map = | |
| 37 handle(native_context->slow_object_with_null_prototype_map(), isolate); | |
|
Toon Verwaest
2017/04/27 10:27:17
map = isolate->slow_object_with_null_prototype_map
| |
| 38 } else { | |
| 39 map = isolate->factory()->ObjectLiteralMapFromCache(native_context, | |
| 40 number_of_properties); | |
| 41 } | |
| 44 | 42 |
| 45 PretenureFlag pretenure_flag = | 43 PretenureFlag pretenure_flag = |
| 46 isolate->heap()->InNewSpace(*vector) ? NOT_TENURED : TENURED; | 44 isolate->heap()->InNewSpace(*vector) ? NOT_TENURED : TENURED; |
| 47 | 45 |
| 48 Handle<JSObject> boilerplate = | 46 Handle<JSObject> boilerplate; |
| 49 isolate->factory()->NewJSObjectFromMap(map, pretenure_flag); | 47 if (map->is_dictionary_map()) { |
| 48 boilerplate = isolate->factory()->NewSlowJSObjectFromMap( | |
| 49 map, number_of_properties, pretenure_flag); | |
| 50 } else { | |
| 51 boilerplate = isolate->factory()->NewJSObjectFromMap(map, pretenure_flag); | |
| 52 } | |
| 50 | 53 |
| 51 // Normalize the elements of the boilerplate to save space if needed. | 54 // Normalize the elements of the boilerplate to save space if needed. |
| 52 if (!should_have_fast_elements) JSObject::NormalizeElements(boilerplate); | 55 if (!use_fast_elements) JSObject::NormalizeElements(boilerplate); |
| 53 | 56 |
| 54 // Add the constant properties to the boilerplate. | 57 // Add the constant properties to the boilerplate. |
| 55 int length = boilerplate_description->size(); | 58 int length = boilerplate_description->size(); |
| 56 bool should_transform = | |
| 57 !is_result_from_cache && boilerplate->HasFastProperties(); | |
| 58 bool should_normalize = should_transform; | |
| 59 if (should_normalize) { | |
| 60 // TODO(verwaest): We might not want to ever normalize here. | |
| 61 JSObject::NormalizeProperties(boilerplate, KEEP_INOBJECT_PROPERTIES, length, | |
| 62 "Boilerplate"); | |
| 63 } | |
| 64 // TODO(verwaest): Support tracking representations in the boilerplate. | 59 // TODO(verwaest): Support tracking representations in the boilerplate. |
| 65 for (int index = 0; index < length; index++) { | 60 for (int index = 0; index < length; index++) { |
| 66 Handle<Object> key(boilerplate_description->name(index), isolate); | 61 Handle<Object> key(boilerplate_description->name(index), isolate); |
| 67 Handle<Object> value(boilerplate_description->value(index), isolate); | 62 Handle<Object> value(boilerplate_description->value(index), isolate); |
| 68 if (value->IsBoilerplateDescription()) { | 63 if (value->IsFixedArray()) { |
| 69 // The value contains the boilerplate properties of a | 64 // The value contains the CompileTimeValue with the boilerplate properties |
| 70 // simple object or array literal. | 65 // of a simple object or array literal. |
| 71 Handle<BoilerplateDescription> boilerplate = | 66 Handle<FixedArray> compile_time_value = Handle<FixedArray>::cast(value); |
| 72 Handle<BoilerplateDescription>::cast(value); | |
| 73 ASSIGN_RETURN_ON_EXCEPTION( | 67 ASSIGN_RETURN_ON_EXCEPTION( |
| 74 isolate, value, | 68 isolate, value, |
| 75 CreateLiteralBoilerplate(isolate, vector, boilerplate), Object); | 69 CreateLiteralBoilerplate(isolate, vector, compile_time_value), |
| 70 Object); | |
| 76 } | 71 } |
| 77 MaybeHandle<Object> maybe_result; | 72 MaybeHandle<Object> maybe_result; |
| 78 uint32_t element_index = 0; | 73 uint32_t element_index = 0; |
| 79 if (key->ToArrayIndex(&element_index)) { | 74 if (key->ToArrayIndex(&element_index)) { |
| 80 // Array index (uint32). | 75 // Array index (uint32). |
| 81 if (value->IsUninitialized(isolate)) { | 76 if (value->IsUninitialized(isolate)) { |
| 82 value = handle(Smi::kZero, isolate); | 77 value = handle(Smi::kZero, isolate); |
| 83 } | 78 } |
| 84 maybe_result = JSObject::SetOwnElementIgnoreAttributes( | 79 maybe_result = JSObject::SetOwnElementIgnoreAttributes( |
| 85 boilerplate, element_index, value, NONE); | 80 boilerplate, element_index, value, NONE); |
| 86 } else { | 81 } else { |
| 87 Handle<String> name = Handle<String>::cast(key); | 82 Handle<String> name = Handle<String>::cast(key); |
| 88 DCHECK(!name->AsArrayIndex(&element_index)); | 83 DCHECK(!name->AsArrayIndex(&element_index)); |
| 89 maybe_result = JSObject::SetOwnPropertyIgnoreAttributes(boilerplate, name, | 84 maybe_result = JSObject::SetOwnPropertyIgnoreAttributes(boilerplate, name, |
| 90 value, NONE); | 85 value, NONE); |
| 91 } | 86 } |
| 92 RETURN_ON_EXCEPTION(isolate, maybe_result, Object); | 87 RETURN_ON_EXCEPTION(isolate, maybe_result, Object); |
| 93 } | 88 } |
| 94 | 89 |
| 95 // Transform to fast properties if necessary. For object literals with | 90 if (map->is_dictionary_map() && !has_null_prototype) { |
| 96 // containing function literals we defer this operation until after all | 91 // TODO(cbruni): avoid making the boilerplate fast again, the clone stub |
| 97 // computed properties have been assigned so that we can generate | 92 // supports dict-mode objects directly. |
| 98 // constant function properties. | |
| 99 if (should_transform) { | |
| 100 JSObject::MigrateSlowToFast(boilerplate, | 93 JSObject::MigrateSlowToFast(boilerplate, |
| 101 boilerplate->map()->unused_property_fields(), | 94 boilerplate->map()->unused_property_fields(), |
| 102 "FastLiteral"); | 95 "FastLiteral"); |
| 103 } | 96 } |
| 104 return boilerplate; | 97 return boilerplate; |
| 105 } | 98 } |
| 106 | 99 |
| 107 static MaybeHandle<Object> CreateArrayLiteralBoilerplate( | 100 static MaybeHandle<Object> CreateArrayLiteralBoilerplate( |
| 108 Isolate* isolate, Handle<FeedbackVector> vector, | 101 Isolate* isolate, Handle<FeedbackVector> vector, |
| 109 Handle<ConstantElementsPair> elements) { | 102 Handle<ConstantElementsPair> elements) { |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 147 } | 140 } |
| 148 #endif | 141 #endif |
| 149 } else { | 142 } else { |
| 150 Handle<FixedArray> fixed_array_values = | 143 Handle<FixedArray> fixed_array_values = |
| 151 Handle<FixedArray>::cast(constant_elements_values); | 144 Handle<FixedArray>::cast(constant_elements_values); |
| 152 Handle<FixedArray> fixed_array_values_copy = | 145 Handle<FixedArray> fixed_array_values_copy = |
| 153 isolate->factory()->CopyFixedArray(fixed_array_values); | 146 isolate->factory()->CopyFixedArray(fixed_array_values); |
| 154 copied_elements_values = fixed_array_values_copy; | 147 copied_elements_values = fixed_array_values_copy; |
| 155 FOR_WITH_HANDLE_SCOPE( | 148 FOR_WITH_HANDLE_SCOPE( |
| 156 isolate, int, i = 0, i, i < fixed_array_values->length(), i++, { | 149 isolate, int, i = 0, i, i < fixed_array_values->length(), i++, { |
| 157 if (fixed_array_values->get(i)->IsBoilerplateDescription()) { | 150 if (fixed_array_values->get(i)->IsFixedArray()) { |
| 158 // The value contains the boilerplate properties of a | 151 // The value contains the CompileTimeValue with the |
| 159 // simple object or array literal. | 152 // boilerplate description of a simple object or |
| 160 Handle<BoilerplateDescription> boilerplate( | 153 // array literal. |
| 161 BoilerplateDescription::cast(fixed_array_values->get(i))); | 154 Handle<FixedArray> compile_time_value( |
| 155 FixedArray::cast(fixed_array_values->get(i))); | |
| 162 Handle<Object> result; | 156 Handle<Object> result; |
| 163 ASSIGN_RETURN_ON_EXCEPTION( | 157 ASSIGN_RETURN_ON_EXCEPTION( |
| 164 isolate, result, | 158 isolate, result, |
| 165 CreateLiteralBoilerplate(isolate, vector, boilerplate), | 159 CreateLiteralBoilerplate(isolate, vector, compile_time_value), |
| 166 Object); | 160 Object); |
| 167 fixed_array_values_copy->set(i, *result); | 161 fixed_array_values_copy->set(i, *result); |
| 168 } | 162 } |
| 169 }); | 163 }); |
| 170 } | 164 } |
| 171 } | 165 } |
| 172 object->set_elements(*copied_elements_values); | 166 object->set_elements(*copied_elements_values); |
| 173 object->set_length(Smi::FromInt(copied_elements_values->length())); | 167 object->set_length(Smi::FromInt(copied_elements_values->length())); |
| 174 | 168 |
| 175 JSObject::ValidateElements(object); | 169 JSObject::ValidateElements(object); |
| 176 return object; | 170 return object; |
| 177 } | 171 } |
| 178 | 172 |
| 179 MUST_USE_RESULT static MaybeHandle<Object> CreateLiteralBoilerplate( | 173 MUST_USE_RESULT static MaybeHandle<Object> CreateLiteralBoilerplate( |
| 180 Isolate* isolate, Handle<FeedbackVector> vector, | 174 Isolate* isolate, Handle<FeedbackVector> vector, |
| 181 Handle<BoilerplateDescription> array) { | 175 Handle<FixedArray> compile_time_value) { |
| 182 Handle<HeapObject> elements = CompileTimeValue::GetElements(array); | 176 Handle<HeapObject> elements = |
| 183 switch (CompileTimeValue::GetLiteralType(array)) { | 177 CompileTimeValue::GetElements(compile_time_value); |
| 184 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS: { | 178 int flags = CompileTimeValue::GetLiteralTypeFlags(compile_time_value); |
| 185 Handle<BoilerplateDescription> props = | 179 if (flags == CompileTimeValue::kArrayLiteralFlag) { |
| 186 Handle<BoilerplateDescription>::cast(elements); | 180 Handle<ConstantElementsPair> elems = |
| 187 return CreateObjectLiteralBoilerplate(isolate, vector, props, true); | 181 Handle<ConstantElementsPair>::cast(elements); |
| 188 } | 182 return CreateArrayLiteralBoilerplate(isolate, vector, elems); |
| 189 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS: { | |
| 190 Handle<BoilerplateDescription> props = | |
| 191 Handle<BoilerplateDescription>::cast(elements); | |
| 192 return CreateObjectLiteralBoilerplate(isolate, vector, props, false); | |
| 193 } | |
| 194 case CompileTimeValue::ARRAY_LITERAL: { | |
| 195 Handle<ConstantElementsPair> elems = | |
| 196 Handle<ConstantElementsPair>::cast(elements); | |
| 197 return CreateArrayLiteralBoilerplate(isolate, vector, elems); | |
| 198 } | |
| 199 default: | |
| 200 UNREACHABLE(); | |
| 201 return MaybeHandle<Object>(); | |
| 202 } | 183 } |
| 184 Handle<BoilerplateDescription> props = | |
| 185 Handle<BoilerplateDescription>::cast(elements); | |
| 186 bool use_fast_elements = (flags & ObjectLiteral::kFastElements) != 0; | |
| 187 bool has_null_prototype = (flags & ObjectLiteral::kHasNullPrototype) != 0; | |
| 188 return CreateObjectLiteralBoilerplate(isolate, vector, props, | |
| 189 use_fast_elements, has_null_prototype); | |
| 203 } | 190 } |
| 204 | 191 |
| 205 | 192 |
| 206 RUNTIME_FUNCTION(Runtime_CreateRegExpLiteral) { | 193 RUNTIME_FUNCTION(Runtime_CreateRegExpLiteral) { |
| 207 HandleScope scope(isolate); | 194 HandleScope scope(isolate); |
| 208 DCHECK_EQ(4, args.length()); | 195 DCHECK_EQ(4, args.length()); |
| 209 CONVERT_ARG_HANDLE_CHECKED(JSFunction, closure, 0); | 196 CONVERT_ARG_HANDLE_CHECKED(JSFunction, closure, 0); |
| 210 CONVERT_SMI_ARG_CHECKED(index, 1); | 197 CONVERT_SMI_ARG_CHECKED(index, 1); |
| 211 CONVERT_ARG_HANDLE_CHECKED(String, pattern, 2); | 198 CONVERT_ARG_HANDLE_CHECKED(String, pattern, 2); |
| 212 CONVERT_SMI_ARG_CHECKED(flags, 3); | 199 CONVERT_SMI_ARG_CHECKED(flags, 3); |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 226 | 213 |
| 227 RUNTIME_FUNCTION(Runtime_CreateObjectLiteral) { | 214 RUNTIME_FUNCTION(Runtime_CreateObjectLiteral) { |
| 228 HandleScope scope(isolate); | 215 HandleScope scope(isolate); |
| 229 DCHECK_EQ(4, args.length()); | 216 DCHECK_EQ(4, args.length()); |
| 230 CONVERT_ARG_HANDLE_CHECKED(JSFunction, closure, 0); | 217 CONVERT_ARG_HANDLE_CHECKED(JSFunction, closure, 0); |
| 231 CONVERT_SMI_ARG_CHECKED(literals_index, 1); | 218 CONVERT_SMI_ARG_CHECKED(literals_index, 1); |
| 232 CONVERT_ARG_HANDLE_CHECKED(BoilerplateDescription, boilerplate_description, | 219 CONVERT_ARG_HANDLE_CHECKED(BoilerplateDescription, boilerplate_description, |
| 233 2); | 220 2); |
| 234 CONVERT_SMI_ARG_CHECKED(flags, 3); | 221 CONVERT_SMI_ARG_CHECKED(flags, 3); |
| 235 Handle<FeedbackVector> vector(closure->feedback_vector(), isolate); | 222 Handle<FeedbackVector> vector(closure->feedback_vector(), isolate); |
| 236 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0; | 223 bool use_fast_elements = (flags & ObjectLiteral::kFastElements) != 0; |
| 237 bool enable_mementos = (flags & ObjectLiteral::kDisableMementos) == 0; | 224 bool enable_mementos = (flags & ObjectLiteral::kDisableMementos) == 0; |
| 225 bool has_null_prototype = (flags & ObjectLiteral::kHasNullPrototype) != 0; | |
| 238 | 226 |
| 239 FeedbackSlot literals_slot(FeedbackVector::ToSlot(literals_index)); | 227 FeedbackSlot literals_slot(FeedbackVector::ToSlot(literals_index)); |
| 240 CHECK(literals_slot.ToInt() < vector->slot_count()); | 228 CHECK(literals_slot.ToInt() < vector->slot_count()); |
| 241 | 229 |
| 242 // Check if boilerplate exists. If not, create it first. | 230 // Check if boilerplate exists. If not, create it first. |
| 243 Handle<Object> literal_site(vector->Get(literals_slot), isolate); | 231 Handle<Object> literal_site(vector->Get(literals_slot), isolate); |
| 244 Handle<AllocationSite> site; | 232 Handle<AllocationSite> site; |
| 245 Handle<JSObject> boilerplate; | 233 Handle<JSObject> boilerplate; |
| 246 if (literal_site->IsUndefined(isolate)) { | 234 if (literal_site->IsUndefined(isolate)) { |
| 247 Handle<Object> raw_boilerplate; | 235 Handle<Object> raw_boilerplate; |
| 248 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 236 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
| 249 isolate, raw_boilerplate, | 237 isolate, raw_boilerplate, |
| 250 CreateObjectLiteralBoilerplate(isolate, vector, boilerplate_description, | 238 CreateObjectLiteralBoilerplate(isolate, vector, boilerplate_description, |
| 251 should_have_fast_elements)); | 239 use_fast_elements, has_null_prototype)); |
| 252 boilerplate = Handle<JSObject>::cast(raw_boilerplate); | 240 boilerplate = Handle<JSObject>::cast(raw_boilerplate); |
| 253 | 241 |
| 254 AllocationSiteCreationContext creation_context(isolate); | 242 AllocationSiteCreationContext creation_context(isolate); |
| 255 site = creation_context.EnterNewScope(); | 243 site = creation_context.EnterNewScope(); |
| 256 RETURN_FAILURE_ON_EXCEPTION( | 244 RETURN_FAILURE_ON_EXCEPTION( |
| 257 isolate, JSObject::DeepWalk(boilerplate, &creation_context)); | 245 isolate, JSObject::DeepWalk(boilerplate, &creation_context)); |
| 258 creation_context.ExitScope(site, boilerplate); | 246 creation_context.ExitScope(site, boilerplate); |
| 259 | 247 |
| 260 // Update the functions literal and return the boilerplate. | 248 // Update the functions literal and return the boilerplate. |
| 261 vector->Set(literals_slot, *site); | 249 vector->Set(literals_slot, *site); |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 351 | 339 |
| 352 Handle<FeedbackVector> vector(closure->feedback_vector(), isolate); | 340 Handle<FeedbackVector> vector(closure->feedback_vector(), isolate); |
| 353 FeedbackSlot literals_slot(FeedbackVector::ToSlot(literals_index)); | 341 FeedbackSlot literals_slot(FeedbackVector::ToSlot(literals_index)); |
| 354 RETURN_RESULT_OR_FAILURE( | 342 RETURN_RESULT_OR_FAILURE( |
| 355 isolate, CreateArrayLiteralImpl(isolate, vector, literals_slot, elements, | 343 isolate, CreateArrayLiteralImpl(isolate, vector, literals_slot, elements, |
| 356 ArrayLiteral::kShallowElements)); | 344 ArrayLiteral::kShallowElements)); |
| 357 } | 345 } |
| 358 | 346 |
| 359 } // namespace internal | 347 } // namespace internal |
| 360 } // namespace v8 | 348 } // namespace v8 |
| OLD | NEW |