OLD | NEW |
(Empty) | |
| 1 // Copyright 2017 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "src/builtins/builtins-utils-gen.h" |
| 6 #include "src/builtins/builtins.h" |
| 7 #include "src/code-stub-assembler.h" |
| 8 |
| 9 namespace v8 { |
| 10 namespace internal { |
| 11 |
| 12 // ----------------------------------------------------------------------------- |
| 13 // ES6 section 19.1 Object Objects |
| 14 |
| 15 typedef compiler::Node Node; |
| 16 |
| 17 class ObjectBuiltinsAssembler : public CodeStubAssembler { |
| 18 public: |
| 19 explicit ObjectBuiltinsAssembler(compiler::CodeAssemblerState* state) |
| 20 : CodeStubAssembler(state) {} |
| 21 |
| 22 protected: |
| 23 void IsString(Node* object, Label* if_string, Label* if_notstring); |
| 24 void ReturnToStringFormat(Node* context, Node* string); |
| 25 }; |
| 26 |
| 27 void ObjectBuiltinsAssembler::IsString(Node* object, Label* if_string, |
| 28 Label* if_notstring) { |
| 29 Label if_notsmi(this); |
| 30 Branch(TaggedIsSmi(object), if_notstring, &if_notsmi); |
| 31 |
| 32 Bind(&if_notsmi); |
| 33 { |
| 34 Node* instance_type = LoadInstanceType(object); |
| 35 |
| 36 Branch(IsStringInstanceType(instance_type), if_string, if_notstring); |
| 37 } |
| 38 } |
| 39 |
| 40 void ObjectBuiltinsAssembler::ReturnToStringFormat(Node* context, |
| 41 Node* string) { |
| 42 Node* lhs = HeapConstant(factory()->NewStringFromStaticChars("[object ")); |
| 43 Node* rhs = HeapConstant(factory()->NewStringFromStaticChars("]")); |
| 44 |
| 45 Callable callable = |
| 46 CodeFactory::StringAdd(isolate(), STRING_ADD_CHECK_NONE, NOT_TENURED); |
| 47 |
| 48 Return(CallStub(callable, context, CallStub(callable, context, lhs, string), |
| 49 rhs)); |
| 50 } |
| 51 |
| 52 TF_BUILTIN(ObjectHasOwnProperty, ObjectBuiltinsAssembler) { |
| 53 Node* object = Parameter(0); |
| 54 Node* key = Parameter(1); |
| 55 Node* context = Parameter(4); |
| 56 |
| 57 Label call_runtime(this), return_true(this), return_false(this); |
| 58 |
| 59 // Smi receivers do not have own properties. |
| 60 Label if_objectisnotsmi(this); |
| 61 Branch(TaggedIsSmi(object), &return_false, &if_objectisnotsmi); |
| 62 Bind(&if_objectisnotsmi); |
| 63 |
| 64 Node* map = LoadMap(object); |
| 65 Node* instance_type = LoadMapInstanceType(map); |
| 66 |
| 67 { |
| 68 Variable var_index(this, MachineType::PointerRepresentation()); |
| 69 Variable var_unique(this, MachineRepresentation::kTagged); |
| 70 |
| 71 Label keyisindex(this), if_iskeyunique(this); |
| 72 TryToName(key, &keyisindex, &var_index, &if_iskeyunique, &var_unique, |
| 73 &call_runtime); |
| 74 |
| 75 Bind(&if_iskeyunique); |
| 76 TryHasOwnProperty(object, map, instance_type, var_unique.value(), |
| 77 &return_true, &return_false, &call_runtime); |
| 78 |
| 79 Bind(&keyisindex); |
| 80 // Handle negative keys in the runtime. |
| 81 GotoIf(IntPtrLessThan(var_index.value(), IntPtrConstant(0)), &call_runtime); |
| 82 TryLookupElement(object, map, instance_type, var_index.value(), |
| 83 &return_true, &return_false, &call_runtime); |
| 84 } |
| 85 Bind(&return_true); |
| 86 Return(BooleanConstant(true)); |
| 87 |
| 88 Bind(&return_false); |
| 89 Return(BooleanConstant(false)); |
| 90 |
| 91 Bind(&call_runtime); |
| 92 Return(CallRuntime(Runtime::kObjectHasOwnProperty, context, object, key)); |
| 93 } |
| 94 |
| 95 // ES6 section 19.1.3.6 Object.prototype.toString |
| 96 TF_BUILTIN(ObjectProtoToString, ObjectBuiltinsAssembler) { |
| 97 Label return_undefined(this, Label::kDeferred), |
| 98 return_null(this, Label::kDeferred), |
| 99 return_arguments(this, Label::kDeferred), return_array(this), |
| 100 return_api(this, Label::kDeferred), return_object(this), |
| 101 return_regexp(this), return_function(this), return_error(this), |
| 102 return_date(this), return_jsvalue(this), |
| 103 return_jsproxy(this, Label::kDeferred); |
| 104 |
| 105 Label if_isproxy(this, Label::kDeferred); |
| 106 |
| 107 Label checkstringtag(this); |
| 108 Label if_tostringtag(this), if_notostringtag(this); |
| 109 |
| 110 Node* receiver = Parameter(0); |
| 111 Node* context = Parameter(3); |
| 112 |
| 113 GotoIf(WordEqual(receiver, UndefinedConstant()), &return_undefined); |
| 114 |
| 115 GotoIf(WordEqual(receiver, NullConstant()), &return_null); |
| 116 |
| 117 Callable to_object = CodeFactory::ToObject(isolate()); |
| 118 receiver = CallStub(to_object, context, receiver); |
| 119 |
| 120 Node* receiver_instance_type = LoadInstanceType(receiver); |
| 121 |
| 122 // for proxies, check IsArray before getting @@toStringTag |
| 123 Variable var_proxy_is_array(this, MachineRepresentation::kTagged); |
| 124 var_proxy_is_array.Bind(BooleanConstant(false)); |
| 125 |
| 126 Branch(Word32Equal(receiver_instance_type, Int32Constant(JS_PROXY_TYPE)), |
| 127 &if_isproxy, &checkstringtag); |
| 128 |
| 129 Bind(&if_isproxy); |
| 130 { |
| 131 // This can throw |
| 132 var_proxy_is_array.Bind( |
| 133 CallRuntime(Runtime::kArrayIsArray, context, receiver)); |
| 134 Goto(&checkstringtag); |
| 135 } |
| 136 |
| 137 Bind(&checkstringtag); |
| 138 { |
| 139 Node* to_string_tag_symbol = |
| 140 HeapConstant(isolate()->factory()->to_string_tag_symbol()); |
| 141 |
| 142 GetPropertyStub stub(isolate()); |
| 143 Callable get_property = |
| 144 Callable(stub.GetCode(), stub.GetCallInterfaceDescriptor()); |
| 145 Node* to_string_tag_value = |
| 146 CallStub(get_property, context, receiver, to_string_tag_symbol); |
| 147 |
| 148 IsString(to_string_tag_value, &if_tostringtag, &if_notostringtag); |
| 149 |
| 150 Bind(&if_tostringtag); |
| 151 ReturnToStringFormat(context, to_string_tag_value); |
| 152 } |
| 153 Bind(&if_notostringtag); |
| 154 { |
| 155 size_t const kNumCases = 11; |
| 156 Label* case_labels[kNumCases]; |
| 157 int32_t case_values[kNumCases]; |
| 158 case_labels[0] = &return_api; |
| 159 case_values[0] = JS_API_OBJECT_TYPE; |
| 160 case_labels[1] = &return_api; |
| 161 case_values[1] = JS_SPECIAL_API_OBJECT_TYPE; |
| 162 case_labels[2] = &return_arguments; |
| 163 case_values[2] = JS_ARGUMENTS_TYPE; |
| 164 case_labels[3] = &return_array; |
| 165 case_values[3] = JS_ARRAY_TYPE; |
| 166 case_labels[4] = &return_function; |
| 167 case_values[4] = JS_BOUND_FUNCTION_TYPE; |
| 168 case_labels[5] = &return_function; |
| 169 case_values[5] = JS_FUNCTION_TYPE; |
| 170 case_labels[6] = &return_error; |
| 171 case_values[6] = JS_ERROR_TYPE; |
| 172 case_labels[7] = &return_date; |
| 173 case_values[7] = JS_DATE_TYPE; |
| 174 case_labels[8] = &return_regexp; |
| 175 case_values[8] = JS_REGEXP_TYPE; |
| 176 case_labels[9] = &return_jsvalue; |
| 177 case_values[9] = JS_VALUE_TYPE; |
| 178 case_labels[10] = &return_jsproxy; |
| 179 case_values[10] = JS_PROXY_TYPE; |
| 180 |
| 181 Switch(receiver_instance_type, &return_object, case_values, case_labels, |
| 182 arraysize(case_values)); |
| 183 |
| 184 Bind(&return_undefined); |
| 185 Return(HeapConstant(isolate()->factory()->undefined_to_string())); |
| 186 |
| 187 Bind(&return_null); |
| 188 Return(HeapConstant(isolate()->factory()->null_to_string())); |
| 189 |
| 190 Bind(&return_arguments); |
| 191 Return(HeapConstant(isolate()->factory()->arguments_to_string())); |
| 192 |
| 193 Bind(&return_array); |
| 194 Return(HeapConstant(isolate()->factory()->array_to_string())); |
| 195 |
| 196 Bind(&return_function); |
| 197 Return(HeapConstant(isolate()->factory()->function_to_string())); |
| 198 |
| 199 Bind(&return_error); |
| 200 Return(HeapConstant(isolate()->factory()->error_to_string())); |
| 201 |
| 202 Bind(&return_date); |
| 203 Return(HeapConstant(isolate()->factory()->date_to_string())); |
| 204 |
| 205 Bind(&return_regexp); |
| 206 Return(HeapConstant(isolate()->factory()->regexp_to_string())); |
| 207 |
| 208 Bind(&return_api); |
| 209 { |
| 210 Node* class_name = CallRuntime(Runtime::kClassOf, context, receiver); |
| 211 ReturnToStringFormat(context, class_name); |
| 212 } |
| 213 |
| 214 Bind(&return_jsvalue); |
| 215 { |
| 216 Label return_boolean(this), return_number(this), return_string(this); |
| 217 |
| 218 Node* value = LoadJSValueValue(receiver); |
| 219 GotoIf(TaggedIsSmi(value), &return_number); |
| 220 Node* instance_type = LoadInstanceType(value); |
| 221 |
| 222 GotoIf(IsStringInstanceType(instance_type), &return_string); |
| 223 GotoIf(Word32Equal(instance_type, Int32Constant(HEAP_NUMBER_TYPE)), |
| 224 &return_number); |
| 225 GotoIf(Word32Equal(instance_type, Int32Constant(ODDBALL_TYPE)), |
| 226 &return_boolean); |
| 227 |
| 228 CSA_ASSERT(this, Word32Equal(instance_type, Int32Constant(SYMBOL_TYPE))); |
| 229 Goto(&return_object); |
| 230 |
| 231 Bind(&return_string); |
| 232 Return(HeapConstant(isolate()->factory()->string_to_string())); |
| 233 |
| 234 Bind(&return_number); |
| 235 Return(HeapConstant(isolate()->factory()->number_to_string())); |
| 236 |
| 237 Bind(&return_boolean); |
| 238 Return(HeapConstant(isolate()->factory()->boolean_to_string())); |
| 239 } |
| 240 |
| 241 Bind(&return_jsproxy); |
| 242 { |
| 243 GotoIf(WordEqual(var_proxy_is_array.value(), BooleanConstant(true)), |
| 244 &return_array); |
| 245 |
| 246 Node* map = LoadMap(receiver); |
| 247 |
| 248 // Return object if the proxy {receiver} is not callable. |
| 249 Branch(IsCallableMap(map), &return_function, &return_object); |
| 250 } |
| 251 |
| 252 // Default |
| 253 Bind(&return_object); |
| 254 Return(HeapConstant(isolate()->factory()->object_to_string())); |
| 255 } |
| 256 } |
| 257 |
| 258 // ES6 19.3.7 Object.prototype.valueOf |
| 259 TF_BUILTIN(ObjectPrototypeValueOf, CodeStubAssembler) { |
| 260 Node* receiver = Parameter(0); |
| 261 Node* context = Parameter(3); |
| 262 |
| 263 Callable to_object = CodeFactory::ToObject(isolate()); |
| 264 receiver = CallStub(to_object, context, receiver); |
| 265 |
| 266 Return(receiver); |
| 267 } |
| 268 |
| 269 TF_BUILTIN(ObjectCreate, ObjectBuiltinsAssembler) { |
| 270 Node* prototype = Parameter(1); |
| 271 Node* properties = Parameter(2); |
| 272 Node* context = Parameter(3 + 2); |
| 273 |
| 274 Label call_runtime(this, Label::kDeferred), prototype_valid(this), |
| 275 no_properties(this); |
| 276 { |
| 277 Comment("Argument 1 check: prototype"); |
| 278 GotoIf(WordEqual(prototype, NullConstant()), &prototype_valid); |
| 279 BranchIfJSReceiver(prototype, &prototype_valid, &call_runtime); |
| 280 } |
| 281 |
| 282 Bind(&prototype_valid); |
| 283 { |
| 284 Comment("Argument 2 check: properties"); |
| 285 // Check that we have a simple object |
| 286 GotoIf(TaggedIsSmi(properties), &call_runtime); |
| 287 // Undefined implies no properties. |
| 288 GotoIf(WordEqual(properties, UndefinedConstant()), &no_properties); |
| 289 Node* properties_map = LoadMap(properties); |
| 290 GotoIf(IsSpecialReceiverMap(properties_map), &call_runtime); |
| 291 // Stay on the fast path only if there are no elements. |
| 292 GotoIfNot(WordEqual(LoadElements(properties), |
| 293 LoadRoot(Heap::kEmptyFixedArrayRootIndex)), |
| 294 &call_runtime); |
| 295 // Handle dictionary objects or fast objects with properties in runtime. |
| 296 Node* bit_field3 = LoadMapBitField3(properties_map); |
| 297 GotoIf(IsSetWord32<Map::DictionaryMap>(bit_field3), &call_runtime); |
| 298 Branch(IsSetWord32<Map::NumberOfOwnDescriptorsBits>(bit_field3), |
| 299 &call_runtime, &no_properties); |
| 300 } |
| 301 |
| 302 // Create a new object with the given prototype. |
| 303 Bind(&no_properties); |
| 304 { |
| 305 Variable map(this, MachineRepresentation::kTagged); |
| 306 Variable properties(this, MachineRepresentation::kTagged); |
| 307 Label non_null_proto(this), instantiate_map(this), good(this); |
| 308 |
| 309 Branch(WordEqual(prototype, NullConstant()), &good, &non_null_proto); |
| 310 |
| 311 Bind(&good); |
| 312 { |
| 313 map.Bind(LoadContextElement( |
| 314 context, Context::SLOW_OBJECT_WITH_NULL_PROTOTYPE_MAP)); |
| 315 properties.Bind(AllocateNameDictionary(NameDictionary::kInitialCapacity)); |
| 316 Goto(&instantiate_map); |
| 317 } |
| 318 |
| 319 Bind(&non_null_proto); |
| 320 { |
| 321 properties.Bind(EmptyFixedArrayConstant()); |
| 322 Node* object_function = |
| 323 LoadContextElement(context, Context::OBJECT_FUNCTION_INDEX); |
| 324 Node* object_function_map = LoadObjectField( |
| 325 object_function, JSFunction::kPrototypeOrInitialMapOffset); |
| 326 map.Bind(object_function_map); |
| 327 GotoIf(WordEqual(prototype, LoadMapPrototype(map.value())), |
| 328 &instantiate_map); |
| 329 // Try loading the prototype info. |
| 330 Node* prototype_info = |
| 331 LoadMapPrototypeInfo(LoadMap(prototype), &call_runtime); |
| 332 Comment("Load ObjectCreateMap from PrototypeInfo"); |
| 333 Node* weak_cell = |
| 334 LoadObjectField(prototype_info, PrototypeInfo::kObjectCreateMap); |
| 335 GotoIf(WordEqual(weak_cell, UndefinedConstant()), &call_runtime); |
| 336 map.Bind(LoadWeakCellValue(weak_cell, &call_runtime)); |
| 337 Goto(&instantiate_map); |
| 338 } |
| 339 |
| 340 Bind(&instantiate_map); |
| 341 { |
| 342 Node* instance = AllocateJSObjectFromMap(map.value(), properties.value()); |
| 343 Return(instance); |
| 344 } |
| 345 } |
| 346 |
| 347 Bind(&call_runtime); |
| 348 { |
| 349 Return(CallRuntime(Runtime::kObjectCreate, context, prototype, properties)); |
| 350 } |
| 351 } |
| 352 |
| 353 TF_BUILTIN(CreateIterResultObject, ObjectBuiltinsAssembler) { |
| 354 typedef CreateIterResultObjectDescriptor Descriptor; |
| 355 |
| 356 Node* const value = Parameter(Descriptor::kValue); |
| 357 Node* const done = Parameter(Descriptor::kDone); |
| 358 Node* const context = Parameter(Descriptor::kContext); |
| 359 |
| 360 Node* const native_context = LoadNativeContext(context); |
| 361 Node* const map = |
| 362 LoadContextElement(native_context, Context::ITERATOR_RESULT_MAP_INDEX); |
| 363 |
| 364 Node* const result = AllocateJSObjectFromMap(map); |
| 365 |
| 366 StoreObjectFieldNoWriteBarrier(result, JSIteratorResult::kValueOffset, value); |
| 367 StoreObjectFieldNoWriteBarrier(result, JSIteratorResult::kDoneOffset, done); |
| 368 |
| 369 Return(result); |
| 370 } |
| 371 |
| 372 TF_BUILTIN(HasProperty, ObjectBuiltinsAssembler) { |
| 373 typedef HasPropertyDescriptor Descriptor; |
| 374 |
| 375 Node* key = Parameter(Descriptor::kKey); |
| 376 Node* object = Parameter(Descriptor::kObject); |
| 377 Node* context = Parameter(Descriptor::kContext); |
| 378 |
| 379 Return(HasProperty(object, key, context, Runtime::kHasProperty)); |
| 380 } |
| 381 |
| 382 TF_BUILTIN(InstanceOf, ObjectBuiltinsAssembler) { |
| 383 typedef CompareDescriptor Descriptor; |
| 384 |
| 385 Node* object = Parameter(Descriptor::kLeft); |
| 386 Node* callable = Parameter(Descriptor::kRight); |
| 387 Node* context = Parameter(Descriptor::kContext); |
| 388 |
| 389 Return(InstanceOf(object, callable, context)); |
| 390 } |
| 391 |
| 392 // ES6 section 7.3.19 OrdinaryHasInstance ( C, O ) |
| 393 TF_BUILTIN(OrdinaryHasInstance, ObjectBuiltinsAssembler) { |
| 394 typedef CompareDescriptor Descriptor; |
| 395 |
| 396 Node* constructor = Parameter(Descriptor::kLeft); |
| 397 Node* object = Parameter(Descriptor::kRight); |
| 398 Node* context = Parameter(Descriptor::kContext); |
| 399 |
| 400 Return(OrdinaryHasInstance(context, constructor, object)); |
| 401 } |
| 402 |
| 403 TF_BUILTIN(GetSuperConstructor, ObjectBuiltinsAssembler) { |
| 404 typedef TypeofDescriptor Descriptor; |
| 405 |
| 406 Node* object = Parameter(Descriptor::kObject); |
| 407 Node* context = Parameter(Descriptor::kContext); |
| 408 |
| 409 Return(GetSuperConstructor(object, context)); |
| 410 } |
| 411 |
| 412 } // namespace internal |
| 413 } // namespace v8 |
OLD | NEW |