OLD | NEW |
1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 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/builtins/builtins-utils.h" | 5 #include "src/builtins/builtins-utils.h" |
6 #include "src/builtins/builtins.h" | 6 #include "src/builtins/builtins.h" |
7 #include "src/code-factory.h" | 7 #include "src/code-factory.h" |
8 #include "src/code-stub-assembler.h" | 8 #include "src/code-stub-assembler.h" |
9 #include "src/counters.h" | 9 #include "src/counters.h" |
10 #include "src/keys.h" | 10 #include "src/keys.h" |
11 #include "src/lookup.h" | 11 #include "src/lookup.h" |
12 #include "src/objects-inl.h" | 12 #include "src/objects-inl.h" |
13 #include "src/property-descriptor.h" | 13 #include "src/property-descriptor.h" |
14 | 14 |
15 namespace v8 { | 15 namespace v8 { |
16 namespace internal { | 16 namespace internal { |
17 | 17 |
18 typedef compiler::Node Node; | |
19 | |
20 class ObjectBuiltinsAssembler : public CodeStubAssembler { | |
21 public: | |
22 explicit ObjectBuiltinsAssembler(compiler::CodeAssemblerState* state) | |
23 : CodeStubAssembler(state) {} | |
24 | |
25 protected: | |
26 void IsString(Node* object, Label* if_string, Label* if_notstring); | |
27 void ReturnToStringFormat(Node* context, Node* string); | |
28 }; | |
29 | |
30 void ObjectBuiltinsAssembler::IsString(Node* object, Label* if_string, | |
31 Label* if_notstring) { | |
32 Label if_notsmi(this); | |
33 Branch(TaggedIsSmi(object), if_notstring, &if_notsmi); | |
34 | |
35 Bind(&if_notsmi); | |
36 { | |
37 Node* instance_type = LoadInstanceType(object); | |
38 | |
39 Branch(IsStringInstanceType(instance_type), if_string, if_notstring); | |
40 } | |
41 } | |
42 | |
43 void ObjectBuiltinsAssembler::ReturnToStringFormat(Node* context, | |
44 Node* string) { | |
45 Node* lhs = HeapConstant(factory()->NewStringFromStaticChars("[object ")); | |
46 Node* rhs = HeapConstant(factory()->NewStringFromStaticChars("]")); | |
47 | |
48 Callable callable = | |
49 CodeFactory::StringAdd(isolate(), STRING_ADD_CHECK_NONE, NOT_TENURED); | |
50 | |
51 Return(CallStub(callable, context, CallStub(callable, context, lhs, string), | |
52 rhs)); | |
53 } | |
54 | |
55 // ----------------------------------------------------------------------------- | 18 // ----------------------------------------------------------------------------- |
56 // ES6 section 19.1 Object Objects | 19 // ES6 section 19.1 Object Objects |
57 | 20 |
58 TF_BUILTIN(ObjectHasOwnProperty, ObjectBuiltinsAssembler) { | |
59 Node* object = Parameter(0); | |
60 Node* key = Parameter(1); | |
61 Node* context = Parameter(4); | |
62 | |
63 Label call_runtime(this), return_true(this), return_false(this); | |
64 | |
65 // Smi receivers do not have own properties. | |
66 Label if_objectisnotsmi(this); | |
67 Branch(TaggedIsSmi(object), &return_false, &if_objectisnotsmi); | |
68 Bind(&if_objectisnotsmi); | |
69 | |
70 Node* map = LoadMap(object); | |
71 Node* instance_type = LoadMapInstanceType(map); | |
72 | |
73 { | |
74 Variable var_index(this, MachineType::PointerRepresentation()); | |
75 Variable var_unique(this, MachineRepresentation::kTagged); | |
76 | |
77 Label keyisindex(this), if_iskeyunique(this); | |
78 TryToName(key, &keyisindex, &var_index, &if_iskeyunique, &var_unique, | |
79 &call_runtime); | |
80 | |
81 Bind(&if_iskeyunique); | |
82 TryHasOwnProperty(object, map, instance_type, var_unique.value(), | |
83 &return_true, &return_false, &call_runtime); | |
84 | |
85 Bind(&keyisindex); | |
86 // Handle negative keys in the runtime. | |
87 GotoIf(IntPtrLessThan(var_index.value(), IntPtrConstant(0)), &call_runtime); | |
88 TryLookupElement(object, map, instance_type, var_index.value(), | |
89 &return_true, &return_false, &call_runtime); | |
90 } | |
91 Bind(&return_true); | |
92 Return(BooleanConstant(true)); | |
93 | |
94 Bind(&return_false); | |
95 Return(BooleanConstant(false)); | |
96 | |
97 Bind(&call_runtime); | |
98 Return(CallRuntime(Runtime::kObjectHasOwnProperty, context, object, key)); | |
99 } | |
100 | |
101 // ES6 19.1.2.1 Object.assign | 21 // ES6 19.1.2.1 Object.assign |
102 BUILTIN(ObjectAssign) { | 22 BUILTIN(ObjectAssign) { |
103 HandleScope scope(isolate); | 23 HandleScope scope(isolate); |
104 Handle<Object> target = args.atOrUndefined(isolate, 1); | 24 Handle<Object> target = args.atOrUndefined(isolate, 1); |
105 | 25 |
106 // 1. Let to be ? ToObject(target). | 26 // 1. Let to be ? ToObject(target). |
107 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, target, | 27 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, target, |
108 Object::ToObject(isolate, target)); | 28 Object::ToObject(isolate, target)); |
109 Handle<JSReceiver> to = Handle<JSReceiver>::cast(target); | 29 Handle<JSReceiver> to = Handle<JSReceiver>::cast(target); |
110 // 2. If only one argument was passed, return to. | 30 // 2. If only one argument was passed, return to. |
(...skipping 19 matching lines...) Expand all Loading... |
130 isolate, name, Object::ToName(isolate, args.atOrUndefined(isolate, 1))); | 50 isolate, name, Object::ToName(isolate, args.atOrUndefined(isolate, 1))); |
131 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | 51 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( |
132 isolate, object, JSReceiver::ToObject(isolate, args.receiver())); | 52 isolate, object, JSReceiver::ToObject(isolate, args.receiver())); |
133 Maybe<PropertyAttributes> maybe = | 53 Maybe<PropertyAttributes> maybe = |
134 JSReceiver::GetOwnPropertyAttributes(object, name); | 54 JSReceiver::GetOwnPropertyAttributes(object, name); |
135 if (!maybe.IsJust()) return isolate->heap()->exception(); | 55 if (!maybe.IsJust()) return isolate->heap()->exception(); |
136 if (maybe.FromJust() == ABSENT) return isolate->heap()->false_value(); | 56 if (maybe.FromJust() == ABSENT) return isolate->heap()->false_value(); |
137 return isolate->heap()->ToBoolean((maybe.FromJust() & DONT_ENUM) == 0); | 57 return isolate->heap()->ToBoolean((maybe.FromJust() & DONT_ENUM) == 0); |
138 } | 58 } |
139 | 59 |
140 // ES6 section 19.1.3.6 Object.prototype.toString | |
141 TF_BUILTIN(ObjectProtoToString, ObjectBuiltinsAssembler) { | |
142 Label return_undefined(this, Label::kDeferred), | |
143 return_null(this, Label::kDeferred), | |
144 return_arguments(this, Label::kDeferred), return_array(this), | |
145 return_api(this, Label::kDeferred), return_object(this), | |
146 return_regexp(this), return_function(this), return_error(this), | |
147 return_date(this), return_jsvalue(this), | |
148 return_jsproxy(this, Label::kDeferred); | |
149 | |
150 Label if_isproxy(this, Label::kDeferred); | |
151 | |
152 Label checkstringtag(this); | |
153 Label if_tostringtag(this), if_notostringtag(this); | |
154 | |
155 Node* receiver = Parameter(0); | |
156 Node* context = Parameter(3); | |
157 | |
158 GotoIf(WordEqual(receiver, UndefinedConstant()), &return_undefined); | |
159 | |
160 GotoIf(WordEqual(receiver, NullConstant()), &return_null); | |
161 | |
162 Callable to_object = CodeFactory::ToObject(isolate()); | |
163 receiver = CallStub(to_object, context, receiver); | |
164 | |
165 Node* receiver_instance_type = LoadInstanceType(receiver); | |
166 | |
167 // for proxies, check IsArray before getting @@toStringTag | |
168 Variable var_proxy_is_array(this, MachineRepresentation::kTagged); | |
169 var_proxy_is_array.Bind(BooleanConstant(false)); | |
170 | |
171 Branch(Word32Equal(receiver_instance_type, Int32Constant(JS_PROXY_TYPE)), | |
172 &if_isproxy, &checkstringtag); | |
173 | |
174 Bind(&if_isproxy); | |
175 { | |
176 // This can throw | |
177 var_proxy_is_array.Bind( | |
178 CallRuntime(Runtime::kArrayIsArray, context, receiver)); | |
179 Goto(&checkstringtag); | |
180 } | |
181 | |
182 Bind(&checkstringtag); | |
183 { | |
184 Node* to_string_tag_symbol = | |
185 HeapConstant(isolate()->factory()->to_string_tag_symbol()); | |
186 | |
187 GetPropertyStub stub(isolate()); | |
188 Callable get_property = | |
189 Callable(stub.GetCode(), stub.GetCallInterfaceDescriptor()); | |
190 Node* to_string_tag_value = | |
191 CallStub(get_property, context, receiver, to_string_tag_symbol); | |
192 | |
193 IsString(to_string_tag_value, &if_tostringtag, &if_notostringtag); | |
194 | |
195 Bind(&if_tostringtag); | |
196 ReturnToStringFormat(context, to_string_tag_value); | |
197 } | |
198 Bind(&if_notostringtag); | |
199 { | |
200 size_t const kNumCases = 11; | |
201 Label* case_labels[kNumCases]; | |
202 int32_t case_values[kNumCases]; | |
203 case_labels[0] = &return_api; | |
204 case_values[0] = JS_API_OBJECT_TYPE; | |
205 case_labels[1] = &return_api; | |
206 case_values[1] = JS_SPECIAL_API_OBJECT_TYPE; | |
207 case_labels[2] = &return_arguments; | |
208 case_values[2] = JS_ARGUMENTS_TYPE; | |
209 case_labels[3] = &return_array; | |
210 case_values[3] = JS_ARRAY_TYPE; | |
211 case_labels[4] = &return_function; | |
212 case_values[4] = JS_BOUND_FUNCTION_TYPE; | |
213 case_labels[5] = &return_function; | |
214 case_values[5] = JS_FUNCTION_TYPE; | |
215 case_labels[6] = &return_error; | |
216 case_values[6] = JS_ERROR_TYPE; | |
217 case_labels[7] = &return_date; | |
218 case_values[7] = JS_DATE_TYPE; | |
219 case_labels[8] = &return_regexp; | |
220 case_values[8] = JS_REGEXP_TYPE; | |
221 case_labels[9] = &return_jsvalue; | |
222 case_values[9] = JS_VALUE_TYPE; | |
223 case_labels[10] = &return_jsproxy; | |
224 case_values[10] = JS_PROXY_TYPE; | |
225 | |
226 Switch(receiver_instance_type, &return_object, case_values, case_labels, | |
227 arraysize(case_values)); | |
228 | |
229 Bind(&return_undefined); | |
230 Return(HeapConstant(isolate()->factory()->undefined_to_string())); | |
231 | |
232 Bind(&return_null); | |
233 Return(HeapConstant(isolate()->factory()->null_to_string())); | |
234 | |
235 Bind(&return_arguments); | |
236 Return(HeapConstant(isolate()->factory()->arguments_to_string())); | |
237 | |
238 Bind(&return_array); | |
239 Return(HeapConstant(isolate()->factory()->array_to_string())); | |
240 | |
241 Bind(&return_function); | |
242 Return(HeapConstant(isolate()->factory()->function_to_string())); | |
243 | |
244 Bind(&return_error); | |
245 Return(HeapConstant(isolate()->factory()->error_to_string())); | |
246 | |
247 Bind(&return_date); | |
248 Return(HeapConstant(isolate()->factory()->date_to_string())); | |
249 | |
250 Bind(&return_regexp); | |
251 Return(HeapConstant(isolate()->factory()->regexp_to_string())); | |
252 | |
253 Bind(&return_api); | |
254 { | |
255 Node* class_name = CallRuntime(Runtime::kClassOf, context, receiver); | |
256 ReturnToStringFormat(context, class_name); | |
257 } | |
258 | |
259 Bind(&return_jsvalue); | |
260 { | |
261 Label return_boolean(this), return_number(this), return_string(this); | |
262 | |
263 Node* value = LoadJSValueValue(receiver); | |
264 GotoIf(TaggedIsSmi(value), &return_number); | |
265 Node* instance_type = LoadInstanceType(value); | |
266 | |
267 GotoIf(IsStringInstanceType(instance_type), &return_string); | |
268 GotoIf(Word32Equal(instance_type, Int32Constant(HEAP_NUMBER_TYPE)), | |
269 &return_number); | |
270 GotoIf(Word32Equal(instance_type, Int32Constant(ODDBALL_TYPE)), | |
271 &return_boolean); | |
272 | |
273 CSA_ASSERT(this, Word32Equal(instance_type, Int32Constant(SYMBOL_TYPE))); | |
274 Goto(&return_object); | |
275 | |
276 Bind(&return_string); | |
277 Return(HeapConstant(isolate()->factory()->string_to_string())); | |
278 | |
279 Bind(&return_number); | |
280 Return(HeapConstant(isolate()->factory()->number_to_string())); | |
281 | |
282 Bind(&return_boolean); | |
283 Return(HeapConstant(isolate()->factory()->boolean_to_string())); | |
284 } | |
285 | |
286 Bind(&return_jsproxy); | |
287 { | |
288 GotoIf(WordEqual(var_proxy_is_array.value(), BooleanConstant(true)), | |
289 &return_array); | |
290 | |
291 Node* map = LoadMap(receiver); | |
292 | |
293 // Return object if the proxy {receiver} is not callable. | |
294 Branch(IsCallableMap(map), &return_function, &return_object); | |
295 } | |
296 | |
297 // Default | |
298 Bind(&return_object); | |
299 Return(HeapConstant(isolate()->factory()->object_to_string())); | |
300 } | |
301 } | |
302 | |
303 // ES6 19.3.7 Object.prototype.valueOf | |
304 TF_BUILTIN(ObjectPrototypeValueOf, CodeStubAssembler) { | |
305 Node* receiver = Parameter(0); | |
306 Node* context = Parameter(3); | |
307 | |
308 Callable to_object = CodeFactory::ToObject(isolate()); | |
309 receiver = CallStub(to_object, context, receiver); | |
310 | |
311 Return(receiver); | |
312 } | |
313 | |
314 TF_BUILTIN(ObjectCreate, ObjectBuiltinsAssembler) { | |
315 Node* prototype = Parameter(1); | |
316 Node* properties = Parameter(2); | |
317 Node* context = Parameter(3 + 2); | |
318 | |
319 Label call_runtime(this, Label::kDeferred), prototype_valid(this), | |
320 no_properties(this); | |
321 { | |
322 Comment("Argument 1 check: prototype"); | |
323 GotoIf(WordEqual(prototype, NullConstant()), &prototype_valid); | |
324 BranchIfJSReceiver(prototype, &prototype_valid, &call_runtime); | |
325 } | |
326 | |
327 Bind(&prototype_valid); | |
328 { | |
329 Comment("Argument 2 check: properties"); | |
330 // Check that we have a simple object | |
331 GotoIf(TaggedIsSmi(properties), &call_runtime); | |
332 // Undefined implies no properties. | |
333 GotoIf(WordEqual(properties, UndefinedConstant()), &no_properties); | |
334 Node* properties_map = LoadMap(properties); | |
335 GotoIf(IsSpecialReceiverMap(properties_map), &call_runtime); | |
336 // Stay on the fast path only if there are no elements. | |
337 GotoIfNot(WordEqual(LoadElements(properties), | |
338 LoadRoot(Heap::kEmptyFixedArrayRootIndex)), | |
339 &call_runtime); | |
340 // Handle dictionary objects or fast objects with properties in runtime. | |
341 Node* bit_field3 = LoadMapBitField3(properties_map); | |
342 GotoIf(IsSetWord32<Map::DictionaryMap>(bit_field3), &call_runtime); | |
343 Branch(IsSetWord32<Map::NumberOfOwnDescriptorsBits>(bit_field3), | |
344 &call_runtime, &no_properties); | |
345 } | |
346 | |
347 // Create a new object with the given prototype. | |
348 Bind(&no_properties); | |
349 { | |
350 Variable map(this, MachineRepresentation::kTagged); | |
351 Variable properties(this, MachineRepresentation::kTagged); | |
352 Label non_null_proto(this), instantiate_map(this), good(this); | |
353 | |
354 Branch(WordEqual(prototype, NullConstant()), &good, &non_null_proto); | |
355 | |
356 Bind(&good); | |
357 { | |
358 map.Bind(LoadContextElement( | |
359 context, Context::SLOW_OBJECT_WITH_NULL_PROTOTYPE_MAP)); | |
360 properties.Bind(AllocateNameDictionary(NameDictionary::kInitialCapacity)); | |
361 Goto(&instantiate_map); | |
362 } | |
363 | |
364 Bind(&non_null_proto); | |
365 { | |
366 properties.Bind(EmptyFixedArrayConstant()); | |
367 Node* object_function = | |
368 LoadContextElement(context, Context::OBJECT_FUNCTION_INDEX); | |
369 Node* object_function_map = LoadObjectField( | |
370 object_function, JSFunction::kPrototypeOrInitialMapOffset); | |
371 map.Bind(object_function_map); | |
372 GotoIf(WordEqual(prototype, LoadMapPrototype(map.value())), | |
373 &instantiate_map); | |
374 // Try loading the prototype info. | |
375 Node* prototype_info = | |
376 LoadMapPrototypeInfo(LoadMap(prototype), &call_runtime); | |
377 Comment("Load ObjectCreateMap from PrototypeInfo"); | |
378 Node* weak_cell = | |
379 LoadObjectField(prototype_info, PrototypeInfo::kObjectCreateMap); | |
380 GotoIf(WordEqual(weak_cell, UndefinedConstant()), &call_runtime); | |
381 map.Bind(LoadWeakCellValue(weak_cell, &call_runtime)); | |
382 Goto(&instantiate_map); | |
383 } | |
384 | |
385 Bind(&instantiate_map); | |
386 { | |
387 Node* instance = AllocateJSObjectFromMap(map.value(), properties.value()); | |
388 Return(instance); | |
389 } | |
390 } | |
391 | |
392 Bind(&call_runtime); | |
393 { | |
394 Return(CallRuntime(Runtime::kObjectCreate, context, prototype, properties)); | |
395 } | |
396 } | |
397 | |
398 // ES6 section 19.1.2.3 Object.defineProperties | 60 // ES6 section 19.1.2.3 Object.defineProperties |
399 BUILTIN(ObjectDefineProperties) { | 61 BUILTIN(ObjectDefineProperties) { |
400 HandleScope scope(isolate); | 62 HandleScope scope(isolate); |
401 DCHECK_EQ(3, args.length()); | 63 DCHECK_EQ(3, args.length()); |
402 Handle<Object> target = args.at(1); | 64 Handle<Object> target = args.at(1); |
403 Handle<Object> properties = args.at(2); | 65 Handle<Object> properties = args.at(2); |
404 | 66 |
405 RETURN_RESULT_OR_FAILURE( | 67 RETURN_RESULT_OR_FAILURE( |
406 isolate, JSReceiver::DefineProperties(isolate, target, properties)); | 68 isolate, JSReceiver::DefineProperties(isolate, target, properties)); |
407 } | 69 } |
(...skipping 473 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
881 HandleScope scope(isolate); | 543 HandleScope scope(isolate); |
882 Handle<Object> object = args.atOrUndefined(isolate, 1); | 544 Handle<Object> object = args.atOrUndefined(isolate, 1); |
883 if (object->IsJSReceiver()) { | 545 if (object->IsJSReceiver()) { |
884 MAYBE_RETURN(JSReceiver::SetIntegrityLevel(Handle<JSReceiver>::cast(object), | 546 MAYBE_RETURN(JSReceiver::SetIntegrityLevel(Handle<JSReceiver>::cast(object), |
885 SEALED, Object::THROW_ON_ERROR), | 547 SEALED, Object::THROW_ON_ERROR), |
886 isolate->heap()->exception()); | 548 isolate->heap()->exception()); |
887 } | 549 } |
888 return *object; | 550 return *object; |
889 } | 551 } |
890 | 552 |
891 TF_BUILTIN(CreateIterResultObject, ObjectBuiltinsAssembler) { | |
892 typedef CreateIterResultObjectDescriptor Descriptor; | |
893 | |
894 Node* const value = Parameter(Descriptor::kValue); | |
895 Node* const done = Parameter(Descriptor::kDone); | |
896 Node* const context = Parameter(Descriptor::kContext); | |
897 | |
898 Node* const native_context = LoadNativeContext(context); | |
899 Node* const map = | |
900 LoadContextElement(native_context, Context::ITERATOR_RESULT_MAP_INDEX); | |
901 | |
902 Node* const result = AllocateJSObjectFromMap(map); | |
903 | |
904 StoreObjectFieldNoWriteBarrier(result, JSIteratorResult::kValueOffset, value); | |
905 StoreObjectFieldNoWriteBarrier(result, JSIteratorResult::kDoneOffset, done); | |
906 | |
907 Return(result); | |
908 } | |
909 | |
910 TF_BUILTIN(HasProperty, ObjectBuiltinsAssembler) { | |
911 typedef HasPropertyDescriptor Descriptor; | |
912 | |
913 Node* key = Parameter(Descriptor::kKey); | |
914 Node* object = Parameter(Descriptor::kObject); | |
915 Node* context = Parameter(Descriptor::kContext); | |
916 | |
917 Return(HasProperty(object, key, context, Runtime::kHasProperty)); | |
918 } | |
919 | |
920 TF_BUILTIN(InstanceOf, ObjectBuiltinsAssembler) { | |
921 typedef CompareDescriptor Descriptor; | |
922 | |
923 Node* object = Parameter(Descriptor::kLeft); | |
924 Node* callable = Parameter(Descriptor::kRight); | |
925 Node* context = Parameter(Descriptor::kContext); | |
926 | |
927 Return(InstanceOf(object, callable, context)); | |
928 } | |
929 | |
930 // ES6 section 7.3.19 OrdinaryHasInstance ( C, O ) | |
931 TF_BUILTIN(OrdinaryHasInstance, ObjectBuiltinsAssembler) { | |
932 typedef CompareDescriptor Descriptor; | |
933 | |
934 Node* constructor = Parameter(Descriptor::kLeft); | |
935 Node* object = Parameter(Descriptor::kRight); | |
936 Node* context = Parameter(Descriptor::kContext); | |
937 | |
938 Return(OrdinaryHasInstance(context, constructor, object)); | |
939 } | |
940 | |
941 TF_BUILTIN(GetSuperConstructor, ObjectBuiltinsAssembler) { | |
942 typedef TypeofDescriptor Descriptor; | |
943 | |
944 Node* object = Parameter(Descriptor::kObject); | |
945 Node* context = Parameter(Descriptor::kContext); | |
946 | |
947 Return(GetSuperConstructor(object, context)); | |
948 } | |
949 | |
950 } // namespace internal | 553 } // namespace internal |
951 } // namespace v8 | 554 } // namespace v8 |
OLD | NEW |