OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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.h" | 5 #include "src/builtins/builtins.h" |
6 #include "src/builtins/builtins-utils.h" | 6 #include "src/builtins/builtins-utils.h" |
7 | 7 |
8 #include "src/api-arguments.h" | 8 #include "src/api-arguments.h" |
9 #include "src/api-natives.h" | 9 #include "src/api-natives.h" |
10 #include "src/base/ieee754.h" | |
11 #include "src/base/once.h" | |
12 #include "src/bootstrapper.h" | |
13 #include "src/code-factory.h" | 10 #include "src/code-factory.h" |
14 #include "src/dateparser-inl.h" | |
15 #include "src/frames-inl.h" | |
16 #include "src/gdb-jit.h" | |
17 #include "src/globals.h" | |
18 #include "src/ic/handler-compiler.h" | 11 #include "src/ic/handler-compiler.h" |
19 #include "src/ic/ic.h" | 12 #include "src/ic/ic.h" |
20 #include "src/isolate-inl.h" | |
21 #include "src/json-parser.h" | |
22 #include "src/json-stringifier.h" | |
23 #include "src/messages.h" | |
24 #include "src/property-descriptor.h" | |
25 #include "src/prototype.h" | |
26 #include "src/string-builder.h" | |
27 #include "src/uri.h" | |
28 #include "src/vm-state-inl.h" | 13 #include "src/vm-state-inl.h" |
29 | 14 |
30 namespace v8 { | 15 namespace v8 { |
31 namespace internal { | 16 namespace internal { |
32 | 17 |
33 // Forward declarations for C++ builtins. | 18 // Forward declarations for C++ builtins. |
34 #define FORWARD_DECLARE(Name) \ | 19 #define FORWARD_DECLARE(Name) \ |
35 Object* Builtin_##Name(int argc, Object** args, Isolate* isolate); | 20 Object* Builtin_##Name(int argc, Object** args, Isolate* isolate); |
36 BUILTIN_LIST_C(FORWARD_DECLARE) | 21 BUILTIN_LIST_C(FORWARD_DECLARE) |
37 #undef FORWARD_DECLARE | 22 #undef FORWARD_DECLARE |
38 | 23 |
39 BUILTIN(Illegal) { | |
40 UNREACHABLE(); | |
41 return isolate->heap()->undefined_value(); // Make compiler happy. | |
42 } | |
43 | |
44 BUILTIN(EmptyFunction) { return isolate->heap()->undefined_value(); } | |
45 | |
46 | |
47 void Builtins::Generate_ObjectHasOwnProperty(CodeStubAssembler* assembler) { | |
48 typedef compiler::Node Node; | |
49 typedef CodeStubAssembler::Label Label; | |
50 typedef CodeStubAssembler::Variable Variable; | |
51 | |
52 Node* object = assembler->Parameter(0); | |
53 Node* key = assembler->Parameter(1); | |
54 Node* context = assembler->Parameter(4); | |
55 | |
56 Label call_runtime(assembler), return_true(assembler), | |
57 return_false(assembler); | |
58 | |
59 // Smi receivers do not have own properties. | |
60 Label if_objectisnotsmi(assembler); | |
61 assembler->Branch(assembler->WordIsSmi(object), &return_false, | |
62 &if_objectisnotsmi); | |
63 assembler->Bind(&if_objectisnotsmi); | |
64 | |
65 Node* map = assembler->LoadMap(object); | |
66 Node* instance_type = assembler->LoadMapInstanceType(map); | |
67 | |
68 Variable var_index(assembler, MachineRepresentation::kWord32); | |
69 | |
70 Label keyisindex(assembler), if_iskeyunique(assembler); | |
71 assembler->TryToName(key, &keyisindex, &var_index, &if_iskeyunique, | |
72 &call_runtime); | |
73 | |
74 assembler->Bind(&if_iskeyunique); | |
75 assembler->TryHasOwnProperty(object, map, instance_type, key, &return_true, | |
76 &return_false, &call_runtime); | |
77 | |
78 assembler->Bind(&keyisindex); | |
79 assembler->TryLookupElement(object, map, instance_type, var_index.value(), | |
80 &return_true, &return_false, &call_runtime); | |
81 | |
82 assembler->Bind(&return_true); | |
83 assembler->Return(assembler->BooleanConstant(true)); | |
84 | |
85 assembler->Bind(&return_false); | |
86 assembler->Return(assembler->BooleanConstant(false)); | |
87 | |
88 assembler->Bind(&call_runtime); | |
89 assembler->Return(assembler->CallRuntime(Runtime::kObjectHasOwnProperty, | |
90 context, object, key)); | |
91 } | |
92 | |
93 namespace { | |
94 | |
95 MUST_USE_RESULT Maybe<bool> FastAssign(Handle<JSReceiver> to, | |
96 Handle<Object> next_source) { | |
97 // Non-empty strings are the only non-JSReceivers that need to be handled | |
98 // explicitly by Object.assign. | |
99 if (!next_source->IsJSReceiver()) { | |
100 return Just(!next_source->IsString() || | |
101 String::cast(*next_source)->length() == 0); | |
102 } | |
103 | |
104 // If the target is deprecated, the object will be updated on first store. If | |
105 // the source for that store equals the target, this will invalidate the | |
106 // cached representation of the source. Preventively upgrade the target. | |
107 // Do this on each iteration since any property load could cause deprecation. | |
108 if (to->map()->is_deprecated()) { | |
109 JSObject::MigrateInstance(Handle<JSObject>::cast(to)); | |
110 } | |
111 | |
112 Isolate* isolate = to->GetIsolate(); | |
113 Handle<Map> map(JSReceiver::cast(*next_source)->map(), isolate); | |
114 | |
115 if (!map->IsJSObjectMap()) return Just(false); | |
116 if (!map->OnlyHasSimpleProperties()) return Just(false); | |
117 | |
118 Handle<JSObject> from = Handle<JSObject>::cast(next_source); | |
119 if (from->elements() != isolate->heap()->empty_fixed_array()) { | |
120 return Just(false); | |
121 } | |
122 | |
123 Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate); | |
124 int length = map->NumberOfOwnDescriptors(); | |
125 | |
126 bool stable = true; | |
127 | |
128 for (int i = 0; i < length; i++) { | |
129 Handle<Name> next_key(descriptors->GetKey(i), isolate); | |
130 Handle<Object> prop_value; | |
131 // Directly decode from the descriptor array if |from| did not change shape. | |
132 if (stable) { | |
133 PropertyDetails details = descriptors->GetDetails(i); | |
134 if (!details.IsEnumerable()) continue; | |
135 if (details.kind() == kData) { | |
136 if (details.location() == kDescriptor) { | |
137 prop_value = handle(descriptors->GetValue(i), isolate); | |
138 } else { | |
139 Representation representation = details.representation(); | |
140 FieldIndex index = FieldIndex::ForDescriptor(*map, i); | |
141 prop_value = JSObject::FastPropertyAt(from, representation, index); | |
142 } | |
143 } else { | |
144 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | |
145 isolate, prop_value, JSReceiver::GetProperty(from, next_key), | |
146 Nothing<bool>()); | |
147 stable = from->map() == *map; | |
148 } | |
149 } else { | |
150 // If the map did change, do a slower lookup. We are still guaranteed that | |
151 // the object has a simple shape, and that the key is a name. | |
152 LookupIterator it(from, next_key, from, | |
153 LookupIterator::OWN_SKIP_INTERCEPTOR); | |
154 if (!it.IsFound()) continue; | |
155 DCHECK(it.state() == LookupIterator::DATA || | |
156 it.state() == LookupIterator::ACCESSOR); | |
157 if (!it.IsEnumerable()) continue; | |
158 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | |
159 isolate, prop_value, Object::GetProperty(&it), Nothing<bool>()); | |
160 } | |
161 LookupIterator it(to, next_key, to); | |
162 bool call_to_js = it.IsFound() && it.state() != LookupIterator::DATA; | |
163 Maybe<bool> result = Object::SetProperty( | |
164 &it, prop_value, STRICT, Object::CERTAINLY_NOT_STORE_FROM_KEYED); | |
165 if (result.IsNothing()) return result; | |
166 if (stable && call_to_js) stable = from->map() == *map; | |
167 } | |
168 | |
169 return Just(true); | |
170 } | |
171 | |
172 } // namespace | |
173 | |
174 // ES6 19.1.2.1 Object.assign | |
175 BUILTIN(ObjectAssign) { | |
176 HandleScope scope(isolate); | |
177 Handle<Object> target = args.atOrUndefined(isolate, 1); | |
178 | |
179 // 1. Let to be ? ToObject(target). | |
180 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, target, | |
181 Object::ToObject(isolate, target)); | |
182 Handle<JSReceiver> to = Handle<JSReceiver>::cast(target); | |
183 // 2. If only one argument was passed, return to. | |
184 if (args.length() == 2) return *to; | |
185 // 3. Let sources be the List of argument values starting with the | |
186 // second argument. | |
187 // 4. For each element nextSource of sources, in ascending index order, | |
188 for (int i = 2; i < args.length(); ++i) { | |
189 Handle<Object> next_source = args.at<Object>(i); | |
190 Maybe<bool> fast_assign = FastAssign(to, next_source); | |
191 if (fast_assign.IsNothing()) return isolate->heap()->exception(); | |
192 if (fast_assign.FromJust()) continue; | |
193 // 4a. If nextSource is undefined or null, let keys be an empty List. | |
194 // 4b. Else, | |
195 // 4b i. Let from be ToObject(nextSource). | |
196 // Only non-empty strings and JSReceivers have enumerable properties. | |
197 Handle<JSReceiver> from = | |
198 Object::ToObject(isolate, next_source).ToHandleChecked(); | |
199 // 4b ii. Let keys be ? from.[[OwnPropertyKeys]](). | |
200 Handle<FixedArray> keys; | |
201 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
202 isolate, keys, KeyAccumulator::GetKeys( | |
203 from, KeyCollectionMode::kOwnOnly, ALL_PROPERTIES, | |
204 GetKeysConversion::kKeepNumbers)); | |
205 // 4c. Repeat for each element nextKey of keys in List order, | |
206 for (int j = 0; j < keys->length(); ++j) { | |
207 Handle<Object> next_key(keys->get(j), isolate); | |
208 // 4c i. Let desc be ? from.[[GetOwnProperty]](nextKey). | |
209 PropertyDescriptor desc; | |
210 Maybe<bool> found = | |
211 JSReceiver::GetOwnPropertyDescriptor(isolate, from, next_key, &desc); | |
212 if (found.IsNothing()) return isolate->heap()->exception(); | |
213 // 4c ii. If desc is not undefined and desc.[[Enumerable]] is true, then | |
214 if (found.FromJust() && desc.enumerable()) { | |
215 // 4c ii 1. Let propValue be ? Get(from, nextKey). | |
216 Handle<Object> prop_value; | |
217 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
218 isolate, prop_value, | |
219 Runtime::GetObjectProperty(isolate, from, next_key)); | |
220 // 4c ii 2. Let status be ? Set(to, nextKey, propValue, true). | |
221 Handle<Object> status; | |
222 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
223 isolate, status, Runtime::SetObjectProperty(isolate, to, next_key, | |
224 prop_value, STRICT)); | |
225 } | |
226 } | |
227 } | |
228 // 5. Return to. | |
229 return *to; | |
230 } | |
231 | |
232 namespace { // anonymous namespace for ObjectProtoToString() | |
233 | |
234 void IsString(CodeStubAssembler* assembler, compiler::Node* object, | |
235 CodeStubAssembler::Label* if_string, | |
236 CodeStubAssembler::Label* if_notstring) { | |
237 typedef compiler::Node Node; | |
238 typedef CodeStubAssembler::Label Label; | |
239 | |
240 Label if_notsmi(assembler); | |
241 assembler->Branch(assembler->WordIsSmi(object), if_notstring, &if_notsmi); | |
242 | |
243 assembler->Bind(&if_notsmi); | |
244 { | |
245 Node* instance_type = assembler->LoadInstanceType(object); | |
246 | |
247 assembler->Branch( | |
248 assembler->Int32LessThan( | |
249 instance_type, assembler->Int32Constant(FIRST_NONSTRING_TYPE)), | |
250 if_string, if_notstring); | |
251 } | |
252 } | |
253 | |
254 void ReturnToStringFormat(CodeStubAssembler* assembler, compiler::Node* context, | |
255 compiler::Node* string) { | |
256 typedef compiler::Node Node; | |
257 | |
258 Node* lhs = assembler->HeapConstant( | |
259 assembler->factory()->NewStringFromStaticChars("[object ")); | |
260 Node* rhs = assembler->HeapConstant( | |
261 assembler->factory()->NewStringFromStaticChars("]")); | |
262 | |
263 Callable callable = CodeFactory::StringAdd( | |
264 assembler->isolate(), STRING_ADD_CHECK_NONE, NOT_TENURED); | |
265 | |
266 assembler->Return(assembler->CallStub( | |
267 callable, context, assembler->CallStub(callable, context, lhs, string), | |
268 rhs)); | |
269 } | |
270 | |
271 void ReturnIfPrimitive(CodeStubAssembler* assembler, | |
272 compiler::Node* instance_type, | |
273 CodeStubAssembler::Label* return_string, | |
274 CodeStubAssembler::Label* return_boolean, | |
275 CodeStubAssembler::Label* return_number) { | |
276 assembler->GotoIf( | |
277 assembler->Int32LessThan(instance_type, | |
278 assembler->Int32Constant(FIRST_NONSTRING_TYPE)), | |
279 return_string); | |
280 | |
281 assembler->GotoIf(assembler->Word32Equal( | |
282 instance_type, assembler->Int32Constant(ODDBALL_TYPE)), | |
283 return_boolean); | |
284 | |
285 assembler->GotoIf( | |
286 assembler->Word32Equal(instance_type, | |
287 assembler->Int32Constant(HEAP_NUMBER_TYPE)), | |
288 return_number); | |
289 } | |
290 | |
291 } // namespace | |
292 | |
293 // ES6 section 19.1.3.6 Object.prototype.toString | |
294 void Builtins::Generate_ObjectProtoToString(CodeStubAssembler* assembler) { | |
295 typedef compiler::Node Node; | |
296 typedef CodeStubAssembler::Label Label; | |
297 typedef CodeStubAssembler::Variable Variable; | |
298 | |
299 Label return_undefined(assembler, Label::kDeferred), | |
300 return_null(assembler, Label::kDeferred), | |
301 return_arguments(assembler, Label::kDeferred), return_array(assembler), | |
302 return_api(assembler, Label::kDeferred), return_object(assembler), | |
303 return_regexp(assembler), return_function(assembler), | |
304 return_error(assembler), return_date(assembler), return_string(assembler), | |
305 return_boolean(assembler), return_jsvalue(assembler), | |
306 return_jsproxy(assembler, Label::kDeferred), return_number(assembler); | |
307 | |
308 Label if_isproxy(assembler, Label::kDeferred); | |
309 | |
310 Label checkstringtag(assembler); | |
311 Label if_tostringtag(assembler), if_notostringtag(assembler); | |
312 | |
313 Node* receiver = assembler->Parameter(0); | |
314 Node* context = assembler->Parameter(3); | |
315 | |
316 assembler->GotoIf( | |
317 assembler->Word32Equal(receiver, assembler->UndefinedConstant()), | |
318 &return_undefined); | |
319 | |
320 assembler->GotoIf(assembler->Word32Equal(receiver, assembler->NullConstant()), | |
321 &return_null); | |
322 | |
323 assembler->GotoIf(assembler->WordIsSmi(receiver), &return_number); | |
324 | |
325 Node* receiver_instance_type = assembler->LoadInstanceType(receiver); | |
326 ReturnIfPrimitive(assembler, receiver_instance_type, &return_string, | |
327 &return_boolean, &return_number); | |
328 | |
329 // for proxies, check IsArray before getting @@toStringTag | |
330 Variable var_proxy_is_array(assembler, MachineRepresentation::kTagged); | |
331 var_proxy_is_array.Bind(assembler->BooleanConstant(false)); | |
332 | |
333 assembler->Branch( | |
334 assembler->Word32Equal(receiver_instance_type, | |
335 assembler->Int32Constant(JS_PROXY_TYPE)), | |
336 &if_isproxy, &checkstringtag); | |
337 | |
338 assembler->Bind(&if_isproxy); | |
339 { | |
340 // This can throw | |
341 var_proxy_is_array.Bind( | |
342 assembler->CallRuntime(Runtime::kArrayIsArray, context, receiver)); | |
343 assembler->Goto(&checkstringtag); | |
344 } | |
345 | |
346 assembler->Bind(&checkstringtag); | |
347 { | |
348 Node* to_string_tag_symbol = assembler->HeapConstant( | |
349 assembler->isolate()->factory()->to_string_tag_symbol()); | |
350 | |
351 GetPropertyStub stub(assembler->isolate()); | |
352 Callable get_property = | |
353 Callable(stub.GetCode(), stub.GetCallInterfaceDescriptor()); | |
354 Node* to_string_tag_value = assembler->CallStub( | |
355 get_property, context, receiver, to_string_tag_symbol); | |
356 | |
357 IsString(assembler, to_string_tag_value, &if_tostringtag, | |
358 &if_notostringtag); | |
359 | |
360 assembler->Bind(&if_tostringtag); | |
361 ReturnToStringFormat(assembler, context, to_string_tag_value); | |
362 } | |
363 assembler->Bind(&if_notostringtag); | |
364 { | |
365 size_t const kNumCases = 11; | |
366 Label* case_labels[kNumCases]; | |
367 int32_t case_values[kNumCases]; | |
368 case_labels[0] = &return_api; | |
369 case_values[0] = JS_API_OBJECT_TYPE; | |
370 case_labels[1] = &return_api; | |
371 case_values[1] = JS_SPECIAL_API_OBJECT_TYPE; | |
372 case_labels[2] = &return_arguments; | |
373 case_values[2] = JS_ARGUMENTS_TYPE; | |
374 case_labels[3] = &return_array; | |
375 case_values[3] = JS_ARRAY_TYPE; | |
376 case_labels[4] = &return_function; | |
377 case_values[4] = JS_BOUND_FUNCTION_TYPE; | |
378 case_labels[5] = &return_function; | |
379 case_values[5] = JS_FUNCTION_TYPE; | |
380 case_labels[6] = &return_error; | |
381 case_values[6] = JS_ERROR_TYPE; | |
382 case_labels[7] = &return_date; | |
383 case_values[7] = JS_DATE_TYPE; | |
384 case_labels[8] = &return_regexp; | |
385 case_values[8] = JS_REGEXP_TYPE; | |
386 case_labels[9] = &return_jsvalue; | |
387 case_values[9] = JS_VALUE_TYPE; | |
388 case_labels[10] = &return_jsproxy; | |
389 case_values[10] = JS_PROXY_TYPE; | |
390 | |
391 assembler->Switch(receiver_instance_type, &return_object, case_values, | |
392 case_labels, arraysize(case_values)); | |
393 | |
394 assembler->Bind(&return_undefined); | |
395 assembler->Return(assembler->HeapConstant( | |
396 assembler->isolate()->factory()->undefined_to_string())); | |
397 | |
398 assembler->Bind(&return_null); | |
399 assembler->Return(assembler->HeapConstant( | |
400 assembler->isolate()->factory()->null_to_string())); | |
401 | |
402 assembler->Bind(&return_number); | |
403 assembler->Return(assembler->HeapConstant( | |
404 assembler->isolate()->factory()->number_to_string())); | |
405 | |
406 assembler->Bind(&return_string); | |
407 assembler->Return(assembler->HeapConstant( | |
408 assembler->isolate()->factory()->string_to_string())); | |
409 | |
410 assembler->Bind(&return_boolean); | |
411 assembler->Return(assembler->HeapConstant( | |
412 assembler->isolate()->factory()->boolean_to_string())); | |
413 | |
414 assembler->Bind(&return_arguments); | |
415 assembler->Return(assembler->HeapConstant( | |
416 assembler->isolate()->factory()->arguments_to_string())); | |
417 | |
418 assembler->Bind(&return_array); | |
419 assembler->Return(assembler->HeapConstant( | |
420 assembler->isolate()->factory()->array_to_string())); | |
421 | |
422 assembler->Bind(&return_function); | |
423 assembler->Return(assembler->HeapConstant( | |
424 assembler->isolate()->factory()->function_to_string())); | |
425 | |
426 assembler->Bind(&return_error); | |
427 assembler->Return(assembler->HeapConstant( | |
428 assembler->isolate()->factory()->error_to_string())); | |
429 | |
430 assembler->Bind(&return_date); | |
431 assembler->Return(assembler->HeapConstant( | |
432 assembler->isolate()->factory()->date_to_string())); | |
433 | |
434 assembler->Bind(&return_regexp); | |
435 assembler->Return(assembler->HeapConstant( | |
436 assembler->isolate()->factory()->regexp_to_string())); | |
437 | |
438 assembler->Bind(&return_api); | |
439 { | |
440 Node* class_name = | |
441 assembler->CallRuntime(Runtime::kClassOf, context, receiver); | |
442 ReturnToStringFormat(assembler, context, class_name); | |
443 } | |
444 | |
445 assembler->Bind(&return_jsvalue); | |
446 { | |
447 Node* value = assembler->LoadJSValueValue(receiver); | |
448 assembler->GotoIf(assembler->WordIsSmi(value), &return_number); | |
449 | |
450 ReturnIfPrimitive(assembler, assembler->LoadInstanceType(value), | |
451 &return_string, &return_boolean, &return_number); | |
452 assembler->Goto(&return_object); | |
453 } | |
454 | |
455 assembler->Bind(&return_jsproxy); | |
456 { | |
457 assembler->GotoIf(assembler->WordEqual(var_proxy_is_array.value(), | |
458 assembler->BooleanConstant(true)), | |
459 &return_array); | |
460 | |
461 Node* map = assembler->LoadMap(receiver); | |
462 | |
463 // Return object if the proxy {receiver} is not callable. | |
464 assembler->Branch( | |
465 assembler->Word32Equal( | |
466 assembler->Word32And( | |
467 assembler->LoadMapBitField(map), | |
468 assembler->Int32Constant(1 << Map::kIsCallable)), | |
469 assembler->Int32Constant(0)), | |
470 &return_object, &return_function); | |
471 } | |
472 | |
473 // Default | |
474 assembler->Bind(&return_object); | |
475 assembler->Return(assembler->HeapConstant( | |
476 assembler->isolate()->factory()->object_to_string())); | |
477 } | |
478 } | |
479 | |
480 // ES6 section 19.1.2.2 Object.create ( O [ , Properties ] ) | |
481 // TODO(verwaest): Support the common cases with precached map directly in | |
482 // an Object.create stub. | |
483 BUILTIN(ObjectCreate) { | |
484 HandleScope scope(isolate); | |
485 Handle<Object> prototype = args.atOrUndefined(isolate, 1); | |
486 if (!prototype->IsNull(isolate) && !prototype->IsJSReceiver()) { | |
487 THROW_NEW_ERROR_RETURN_FAILURE( | |
488 isolate, NewTypeError(MessageTemplate::kProtoObjectOrNull, prototype)); | |
489 } | |
490 | |
491 // Generate the map with the specified {prototype} based on the Object | |
492 // function's initial map from the current native context. | |
493 // TODO(bmeurer): Use a dedicated cache for Object.create; think about | |
494 // slack tracking for Object.create. | |
495 Handle<Map> map(isolate->native_context()->object_function()->initial_map(), | |
496 isolate); | |
497 if (map->prototype() != *prototype) { | |
498 if (prototype->IsNull(isolate)) { | |
499 map = isolate->object_with_null_prototype_map(); | |
500 } else if (prototype->IsJSObject()) { | |
501 Handle<JSObject> js_prototype = Handle<JSObject>::cast(prototype); | |
502 if (!js_prototype->map()->is_prototype_map()) { | |
503 JSObject::OptimizeAsPrototype(js_prototype, FAST_PROTOTYPE); | |
504 } | |
505 Handle<PrototypeInfo> info = | |
506 Map::GetOrCreatePrototypeInfo(js_prototype, isolate); | |
507 // TODO(verwaest): Use inobject slack tracking for this map. | |
508 if (info->HasObjectCreateMap()) { | |
509 map = handle(info->ObjectCreateMap(), isolate); | |
510 } else { | |
511 map = Map::CopyInitialMap(map); | |
512 Map::SetPrototype(map, prototype, FAST_PROTOTYPE); | |
513 PrototypeInfo::SetObjectCreateMap(info, map); | |
514 } | |
515 } else { | |
516 map = Map::TransitionToPrototype(map, prototype, REGULAR_PROTOTYPE); | |
517 } | |
518 } | |
519 | |
520 // Actually allocate the object. | |
521 Handle<JSObject> object = isolate->factory()->NewJSObjectFromMap(map); | |
522 | |
523 // Define the properties if properties was specified and is not undefined. | |
524 Handle<Object> properties = args.atOrUndefined(isolate, 2); | |
525 if (!properties->IsUndefined(isolate)) { | |
526 RETURN_FAILURE_ON_EXCEPTION( | |
527 isolate, JSReceiver::DefineProperties(isolate, object, properties)); | |
528 } | |
529 | |
530 return *object; | |
531 } | |
532 | |
533 // ES6 section 19.1.2.3 Object.defineProperties | |
534 BUILTIN(ObjectDefineProperties) { | |
535 HandleScope scope(isolate); | |
536 DCHECK_EQ(3, args.length()); | |
537 Handle<Object> target = args.at<Object>(1); | |
538 Handle<Object> properties = args.at<Object>(2); | |
539 | |
540 RETURN_RESULT_OR_FAILURE( | |
541 isolate, JSReceiver::DefineProperties(isolate, target, properties)); | |
542 } | |
543 | |
544 // ES6 section 19.1.2.4 Object.defineProperty | |
545 BUILTIN(ObjectDefineProperty) { | |
546 HandleScope scope(isolate); | |
547 DCHECK_EQ(4, args.length()); | |
548 Handle<Object> target = args.at<Object>(1); | |
549 Handle<Object> key = args.at<Object>(2); | |
550 Handle<Object> attributes = args.at<Object>(3); | |
551 | |
552 return JSReceiver::DefineProperty(isolate, target, key, attributes); | |
553 } | |
554 | |
555 namespace { | |
556 | |
557 template <AccessorComponent which_accessor> | |
558 Object* ObjectDefineAccessor(Isolate* isolate, Handle<Object> object, | |
559 Handle<Object> name, Handle<Object> accessor) { | |
560 // 1. Let O be ? ToObject(this value). | |
561 Handle<JSReceiver> receiver; | |
562 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver, | |
563 Object::ConvertReceiver(isolate, object)); | |
564 // 2. If IsCallable(getter) is false, throw a TypeError exception. | |
565 if (!accessor->IsCallable()) { | |
566 MessageTemplate::Template message = | |
567 which_accessor == ACCESSOR_GETTER | |
568 ? MessageTemplate::kObjectGetterExpectingFunction | |
569 : MessageTemplate::kObjectSetterExpectingFunction; | |
570 THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewTypeError(message)); | |
571 } | |
572 // 3. Let desc be PropertyDescriptor{[[Get]]: getter, [[Enumerable]]: true, | |
573 // [[Configurable]]: true}. | |
574 PropertyDescriptor desc; | |
575 if (which_accessor == ACCESSOR_GETTER) { | |
576 desc.set_get(accessor); | |
577 } else { | |
578 DCHECK(which_accessor == ACCESSOR_SETTER); | |
579 desc.set_set(accessor); | |
580 } | |
581 desc.set_enumerable(true); | |
582 desc.set_configurable(true); | |
583 // 4. Let key be ? ToPropertyKey(P). | |
584 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name, | |
585 Object::ToPropertyKey(isolate, name)); | |
586 // 5. Perform ? DefinePropertyOrThrow(O, key, desc). | |
587 // To preserve legacy behavior, we ignore errors silently rather than | |
588 // throwing an exception. | |
589 Maybe<bool> success = JSReceiver::DefineOwnProperty( | |
590 isolate, receiver, name, &desc, Object::DONT_THROW); | |
591 MAYBE_RETURN(success, isolate->heap()->exception()); | |
592 if (!success.FromJust()) { | |
593 isolate->CountUsage(v8::Isolate::kDefineGetterOrSetterWouldThrow); | |
594 } | |
595 // 6. Return undefined. | |
596 return isolate->heap()->undefined_value(); | |
597 } | |
598 | |
599 Object* ObjectLookupAccessor(Isolate* isolate, Handle<Object> object, | |
600 Handle<Object> key, AccessorComponent component) { | |
601 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, object, | |
602 Object::ConvertReceiver(isolate, object)); | |
603 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, key, | |
604 Object::ToPropertyKey(isolate, key)); | |
605 bool success = false; | |
606 LookupIterator it = LookupIterator::PropertyOrElement( | |
607 isolate, object, key, &success, | |
608 LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR); | |
609 DCHECK(success); | |
610 | |
611 for (; it.IsFound(); it.Next()) { | |
612 switch (it.state()) { | |
613 case LookupIterator::INTERCEPTOR: | |
614 case LookupIterator::NOT_FOUND: | |
615 case LookupIterator::TRANSITION: | |
616 UNREACHABLE(); | |
617 | |
618 case LookupIterator::ACCESS_CHECK: | |
619 if (it.HasAccess()) continue; | |
620 isolate->ReportFailedAccessCheck(it.GetHolder<JSObject>()); | |
621 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); | |
622 return isolate->heap()->undefined_value(); | |
623 | |
624 case LookupIterator::JSPROXY: | |
625 return isolate->heap()->undefined_value(); | |
626 | |
627 case LookupIterator::INTEGER_INDEXED_EXOTIC: | |
628 return isolate->heap()->undefined_value(); | |
629 case LookupIterator::DATA: | |
630 continue; | |
631 case LookupIterator::ACCESSOR: { | |
632 Handle<Object> maybe_pair = it.GetAccessors(); | |
633 if (maybe_pair->IsAccessorPair()) { | |
634 return *AccessorPair::GetComponent( | |
635 Handle<AccessorPair>::cast(maybe_pair), component); | |
636 } | |
637 } | |
638 } | |
639 } | |
640 | |
641 return isolate->heap()->undefined_value(); | |
642 } | |
643 | |
644 } // namespace | |
645 | |
646 // ES6 B.2.2.2 a.k.a. | |
647 // https://tc39.github.io/ecma262/#sec-object.prototype.__defineGetter__ | |
648 BUILTIN(ObjectDefineGetter) { | |
649 HandleScope scope(isolate); | |
650 Handle<Object> object = args.at<Object>(0); // Receiver. | |
651 Handle<Object> name = args.at<Object>(1); | |
652 Handle<Object> getter = args.at<Object>(2); | |
653 return ObjectDefineAccessor<ACCESSOR_GETTER>(isolate, object, name, getter); | |
654 } | |
655 | |
656 // ES6 B.2.2.3 a.k.a. | |
657 // https://tc39.github.io/ecma262/#sec-object.prototype.__defineSetter__ | |
658 BUILTIN(ObjectDefineSetter) { | |
659 HandleScope scope(isolate); | |
660 Handle<Object> object = args.at<Object>(0); // Receiver. | |
661 Handle<Object> name = args.at<Object>(1); | |
662 Handle<Object> setter = args.at<Object>(2); | |
663 return ObjectDefineAccessor<ACCESSOR_SETTER>(isolate, object, name, setter); | |
664 } | |
665 | |
666 // ES6 B.2.2.4 a.k.a. | |
667 // https://tc39.github.io/ecma262/#sec-object.prototype.__lookupGetter__ | |
668 BUILTIN(ObjectLookupGetter) { | |
669 HandleScope scope(isolate); | |
670 Handle<Object> object = args.at<Object>(0); | |
671 Handle<Object> name = args.at<Object>(1); | |
672 return ObjectLookupAccessor(isolate, object, name, ACCESSOR_GETTER); | |
673 } | |
674 | |
675 // ES6 B.2.2.5 a.k.a. | |
676 // https://tc39.github.io/ecma262/#sec-object.prototype.__lookupSetter__ | |
677 BUILTIN(ObjectLookupSetter) { | |
678 HandleScope scope(isolate); | |
679 Handle<Object> object = args.at<Object>(0); | |
680 Handle<Object> name = args.at<Object>(1); | |
681 return ObjectLookupAccessor(isolate, object, name, ACCESSOR_SETTER); | |
682 } | |
683 | |
684 // ES6 section 19.1.2.5 Object.freeze ( O ) | |
685 BUILTIN(ObjectFreeze) { | |
686 HandleScope scope(isolate); | |
687 Handle<Object> object = args.atOrUndefined(isolate, 1); | |
688 if (object->IsJSReceiver()) { | |
689 MAYBE_RETURN(JSReceiver::SetIntegrityLevel(Handle<JSReceiver>::cast(object), | |
690 FROZEN, Object::THROW_ON_ERROR), | |
691 isolate->heap()->exception()); | |
692 } | |
693 return *object; | |
694 } | |
695 | |
696 // ES section 19.1.2.9 Object.getPrototypeOf ( O ) | |
697 BUILTIN(ObjectGetPrototypeOf) { | |
698 HandleScope scope(isolate); | |
699 Handle<Object> object = args.atOrUndefined(isolate, 1); | |
700 | |
701 Handle<JSReceiver> receiver; | |
702 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver, | |
703 Object::ToObject(isolate, object)); | |
704 | |
705 RETURN_RESULT_OR_FAILURE(isolate, | |
706 JSReceiver::GetPrototype(isolate, receiver)); | |
707 } | |
708 | |
709 // ES6 section 19.1.2.6 Object.getOwnPropertyDescriptor ( O, P ) | |
710 BUILTIN(ObjectGetOwnPropertyDescriptor) { | |
711 HandleScope scope(isolate); | |
712 // 1. Let obj be ? ToObject(O). | |
713 Handle<Object> object = args.atOrUndefined(isolate, 1); | |
714 Handle<JSReceiver> receiver; | |
715 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver, | |
716 Object::ToObject(isolate, object)); | |
717 // 2. Let key be ? ToPropertyKey(P). | |
718 Handle<Object> property = args.atOrUndefined(isolate, 2); | |
719 Handle<Name> key; | |
720 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, key, | |
721 Object::ToName(isolate, property)); | |
722 // 3. Let desc be ? obj.[[GetOwnProperty]](key). | |
723 PropertyDescriptor desc; | |
724 Maybe<bool> found = | |
725 JSReceiver::GetOwnPropertyDescriptor(isolate, receiver, key, &desc); | |
726 MAYBE_RETURN(found, isolate->heap()->exception()); | |
727 // 4. Return FromPropertyDescriptor(desc). | |
728 if (!found.FromJust()) return isolate->heap()->undefined_value(); | |
729 return *desc.ToObject(isolate); | |
730 } | |
731 | |
732 namespace { | |
733 | |
734 Object* GetOwnPropertyKeys(Isolate* isolate, BuiltinArguments args, | |
735 PropertyFilter filter) { | |
736 HandleScope scope(isolate); | |
737 Handle<Object> object = args.atOrUndefined(isolate, 1); | |
738 Handle<JSReceiver> receiver; | |
739 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver, | |
740 Object::ToObject(isolate, object)); | |
741 Handle<FixedArray> keys; | |
742 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
743 isolate, keys, | |
744 KeyAccumulator::GetKeys(receiver, KeyCollectionMode::kOwnOnly, filter, | |
745 GetKeysConversion::kConvertToString)); | |
746 return *isolate->factory()->NewJSArrayWithElements(keys); | |
747 } | |
748 | |
749 } // namespace | |
750 | |
751 // ES6 section 19.1.2.7 Object.getOwnPropertyNames ( O ) | |
752 BUILTIN(ObjectGetOwnPropertyNames) { | |
753 return GetOwnPropertyKeys(isolate, args, SKIP_SYMBOLS); | |
754 } | |
755 | |
756 // ES6 section 19.1.2.8 Object.getOwnPropertySymbols ( O ) | |
757 BUILTIN(ObjectGetOwnPropertySymbols) { | |
758 return GetOwnPropertyKeys(isolate, args, SKIP_STRINGS); | |
759 } | |
760 | |
761 // ES#sec-object.is Object.is ( value1, value2 ) | |
762 BUILTIN(ObjectIs) { | |
763 SealHandleScope shs(isolate); | |
764 DCHECK_EQ(3, args.length()); | |
765 Handle<Object> value1 = args.at<Object>(1); | |
766 Handle<Object> value2 = args.at<Object>(2); | |
767 return isolate->heap()->ToBoolean(value1->SameValue(*value2)); | |
768 } | |
769 | |
770 // ES6 section 19.1.2.11 Object.isExtensible ( O ) | |
771 BUILTIN(ObjectIsExtensible) { | |
772 HandleScope scope(isolate); | |
773 Handle<Object> object = args.atOrUndefined(isolate, 1); | |
774 Maybe<bool> result = | |
775 object->IsJSReceiver() | |
776 ? JSReceiver::IsExtensible(Handle<JSReceiver>::cast(object)) | |
777 : Just(false); | |
778 MAYBE_RETURN(result, isolate->heap()->exception()); | |
779 return isolate->heap()->ToBoolean(result.FromJust()); | |
780 } | |
781 | |
782 // ES6 section 19.1.2.12 Object.isFrozen ( O ) | |
783 BUILTIN(ObjectIsFrozen) { | |
784 HandleScope scope(isolate); | |
785 Handle<Object> object = args.atOrUndefined(isolate, 1); | |
786 Maybe<bool> result = object->IsJSReceiver() | |
787 ? JSReceiver::TestIntegrityLevel( | |
788 Handle<JSReceiver>::cast(object), FROZEN) | |
789 : Just(true); | |
790 MAYBE_RETURN(result, isolate->heap()->exception()); | |
791 return isolate->heap()->ToBoolean(result.FromJust()); | |
792 } | |
793 | |
794 // ES6 section 19.1.2.13 Object.isSealed ( O ) | |
795 BUILTIN(ObjectIsSealed) { | |
796 HandleScope scope(isolate); | |
797 Handle<Object> object = args.atOrUndefined(isolate, 1); | |
798 Maybe<bool> result = object->IsJSReceiver() | |
799 ? JSReceiver::TestIntegrityLevel( | |
800 Handle<JSReceiver>::cast(object), SEALED) | |
801 : Just(true); | |
802 MAYBE_RETURN(result, isolate->heap()->exception()); | |
803 return isolate->heap()->ToBoolean(result.FromJust()); | |
804 } | |
805 | |
806 // ES6 section 19.1.2.14 Object.keys ( O ) | |
807 BUILTIN(ObjectKeys) { | |
808 HandleScope scope(isolate); | |
809 Handle<Object> object = args.atOrUndefined(isolate, 1); | |
810 Handle<JSReceiver> receiver; | |
811 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver, | |
812 Object::ToObject(isolate, object)); | |
813 | |
814 Handle<FixedArray> keys; | |
815 int enum_length = receiver->map()->EnumLength(); | |
816 if (enum_length != kInvalidEnumCacheSentinel && | |
817 JSObject::cast(*receiver)->elements() == | |
818 isolate->heap()->empty_fixed_array()) { | |
819 DCHECK(receiver->IsJSObject()); | |
820 DCHECK(!JSObject::cast(*receiver)->HasNamedInterceptor()); | |
821 DCHECK(!JSObject::cast(*receiver)->IsAccessCheckNeeded()); | |
822 DCHECK(!receiver->map()->has_hidden_prototype()); | |
823 DCHECK(JSObject::cast(*receiver)->HasFastProperties()); | |
824 if (enum_length == 0) { | |
825 keys = isolate->factory()->empty_fixed_array(); | |
826 } else { | |
827 Handle<FixedArray> cache( | |
828 receiver->map()->instance_descriptors()->GetEnumCache()); | |
829 keys = isolate->factory()->CopyFixedArrayUpTo(cache, enum_length); | |
830 } | |
831 } else { | |
832 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
833 isolate, keys, | |
834 KeyAccumulator::GetKeys(receiver, KeyCollectionMode::kOwnOnly, | |
835 ENUMERABLE_STRINGS, | |
836 GetKeysConversion::kConvertToString)); | |
837 } | |
838 return *isolate->factory()->NewJSArrayWithElements(keys, FAST_ELEMENTS); | |
839 } | |
840 | |
841 BUILTIN(ObjectValues) { | |
842 HandleScope scope(isolate); | |
843 Handle<Object> object = args.atOrUndefined(isolate, 1); | |
844 Handle<JSReceiver> receiver; | |
845 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver, | |
846 Object::ToObject(isolate, object)); | |
847 Handle<FixedArray> values; | |
848 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
849 isolate, values, JSReceiver::GetOwnValues(receiver, ENUMERABLE_STRINGS)); | |
850 return *isolate->factory()->NewJSArrayWithElements(values); | |
851 } | |
852 | |
853 BUILTIN(ObjectEntries) { | |
854 HandleScope scope(isolate); | |
855 Handle<Object> object = args.atOrUndefined(isolate, 1); | |
856 Handle<JSReceiver> receiver; | |
857 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver, | |
858 Object::ToObject(isolate, object)); | |
859 Handle<FixedArray> entries; | |
860 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
861 isolate, entries, | |
862 JSReceiver::GetOwnEntries(receiver, ENUMERABLE_STRINGS)); | |
863 return *isolate->factory()->NewJSArrayWithElements(entries); | |
864 } | |
865 | |
866 BUILTIN(ObjectGetOwnPropertyDescriptors) { | |
867 HandleScope scope(isolate); | |
868 Handle<Object> object = args.atOrUndefined(isolate, 1); | |
869 | |
870 Handle<JSReceiver> receiver; | |
871 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver, | |
872 Object::ToObject(isolate, object)); | |
873 | |
874 Handle<FixedArray> keys; | |
875 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
876 isolate, keys, KeyAccumulator::GetKeys( | |
877 receiver, KeyCollectionMode::kOwnOnly, ALL_PROPERTIES, | |
878 GetKeysConversion::kConvertToString)); | |
879 | |
880 Handle<JSObject> descriptors = | |
881 isolate->factory()->NewJSObject(isolate->object_function()); | |
882 | |
883 for (int i = 0; i < keys->length(); ++i) { | |
884 Handle<Name> key = Handle<Name>::cast(FixedArray::get(*keys, i, isolate)); | |
885 PropertyDescriptor descriptor; | |
886 Maybe<bool> did_get_descriptor = JSReceiver::GetOwnPropertyDescriptor( | |
887 isolate, receiver, key, &descriptor); | |
888 MAYBE_RETURN(did_get_descriptor, isolate->heap()->exception()); | |
889 | |
890 if (!did_get_descriptor.FromJust()) continue; | |
891 Handle<Object> from_descriptor = descriptor.ToObject(isolate); | |
892 | |
893 LookupIterator it = LookupIterator::PropertyOrElement( | |
894 isolate, descriptors, key, descriptors, LookupIterator::OWN); | |
895 Maybe<bool> success = JSReceiver::CreateDataProperty(&it, from_descriptor, | |
896 Object::DONT_THROW); | |
897 CHECK(success.FromJust()); | |
898 } | |
899 | |
900 return *descriptors; | |
901 } | |
902 | |
903 // ES6 section 19.1.2.15 Object.preventExtensions ( O ) | |
904 BUILTIN(ObjectPreventExtensions) { | |
905 HandleScope scope(isolate); | |
906 Handle<Object> object = args.atOrUndefined(isolate, 1); | |
907 if (object->IsJSReceiver()) { | |
908 MAYBE_RETURN(JSReceiver::PreventExtensions(Handle<JSReceiver>::cast(object), | |
909 Object::THROW_ON_ERROR), | |
910 isolate->heap()->exception()); | |
911 } | |
912 return *object; | |
913 } | |
914 | |
915 // ES6 section 19.1.2.17 Object.seal ( O ) | |
916 BUILTIN(ObjectSeal) { | |
917 HandleScope scope(isolate); | |
918 Handle<Object> object = args.atOrUndefined(isolate, 1); | |
919 if (object->IsJSReceiver()) { | |
920 MAYBE_RETURN(JSReceiver::SetIntegrityLevel(Handle<JSReceiver>::cast(object), | |
921 SEALED, Object::THROW_ON_ERROR), | |
922 isolate->heap()->exception()); | |
923 } | |
924 return *object; | |
925 } | |
926 | |
927 // ES6 section 18.2.6.2 decodeURI (encodedURI) | |
928 BUILTIN(GlobalDecodeURI) { | |
929 HandleScope scope(isolate); | |
930 Handle<String> encoded_uri; | |
931 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
932 isolate, encoded_uri, | |
933 Object::ToString(isolate, args.atOrUndefined(isolate, 1))); | |
934 | |
935 RETURN_RESULT_OR_FAILURE(isolate, Uri::DecodeUri(isolate, encoded_uri)); | |
936 } | |
937 | |
938 // ES6 section 18.2.6.3 decodeURIComponent (encodedURIComponent) | |
939 BUILTIN(GlobalDecodeURIComponent) { | |
940 HandleScope scope(isolate); | |
941 Handle<String> encoded_uri_component; | |
942 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
943 isolate, encoded_uri_component, | |
944 Object::ToString(isolate, args.atOrUndefined(isolate, 1))); | |
945 | |
946 RETURN_RESULT_OR_FAILURE( | |
947 isolate, Uri::DecodeUriComponent(isolate, encoded_uri_component)); | |
948 } | |
949 | |
950 // ES6 section 18.2.6.4 encodeURI (uri) | |
951 BUILTIN(GlobalEncodeURI) { | |
952 HandleScope scope(isolate); | |
953 Handle<String> uri; | |
954 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
955 isolate, uri, Object::ToString(isolate, args.atOrUndefined(isolate, 1))); | |
956 | |
957 RETURN_RESULT_OR_FAILURE(isolate, Uri::EncodeUri(isolate, uri)); | |
958 } | |
959 | |
960 // ES6 section 18.2.6.5 encodeURIComponenet (uriComponent) | |
961 BUILTIN(GlobalEncodeURIComponent) { | |
962 HandleScope scope(isolate); | |
963 Handle<String> uri_component; | |
964 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
965 isolate, uri_component, | |
966 Object::ToString(isolate, args.atOrUndefined(isolate, 1))); | |
967 | |
968 RETURN_RESULT_OR_FAILURE(isolate, | |
969 Uri::EncodeUriComponent(isolate, uri_component)); | |
970 } | |
971 | |
972 // ES6 section B.2.1.1 escape (string) | |
973 BUILTIN(GlobalEscape) { | |
974 HandleScope scope(isolate); | |
975 Handle<String> string; | |
976 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
977 isolate, string, | |
978 Object::ToString(isolate, args.atOrUndefined(isolate, 1))); | |
979 | |
980 RETURN_RESULT_OR_FAILURE(isolate, Uri::Escape(isolate, string)); | |
981 } | |
982 | |
983 // ES6 section B.2.1.2 unescape (string) | |
984 BUILTIN(GlobalUnescape) { | |
985 HandleScope scope(isolate); | |
986 Handle<String> string; | |
987 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
988 isolate, string, | |
989 Object::ToString(isolate, args.atOrUndefined(isolate, 1))); | |
990 | |
991 RETURN_RESULT_OR_FAILURE(isolate, Uri::Unescape(isolate, string)); | |
992 } | |
993 | |
994 namespace { | |
995 | |
996 bool CodeGenerationFromStringsAllowed(Isolate* isolate, | |
997 Handle<Context> context) { | |
998 DCHECK(context->allow_code_gen_from_strings()->IsFalse(isolate)); | |
999 // Check with callback if set. | |
1000 AllowCodeGenerationFromStringsCallback callback = | |
1001 isolate->allow_code_gen_callback(); | |
1002 if (callback == NULL) { | |
1003 // No callback set and code generation disallowed. | |
1004 return false; | |
1005 } else { | |
1006 // Callback set. Let it decide if code generation is allowed. | |
1007 VMState<EXTERNAL> state(isolate); | |
1008 return callback(v8::Utils::ToLocal(context)); | |
1009 } | |
1010 } | |
1011 | |
1012 MaybeHandle<JSFunction> CompileString(Handle<Context> context, | |
1013 Handle<String> source, | |
1014 ParseRestriction restriction) { | |
1015 Isolate* const isolate = context->GetIsolate(); | |
1016 Handle<Context> native_context(context->native_context(), isolate); | |
1017 | |
1018 // Check if native context allows code generation from | |
1019 // strings. Throw an exception if it doesn't. | |
1020 if (native_context->allow_code_gen_from_strings()->IsFalse(isolate) && | |
1021 !CodeGenerationFromStringsAllowed(isolate, native_context)) { | |
1022 Handle<Object> error_message = | |
1023 native_context->ErrorMessageForCodeGenerationFromStrings(); | |
1024 THROW_NEW_ERROR(isolate, NewEvalError(MessageTemplate::kCodeGenFromStrings, | |
1025 error_message), | |
1026 JSFunction); | |
1027 } | |
1028 | |
1029 // Compile source string in the native context. | |
1030 int eval_scope_position = 0; | |
1031 int eval_position = kNoSourcePosition; | |
1032 Handle<SharedFunctionInfo> outer_info(native_context->closure()->shared()); | |
1033 return Compiler::GetFunctionFromEval(source, outer_info, native_context, | |
1034 SLOPPY, restriction, eval_scope_position, | |
1035 eval_position); | |
1036 } | |
1037 | |
1038 } // namespace | |
1039 | |
1040 // ES6 section 18.2.1 eval (x) | |
1041 BUILTIN(GlobalEval) { | |
1042 HandleScope scope(isolate); | |
1043 Handle<Object> x = args.atOrUndefined(isolate, 1); | |
1044 Handle<JSFunction> target = args.target<JSFunction>(); | |
1045 Handle<JSObject> target_global_proxy(target->global_proxy(), isolate); | |
1046 if (!x->IsString()) return *x; | |
1047 Handle<JSFunction> function; | |
1048 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
1049 isolate, function, | |
1050 CompileString(handle(target->native_context(), isolate), | |
1051 Handle<String>::cast(x), NO_PARSE_RESTRICTION)); | |
1052 RETURN_RESULT_OR_FAILURE( | |
1053 isolate, | |
1054 Execution::Call(isolate, function, target_global_proxy, 0, nullptr)); | |
1055 } | |
1056 | |
1057 // ES6 section 24.3.1 JSON.parse. | |
1058 BUILTIN(JsonParse) { | |
1059 HandleScope scope(isolate); | |
1060 Handle<Object> source = args.atOrUndefined(isolate, 1); | |
1061 Handle<Object> reviver = args.atOrUndefined(isolate, 2); | |
1062 Handle<String> string; | |
1063 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, string, | |
1064 Object::ToString(isolate, source)); | |
1065 string = String::Flatten(string); | |
1066 RETURN_RESULT_OR_FAILURE( | |
1067 isolate, string->IsSeqOneByteString() | |
1068 ? JsonParser<true>::Parse(isolate, string, reviver) | |
1069 : JsonParser<false>::Parse(isolate, string, reviver)); | |
1070 } | |
1071 | |
1072 // ES6 section 24.3.2 JSON.stringify. | |
1073 BUILTIN(JsonStringify) { | |
1074 HandleScope scope(isolate); | |
1075 JsonStringifier stringifier(isolate); | |
1076 Handle<Object> object = args.atOrUndefined(isolate, 1); | |
1077 Handle<Object> replacer = args.atOrUndefined(isolate, 2); | |
1078 Handle<Object> indent = args.atOrUndefined(isolate, 3); | |
1079 RETURN_RESULT_OR_FAILURE(isolate, | |
1080 stringifier.Stringify(object, replacer, indent)); | |
1081 } | |
1082 | |
1083 // ----------------------------------------------------------------------------- | |
1084 // ES6 section 20.1 Number Objects | |
1085 | |
1086 // ES6 section 20.1.3.2 Number.prototype.toExponential ( fractionDigits ) | |
1087 BUILTIN(NumberPrototypeToExponential) { | |
1088 HandleScope scope(isolate); | |
1089 Handle<Object> value = args.at<Object>(0); | |
1090 Handle<Object> fraction_digits = args.atOrUndefined(isolate, 1); | |
1091 | |
1092 // Unwrap the receiver {value}. | |
1093 if (value->IsJSValue()) { | |
1094 value = handle(Handle<JSValue>::cast(value)->value(), isolate); | |
1095 } | |
1096 if (!value->IsNumber()) { | |
1097 THROW_NEW_ERROR_RETURN_FAILURE( | |
1098 isolate, NewTypeError(MessageTemplate::kNotGeneric, | |
1099 isolate->factory()->NewStringFromAsciiChecked( | |
1100 "Number.prototype.toExponential"))); | |
1101 } | |
1102 double const value_number = value->Number(); | |
1103 | |
1104 // Convert the {fraction_digits} to an integer first. | |
1105 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
1106 isolate, fraction_digits, Object::ToInteger(isolate, fraction_digits)); | |
1107 double const fraction_digits_number = fraction_digits->Number(); | |
1108 | |
1109 if (std::isnan(value_number)) return isolate->heap()->nan_string(); | |
1110 if (std::isinf(value_number)) { | |
1111 return (value_number < 0.0) ? isolate->heap()->minus_infinity_string() | |
1112 : isolate->heap()->infinity_string(); | |
1113 } | |
1114 if (fraction_digits_number < 0.0 || fraction_digits_number > 20.0) { | |
1115 THROW_NEW_ERROR_RETURN_FAILURE( | |
1116 isolate, NewRangeError(MessageTemplate::kNumberFormatRange, | |
1117 isolate->factory()->NewStringFromAsciiChecked( | |
1118 "toExponential()"))); | |
1119 } | |
1120 int const f = args.atOrUndefined(isolate, 1)->IsUndefined(isolate) | |
1121 ? -1 | |
1122 : static_cast<int>(fraction_digits_number); | |
1123 char* const str = DoubleToExponentialCString(value_number, f); | |
1124 Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str); | |
1125 DeleteArray(str); | |
1126 return *result; | |
1127 } | |
1128 | |
1129 // ES6 section 20.1.3.3 Number.prototype.toFixed ( fractionDigits ) | |
1130 BUILTIN(NumberPrototypeToFixed) { | |
1131 HandleScope scope(isolate); | |
1132 Handle<Object> value = args.at<Object>(0); | |
1133 Handle<Object> fraction_digits = args.atOrUndefined(isolate, 1); | |
1134 | |
1135 // Unwrap the receiver {value}. | |
1136 if (value->IsJSValue()) { | |
1137 value = handle(Handle<JSValue>::cast(value)->value(), isolate); | |
1138 } | |
1139 if (!value->IsNumber()) { | |
1140 THROW_NEW_ERROR_RETURN_FAILURE( | |
1141 isolate, NewTypeError(MessageTemplate::kNotGeneric, | |
1142 isolate->factory()->NewStringFromAsciiChecked( | |
1143 "Number.prototype.toFixed"))); | |
1144 } | |
1145 double const value_number = value->Number(); | |
1146 | |
1147 // Convert the {fraction_digits} to an integer first. | |
1148 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
1149 isolate, fraction_digits, Object::ToInteger(isolate, fraction_digits)); | |
1150 double const fraction_digits_number = fraction_digits->Number(); | |
1151 | |
1152 // Check if the {fraction_digits} are in the supported range. | |
1153 if (fraction_digits_number < 0.0 || fraction_digits_number > 20.0) { | |
1154 THROW_NEW_ERROR_RETURN_FAILURE( | |
1155 isolate, NewRangeError(MessageTemplate::kNumberFormatRange, | |
1156 isolate->factory()->NewStringFromAsciiChecked( | |
1157 "toFixed() digits"))); | |
1158 } | |
1159 | |
1160 if (std::isnan(value_number)) return isolate->heap()->nan_string(); | |
1161 if (std::isinf(value_number)) { | |
1162 return (value_number < 0.0) ? isolate->heap()->minus_infinity_string() | |
1163 : isolate->heap()->infinity_string(); | |
1164 } | |
1165 char* const str = DoubleToFixedCString( | |
1166 value_number, static_cast<int>(fraction_digits_number)); | |
1167 Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str); | |
1168 DeleteArray(str); | |
1169 return *result; | |
1170 } | |
1171 | |
1172 // ES6 section 20.1.3.4 Number.prototype.toLocaleString ( [ r1 [ , r2 ] ] ) | |
1173 BUILTIN(NumberPrototypeToLocaleString) { | |
1174 HandleScope scope(isolate); | |
1175 Handle<Object> value = args.at<Object>(0); | |
1176 | |
1177 // Unwrap the receiver {value}. | |
1178 if (value->IsJSValue()) { | |
1179 value = handle(Handle<JSValue>::cast(value)->value(), isolate); | |
1180 } | |
1181 if (!value->IsNumber()) { | |
1182 THROW_NEW_ERROR_RETURN_FAILURE( | |
1183 isolate, NewTypeError(MessageTemplate::kNotGeneric, | |
1184 isolate->factory()->NewStringFromAsciiChecked( | |
1185 "Number.prototype.toLocaleString"))); | |
1186 } | |
1187 | |
1188 // Turn the {value} into a String. | |
1189 return *isolate->factory()->NumberToString(value); | |
1190 } | |
1191 | |
1192 // ES6 section 20.1.3.5 Number.prototype.toPrecision ( precision ) | |
1193 BUILTIN(NumberPrototypeToPrecision) { | |
1194 HandleScope scope(isolate); | |
1195 Handle<Object> value = args.at<Object>(0); | |
1196 Handle<Object> precision = args.atOrUndefined(isolate, 1); | |
1197 | |
1198 // Unwrap the receiver {value}. | |
1199 if (value->IsJSValue()) { | |
1200 value = handle(Handle<JSValue>::cast(value)->value(), isolate); | |
1201 } | |
1202 if (!value->IsNumber()) { | |
1203 THROW_NEW_ERROR_RETURN_FAILURE( | |
1204 isolate, NewTypeError(MessageTemplate::kNotGeneric, | |
1205 isolate->factory()->NewStringFromAsciiChecked( | |
1206 "Number.prototype.toPrecision"))); | |
1207 } | |
1208 double const value_number = value->Number(); | |
1209 | |
1210 // If no {precision} was specified, just return ToString of {value}. | |
1211 if (precision->IsUndefined(isolate)) { | |
1212 return *isolate->factory()->NumberToString(value); | |
1213 } | |
1214 | |
1215 // Convert the {precision} to an integer first. | |
1216 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, precision, | |
1217 Object::ToInteger(isolate, precision)); | |
1218 double const precision_number = precision->Number(); | |
1219 | |
1220 if (std::isnan(value_number)) return isolate->heap()->nan_string(); | |
1221 if (std::isinf(value_number)) { | |
1222 return (value_number < 0.0) ? isolate->heap()->minus_infinity_string() | |
1223 : isolate->heap()->infinity_string(); | |
1224 } | |
1225 if (precision_number < 1.0 || precision_number > 21.0) { | |
1226 THROW_NEW_ERROR_RETURN_FAILURE( | |
1227 isolate, NewRangeError(MessageTemplate::kToPrecisionFormatRange)); | |
1228 } | |
1229 char* const str = DoubleToPrecisionCString( | |
1230 value_number, static_cast<int>(precision_number)); | |
1231 Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str); | |
1232 DeleteArray(str); | |
1233 return *result; | |
1234 } | |
1235 | |
1236 // ES6 section 20.1.3.6 Number.prototype.toString ( [ radix ] ) | |
1237 BUILTIN(NumberPrototypeToString) { | |
1238 HandleScope scope(isolate); | |
1239 Handle<Object> value = args.at<Object>(0); | |
1240 Handle<Object> radix = args.atOrUndefined(isolate, 1); | |
1241 | |
1242 // Unwrap the receiver {value}. | |
1243 if (value->IsJSValue()) { | |
1244 value = handle(Handle<JSValue>::cast(value)->value(), isolate); | |
1245 } | |
1246 if (!value->IsNumber()) { | |
1247 THROW_NEW_ERROR_RETURN_FAILURE( | |
1248 isolate, NewTypeError(MessageTemplate::kNotGeneric, | |
1249 isolate->factory()->NewStringFromAsciiChecked( | |
1250 "Number.prototype.toString"))); | |
1251 } | |
1252 double const value_number = value->Number(); | |
1253 | |
1254 // If no {radix} was specified, just return ToString of {value}. | |
1255 if (radix->IsUndefined(isolate)) { | |
1256 return *isolate->factory()->NumberToString(value); | |
1257 } | |
1258 | |
1259 // Convert the {radix} to an integer first. | |
1260 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, radix, | |
1261 Object::ToInteger(isolate, radix)); | |
1262 double const radix_number = radix->Number(); | |
1263 | |
1264 // If {radix} is 10, just return ToString of {value}. | |
1265 if (radix_number == 10.0) return *isolate->factory()->NumberToString(value); | |
1266 | |
1267 // Make sure the {radix} is within the valid range. | |
1268 if (radix_number < 2.0 || radix_number > 36.0) { | |
1269 THROW_NEW_ERROR_RETURN_FAILURE( | |
1270 isolate, NewRangeError(MessageTemplate::kToRadixFormatRange)); | |
1271 } | |
1272 | |
1273 // Fast case where the result is a one character string. | |
1274 if (IsUint32Double(value_number) && value_number < radix_number) { | |
1275 // Character array used for conversion. | |
1276 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz"; | |
1277 return *isolate->factory()->LookupSingleCharacterStringFromCode( | |
1278 kCharTable[static_cast<uint32_t>(value_number)]); | |
1279 } | |
1280 | |
1281 // Slow case. | |
1282 if (std::isnan(value_number)) return isolate->heap()->nan_string(); | |
1283 if (std::isinf(value_number)) { | |
1284 return (value_number < 0.0) ? isolate->heap()->minus_infinity_string() | |
1285 : isolate->heap()->infinity_string(); | |
1286 } | |
1287 char* const str = | |
1288 DoubleToRadixCString(value_number, static_cast<int>(radix_number)); | |
1289 Handle<String> result = isolate->factory()->NewStringFromAsciiChecked(str); | |
1290 DeleteArray(str); | |
1291 return *result; | |
1292 } | |
1293 | |
1294 // ES6 section 20.1.3.7 Number.prototype.valueOf ( ) | |
1295 void Builtins::Generate_NumberPrototypeValueOf(CodeStubAssembler* assembler) { | |
1296 typedef compiler::Node Node; | |
1297 | |
1298 Node* receiver = assembler->Parameter(0); | |
1299 Node* context = assembler->Parameter(3); | |
1300 | |
1301 Node* result = assembler->ToThisValue( | |
1302 context, receiver, PrimitiveType::kNumber, "Number.prototype.valueOf"); | |
1303 assembler->Return(result); | |
1304 } | |
1305 | |
1306 // ----------------------------------------------------------------------------- | |
1307 // ES6 section 20.2.2 Function Properties of the Math Object | |
1308 | |
1309 // ES6 section - 20.2.2.1 Math.abs ( x ) | |
1310 void Builtins::Generate_MathAbs(CodeStubAssembler* assembler) { | |
1311 using compiler::Node; | |
1312 Node* x = assembler->Parameter(1); | |
1313 Node* context = assembler->Parameter(4); | |
1314 Node* x_value = assembler->TruncateTaggedToFloat64(context, x); | |
1315 Node* value = assembler->Float64Abs(x_value); | |
1316 Node* result = assembler->ChangeFloat64ToTagged(value); | |
1317 assembler->Return(result); | |
1318 } | |
1319 | |
1320 // ES6 section 20.2.2.2 Math.acos ( x ) | |
1321 void Builtins::Generate_MathAcos(CodeStubAssembler* assembler) { | |
1322 using compiler::Node; | |
1323 | |
1324 Node* x = assembler->Parameter(1); | |
1325 Node* context = assembler->Parameter(4); | |
1326 Node* x_value = assembler->TruncateTaggedToFloat64(context, x); | |
1327 Node* value = assembler->Float64Acos(x_value); | |
1328 Node* result = assembler->ChangeFloat64ToTagged(value); | |
1329 assembler->Return(result); | |
1330 } | |
1331 | |
1332 // ES6 section 20.2.2.3 Math.acosh ( x ) | |
1333 void Builtins::Generate_MathAcosh(CodeStubAssembler* assembler) { | |
1334 using compiler::Node; | |
1335 | |
1336 Node* x = assembler->Parameter(1); | |
1337 Node* context = assembler->Parameter(4); | |
1338 Node* x_value = assembler->TruncateTaggedToFloat64(context, x); | |
1339 Node* value = assembler->Float64Acosh(x_value); | |
1340 Node* result = assembler->ChangeFloat64ToTagged(value); | |
1341 assembler->Return(result); | |
1342 } | |
1343 | |
1344 // ES6 section 20.2.2.4 Math.asin ( x ) | |
1345 void Builtins::Generate_MathAsin(CodeStubAssembler* assembler) { | |
1346 using compiler::Node; | |
1347 | |
1348 Node* x = assembler->Parameter(1); | |
1349 Node* context = assembler->Parameter(4); | |
1350 Node* x_value = assembler->TruncateTaggedToFloat64(context, x); | |
1351 Node* value = assembler->Float64Asin(x_value); | |
1352 Node* result = assembler->ChangeFloat64ToTagged(value); | |
1353 assembler->Return(result); | |
1354 } | |
1355 | |
1356 // ES6 section 20.2.2.5 Math.asinh ( x ) | |
1357 void Builtins::Generate_MathAsinh(CodeStubAssembler* assembler) { | |
1358 using compiler::Node; | |
1359 | |
1360 Node* x = assembler->Parameter(1); | |
1361 Node* context = assembler->Parameter(4); | |
1362 Node* x_value = assembler->TruncateTaggedToFloat64(context, x); | |
1363 Node* value = assembler->Float64Asinh(x_value); | |
1364 Node* result = assembler->ChangeFloat64ToTagged(value); | |
1365 assembler->Return(result); | |
1366 } | |
1367 | |
1368 // ES6 section 20.2.2.6 Math.atan ( x ) | |
1369 void Builtins::Generate_MathAtan(CodeStubAssembler* assembler) { | |
1370 using compiler::Node; | |
1371 | |
1372 Node* x = assembler->Parameter(1); | |
1373 Node* context = assembler->Parameter(4); | |
1374 Node* x_value = assembler->TruncateTaggedToFloat64(context, x); | |
1375 Node* value = assembler->Float64Atan(x_value); | |
1376 Node* result = assembler->ChangeFloat64ToTagged(value); | |
1377 assembler->Return(result); | |
1378 } | |
1379 | |
1380 // ES6 section 20.2.2.7 Math.atanh ( x ) | |
1381 void Builtins::Generate_MathAtanh(CodeStubAssembler* assembler) { | |
1382 using compiler::Node; | |
1383 | |
1384 Node* x = assembler->Parameter(1); | |
1385 Node* context = assembler->Parameter(4); | |
1386 Node* x_value = assembler->TruncateTaggedToFloat64(context, x); | |
1387 Node* value = assembler->Float64Atanh(x_value); | |
1388 Node* result = assembler->ChangeFloat64ToTagged(value); | |
1389 assembler->Return(result); | |
1390 } | |
1391 | |
1392 // ES6 section 20.2.2.8 Math.atan2 ( y, x ) | |
1393 void Builtins::Generate_MathAtan2(CodeStubAssembler* assembler) { | |
1394 using compiler::Node; | |
1395 | |
1396 Node* y = assembler->Parameter(1); | |
1397 Node* x = assembler->Parameter(2); | |
1398 Node* context = assembler->Parameter(5); | |
1399 Node* y_value = assembler->TruncateTaggedToFloat64(context, y); | |
1400 Node* x_value = assembler->TruncateTaggedToFloat64(context, x); | |
1401 Node* value = assembler->Float64Atan2(y_value, x_value); | |
1402 Node* result = assembler->ChangeFloat64ToTagged(value); | |
1403 assembler->Return(result); | |
1404 } | |
1405 | |
1406 namespace { | |
1407 | |
1408 void Generate_MathRoundingOperation( | |
1409 CodeStubAssembler* assembler, | |
1410 compiler::Node* (CodeStubAssembler::*float64op)(compiler::Node*)) { | |
1411 typedef CodeStubAssembler::Label Label; | |
1412 typedef compiler::Node Node; | |
1413 typedef CodeStubAssembler::Variable Variable; | |
1414 | |
1415 Node* context = assembler->Parameter(4); | |
1416 | |
1417 // We might need to loop once for ToNumber conversion. | |
1418 Variable var_x(assembler, MachineRepresentation::kTagged); | |
1419 Label loop(assembler, &var_x); | |
1420 var_x.Bind(assembler->Parameter(1)); | |
1421 assembler->Goto(&loop); | |
1422 assembler->Bind(&loop); | |
1423 { | |
1424 // Load the current {x} value. | |
1425 Node* x = var_x.value(); | |
1426 | |
1427 // Check if {x} is a Smi or a HeapObject. | |
1428 Label if_xissmi(assembler), if_xisnotsmi(assembler); | |
1429 assembler->Branch(assembler->WordIsSmi(x), &if_xissmi, &if_xisnotsmi); | |
1430 | |
1431 assembler->Bind(&if_xissmi); | |
1432 { | |
1433 // Nothing to do when {x} is a Smi. | |
1434 assembler->Return(x); | |
1435 } | |
1436 | |
1437 assembler->Bind(&if_xisnotsmi); | |
1438 { | |
1439 // Check if {x} is a HeapNumber. | |
1440 Label if_xisheapnumber(assembler), | |
1441 if_xisnotheapnumber(assembler, Label::kDeferred); | |
1442 assembler->Branch( | |
1443 assembler->WordEqual(assembler->LoadMap(x), | |
1444 assembler->HeapNumberMapConstant()), | |
1445 &if_xisheapnumber, &if_xisnotheapnumber); | |
1446 | |
1447 assembler->Bind(&if_xisheapnumber); | |
1448 { | |
1449 Node* x_value = assembler->LoadHeapNumberValue(x); | |
1450 Node* value = (assembler->*float64op)(x_value); | |
1451 Node* result = assembler->ChangeFloat64ToTagged(value); | |
1452 assembler->Return(result); | |
1453 } | |
1454 | |
1455 assembler->Bind(&if_xisnotheapnumber); | |
1456 { | |
1457 // Need to convert {x} to a Number first. | |
1458 Callable callable = | |
1459 CodeFactory::NonNumberToNumber(assembler->isolate()); | |
1460 var_x.Bind(assembler->CallStub(callable, context, x)); | |
1461 assembler->Goto(&loop); | |
1462 } | |
1463 } | |
1464 } | |
1465 } | |
1466 | |
1467 } // namespace | |
1468 | |
1469 // ES6 section 20.2.2.10 Math.ceil ( x ) | |
1470 void Builtins::Generate_MathCeil(CodeStubAssembler* assembler) { | |
1471 Generate_MathRoundingOperation(assembler, &CodeStubAssembler::Float64Ceil); | |
1472 } | |
1473 | |
1474 // ES6 section 20.2.2.9 Math.cbrt ( x ) | |
1475 void Builtins::Generate_MathCbrt(CodeStubAssembler* assembler) { | |
1476 using compiler::Node; | |
1477 | |
1478 Node* x = assembler->Parameter(1); | |
1479 Node* context = assembler->Parameter(4); | |
1480 Node* x_value = assembler->TruncateTaggedToFloat64(context, x); | |
1481 Node* value = assembler->Float64Cbrt(x_value); | |
1482 Node* result = assembler->ChangeFloat64ToTagged(value); | |
1483 assembler->Return(result); | |
1484 } | |
1485 | |
1486 // ES6 section 20.2.2.11 Math.clz32 ( x ) | |
1487 void Builtins::Generate_MathClz32(CodeStubAssembler* assembler) { | |
1488 typedef CodeStubAssembler::Label Label; | |
1489 typedef compiler::Node Node; | |
1490 typedef CodeStubAssembler::Variable Variable; | |
1491 | |
1492 Node* context = assembler->Parameter(4); | |
1493 | |
1494 // Shared entry point for the clz32 operation. | |
1495 Variable var_clz32_x(assembler, MachineRepresentation::kWord32); | |
1496 Label do_clz32(assembler); | |
1497 | |
1498 // We might need to loop once for ToNumber conversion. | |
1499 Variable var_x(assembler, MachineRepresentation::kTagged); | |
1500 Label loop(assembler, &var_x); | |
1501 var_x.Bind(assembler->Parameter(1)); | |
1502 assembler->Goto(&loop); | |
1503 assembler->Bind(&loop); | |
1504 { | |
1505 // Load the current {x} value. | |
1506 Node* x = var_x.value(); | |
1507 | |
1508 // Check if {x} is a Smi or a HeapObject. | |
1509 Label if_xissmi(assembler), if_xisnotsmi(assembler); | |
1510 assembler->Branch(assembler->WordIsSmi(x), &if_xissmi, &if_xisnotsmi); | |
1511 | |
1512 assembler->Bind(&if_xissmi); | |
1513 { | |
1514 var_clz32_x.Bind(assembler->SmiToWord32(x)); | |
1515 assembler->Goto(&do_clz32); | |
1516 } | |
1517 | |
1518 assembler->Bind(&if_xisnotsmi); | |
1519 { | |
1520 // Check if {x} is a HeapNumber. | |
1521 Label if_xisheapnumber(assembler), | |
1522 if_xisnotheapnumber(assembler, Label::kDeferred); | |
1523 assembler->Branch( | |
1524 assembler->WordEqual(assembler->LoadMap(x), | |
1525 assembler->HeapNumberMapConstant()), | |
1526 &if_xisheapnumber, &if_xisnotheapnumber); | |
1527 | |
1528 assembler->Bind(&if_xisheapnumber); | |
1529 { | |
1530 var_clz32_x.Bind(assembler->TruncateHeapNumberValueToWord32(x)); | |
1531 assembler->Goto(&do_clz32); | |
1532 } | |
1533 | |
1534 assembler->Bind(&if_xisnotheapnumber); | |
1535 { | |
1536 // Need to convert {x} to a Number first. | |
1537 Callable callable = | |
1538 CodeFactory::NonNumberToNumber(assembler->isolate()); | |
1539 var_x.Bind(assembler->CallStub(callable, context, x)); | |
1540 assembler->Goto(&loop); | |
1541 } | |
1542 } | |
1543 } | |
1544 | |
1545 assembler->Bind(&do_clz32); | |
1546 { | |
1547 Node* x_value = var_clz32_x.value(); | |
1548 Node* value = assembler->Word32Clz(x_value); | |
1549 Node* result = assembler->ChangeInt32ToTagged(value); | |
1550 assembler->Return(result); | |
1551 } | |
1552 } | |
1553 | |
1554 // ES6 section 20.2.2.12 Math.cos ( x ) | |
1555 void Builtins::Generate_MathCos(CodeStubAssembler* assembler) { | |
1556 using compiler::Node; | |
1557 | |
1558 Node* x = assembler->Parameter(1); | |
1559 Node* context = assembler->Parameter(4); | |
1560 Node* x_value = assembler->TruncateTaggedToFloat64(context, x); | |
1561 Node* value = assembler->Float64Cos(x_value); | |
1562 Node* result = assembler->ChangeFloat64ToTagged(value); | |
1563 assembler->Return(result); | |
1564 } | |
1565 | |
1566 // ES6 section 20.2.2.13 Math.cosh ( x ) | |
1567 void Builtins::Generate_MathCosh(CodeStubAssembler* assembler) { | |
1568 using compiler::Node; | |
1569 | |
1570 Node* x = assembler->Parameter(1); | |
1571 Node* context = assembler->Parameter(4); | |
1572 Node* x_value = assembler->TruncateTaggedToFloat64(context, x); | |
1573 Node* value = assembler->Float64Cosh(x_value); | |
1574 Node* result = assembler->ChangeFloat64ToTagged(value); | |
1575 assembler->Return(result); | |
1576 } | |
1577 | |
1578 // ES6 section 20.2.2.14 Math.exp ( x ) | |
1579 void Builtins::Generate_MathExp(CodeStubAssembler* assembler) { | |
1580 using compiler::Node; | |
1581 | |
1582 Node* x = assembler->Parameter(1); | |
1583 Node* context = assembler->Parameter(4); | |
1584 Node* x_value = assembler->TruncateTaggedToFloat64(context, x); | |
1585 Node* value = assembler->Float64Exp(x_value); | |
1586 Node* result = assembler->ChangeFloat64ToTagged(value); | |
1587 assembler->Return(result); | |
1588 } | |
1589 | |
1590 // ES6 section 20.2.2.16 Math.floor ( x ) | |
1591 void Builtins::Generate_MathFloor(CodeStubAssembler* assembler) { | |
1592 Generate_MathRoundingOperation(assembler, &CodeStubAssembler::Float64Floor); | |
1593 } | |
1594 | |
1595 // ES6 section 20.2.2.17 Math.fround ( x ) | |
1596 void Builtins::Generate_MathFround(CodeStubAssembler* assembler) { | |
1597 using compiler::Node; | |
1598 | |
1599 Node* x = assembler->Parameter(1); | |
1600 Node* context = assembler->Parameter(4); | |
1601 Node* x_value = assembler->TruncateTaggedToFloat64(context, x); | |
1602 Node* value32 = assembler->TruncateFloat64ToFloat32(x_value); | |
1603 Node* value = assembler->ChangeFloat32ToFloat64(value32); | |
1604 Node* result = assembler->ChangeFloat64ToTagged(value); | |
1605 assembler->Return(result); | |
1606 } | |
1607 | |
1608 // ES6 section 20.2.2.18 Math.hypot ( value1, value2, ...values ) | |
1609 BUILTIN(MathHypot) { | |
1610 HandleScope scope(isolate); | |
1611 int const length = args.length() - 1; | |
1612 if (length == 0) return Smi::FromInt(0); | |
1613 DCHECK_LT(0, length); | |
1614 double max = 0; | |
1615 bool one_arg_is_nan = false; | |
1616 List<double> abs_values(length); | |
1617 for (int i = 0; i < length; i++) { | |
1618 Handle<Object> x = args.at<Object>(i + 1); | |
1619 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, x, Object::ToNumber(x)); | |
1620 double abs_value = std::abs(x->Number()); | |
1621 | |
1622 if (std::isnan(abs_value)) { | |
1623 one_arg_is_nan = true; | |
1624 } else { | |
1625 abs_values.Add(abs_value); | |
1626 if (max < abs_value) { | |
1627 max = abs_value; | |
1628 } | |
1629 } | |
1630 } | |
1631 | |
1632 if (max == V8_INFINITY) { | |
1633 return *isolate->factory()->NewNumber(V8_INFINITY); | |
1634 } | |
1635 | |
1636 if (one_arg_is_nan) { | |
1637 return *isolate->factory()->nan_value(); | |
1638 } | |
1639 | |
1640 if (max == 0) { | |
1641 return Smi::FromInt(0); | |
1642 } | |
1643 DCHECK_GT(max, 0); | |
1644 | |
1645 // Kahan summation to avoid rounding errors. | |
1646 // Normalize the numbers to the largest one to avoid overflow. | |
1647 double sum = 0; | |
1648 double compensation = 0; | |
1649 for (int i = 0; i < length; i++) { | |
1650 double n = abs_values.at(i) / max; | |
1651 double summand = n * n - compensation; | |
1652 double preliminary = sum + summand; | |
1653 compensation = (preliminary - sum) - summand; | |
1654 sum = preliminary; | |
1655 } | |
1656 | |
1657 return *isolate->factory()->NewNumber(std::sqrt(sum) * max); | |
1658 } | |
1659 | |
1660 // ES6 section 20.2.2.19 Math.imul ( x, y ) | |
1661 void Builtins::Generate_MathImul(CodeStubAssembler* assembler) { | |
1662 using compiler::Node; | |
1663 | |
1664 Node* x = assembler->Parameter(1); | |
1665 Node* y = assembler->Parameter(2); | |
1666 Node* context = assembler->Parameter(5); | |
1667 Node* x_value = assembler->TruncateTaggedToWord32(context, x); | |
1668 Node* y_value = assembler->TruncateTaggedToWord32(context, y); | |
1669 Node* value = assembler->Int32Mul(x_value, y_value); | |
1670 Node* result = assembler->ChangeInt32ToTagged(value); | |
1671 assembler->Return(result); | |
1672 } | |
1673 | |
1674 // ES6 section 20.2.2.20 Math.log ( x ) | |
1675 void Builtins::Generate_MathLog(CodeStubAssembler* assembler) { | |
1676 using compiler::Node; | |
1677 | |
1678 Node* x = assembler->Parameter(1); | |
1679 Node* context = assembler->Parameter(4); | |
1680 Node* x_value = assembler->TruncateTaggedToFloat64(context, x); | |
1681 Node* value = assembler->Float64Log(x_value); | |
1682 Node* result = assembler->ChangeFloat64ToTagged(value); | |
1683 assembler->Return(result); | |
1684 } | |
1685 | |
1686 // ES6 section 20.2.2.21 Math.log1p ( x ) | |
1687 void Builtins::Generate_MathLog1p(CodeStubAssembler* assembler) { | |
1688 using compiler::Node; | |
1689 | |
1690 Node* x = assembler->Parameter(1); | |
1691 Node* context = assembler->Parameter(4); | |
1692 Node* x_value = assembler->TruncateTaggedToFloat64(context, x); | |
1693 Node* value = assembler->Float64Log1p(x_value); | |
1694 Node* result = assembler->ChangeFloat64ToTagged(value); | |
1695 assembler->Return(result); | |
1696 } | |
1697 | |
1698 // ES6 section 20.2.2.22 Math.log10 ( x ) | |
1699 void Builtins::Generate_MathLog10(CodeStubAssembler* assembler) { | |
1700 using compiler::Node; | |
1701 | |
1702 Node* x = assembler->Parameter(1); | |
1703 Node* context = assembler->Parameter(4); | |
1704 Node* x_value = assembler->TruncateTaggedToFloat64(context, x); | |
1705 Node* value = assembler->Float64Log10(x_value); | |
1706 Node* result = assembler->ChangeFloat64ToTagged(value); | |
1707 assembler->Return(result); | |
1708 } | |
1709 | |
1710 // ES6 section 20.2.2.23 Math.log2 ( x ) | |
1711 void Builtins::Generate_MathLog2(CodeStubAssembler* assembler) { | |
1712 using compiler::Node; | |
1713 | |
1714 Node* x = assembler->Parameter(1); | |
1715 Node* context = assembler->Parameter(4); | |
1716 Node* x_value = assembler->TruncateTaggedToFloat64(context, x); | |
1717 Node* value = assembler->Float64Log2(x_value); | |
1718 Node* result = assembler->ChangeFloat64ToTagged(value); | |
1719 assembler->Return(result); | |
1720 } | |
1721 | |
1722 // ES6 section 20.2.2.15 Math.expm1 ( x ) | |
1723 void Builtins::Generate_MathExpm1(CodeStubAssembler* assembler) { | |
1724 using compiler::Node; | |
1725 | |
1726 Node* x = assembler->Parameter(1); | |
1727 Node* context = assembler->Parameter(4); | |
1728 Node* x_value = assembler->TruncateTaggedToFloat64(context, x); | |
1729 Node* value = assembler->Float64Expm1(x_value); | |
1730 Node* result = assembler->ChangeFloat64ToTagged(value); | |
1731 assembler->Return(result); | |
1732 } | |
1733 | |
1734 // ES6 section 20.2.2.26 Math.pow ( x, y ) | |
1735 void Builtins::Generate_MathPow(CodeStubAssembler* assembler) { | |
1736 using compiler::Node; | |
1737 | |
1738 Node* x = assembler->Parameter(1); | |
1739 Node* y = assembler->Parameter(2); | |
1740 Node* context = assembler->Parameter(5); | |
1741 Node* x_value = assembler->TruncateTaggedToFloat64(context, x); | |
1742 Node* y_value = assembler->TruncateTaggedToFloat64(context, y); | |
1743 Node* value = assembler->Float64Pow(x_value, y_value); | |
1744 Node* result = assembler->ChangeFloat64ToTagged(value); | |
1745 assembler->Return(result); | |
1746 } | |
1747 | |
1748 // ES6 section 20.2.2.28 Math.round ( x ) | |
1749 void Builtins::Generate_MathRound(CodeStubAssembler* assembler) { | |
1750 Generate_MathRoundingOperation(assembler, &CodeStubAssembler::Float64Round); | |
1751 } | |
1752 | |
1753 // ES6 section 20.2.2.29 Math.sign ( x ) | |
1754 void Builtins::Generate_MathSign(CodeStubAssembler* assembler) { | |
1755 typedef CodeStubAssembler::Label Label; | |
1756 using compiler::Node; | |
1757 | |
1758 // Convert the {x} value to a Number. | |
1759 Node* x = assembler->Parameter(1); | |
1760 Node* context = assembler->Parameter(4); | |
1761 Node* x_value = assembler->TruncateTaggedToFloat64(context, x); | |
1762 | |
1763 // Return -1 if {x} is negative, 1 if {x} is positive, or {x} itself. | |
1764 Label if_xisnegative(assembler), if_xispositive(assembler); | |
1765 assembler->GotoIf( | |
1766 assembler->Float64LessThan(x_value, assembler->Float64Constant(0.0)), | |
1767 &if_xisnegative); | |
1768 assembler->GotoIf( | |
1769 assembler->Float64LessThan(assembler->Float64Constant(0.0), x_value), | |
1770 &if_xispositive); | |
1771 assembler->Return(assembler->ChangeFloat64ToTagged(x_value)); | |
1772 | |
1773 assembler->Bind(&if_xisnegative); | |
1774 assembler->Return(assembler->SmiConstant(Smi::FromInt(-1))); | |
1775 | |
1776 assembler->Bind(&if_xispositive); | |
1777 assembler->Return(assembler->SmiConstant(Smi::FromInt(1))); | |
1778 } | |
1779 | |
1780 // ES6 section 20.2.2.30 Math.sin ( x ) | |
1781 void Builtins::Generate_MathSin(CodeStubAssembler* assembler) { | |
1782 using compiler::Node; | |
1783 | |
1784 Node* x = assembler->Parameter(1); | |
1785 Node* context = assembler->Parameter(4); | |
1786 Node* x_value = assembler->TruncateTaggedToFloat64(context, x); | |
1787 Node* value = assembler->Float64Sin(x_value); | |
1788 Node* result = assembler->ChangeFloat64ToTagged(value); | |
1789 assembler->Return(result); | |
1790 } | |
1791 | |
1792 // ES6 section 20.2.2.31 Math.sinh ( x ) | |
1793 void Builtins::Generate_MathSinh(CodeStubAssembler* assembler) { | |
1794 using compiler::Node; | |
1795 | |
1796 Node* x = assembler->Parameter(1); | |
1797 Node* context = assembler->Parameter(4); | |
1798 Node* x_value = assembler->TruncateTaggedToFloat64(context, x); | |
1799 Node* value = assembler->Float64Sinh(x_value); | |
1800 Node* result = assembler->ChangeFloat64ToTagged(value); | |
1801 assembler->Return(result); | |
1802 } | |
1803 | |
1804 // ES6 section 20.2.2.32 Math.sqrt ( x ) | |
1805 void Builtins::Generate_MathSqrt(CodeStubAssembler* assembler) { | |
1806 using compiler::Node; | |
1807 | |
1808 Node* x = assembler->Parameter(1); | |
1809 Node* context = assembler->Parameter(4); | |
1810 Node* x_value = assembler->TruncateTaggedToFloat64(context, x); | |
1811 Node* value = assembler->Float64Sqrt(x_value); | |
1812 Node* result = assembler->ChangeFloat64ToTagged(value); | |
1813 assembler->Return(result); | |
1814 } | |
1815 | |
1816 // ES6 section 20.2.2.33 Math.tan ( x ) | |
1817 void Builtins::Generate_MathTan(CodeStubAssembler* assembler) { | |
1818 using compiler::Node; | |
1819 | |
1820 Node* x = assembler->Parameter(1); | |
1821 Node* context = assembler->Parameter(4); | |
1822 Node* x_value = assembler->TruncateTaggedToFloat64(context, x); | |
1823 Node* value = assembler->Float64Tan(x_value); | |
1824 Node* result = assembler->ChangeFloat64ToTagged(value); | |
1825 assembler->Return(result); | |
1826 } | |
1827 | |
1828 // ES6 section 20.2.2.34 Math.tanh ( x ) | |
1829 void Builtins::Generate_MathTanh(CodeStubAssembler* assembler) { | |
1830 using compiler::Node; | |
1831 | |
1832 Node* x = assembler->Parameter(1); | |
1833 Node* context = assembler->Parameter(4); | |
1834 Node* x_value = assembler->TruncateTaggedToFloat64(context, x); | |
1835 Node* value = assembler->Float64Tanh(x_value); | |
1836 Node* result = assembler->ChangeFloat64ToTagged(value); | |
1837 assembler->Return(result); | |
1838 } | |
1839 | |
1840 // ES6 section 20.2.2.35 Math.trunc ( x ) | |
1841 void Builtins::Generate_MathTrunc(CodeStubAssembler* assembler) { | |
1842 Generate_MathRoundingOperation(assembler, &CodeStubAssembler::Float64Trunc); | |
1843 } | |
1844 | |
1845 // ----------------------------------------------------------------------------- | 24 // ----------------------------------------------------------------------------- |
1846 // ES6 section 19.2 Function Objects | 25 // ES6 section 19.2 Function Objects |
1847 | 26 |
1848 // ES6 section 19.2.3.6 Function.prototype [ @@hasInstance ] ( V ) | 27 // ES6 section 19.2.3.6 Function.prototype [ @@hasInstance ] ( V ) |
1849 void Builtins::Generate_FunctionPrototypeHasInstance( | 28 void Builtins::Generate_FunctionPrototypeHasInstance( |
1850 CodeStubAssembler* assembler) { | 29 CodeStubAssembler* assembler) { |
1851 using compiler::Node; | 30 using compiler::Node; |
1852 | 31 |
1853 Node* f = assembler->Parameter(0); | 32 Node* f = assembler->Parameter(0); |
1854 Node* v = assembler->Parameter(1); | 33 Node* v = assembler->Parameter(1); |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1956 "[Generator].prototype.return"); | 135 "[Generator].prototype.return"); |
1957 } | 136 } |
1958 | 137 |
1959 // ES6 section 25.3.1.4 Generator.prototype.throw ( exception ) | 138 // ES6 section 25.3.1.4 Generator.prototype.throw ( exception ) |
1960 void Builtins::Generate_GeneratorPrototypeThrow(CodeStubAssembler* assembler) { | 139 void Builtins::Generate_GeneratorPrototypeThrow(CodeStubAssembler* assembler) { |
1961 Generate_GeneratorPrototypeResume(assembler, JSGeneratorObject::kThrow, | 140 Generate_GeneratorPrototypeResume(assembler, JSGeneratorObject::kThrow, |
1962 "[Generator].prototype.throw"); | 141 "[Generator].prototype.throw"); |
1963 } | 142 } |
1964 | 143 |
1965 // ----------------------------------------------------------------------------- | 144 // ----------------------------------------------------------------------------- |
1966 // ES6 section 26.1 The Reflect Object | |
1967 | |
1968 // ES6 section 26.1.3 Reflect.defineProperty | |
1969 BUILTIN(ReflectDefineProperty) { | |
1970 HandleScope scope(isolate); | |
1971 DCHECK_EQ(4, args.length()); | |
1972 Handle<Object> target = args.at<Object>(1); | |
1973 Handle<Object> key = args.at<Object>(2); | |
1974 Handle<Object> attributes = args.at<Object>(3); | |
1975 | |
1976 if (!target->IsJSReceiver()) { | |
1977 THROW_NEW_ERROR_RETURN_FAILURE( | |
1978 isolate, NewTypeError(MessageTemplate::kCalledOnNonObject, | |
1979 isolate->factory()->NewStringFromAsciiChecked( | |
1980 "Reflect.defineProperty"))); | |
1981 } | |
1982 | |
1983 Handle<Name> name; | |
1984 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name, | |
1985 Object::ToName(isolate, key)); | |
1986 | |
1987 PropertyDescriptor desc; | |
1988 if (!PropertyDescriptor::ToPropertyDescriptor(isolate, attributes, &desc)) { | |
1989 return isolate->heap()->exception(); | |
1990 } | |
1991 | |
1992 Maybe<bool> result = | |
1993 JSReceiver::DefineOwnProperty(isolate, Handle<JSReceiver>::cast(target), | |
1994 name, &desc, Object::DONT_THROW); | |
1995 MAYBE_RETURN(result, isolate->heap()->exception()); | |
1996 return *isolate->factory()->ToBoolean(result.FromJust()); | |
1997 } | |
1998 | |
1999 // ES6 section 26.1.4 Reflect.deleteProperty | |
2000 BUILTIN(ReflectDeleteProperty) { | |
2001 HandleScope scope(isolate); | |
2002 DCHECK_EQ(3, args.length()); | |
2003 Handle<Object> target = args.at<Object>(1); | |
2004 Handle<Object> key = args.at<Object>(2); | |
2005 | |
2006 if (!target->IsJSReceiver()) { | |
2007 THROW_NEW_ERROR_RETURN_FAILURE( | |
2008 isolate, NewTypeError(MessageTemplate::kCalledOnNonObject, | |
2009 isolate->factory()->NewStringFromAsciiChecked( | |
2010 "Reflect.deleteProperty"))); | |
2011 } | |
2012 | |
2013 Handle<Name> name; | |
2014 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name, | |
2015 Object::ToName(isolate, key)); | |
2016 | |
2017 Maybe<bool> result = JSReceiver::DeletePropertyOrElement( | |
2018 Handle<JSReceiver>::cast(target), name, SLOPPY); | |
2019 MAYBE_RETURN(result, isolate->heap()->exception()); | |
2020 return *isolate->factory()->ToBoolean(result.FromJust()); | |
2021 } | |
2022 | |
2023 // ES6 section 26.1.6 Reflect.get | |
2024 BUILTIN(ReflectGet) { | |
2025 HandleScope scope(isolate); | |
2026 Handle<Object> target = args.atOrUndefined(isolate, 1); | |
2027 Handle<Object> key = args.atOrUndefined(isolate, 2); | |
2028 Handle<Object> receiver = args.length() > 3 ? args.at<Object>(3) : target; | |
2029 | |
2030 if (!target->IsJSReceiver()) { | |
2031 THROW_NEW_ERROR_RETURN_FAILURE( | |
2032 isolate, NewTypeError(MessageTemplate::kCalledOnNonObject, | |
2033 isolate->factory()->NewStringFromAsciiChecked( | |
2034 "Reflect.get"))); | |
2035 } | |
2036 | |
2037 Handle<Name> name; | |
2038 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name, | |
2039 Object::ToName(isolate, key)); | |
2040 | |
2041 RETURN_RESULT_OR_FAILURE( | |
2042 isolate, Object::GetPropertyOrElement(receiver, name, | |
2043 Handle<JSReceiver>::cast(target))); | |
2044 } | |
2045 | |
2046 // ES6 section 26.1.7 Reflect.getOwnPropertyDescriptor | |
2047 BUILTIN(ReflectGetOwnPropertyDescriptor) { | |
2048 HandleScope scope(isolate); | |
2049 DCHECK_EQ(3, args.length()); | |
2050 Handle<Object> target = args.at<Object>(1); | |
2051 Handle<Object> key = args.at<Object>(2); | |
2052 | |
2053 if (!target->IsJSReceiver()) { | |
2054 THROW_NEW_ERROR_RETURN_FAILURE( | |
2055 isolate, NewTypeError(MessageTemplate::kCalledOnNonObject, | |
2056 isolate->factory()->NewStringFromAsciiChecked( | |
2057 "Reflect.getOwnPropertyDescriptor"))); | |
2058 } | |
2059 | |
2060 Handle<Name> name; | |
2061 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name, | |
2062 Object::ToName(isolate, key)); | |
2063 | |
2064 PropertyDescriptor desc; | |
2065 Maybe<bool> found = JSReceiver::GetOwnPropertyDescriptor( | |
2066 isolate, Handle<JSReceiver>::cast(target), name, &desc); | |
2067 MAYBE_RETURN(found, isolate->heap()->exception()); | |
2068 if (!found.FromJust()) return isolate->heap()->undefined_value(); | |
2069 return *desc.ToObject(isolate); | |
2070 } | |
2071 | |
2072 // ES6 section 26.1.8 Reflect.getPrototypeOf | |
2073 BUILTIN(ReflectGetPrototypeOf) { | |
2074 HandleScope scope(isolate); | |
2075 DCHECK_EQ(2, args.length()); | |
2076 Handle<Object> target = args.at<Object>(1); | |
2077 | |
2078 if (!target->IsJSReceiver()) { | |
2079 THROW_NEW_ERROR_RETURN_FAILURE( | |
2080 isolate, NewTypeError(MessageTemplate::kCalledOnNonObject, | |
2081 isolate->factory()->NewStringFromAsciiChecked( | |
2082 "Reflect.getPrototypeOf"))); | |
2083 } | |
2084 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(target); | |
2085 RETURN_RESULT_OR_FAILURE(isolate, | |
2086 JSReceiver::GetPrototype(isolate, receiver)); | |
2087 } | |
2088 | |
2089 // ES6 section 26.1.9 Reflect.has | |
2090 BUILTIN(ReflectHas) { | |
2091 HandleScope scope(isolate); | |
2092 DCHECK_EQ(3, args.length()); | |
2093 Handle<Object> target = args.at<Object>(1); | |
2094 Handle<Object> key = args.at<Object>(2); | |
2095 | |
2096 if (!target->IsJSReceiver()) { | |
2097 THROW_NEW_ERROR_RETURN_FAILURE( | |
2098 isolate, NewTypeError(MessageTemplate::kCalledOnNonObject, | |
2099 isolate->factory()->NewStringFromAsciiChecked( | |
2100 "Reflect.has"))); | |
2101 } | |
2102 | |
2103 Handle<Name> name; | |
2104 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name, | |
2105 Object::ToName(isolate, key)); | |
2106 | |
2107 Maybe<bool> result = | |
2108 JSReceiver::HasProperty(Handle<JSReceiver>::cast(target), name); | |
2109 return result.IsJust() ? *isolate->factory()->ToBoolean(result.FromJust()) | |
2110 : isolate->heap()->exception(); | |
2111 } | |
2112 | |
2113 // ES6 section 26.1.10 Reflect.isExtensible | |
2114 BUILTIN(ReflectIsExtensible) { | |
2115 HandleScope scope(isolate); | |
2116 DCHECK_EQ(2, args.length()); | |
2117 Handle<Object> target = args.at<Object>(1); | |
2118 | |
2119 if (!target->IsJSReceiver()) { | |
2120 THROW_NEW_ERROR_RETURN_FAILURE( | |
2121 isolate, NewTypeError(MessageTemplate::kCalledOnNonObject, | |
2122 isolate->factory()->NewStringFromAsciiChecked( | |
2123 "Reflect.isExtensible"))); | |
2124 } | |
2125 | |
2126 Maybe<bool> result = | |
2127 JSReceiver::IsExtensible(Handle<JSReceiver>::cast(target)); | |
2128 MAYBE_RETURN(result, isolate->heap()->exception()); | |
2129 return *isolate->factory()->ToBoolean(result.FromJust()); | |
2130 } | |
2131 | |
2132 // ES6 section 26.1.11 Reflect.ownKeys | |
2133 BUILTIN(ReflectOwnKeys) { | |
2134 HandleScope scope(isolate); | |
2135 DCHECK_EQ(2, args.length()); | |
2136 Handle<Object> target = args.at<Object>(1); | |
2137 | |
2138 if (!target->IsJSReceiver()) { | |
2139 THROW_NEW_ERROR_RETURN_FAILURE( | |
2140 isolate, NewTypeError(MessageTemplate::kCalledOnNonObject, | |
2141 isolate->factory()->NewStringFromAsciiChecked( | |
2142 "Reflect.ownKeys"))); | |
2143 } | |
2144 | |
2145 Handle<FixedArray> keys; | |
2146 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
2147 isolate, keys, | |
2148 KeyAccumulator::GetKeys(Handle<JSReceiver>::cast(target), | |
2149 KeyCollectionMode::kOwnOnly, ALL_PROPERTIES, | |
2150 GetKeysConversion::kConvertToString)); | |
2151 return *isolate->factory()->NewJSArrayWithElements(keys); | |
2152 } | |
2153 | |
2154 // ES6 section 26.1.12 Reflect.preventExtensions | |
2155 BUILTIN(ReflectPreventExtensions) { | |
2156 HandleScope scope(isolate); | |
2157 DCHECK_EQ(2, args.length()); | |
2158 Handle<Object> target = args.at<Object>(1); | |
2159 | |
2160 if (!target->IsJSReceiver()) { | |
2161 THROW_NEW_ERROR_RETURN_FAILURE( | |
2162 isolate, NewTypeError(MessageTemplate::kCalledOnNonObject, | |
2163 isolate->factory()->NewStringFromAsciiChecked( | |
2164 "Reflect.preventExtensions"))); | |
2165 } | |
2166 | |
2167 Maybe<bool> result = JSReceiver::PreventExtensions( | |
2168 Handle<JSReceiver>::cast(target), Object::DONT_THROW); | |
2169 MAYBE_RETURN(result, isolate->heap()->exception()); | |
2170 return *isolate->factory()->ToBoolean(result.FromJust()); | |
2171 } | |
2172 | |
2173 // ES6 section 26.1.13 Reflect.set | |
2174 BUILTIN(ReflectSet) { | |
2175 HandleScope scope(isolate); | |
2176 Handle<Object> target = args.atOrUndefined(isolate, 1); | |
2177 Handle<Object> key = args.atOrUndefined(isolate, 2); | |
2178 Handle<Object> value = args.atOrUndefined(isolate, 3); | |
2179 Handle<Object> receiver = args.length() > 4 ? args.at<Object>(4) : target; | |
2180 | |
2181 if (!target->IsJSReceiver()) { | |
2182 THROW_NEW_ERROR_RETURN_FAILURE( | |
2183 isolate, NewTypeError(MessageTemplate::kCalledOnNonObject, | |
2184 isolate->factory()->NewStringFromAsciiChecked( | |
2185 "Reflect.set"))); | |
2186 } | |
2187 | |
2188 Handle<Name> name; | |
2189 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name, | |
2190 Object::ToName(isolate, key)); | |
2191 | |
2192 LookupIterator it = LookupIterator::PropertyOrElement( | |
2193 isolate, receiver, name, Handle<JSReceiver>::cast(target)); | |
2194 Maybe<bool> result = Object::SetSuperProperty( | |
2195 &it, value, SLOPPY, Object::MAY_BE_STORE_FROM_KEYED); | |
2196 MAYBE_RETURN(result, isolate->heap()->exception()); | |
2197 return *isolate->factory()->ToBoolean(result.FromJust()); | |
2198 } | |
2199 | |
2200 // ES6 section 26.1.14 Reflect.setPrototypeOf | |
2201 BUILTIN(ReflectSetPrototypeOf) { | |
2202 HandleScope scope(isolate); | |
2203 DCHECK_EQ(3, args.length()); | |
2204 Handle<Object> target = args.at<Object>(1); | |
2205 Handle<Object> proto = args.at<Object>(2); | |
2206 | |
2207 if (!target->IsJSReceiver()) { | |
2208 THROW_NEW_ERROR_RETURN_FAILURE( | |
2209 isolate, NewTypeError(MessageTemplate::kCalledOnNonObject, | |
2210 isolate->factory()->NewStringFromAsciiChecked( | |
2211 "Reflect.setPrototypeOf"))); | |
2212 } | |
2213 | |
2214 if (!proto->IsJSReceiver() && !proto->IsNull(isolate)) { | |
2215 THROW_NEW_ERROR_RETURN_FAILURE( | |
2216 isolate, NewTypeError(MessageTemplate::kProtoObjectOrNull, proto)); | |
2217 } | |
2218 | |
2219 Maybe<bool> result = JSReceiver::SetPrototype( | |
2220 Handle<JSReceiver>::cast(target), proto, true, Object::DONT_THROW); | |
2221 MAYBE_RETURN(result, isolate->heap()->exception()); | |
2222 return *isolate->factory()->ToBoolean(result.FromJust()); | |
2223 } | |
2224 | |
2225 // ----------------------------------------------------------------------------- | |
2226 // ES6 section 19.3 Boolean Objects | |
2227 | |
2228 // ES6 section 19.3.1.1 Boolean ( value ) for the [[Call]] case. | |
2229 BUILTIN(BooleanConstructor) { | |
2230 HandleScope scope(isolate); | |
2231 Handle<Object> value = args.atOrUndefined(isolate, 1); | |
2232 return isolate->heap()->ToBoolean(value->BooleanValue()); | |
2233 } | |
2234 | |
2235 // ES6 section 19.3.1.1 Boolean ( value ) for the [[Construct]] case. | |
2236 BUILTIN(BooleanConstructor_ConstructStub) { | |
2237 HandleScope scope(isolate); | |
2238 Handle<Object> value = args.atOrUndefined(isolate, 1); | |
2239 Handle<JSFunction> target = args.target<JSFunction>(); | |
2240 Handle<JSReceiver> new_target = Handle<JSReceiver>::cast(args.new_target()); | |
2241 DCHECK(*target == target->native_context()->boolean_function()); | |
2242 Handle<JSObject> result; | |
2243 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, | |
2244 JSObject::New(target, new_target)); | |
2245 Handle<JSValue>::cast(result)->set_value( | |
2246 isolate->heap()->ToBoolean(value->BooleanValue())); | |
2247 return *result; | |
2248 } | |
2249 | |
2250 // ES6 section 19.3.3.2 Boolean.prototype.toString ( ) | |
2251 void Builtins::Generate_BooleanPrototypeToString(CodeStubAssembler* assembler) { | |
2252 typedef compiler::Node Node; | |
2253 | |
2254 Node* receiver = assembler->Parameter(0); | |
2255 Node* context = assembler->Parameter(3); | |
2256 | |
2257 Node* value = assembler->ToThisValue( | |
2258 context, receiver, PrimitiveType::kBoolean, "Boolean.prototype.toString"); | |
2259 Node* result = assembler->LoadObjectField(value, Oddball::kToStringOffset); | |
2260 assembler->Return(result); | |
2261 } | |
2262 | |
2263 // ES6 section 19.3.3.3 Boolean.prototype.valueOf ( ) | |
2264 void Builtins::Generate_BooleanPrototypeValueOf(CodeStubAssembler* assembler) { | |
2265 typedef compiler::Node Node; | |
2266 | |
2267 Node* receiver = assembler->Parameter(0); | |
2268 Node* context = assembler->Parameter(3); | |
2269 | |
2270 Node* result = assembler->ToThisValue( | |
2271 context, receiver, PrimitiveType::kBoolean, "Boolean.prototype.valueOf"); | |
2272 assembler->Return(result); | |
2273 } | |
2274 | |
2275 // ----------------------------------------------------------------------------- | |
2276 // ES6 section 24.2 DataView Objects | |
2277 | |
2278 // ES6 section 24.2.2 The DataView Constructor for the [[Call]] case. | |
2279 BUILTIN(DataViewConstructor) { | |
2280 HandleScope scope(isolate); | |
2281 THROW_NEW_ERROR_RETURN_FAILURE( | |
2282 isolate, | |
2283 NewTypeError(MessageTemplate::kConstructorNotFunction, | |
2284 isolate->factory()->NewStringFromAsciiChecked("DataView"))); | |
2285 } | |
2286 | |
2287 // ES6 section 24.2.2 The DataView Constructor for the [[Construct]] case. | |
2288 BUILTIN(DataViewConstructor_ConstructStub) { | |
2289 HandleScope scope(isolate); | |
2290 Handle<JSFunction> target = args.target<JSFunction>(); | |
2291 Handle<JSReceiver> new_target = Handle<JSReceiver>::cast(args.new_target()); | |
2292 Handle<Object> buffer = args.atOrUndefined(isolate, 1); | |
2293 Handle<Object> byte_offset = args.atOrUndefined(isolate, 2); | |
2294 Handle<Object> byte_length = args.atOrUndefined(isolate, 3); | |
2295 | |
2296 // 2. If Type(buffer) is not Object, throw a TypeError exception. | |
2297 // 3. If buffer does not have an [[ArrayBufferData]] internal slot, throw a | |
2298 // TypeError exception. | |
2299 if (!buffer->IsJSArrayBuffer()) { | |
2300 THROW_NEW_ERROR_RETURN_FAILURE( | |
2301 isolate, NewTypeError(MessageTemplate::kDataViewNotArrayBuffer)); | |
2302 } | |
2303 Handle<JSArrayBuffer> array_buffer = Handle<JSArrayBuffer>::cast(buffer); | |
2304 | |
2305 // 4. Let numberOffset be ? ToNumber(byteOffset). | |
2306 Handle<Object> number_offset; | |
2307 if (byte_offset->IsUndefined(isolate)) { | |
2308 // We intentionally violate the specification at this point to allow | |
2309 // for new DataView(buffer) invocations to be equivalent to the full | |
2310 // new DataView(buffer, 0) invocation. | |
2311 number_offset = handle(Smi::FromInt(0), isolate); | |
2312 } else { | |
2313 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, number_offset, | |
2314 Object::ToNumber(byte_offset)); | |
2315 } | |
2316 | |
2317 // 5. Let offset be ToInteger(numberOffset). | |
2318 Handle<Object> offset; | |
2319 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, offset, | |
2320 Object::ToInteger(isolate, number_offset)); | |
2321 | |
2322 // 6. If numberOffset ≠offset or offset < 0, throw a RangeError exception. | |
2323 if (number_offset->Number() != offset->Number() || offset->Number() < 0.0) { | |
2324 THROW_NEW_ERROR_RETURN_FAILURE( | |
2325 isolate, NewRangeError(MessageTemplate::kInvalidDataViewOffset)); | |
2326 } | |
2327 | |
2328 // 7. If IsDetachedBuffer(buffer) is true, throw a TypeError exception. | |
2329 // We currently violate the specification at this point. | |
2330 | |
2331 // 8. Let bufferByteLength be the value of buffer's [[ArrayBufferByteLength]] | |
2332 // internal slot. | |
2333 double const buffer_byte_length = array_buffer->byte_length()->Number(); | |
2334 | |
2335 // 9. If offset > bufferByteLength, throw a RangeError exception | |
2336 if (offset->Number() > buffer_byte_length) { | |
2337 THROW_NEW_ERROR_RETURN_FAILURE( | |
2338 isolate, NewRangeError(MessageTemplate::kInvalidDataViewOffset)); | |
2339 } | |
2340 | |
2341 Handle<Object> view_byte_length; | |
2342 if (byte_length->IsUndefined(isolate)) { | |
2343 // 10. If byteLength is undefined, then | |
2344 // a. Let viewByteLength be bufferByteLength - offset. | |
2345 view_byte_length = | |
2346 isolate->factory()->NewNumber(buffer_byte_length - offset->Number()); | |
2347 } else { | |
2348 // 11. Else, | |
2349 // a. Let viewByteLength be ? ToLength(byteLength). | |
2350 // b. If offset+viewByteLength > bufferByteLength, throw a RangeError | |
2351 // exception | |
2352 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, view_byte_length, | |
2353 Object::ToLength(isolate, byte_length)); | |
2354 if (offset->Number() + view_byte_length->Number() > buffer_byte_length) { | |
2355 THROW_NEW_ERROR_RETURN_FAILURE( | |
2356 isolate, NewRangeError(MessageTemplate::kInvalidDataViewLength)); | |
2357 } | |
2358 } | |
2359 | |
2360 // 12. Let O be ? OrdinaryCreateFromConstructor(NewTarget, | |
2361 // "%DataViewPrototype%", «[[DataView]], [[ViewedArrayBuffer]], | |
2362 // [[ByteLength]], [[ByteOffset]]»). | |
2363 // 13. Set O's [[DataView]] internal slot to true. | |
2364 Handle<JSObject> result; | |
2365 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, | |
2366 JSObject::New(target, new_target)); | |
2367 for (int i = 0; i < ArrayBufferView::kInternalFieldCount; ++i) { | |
2368 Handle<JSDataView>::cast(result)->SetInternalField(i, Smi::FromInt(0)); | |
2369 } | |
2370 | |
2371 // 14. Set O's [[ViewedArrayBuffer]] internal slot to buffer. | |
2372 Handle<JSDataView>::cast(result)->set_buffer(*array_buffer); | |
2373 | |
2374 // 15. Set O's [[ByteLength]] internal slot to viewByteLength. | |
2375 Handle<JSDataView>::cast(result)->set_byte_length(*view_byte_length); | |
2376 | |
2377 // 16. Set O's [[ByteOffset]] internal slot to offset. | |
2378 Handle<JSDataView>::cast(result)->set_byte_offset(*offset); | |
2379 | |
2380 // 17. Return O. | |
2381 return *result; | |
2382 } | |
2383 | |
2384 // ES6 section 24.2.4.1 get DataView.prototype.buffer | |
2385 BUILTIN(DataViewPrototypeGetBuffer) { | |
2386 HandleScope scope(isolate); | |
2387 CHECK_RECEIVER(JSDataView, data_view, "get DataView.prototype.buffer"); | |
2388 return data_view->buffer(); | |
2389 } | |
2390 | |
2391 // ES6 section 24.2.4.2 get DataView.prototype.byteLength | |
2392 BUILTIN(DataViewPrototypeGetByteLength) { | |
2393 HandleScope scope(isolate); | |
2394 CHECK_RECEIVER(JSDataView, data_view, "get DataView.prototype.byteLength"); | |
2395 // TODO(bmeurer): According to the ES6 spec, we should throw a TypeError | |
2396 // here if the JSArrayBuffer of the {data_view} was neutered. | |
2397 return data_view->byte_length(); | |
2398 } | |
2399 | |
2400 // ES6 section 24.2.4.3 get DataView.prototype.byteOffset | |
2401 BUILTIN(DataViewPrototypeGetByteOffset) { | |
2402 HandleScope scope(isolate); | |
2403 CHECK_RECEIVER(JSDataView, data_view, "get DataView.prototype.byteOffset"); | |
2404 // TODO(bmeurer): According to the ES6 spec, we should throw a TypeError | |
2405 // here if the JSArrayBuffer of the {data_view} was neutered. | |
2406 return data_view->byte_offset(); | |
2407 } | |
2408 | |
2409 // ----------------------------------------------------------------------------- | |
2410 // ES6 section 22.2 TypedArray Objects | |
2411 | |
2412 // ES6 section 22.2.3.1 get %TypedArray%.prototype.buffer | |
2413 BUILTIN(TypedArrayPrototypeBuffer) { | |
2414 HandleScope scope(isolate); | |
2415 CHECK_RECEIVER(JSTypedArray, typed_array, "get TypedArray.prototype.buffer"); | |
2416 return *typed_array->GetBuffer(); | |
2417 } | |
2418 | |
2419 namespace { | |
2420 | |
2421 void Generate_TypedArrayProtoypeGetter(CodeStubAssembler* assembler, | |
2422 const char* method_name, | |
2423 int object_offset) { | |
2424 typedef CodeStubAssembler::Label Label; | |
2425 typedef compiler::Node Node; | |
2426 | |
2427 Node* receiver = assembler->Parameter(0); | |
2428 Node* context = assembler->Parameter(3); | |
2429 | |
2430 // Check if the {receiver} is actually a JSTypedArray. | |
2431 Label if_receiverisincompatible(assembler, Label::kDeferred); | |
2432 assembler->GotoIf(assembler->WordIsSmi(receiver), &if_receiverisincompatible); | |
2433 Node* receiver_instance_type = assembler->LoadInstanceType(receiver); | |
2434 assembler->GotoUnless( | |
2435 assembler->Word32Equal(receiver_instance_type, | |
2436 assembler->Int32Constant(JS_TYPED_ARRAY_TYPE)), | |
2437 &if_receiverisincompatible); | |
2438 | |
2439 // Check if the {receiver}'s JSArrayBuffer was neutered. | |
2440 Node* receiver_buffer = | |
2441 assembler->LoadObjectField(receiver, JSTypedArray::kBufferOffset); | |
2442 Node* receiver_buffer_bit_field = assembler->LoadObjectField( | |
2443 receiver_buffer, JSArrayBuffer::kBitFieldOffset, MachineType::Uint32()); | |
2444 Label if_receiverisneutered(assembler, Label::kDeferred); | |
2445 assembler->GotoUnless( | |
2446 assembler->Word32Equal( | |
2447 assembler->Word32And( | |
2448 receiver_buffer_bit_field, | |
2449 assembler->Int32Constant(JSArrayBuffer::WasNeutered::kMask)), | |
2450 assembler->Int32Constant(0)), | |
2451 &if_receiverisneutered); | |
2452 assembler->Return(assembler->LoadObjectField(receiver, object_offset)); | |
2453 | |
2454 assembler->Bind(&if_receiverisneutered); | |
2455 { | |
2456 // The {receiver}s buffer was neutered, default to zero. | |
2457 assembler->Return(assembler->SmiConstant(0)); | |
2458 } | |
2459 | |
2460 assembler->Bind(&if_receiverisincompatible); | |
2461 { | |
2462 // The {receiver} is not a valid JSGeneratorObject. | |
2463 Node* result = assembler->CallRuntime( | |
2464 Runtime::kThrowIncompatibleMethodReceiver, context, | |
2465 assembler->HeapConstant(assembler->factory()->NewStringFromAsciiChecked( | |
2466 method_name, TENURED)), | |
2467 receiver); | |
2468 assembler->Return(result); // Never reached. | |
2469 } | |
2470 } | |
2471 | |
2472 } // namespace | |
2473 | |
2474 // ES6 section 22.2.3.2 get %TypedArray%.prototype.byteLength | |
2475 void Builtins::Generate_TypedArrayPrototypeByteLength( | |
2476 CodeStubAssembler* assembler) { | |
2477 Generate_TypedArrayProtoypeGetter(assembler, | |
2478 "get TypedArray.prototype.byteLength", | |
2479 JSTypedArray::kByteLengthOffset); | |
2480 } | |
2481 | |
2482 // ES6 section 22.2.3.3 get %TypedArray%.prototype.byteOffset | |
2483 void Builtins::Generate_TypedArrayPrototypeByteOffset( | |
2484 CodeStubAssembler* assembler) { | |
2485 Generate_TypedArrayProtoypeGetter(assembler, | |
2486 "get TypedArray.prototype.byteOffset", | |
2487 JSTypedArray::kByteOffsetOffset); | |
2488 } | |
2489 | |
2490 // ES6 section 22.2.3.18 get %TypedArray%.prototype.length | |
2491 void Builtins::Generate_TypedArrayPrototypeLength( | |
2492 CodeStubAssembler* assembler) { | |
2493 Generate_TypedArrayProtoypeGetter(assembler, | |
2494 "get TypedArray.prototype.length", | |
2495 JSTypedArray::kLengthOffset); | |
2496 } | |
2497 | |
2498 // ----------------------------------------------------------------------------- | |
2499 // ES6 section 20.3 Date Objects | |
2500 | |
2501 namespace { | |
2502 | |
2503 // ES6 section 20.3.1.1 Time Values and Time Range | |
2504 const double kMinYear = -1000000.0; | |
2505 const double kMaxYear = -kMinYear; | |
2506 const double kMinMonth = -10000000.0; | |
2507 const double kMaxMonth = -kMinMonth; | |
2508 | |
2509 // 20.3.1.2 Day Number and Time within Day | |
2510 const double kMsPerDay = 86400000.0; | |
2511 | |
2512 // ES6 section 20.3.1.11 Hours, Minutes, Second, and Milliseconds | |
2513 const double kMsPerSecond = 1000.0; | |
2514 const double kMsPerMinute = 60000.0; | |
2515 const double kMsPerHour = 3600000.0; | |
2516 | |
2517 // ES6 section 20.3.1.14 MakeDate (day, time) | |
2518 double MakeDate(double day, double time) { | |
2519 if (std::isfinite(day) && std::isfinite(time)) { | |
2520 return time + day * kMsPerDay; | |
2521 } | |
2522 return std::numeric_limits<double>::quiet_NaN(); | |
2523 } | |
2524 | |
2525 // ES6 section 20.3.1.13 MakeDay (year, month, date) | |
2526 double MakeDay(double year, double month, double date) { | |
2527 if ((kMinYear <= year && year <= kMaxYear) && | |
2528 (kMinMonth <= month && month <= kMaxMonth) && std::isfinite(date)) { | |
2529 int y = FastD2I(year); | |
2530 int m = FastD2I(month); | |
2531 y += m / 12; | |
2532 m %= 12; | |
2533 if (m < 0) { | |
2534 m += 12; | |
2535 y -= 1; | |
2536 } | |
2537 DCHECK_LE(0, m); | |
2538 DCHECK_LT(m, 12); | |
2539 | |
2540 // kYearDelta is an arbitrary number such that: | |
2541 // a) kYearDelta = -1 (mod 400) | |
2542 // b) year + kYearDelta > 0 for years in the range defined by | |
2543 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of | |
2544 // Jan 1 1970. This is required so that we don't run into integer | |
2545 // division of negative numbers. | |
2546 // c) there shouldn't be an overflow for 32-bit integers in the following | |
2547 // operations. | |
2548 static const int kYearDelta = 399999; | |
2549 static const int kBaseDay = | |
2550 365 * (1970 + kYearDelta) + (1970 + kYearDelta) / 4 - | |
2551 (1970 + kYearDelta) / 100 + (1970 + kYearDelta) / 400; | |
2552 int day_from_year = 365 * (y + kYearDelta) + (y + kYearDelta) / 4 - | |
2553 (y + kYearDelta) / 100 + (y + kYearDelta) / 400 - | |
2554 kBaseDay; | |
2555 if ((y % 4 != 0) || (y % 100 == 0 && y % 400 != 0)) { | |
2556 static const int kDayFromMonth[] = {0, 31, 59, 90, 120, 151, | |
2557 181, 212, 243, 273, 304, 334}; | |
2558 day_from_year += kDayFromMonth[m]; | |
2559 } else { | |
2560 static const int kDayFromMonth[] = {0, 31, 60, 91, 121, 152, | |
2561 182, 213, 244, 274, 305, 335}; | |
2562 day_from_year += kDayFromMonth[m]; | |
2563 } | |
2564 return static_cast<double>(day_from_year - 1) + date; | |
2565 } | |
2566 return std::numeric_limits<double>::quiet_NaN(); | |
2567 } | |
2568 | |
2569 // ES6 section 20.3.1.12 MakeTime (hour, min, sec, ms) | |
2570 double MakeTime(double hour, double min, double sec, double ms) { | |
2571 if (std::isfinite(hour) && std::isfinite(min) && std::isfinite(sec) && | |
2572 std::isfinite(ms)) { | |
2573 double const h = DoubleToInteger(hour); | |
2574 double const m = DoubleToInteger(min); | |
2575 double const s = DoubleToInteger(sec); | |
2576 double const milli = DoubleToInteger(ms); | |
2577 return h * kMsPerHour + m * kMsPerMinute + s * kMsPerSecond + milli; | |
2578 } | |
2579 return std::numeric_limits<double>::quiet_NaN(); | |
2580 } | |
2581 | |
2582 // ES6 section 20.3.1.15 TimeClip (time) | |
2583 double TimeClip(double time) { | |
2584 if (-DateCache::kMaxTimeInMs <= time && time <= DateCache::kMaxTimeInMs) { | |
2585 return DoubleToInteger(time) + 0.0; | |
2586 } | |
2587 return std::numeric_limits<double>::quiet_NaN(); | |
2588 } | |
2589 | |
2590 const char* kShortWeekDays[] = {"Sun", "Mon", "Tue", "Wed", | |
2591 "Thu", "Fri", "Sat"}; | |
2592 const char* kShortMonths[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", | |
2593 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; | |
2594 | |
2595 // ES6 section 20.3.1.16 Date Time String Format | |
2596 double ParseDateTimeString(Handle<String> str) { | |
2597 Isolate* const isolate = str->GetIsolate(); | |
2598 str = String::Flatten(str); | |
2599 // TODO(bmeurer): Change DateParser to not use the FixedArray. | |
2600 Handle<FixedArray> tmp = | |
2601 isolate->factory()->NewFixedArray(DateParser::OUTPUT_SIZE); | |
2602 DisallowHeapAllocation no_gc; | |
2603 String::FlatContent str_content = str->GetFlatContent(); | |
2604 bool result; | |
2605 if (str_content.IsOneByte()) { | |
2606 result = DateParser::Parse(isolate, str_content.ToOneByteVector(), *tmp); | |
2607 } else { | |
2608 result = DateParser::Parse(isolate, str_content.ToUC16Vector(), *tmp); | |
2609 } | |
2610 if (!result) return std::numeric_limits<double>::quiet_NaN(); | |
2611 double const day = MakeDay(tmp->get(0)->Number(), tmp->get(1)->Number(), | |
2612 tmp->get(2)->Number()); | |
2613 double const time = MakeTime(tmp->get(3)->Number(), tmp->get(4)->Number(), | |
2614 tmp->get(5)->Number(), tmp->get(6)->Number()); | |
2615 double date = MakeDate(day, time); | |
2616 if (tmp->get(7)->IsNull(isolate)) { | |
2617 if (!std::isnan(date)) { | |
2618 date = isolate->date_cache()->ToUTC(static_cast<int64_t>(date)); | |
2619 } | |
2620 } else { | |
2621 date -= tmp->get(7)->Number() * 1000.0; | |
2622 } | |
2623 return date; | |
2624 } | |
2625 | |
2626 enum ToDateStringMode { kDateOnly, kTimeOnly, kDateAndTime }; | |
2627 | |
2628 // ES6 section 20.3.4.41.1 ToDateString(tv) | |
2629 void ToDateString(double time_val, Vector<char> str, DateCache* date_cache, | |
2630 ToDateStringMode mode = kDateAndTime) { | |
2631 if (std::isnan(time_val)) { | |
2632 SNPrintF(str, "Invalid Date"); | |
2633 return; | |
2634 } | |
2635 int64_t time_ms = static_cast<int64_t>(time_val); | |
2636 int64_t local_time_ms = date_cache->ToLocal(time_ms); | |
2637 int year, month, day, weekday, hour, min, sec, ms; | |
2638 date_cache->BreakDownTime(local_time_ms, &year, &month, &day, &weekday, &hour, | |
2639 &min, &sec, &ms); | |
2640 int timezone_offset = -date_cache->TimezoneOffset(time_ms); | |
2641 int timezone_hour = std::abs(timezone_offset) / 60; | |
2642 int timezone_min = std::abs(timezone_offset) % 60; | |
2643 const char* local_timezone = date_cache->LocalTimezone(time_ms); | |
2644 switch (mode) { | |
2645 case kDateOnly: | |
2646 SNPrintF(str, "%s %s %02d %4d", kShortWeekDays[weekday], | |
2647 kShortMonths[month], day, year); | |
2648 return; | |
2649 case kTimeOnly: | |
2650 SNPrintF(str, "%02d:%02d:%02d GMT%c%02d%02d (%s)", hour, min, sec, | |
2651 (timezone_offset < 0) ? '-' : '+', timezone_hour, timezone_min, | |
2652 local_timezone); | |
2653 return; | |
2654 case kDateAndTime: | |
2655 SNPrintF(str, "%s %s %02d %4d %02d:%02d:%02d GMT%c%02d%02d (%s)", | |
2656 kShortWeekDays[weekday], kShortMonths[month], day, year, hour, | |
2657 min, sec, (timezone_offset < 0) ? '-' : '+', timezone_hour, | |
2658 timezone_min, local_timezone); | |
2659 return; | |
2660 } | |
2661 UNREACHABLE(); | |
2662 } | |
2663 | |
2664 Object* SetLocalDateValue(Handle<JSDate> date, double time_val) { | |
2665 if (time_val >= -DateCache::kMaxTimeBeforeUTCInMs && | |
2666 time_val <= DateCache::kMaxTimeBeforeUTCInMs) { | |
2667 Isolate* const isolate = date->GetIsolate(); | |
2668 time_val = isolate->date_cache()->ToUTC(static_cast<int64_t>(time_val)); | |
2669 } else { | |
2670 time_val = std::numeric_limits<double>::quiet_NaN(); | |
2671 } | |
2672 return *JSDate::SetValue(date, TimeClip(time_val)); | |
2673 } | |
2674 | |
2675 } // namespace | |
2676 | |
2677 // ES6 section 20.3.2 The Date Constructor for the [[Call]] case. | |
2678 BUILTIN(DateConstructor) { | |
2679 HandleScope scope(isolate); | |
2680 double const time_val = JSDate::CurrentTimeValue(isolate); | |
2681 char buffer[128]; | |
2682 ToDateString(time_val, ArrayVector(buffer), isolate->date_cache()); | |
2683 RETURN_RESULT_OR_FAILURE( | |
2684 isolate, isolate->factory()->NewStringFromUtf8(CStrVector(buffer))); | |
2685 } | |
2686 | |
2687 // ES6 section 20.3.2 The Date Constructor for the [[Construct]] case. | |
2688 BUILTIN(DateConstructor_ConstructStub) { | |
2689 HandleScope scope(isolate); | |
2690 int const argc = args.length() - 1; | |
2691 Handle<JSFunction> target = args.target<JSFunction>(); | |
2692 Handle<JSReceiver> new_target = Handle<JSReceiver>::cast(args.new_target()); | |
2693 double time_val; | |
2694 if (argc == 0) { | |
2695 time_val = JSDate::CurrentTimeValue(isolate); | |
2696 } else if (argc == 1) { | |
2697 Handle<Object> value = args.at<Object>(1); | |
2698 if (value->IsJSDate()) { | |
2699 time_val = Handle<JSDate>::cast(value)->value()->Number(); | |
2700 } else { | |
2701 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value, | |
2702 Object::ToPrimitive(value)); | |
2703 if (value->IsString()) { | |
2704 time_val = ParseDateTimeString(Handle<String>::cast(value)); | |
2705 } else { | |
2706 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value, | |
2707 Object::ToNumber(value)); | |
2708 time_val = value->Number(); | |
2709 } | |
2710 } | |
2711 } else { | |
2712 Handle<Object> year_object; | |
2713 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, year_object, | |
2714 Object::ToNumber(args.at<Object>(1))); | |
2715 Handle<Object> month_object; | |
2716 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, month_object, | |
2717 Object::ToNumber(args.at<Object>(2))); | |
2718 double year = year_object->Number(); | |
2719 double month = month_object->Number(); | |
2720 double date = 1.0, hours = 0.0, minutes = 0.0, seconds = 0.0, ms = 0.0; | |
2721 if (argc >= 3) { | |
2722 Handle<Object> date_object; | |
2723 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, date_object, | |
2724 Object::ToNumber(args.at<Object>(3))); | |
2725 date = date_object->Number(); | |
2726 if (argc >= 4) { | |
2727 Handle<Object> hours_object; | |
2728 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
2729 isolate, hours_object, Object::ToNumber(args.at<Object>(4))); | |
2730 hours = hours_object->Number(); | |
2731 if (argc >= 5) { | |
2732 Handle<Object> minutes_object; | |
2733 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
2734 isolate, minutes_object, Object::ToNumber(args.at<Object>(5))); | |
2735 minutes = minutes_object->Number(); | |
2736 if (argc >= 6) { | |
2737 Handle<Object> seconds_object; | |
2738 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
2739 isolate, seconds_object, Object::ToNumber(args.at<Object>(6))); | |
2740 seconds = seconds_object->Number(); | |
2741 if (argc >= 7) { | |
2742 Handle<Object> ms_object; | |
2743 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
2744 isolate, ms_object, Object::ToNumber(args.at<Object>(7))); | |
2745 ms = ms_object->Number(); | |
2746 } | |
2747 } | |
2748 } | |
2749 } | |
2750 } | |
2751 if (!std::isnan(year)) { | |
2752 double const y = DoubleToInteger(year); | |
2753 if (0.0 <= y && y <= 99) year = 1900 + y; | |
2754 } | |
2755 double const day = MakeDay(year, month, date); | |
2756 double const time = MakeTime(hours, minutes, seconds, ms); | |
2757 time_val = MakeDate(day, time); | |
2758 if (time_val >= -DateCache::kMaxTimeBeforeUTCInMs && | |
2759 time_val <= DateCache::kMaxTimeBeforeUTCInMs) { | |
2760 time_val = isolate->date_cache()->ToUTC(static_cast<int64_t>(time_val)); | |
2761 } else { | |
2762 time_val = std::numeric_limits<double>::quiet_NaN(); | |
2763 } | |
2764 } | |
2765 RETURN_RESULT_OR_FAILURE(isolate, JSDate::New(target, new_target, time_val)); | |
2766 } | |
2767 | |
2768 // ES6 section 20.3.3.1 Date.now ( ) | |
2769 BUILTIN(DateNow) { | |
2770 HandleScope scope(isolate); | |
2771 return *isolate->factory()->NewNumber(JSDate::CurrentTimeValue(isolate)); | |
2772 } | |
2773 | |
2774 // ES6 section 20.3.3.2 Date.parse ( string ) | |
2775 BUILTIN(DateParse) { | |
2776 HandleScope scope(isolate); | |
2777 Handle<String> string; | |
2778 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
2779 isolate, string, | |
2780 Object::ToString(isolate, args.atOrUndefined(isolate, 1))); | |
2781 return *isolate->factory()->NewNumber(ParseDateTimeString(string)); | |
2782 } | |
2783 | |
2784 // ES6 section 20.3.3.4 Date.UTC (year,month,date,hours,minutes,seconds,ms) | |
2785 BUILTIN(DateUTC) { | |
2786 HandleScope scope(isolate); | |
2787 int const argc = args.length() - 1; | |
2788 double year = std::numeric_limits<double>::quiet_NaN(); | |
2789 double month = std::numeric_limits<double>::quiet_NaN(); | |
2790 double date = 1.0, hours = 0.0, minutes = 0.0, seconds = 0.0, ms = 0.0; | |
2791 if (argc >= 1) { | |
2792 Handle<Object> year_object; | |
2793 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, year_object, | |
2794 Object::ToNumber(args.at<Object>(1))); | |
2795 year = year_object->Number(); | |
2796 if (argc >= 2) { | |
2797 Handle<Object> month_object; | |
2798 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, month_object, | |
2799 Object::ToNumber(args.at<Object>(2))); | |
2800 month = month_object->Number(); | |
2801 if (argc >= 3) { | |
2802 Handle<Object> date_object; | |
2803 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
2804 isolate, date_object, Object::ToNumber(args.at<Object>(3))); | |
2805 date = date_object->Number(); | |
2806 if (argc >= 4) { | |
2807 Handle<Object> hours_object; | |
2808 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
2809 isolate, hours_object, Object::ToNumber(args.at<Object>(4))); | |
2810 hours = hours_object->Number(); | |
2811 if (argc >= 5) { | |
2812 Handle<Object> minutes_object; | |
2813 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
2814 isolate, minutes_object, Object::ToNumber(args.at<Object>(5))); | |
2815 minutes = minutes_object->Number(); | |
2816 if (argc >= 6) { | |
2817 Handle<Object> seconds_object; | |
2818 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
2819 isolate, seconds_object, | |
2820 Object::ToNumber(args.at<Object>(6))); | |
2821 seconds = seconds_object->Number(); | |
2822 if (argc >= 7) { | |
2823 Handle<Object> ms_object; | |
2824 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
2825 isolate, ms_object, Object::ToNumber(args.at<Object>(7))); | |
2826 ms = ms_object->Number(); | |
2827 } | |
2828 } | |
2829 } | |
2830 } | |
2831 } | |
2832 } | |
2833 } | |
2834 if (!std::isnan(year)) { | |
2835 double const y = DoubleToInteger(year); | |
2836 if (0.0 <= y && y <= 99) year = 1900 + y; | |
2837 } | |
2838 double const day = MakeDay(year, month, date); | |
2839 double const time = MakeTime(hours, minutes, seconds, ms); | |
2840 return *isolate->factory()->NewNumber(TimeClip(MakeDate(day, time))); | |
2841 } | |
2842 | |
2843 // ES6 section 20.3.4.20 Date.prototype.setDate ( date ) | |
2844 BUILTIN(DatePrototypeSetDate) { | |
2845 HandleScope scope(isolate); | |
2846 CHECK_RECEIVER(JSDate, date, "Date.prototype.setDate"); | |
2847 Handle<Object> value = args.atOrUndefined(isolate, 1); | |
2848 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value, Object::ToNumber(value)); | |
2849 double time_val = date->value()->Number(); | |
2850 if (!std::isnan(time_val)) { | |
2851 int64_t const time_ms = static_cast<int64_t>(time_val); | |
2852 int64_t local_time_ms = isolate->date_cache()->ToLocal(time_ms); | |
2853 int const days = isolate->date_cache()->DaysFromTime(local_time_ms); | |
2854 int time_within_day = isolate->date_cache()->TimeInDay(local_time_ms, days); | |
2855 int year, month, day; | |
2856 isolate->date_cache()->YearMonthDayFromDays(days, &year, &month, &day); | |
2857 time_val = MakeDate(MakeDay(year, month, value->Number()), time_within_day); | |
2858 } | |
2859 return SetLocalDateValue(date, time_val); | |
2860 } | |
2861 | |
2862 // ES6 section 20.3.4.21 Date.prototype.setFullYear (year, month, date) | |
2863 BUILTIN(DatePrototypeSetFullYear) { | |
2864 HandleScope scope(isolate); | |
2865 CHECK_RECEIVER(JSDate, date, "Date.prototype.setFullYear"); | |
2866 int const argc = args.length() - 1; | |
2867 Handle<Object> year = args.atOrUndefined(isolate, 1); | |
2868 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, year, Object::ToNumber(year)); | |
2869 double y = year->Number(), m = 0.0, dt = 1.0; | |
2870 int time_within_day = 0; | |
2871 if (!std::isnan(date->value()->Number())) { | |
2872 int64_t const time_ms = static_cast<int64_t>(date->value()->Number()); | |
2873 int64_t local_time_ms = isolate->date_cache()->ToLocal(time_ms); | |
2874 int const days = isolate->date_cache()->DaysFromTime(local_time_ms); | |
2875 time_within_day = isolate->date_cache()->TimeInDay(local_time_ms, days); | |
2876 int year, month, day; | |
2877 isolate->date_cache()->YearMonthDayFromDays(days, &year, &month, &day); | |
2878 m = month; | |
2879 dt = day; | |
2880 } | |
2881 if (argc >= 2) { | |
2882 Handle<Object> month = args.at<Object>(2); | |
2883 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, month, Object::ToNumber(month)); | |
2884 m = month->Number(); | |
2885 if (argc >= 3) { | |
2886 Handle<Object> date = args.at<Object>(3); | |
2887 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, date, Object::ToNumber(date)); | |
2888 dt = date->Number(); | |
2889 } | |
2890 } | |
2891 double time_val = MakeDate(MakeDay(y, m, dt), time_within_day); | |
2892 return SetLocalDateValue(date, time_val); | |
2893 } | |
2894 | |
2895 // ES6 section 20.3.4.22 Date.prototype.setHours(hour, min, sec, ms) | |
2896 BUILTIN(DatePrototypeSetHours) { | |
2897 HandleScope scope(isolate); | |
2898 CHECK_RECEIVER(JSDate, date, "Date.prototype.setHours"); | |
2899 int const argc = args.length() - 1; | |
2900 Handle<Object> hour = args.atOrUndefined(isolate, 1); | |
2901 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, hour, Object::ToNumber(hour)); | |
2902 double h = hour->Number(); | |
2903 double time_val = date->value()->Number(); | |
2904 if (!std::isnan(time_val)) { | |
2905 int64_t const time_ms = static_cast<int64_t>(time_val); | |
2906 int64_t local_time_ms = isolate->date_cache()->ToLocal(time_ms); | |
2907 int day = isolate->date_cache()->DaysFromTime(local_time_ms); | |
2908 int time_within_day = isolate->date_cache()->TimeInDay(local_time_ms, day); | |
2909 double m = (time_within_day / (60 * 1000)) % 60; | |
2910 double s = (time_within_day / 1000) % 60; | |
2911 double milli = time_within_day % 1000; | |
2912 if (argc >= 2) { | |
2913 Handle<Object> min = args.at<Object>(2); | |
2914 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, min, Object::ToNumber(min)); | |
2915 m = min->Number(); | |
2916 if (argc >= 3) { | |
2917 Handle<Object> sec = args.at<Object>(3); | |
2918 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, sec, Object::ToNumber(sec)); | |
2919 s = sec->Number(); | |
2920 if (argc >= 4) { | |
2921 Handle<Object> ms = args.at<Object>(4); | |
2922 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, ms, Object::ToNumber(ms)); | |
2923 milli = ms->Number(); | |
2924 } | |
2925 } | |
2926 } | |
2927 time_val = MakeDate(day, MakeTime(h, m, s, milli)); | |
2928 } | |
2929 return SetLocalDateValue(date, time_val); | |
2930 } | |
2931 | |
2932 // ES6 section 20.3.4.23 Date.prototype.setMilliseconds(ms) | |
2933 BUILTIN(DatePrototypeSetMilliseconds) { | |
2934 HandleScope scope(isolate); | |
2935 CHECK_RECEIVER(JSDate, date, "Date.prototype.setMilliseconds"); | |
2936 Handle<Object> ms = args.atOrUndefined(isolate, 1); | |
2937 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, ms, Object::ToNumber(ms)); | |
2938 double time_val = date->value()->Number(); | |
2939 if (!std::isnan(time_val)) { | |
2940 int64_t const time_ms = static_cast<int64_t>(time_val); | |
2941 int64_t local_time_ms = isolate->date_cache()->ToLocal(time_ms); | |
2942 int day = isolate->date_cache()->DaysFromTime(local_time_ms); | |
2943 int time_within_day = isolate->date_cache()->TimeInDay(local_time_ms, day); | |
2944 int h = time_within_day / (60 * 60 * 1000); | |
2945 int m = (time_within_day / (60 * 1000)) % 60; | |
2946 int s = (time_within_day / 1000) % 60; | |
2947 time_val = MakeDate(day, MakeTime(h, m, s, ms->Number())); | |
2948 } | |
2949 return SetLocalDateValue(date, time_val); | |
2950 } | |
2951 | |
2952 // ES6 section 20.3.4.24 Date.prototype.setMinutes ( min, sec, ms ) | |
2953 BUILTIN(DatePrototypeSetMinutes) { | |
2954 HandleScope scope(isolate); | |
2955 CHECK_RECEIVER(JSDate, date, "Date.prototype.setMinutes"); | |
2956 int const argc = args.length() - 1; | |
2957 Handle<Object> min = args.atOrUndefined(isolate, 1); | |
2958 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, min, Object::ToNumber(min)); | |
2959 double time_val = date->value()->Number(); | |
2960 if (!std::isnan(time_val)) { | |
2961 int64_t const time_ms = static_cast<int64_t>(time_val); | |
2962 int64_t local_time_ms = isolate->date_cache()->ToLocal(time_ms); | |
2963 int day = isolate->date_cache()->DaysFromTime(local_time_ms); | |
2964 int time_within_day = isolate->date_cache()->TimeInDay(local_time_ms, day); | |
2965 int h = time_within_day / (60 * 60 * 1000); | |
2966 double m = min->Number(); | |
2967 double s = (time_within_day / 1000) % 60; | |
2968 double milli = time_within_day % 1000; | |
2969 if (argc >= 2) { | |
2970 Handle<Object> sec = args.at<Object>(2); | |
2971 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, sec, Object::ToNumber(sec)); | |
2972 s = sec->Number(); | |
2973 if (argc >= 3) { | |
2974 Handle<Object> ms = args.at<Object>(3); | |
2975 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, ms, Object::ToNumber(ms)); | |
2976 milli = ms->Number(); | |
2977 } | |
2978 } | |
2979 time_val = MakeDate(day, MakeTime(h, m, s, milli)); | |
2980 } | |
2981 return SetLocalDateValue(date, time_val); | |
2982 } | |
2983 | |
2984 // ES6 section 20.3.4.25 Date.prototype.setMonth ( month, date ) | |
2985 BUILTIN(DatePrototypeSetMonth) { | |
2986 HandleScope scope(isolate); | |
2987 CHECK_RECEIVER(JSDate, date, "Date.prototype.setMonth"); | |
2988 int const argc = args.length() - 1; | |
2989 Handle<Object> month = args.atOrUndefined(isolate, 1); | |
2990 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, month, Object::ToNumber(month)); | |
2991 double time_val = date->value()->Number(); | |
2992 if (!std::isnan(time_val)) { | |
2993 int64_t const time_ms = static_cast<int64_t>(time_val); | |
2994 int64_t local_time_ms = isolate->date_cache()->ToLocal(time_ms); | |
2995 int days = isolate->date_cache()->DaysFromTime(local_time_ms); | |
2996 int time_within_day = isolate->date_cache()->TimeInDay(local_time_ms, days); | |
2997 int year, unused, day; | |
2998 isolate->date_cache()->YearMonthDayFromDays(days, &year, &unused, &day); | |
2999 double m = month->Number(); | |
3000 double dt = day; | |
3001 if (argc >= 2) { | |
3002 Handle<Object> date = args.at<Object>(2); | |
3003 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, date, Object::ToNumber(date)); | |
3004 dt = date->Number(); | |
3005 } | |
3006 time_val = MakeDate(MakeDay(year, m, dt), time_within_day); | |
3007 } | |
3008 return SetLocalDateValue(date, time_val); | |
3009 } | |
3010 | |
3011 // ES6 section 20.3.4.26 Date.prototype.setSeconds ( sec, ms ) | |
3012 BUILTIN(DatePrototypeSetSeconds) { | |
3013 HandleScope scope(isolate); | |
3014 CHECK_RECEIVER(JSDate, date, "Date.prototype.setSeconds"); | |
3015 int const argc = args.length() - 1; | |
3016 Handle<Object> sec = args.atOrUndefined(isolate, 1); | |
3017 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, sec, Object::ToNumber(sec)); | |
3018 double time_val = date->value()->Number(); | |
3019 if (!std::isnan(time_val)) { | |
3020 int64_t const time_ms = static_cast<int64_t>(time_val); | |
3021 int64_t local_time_ms = isolate->date_cache()->ToLocal(time_ms); | |
3022 int day = isolate->date_cache()->DaysFromTime(local_time_ms); | |
3023 int time_within_day = isolate->date_cache()->TimeInDay(local_time_ms, day); | |
3024 int h = time_within_day / (60 * 60 * 1000); | |
3025 double m = (time_within_day / (60 * 1000)) % 60; | |
3026 double s = sec->Number(); | |
3027 double milli = time_within_day % 1000; | |
3028 if (argc >= 2) { | |
3029 Handle<Object> ms = args.at<Object>(2); | |
3030 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, ms, Object::ToNumber(ms)); | |
3031 milli = ms->Number(); | |
3032 } | |
3033 time_val = MakeDate(day, MakeTime(h, m, s, milli)); | |
3034 } | |
3035 return SetLocalDateValue(date, time_val); | |
3036 } | |
3037 | |
3038 // ES6 section 20.3.4.27 Date.prototype.setTime ( time ) | |
3039 BUILTIN(DatePrototypeSetTime) { | |
3040 HandleScope scope(isolate); | |
3041 CHECK_RECEIVER(JSDate, date, "Date.prototype.setTime"); | |
3042 Handle<Object> value = args.atOrUndefined(isolate, 1); | |
3043 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value, Object::ToNumber(value)); | |
3044 return *JSDate::SetValue(date, TimeClip(value->Number())); | |
3045 } | |
3046 | |
3047 // ES6 section 20.3.4.28 Date.prototype.setUTCDate ( date ) | |
3048 BUILTIN(DatePrototypeSetUTCDate) { | |
3049 HandleScope scope(isolate); | |
3050 CHECK_RECEIVER(JSDate, date, "Date.prototype.setUTCDate"); | |
3051 Handle<Object> value = args.atOrUndefined(isolate, 1); | |
3052 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value, Object::ToNumber(value)); | |
3053 if (std::isnan(date->value()->Number())) return date->value(); | |
3054 int64_t const time_ms = static_cast<int64_t>(date->value()->Number()); | |
3055 int const days = isolate->date_cache()->DaysFromTime(time_ms); | |
3056 int const time_within_day = isolate->date_cache()->TimeInDay(time_ms, days); | |
3057 int year, month, day; | |
3058 isolate->date_cache()->YearMonthDayFromDays(days, &year, &month, &day); | |
3059 double const time_val = | |
3060 MakeDate(MakeDay(year, month, value->Number()), time_within_day); | |
3061 return *JSDate::SetValue(date, TimeClip(time_val)); | |
3062 } | |
3063 | |
3064 // ES6 section 20.3.4.29 Date.prototype.setUTCFullYear (year, month, date) | |
3065 BUILTIN(DatePrototypeSetUTCFullYear) { | |
3066 HandleScope scope(isolate); | |
3067 CHECK_RECEIVER(JSDate, date, "Date.prototype.setUTCFullYear"); | |
3068 int const argc = args.length() - 1; | |
3069 Handle<Object> year = args.atOrUndefined(isolate, 1); | |
3070 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, year, Object::ToNumber(year)); | |
3071 double y = year->Number(), m = 0.0, dt = 1.0; | |
3072 int time_within_day = 0; | |
3073 if (!std::isnan(date->value()->Number())) { | |
3074 int64_t const time_ms = static_cast<int64_t>(date->value()->Number()); | |
3075 int const days = isolate->date_cache()->DaysFromTime(time_ms); | |
3076 time_within_day = isolate->date_cache()->TimeInDay(time_ms, days); | |
3077 int year, month, day; | |
3078 isolate->date_cache()->YearMonthDayFromDays(days, &year, &month, &day); | |
3079 m = month; | |
3080 dt = day; | |
3081 } | |
3082 if (argc >= 2) { | |
3083 Handle<Object> month = args.at<Object>(2); | |
3084 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, month, Object::ToNumber(month)); | |
3085 m = month->Number(); | |
3086 if (argc >= 3) { | |
3087 Handle<Object> date = args.at<Object>(3); | |
3088 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, date, Object::ToNumber(date)); | |
3089 dt = date->Number(); | |
3090 } | |
3091 } | |
3092 double const time_val = MakeDate(MakeDay(y, m, dt), time_within_day); | |
3093 return *JSDate::SetValue(date, TimeClip(time_val)); | |
3094 } | |
3095 | |
3096 // ES6 section 20.3.4.30 Date.prototype.setUTCHours(hour, min, sec, ms) | |
3097 BUILTIN(DatePrototypeSetUTCHours) { | |
3098 HandleScope scope(isolate); | |
3099 CHECK_RECEIVER(JSDate, date, "Date.prototype.setUTCHours"); | |
3100 int const argc = args.length() - 1; | |
3101 Handle<Object> hour = args.atOrUndefined(isolate, 1); | |
3102 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, hour, Object::ToNumber(hour)); | |
3103 double h = hour->Number(); | |
3104 double time_val = date->value()->Number(); | |
3105 if (!std::isnan(time_val)) { | |
3106 int64_t const time_ms = static_cast<int64_t>(time_val); | |
3107 int day = isolate->date_cache()->DaysFromTime(time_ms); | |
3108 int time_within_day = isolate->date_cache()->TimeInDay(time_ms, day); | |
3109 double m = (time_within_day / (60 * 1000)) % 60; | |
3110 double s = (time_within_day / 1000) % 60; | |
3111 double milli = time_within_day % 1000; | |
3112 if (argc >= 2) { | |
3113 Handle<Object> min = args.at<Object>(2); | |
3114 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, min, Object::ToNumber(min)); | |
3115 m = min->Number(); | |
3116 if (argc >= 3) { | |
3117 Handle<Object> sec = args.at<Object>(3); | |
3118 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, sec, Object::ToNumber(sec)); | |
3119 s = sec->Number(); | |
3120 if (argc >= 4) { | |
3121 Handle<Object> ms = args.at<Object>(4); | |
3122 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, ms, Object::ToNumber(ms)); | |
3123 milli = ms->Number(); | |
3124 } | |
3125 } | |
3126 } | |
3127 time_val = MakeDate(day, MakeTime(h, m, s, milli)); | |
3128 } | |
3129 return *JSDate::SetValue(date, TimeClip(time_val)); | |
3130 } | |
3131 | |
3132 // ES6 section 20.3.4.31 Date.prototype.setUTCMilliseconds(ms) | |
3133 BUILTIN(DatePrototypeSetUTCMilliseconds) { | |
3134 HandleScope scope(isolate); | |
3135 CHECK_RECEIVER(JSDate, date, "Date.prototype.setUTCMilliseconds"); | |
3136 Handle<Object> ms = args.atOrUndefined(isolate, 1); | |
3137 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, ms, Object::ToNumber(ms)); | |
3138 double time_val = date->value()->Number(); | |
3139 if (!std::isnan(time_val)) { | |
3140 int64_t const time_ms = static_cast<int64_t>(time_val); | |
3141 int day = isolate->date_cache()->DaysFromTime(time_ms); | |
3142 int time_within_day = isolate->date_cache()->TimeInDay(time_ms, day); | |
3143 int h = time_within_day / (60 * 60 * 1000); | |
3144 int m = (time_within_day / (60 * 1000)) % 60; | |
3145 int s = (time_within_day / 1000) % 60; | |
3146 time_val = MakeDate(day, MakeTime(h, m, s, ms->Number())); | |
3147 } | |
3148 return *JSDate::SetValue(date, TimeClip(time_val)); | |
3149 } | |
3150 | |
3151 // ES6 section 20.3.4.32 Date.prototype.setUTCMinutes ( min, sec, ms ) | |
3152 BUILTIN(DatePrototypeSetUTCMinutes) { | |
3153 HandleScope scope(isolate); | |
3154 CHECK_RECEIVER(JSDate, date, "Date.prototype.setUTCMinutes"); | |
3155 int const argc = args.length() - 1; | |
3156 Handle<Object> min = args.atOrUndefined(isolate, 1); | |
3157 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, min, Object::ToNumber(min)); | |
3158 double time_val = date->value()->Number(); | |
3159 if (!std::isnan(time_val)) { | |
3160 int64_t const time_ms = static_cast<int64_t>(time_val); | |
3161 int day = isolate->date_cache()->DaysFromTime(time_ms); | |
3162 int time_within_day = isolate->date_cache()->TimeInDay(time_ms, day); | |
3163 int h = time_within_day / (60 * 60 * 1000); | |
3164 double m = min->Number(); | |
3165 double s = (time_within_day / 1000) % 60; | |
3166 double milli = time_within_day % 1000; | |
3167 if (argc >= 2) { | |
3168 Handle<Object> sec = args.at<Object>(2); | |
3169 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, sec, Object::ToNumber(sec)); | |
3170 s = sec->Number(); | |
3171 if (argc >= 3) { | |
3172 Handle<Object> ms = args.at<Object>(3); | |
3173 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, ms, Object::ToNumber(ms)); | |
3174 milli = ms->Number(); | |
3175 } | |
3176 } | |
3177 time_val = MakeDate(day, MakeTime(h, m, s, milli)); | |
3178 } | |
3179 return *JSDate::SetValue(date, TimeClip(time_val)); | |
3180 } | |
3181 | |
3182 // ES6 section 20.3.4.31 Date.prototype.setUTCMonth ( month, date ) | |
3183 BUILTIN(DatePrototypeSetUTCMonth) { | |
3184 HandleScope scope(isolate); | |
3185 CHECK_RECEIVER(JSDate, date, "Date.prototype.setUTCMonth"); | |
3186 int const argc = args.length() - 1; | |
3187 Handle<Object> month = args.atOrUndefined(isolate, 1); | |
3188 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, month, Object::ToNumber(month)); | |
3189 double time_val = date->value()->Number(); | |
3190 if (!std::isnan(time_val)) { | |
3191 int64_t const time_ms = static_cast<int64_t>(time_val); | |
3192 int days = isolate->date_cache()->DaysFromTime(time_ms); | |
3193 int time_within_day = isolate->date_cache()->TimeInDay(time_ms, days); | |
3194 int year, unused, day; | |
3195 isolate->date_cache()->YearMonthDayFromDays(days, &year, &unused, &day); | |
3196 double m = month->Number(); | |
3197 double dt = day; | |
3198 if (argc >= 2) { | |
3199 Handle<Object> date = args.at<Object>(2); | |
3200 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, date, Object::ToNumber(date)); | |
3201 dt = date->Number(); | |
3202 } | |
3203 time_val = MakeDate(MakeDay(year, m, dt), time_within_day); | |
3204 } | |
3205 return *JSDate::SetValue(date, TimeClip(time_val)); | |
3206 } | |
3207 | |
3208 // ES6 section 20.3.4.34 Date.prototype.setUTCSeconds ( sec, ms ) | |
3209 BUILTIN(DatePrototypeSetUTCSeconds) { | |
3210 HandleScope scope(isolate); | |
3211 CHECK_RECEIVER(JSDate, date, "Date.prototype.setUTCSeconds"); | |
3212 int const argc = args.length() - 1; | |
3213 Handle<Object> sec = args.atOrUndefined(isolate, 1); | |
3214 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, sec, Object::ToNumber(sec)); | |
3215 double time_val = date->value()->Number(); | |
3216 if (!std::isnan(time_val)) { | |
3217 int64_t const time_ms = static_cast<int64_t>(time_val); | |
3218 int day = isolate->date_cache()->DaysFromTime(time_ms); | |
3219 int time_within_day = isolate->date_cache()->TimeInDay(time_ms, day); | |
3220 int h = time_within_day / (60 * 60 * 1000); | |
3221 double m = (time_within_day / (60 * 1000)) % 60; | |
3222 double s = sec->Number(); | |
3223 double milli = time_within_day % 1000; | |
3224 if (argc >= 2) { | |
3225 Handle<Object> ms = args.at<Object>(2); | |
3226 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, ms, Object::ToNumber(ms)); | |
3227 milli = ms->Number(); | |
3228 } | |
3229 time_val = MakeDate(day, MakeTime(h, m, s, milli)); | |
3230 } | |
3231 return *JSDate::SetValue(date, TimeClip(time_val)); | |
3232 } | |
3233 | |
3234 // ES6 section 20.3.4.35 Date.prototype.toDateString ( ) | |
3235 BUILTIN(DatePrototypeToDateString) { | |
3236 HandleScope scope(isolate); | |
3237 CHECK_RECEIVER(JSDate, date, "Date.prototype.toDateString"); | |
3238 char buffer[128]; | |
3239 ToDateString(date->value()->Number(), ArrayVector(buffer), | |
3240 isolate->date_cache(), kDateOnly); | |
3241 RETURN_RESULT_OR_FAILURE( | |
3242 isolate, isolate->factory()->NewStringFromUtf8(CStrVector(buffer))); | |
3243 } | |
3244 | |
3245 // ES6 section 20.3.4.36 Date.prototype.toISOString ( ) | |
3246 BUILTIN(DatePrototypeToISOString) { | |
3247 HandleScope scope(isolate); | |
3248 CHECK_RECEIVER(JSDate, date, "Date.prototype.toISOString"); | |
3249 double const time_val = date->value()->Number(); | |
3250 if (std::isnan(time_val)) { | |
3251 THROW_NEW_ERROR_RETURN_FAILURE( | |
3252 isolate, NewRangeError(MessageTemplate::kInvalidTimeValue)); | |
3253 } | |
3254 int64_t const time_ms = static_cast<int64_t>(time_val); | |
3255 int year, month, day, weekday, hour, min, sec, ms; | |
3256 isolate->date_cache()->BreakDownTime(time_ms, &year, &month, &day, &weekday, | |
3257 &hour, &min, &sec, &ms); | |
3258 char buffer[128]; | |
3259 if (year >= 0 && year <= 9999) { | |
3260 SNPrintF(ArrayVector(buffer), "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", year, | |
3261 month + 1, day, hour, min, sec, ms); | |
3262 } else if (year < 0) { | |
3263 SNPrintF(ArrayVector(buffer), "-%06d-%02d-%02dT%02d:%02d:%02d.%03dZ", -year, | |
3264 month + 1, day, hour, min, sec, ms); | |
3265 } else { | |
3266 SNPrintF(ArrayVector(buffer), "+%06d-%02d-%02dT%02d:%02d:%02d.%03dZ", year, | |
3267 month + 1, day, hour, min, sec, ms); | |
3268 } | |
3269 return *isolate->factory()->NewStringFromAsciiChecked(buffer); | |
3270 } | |
3271 | |
3272 // ES6 section 20.3.4.41 Date.prototype.toString ( ) | |
3273 BUILTIN(DatePrototypeToString) { | |
3274 HandleScope scope(isolate); | |
3275 CHECK_RECEIVER(JSDate, date, "Date.prototype.toString"); | |
3276 char buffer[128]; | |
3277 ToDateString(date->value()->Number(), ArrayVector(buffer), | |
3278 isolate->date_cache()); | |
3279 RETURN_RESULT_OR_FAILURE( | |
3280 isolate, isolate->factory()->NewStringFromUtf8(CStrVector(buffer))); | |
3281 } | |
3282 | |
3283 // ES6 section 20.3.4.42 Date.prototype.toTimeString ( ) | |
3284 BUILTIN(DatePrototypeToTimeString) { | |
3285 HandleScope scope(isolate); | |
3286 CHECK_RECEIVER(JSDate, date, "Date.prototype.toTimeString"); | |
3287 char buffer[128]; | |
3288 ToDateString(date->value()->Number(), ArrayVector(buffer), | |
3289 isolate->date_cache(), kTimeOnly); | |
3290 RETURN_RESULT_OR_FAILURE( | |
3291 isolate, isolate->factory()->NewStringFromUtf8(CStrVector(buffer))); | |
3292 } | |
3293 | |
3294 // ES6 section 20.3.4.43 Date.prototype.toUTCString ( ) | |
3295 BUILTIN(DatePrototypeToUTCString) { | |
3296 HandleScope scope(isolate); | |
3297 CHECK_RECEIVER(JSDate, date, "Date.prototype.toUTCString"); | |
3298 double const time_val = date->value()->Number(); | |
3299 if (std::isnan(time_val)) { | |
3300 return *isolate->factory()->NewStringFromAsciiChecked("Invalid Date"); | |
3301 } | |
3302 char buffer[128]; | |
3303 int64_t time_ms = static_cast<int64_t>(time_val); | |
3304 int year, month, day, weekday, hour, min, sec, ms; | |
3305 isolate->date_cache()->BreakDownTime(time_ms, &year, &month, &day, &weekday, | |
3306 &hour, &min, &sec, &ms); | |
3307 SNPrintF(ArrayVector(buffer), "%s, %02d %s %4d %02d:%02d:%02d GMT", | |
3308 kShortWeekDays[weekday], day, kShortMonths[month], year, hour, min, | |
3309 sec); | |
3310 return *isolate->factory()->NewStringFromAsciiChecked(buffer); | |
3311 } | |
3312 | |
3313 // ES6 section 20.3.4.44 Date.prototype.valueOf ( ) | |
3314 BUILTIN(DatePrototypeValueOf) { | |
3315 HandleScope scope(isolate); | |
3316 CHECK_RECEIVER(JSDate, date, "Date.prototype.valueOf"); | |
3317 return date->value(); | |
3318 } | |
3319 | |
3320 // ES6 section 20.3.4.45 Date.prototype [ @@toPrimitive ] ( hint ) | |
3321 BUILTIN(DatePrototypeToPrimitive) { | |
3322 HandleScope scope(isolate); | |
3323 DCHECK_EQ(2, args.length()); | |
3324 CHECK_RECEIVER(JSReceiver, receiver, "Date.prototype [ @@toPrimitive ]"); | |
3325 Handle<Object> hint = args.at<Object>(1); | |
3326 RETURN_RESULT_OR_FAILURE(isolate, JSDate::ToPrimitive(receiver, hint)); | |
3327 } | |
3328 | |
3329 // ES6 section B.2.4.1 Date.prototype.getYear ( ) | |
3330 BUILTIN(DatePrototypeGetYear) { | |
3331 HandleScope scope(isolate); | |
3332 CHECK_RECEIVER(JSDate, date, "Date.prototype.getYear"); | |
3333 double time_val = date->value()->Number(); | |
3334 if (std::isnan(time_val)) return date->value(); | |
3335 int64_t time_ms = static_cast<int64_t>(time_val); | |
3336 int64_t local_time_ms = isolate->date_cache()->ToLocal(time_ms); | |
3337 int days = isolate->date_cache()->DaysFromTime(local_time_ms); | |
3338 int year, month, day; | |
3339 isolate->date_cache()->YearMonthDayFromDays(days, &year, &month, &day); | |
3340 return Smi::FromInt(year - 1900); | |
3341 } | |
3342 | |
3343 // ES6 section B.2.4.2 Date.prototype.setYear ( year ) | |
3344 BUILTIN(DatePrototypeSetYear) { | |
3345 HandleScope scope(isolate); | |
3346 CHECK_RECEIVER(JSDate, date, "Date.prototype.setYear"); | |
3347 Handle<Object> year = args.atOrUndefined(isolate, 1); | |
3348 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, year, Object::ToNumber(year)); | |
3349 double m = 0.0, dt = 1.0, y = year->Number(); | |
3350 if (0.0 <= y && y <= 99.0) { | |
3351 y = 1900.0 + DoubleToInteger(y); | |
3352 } | |
3353 int time_within_day = 0; | |
3354 if (!std::isnan(date->value()->Number())) { | |
3355 int64_t const time_ms = static_cast<int64_t>(date->value()->Number()); | |
3356 int64_t local_time_ms = isolate->date_cache()->ToLocal(time_ms); | |
3357 int const days = isolate->date_cache()->DaysFromTime(local_time_ms); | |
3358 time_within_day = isolate->date_cache()->TimeInDay(local_time_ms, days); | |
3359 int year, month, day; | |
3360 isolate->date_cache()->YearMonthDayFromDays(days, &year, &month, &day); | |
3361 m = month; | |
3362 dt = day; | |
3363 } | |
3364 double time_val = MakeDate(MakeDay(y, m, dt), time_within_day); | |
3365 return SetLocalDateValue(date, time_val); | |
3366 } | |
3367 | |
3368 // ES6 section 20.3.4.37 Date.prototype.toJSON ( key ) | |
3369 BUILTIN(DatePrototypeToJson) { | |
3370 HandleScope scope(isolate); | |
3371 Handle<Object> receiver = args.atOrUndefined(isolate, 0); | |
3372 Handle<JSReceiver> receiver_obj; | |
3373 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver_obj, | |
3374 Object::ToObject(isolate, receiver)); | |
3375 Handle<Object> primitive; | |
3376 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
3377 isolate, primitive, | |
3378 Object::ToPrimitive(receiver_obj, ToPrimitiveHint::kNumber)); | |
3379 if (primitive->IsNumber() && !std::isfinite(primitive->Number())) { | |
3380 return isolate->heap()->null_value(); | |
3381 } else { | |
3382 Handle<String> name = | |
3383 isolate->factory()->NewStringFromAsciiChecked("toISOString"); | |
3384 Handle<Object> function; | |
3385 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, function, | |
3386 Object::GetProperty(receiver_obj, name)); | |
3387 if (!function->IsCallable()) { | |
3388 THROW_NEW_ERROR_RETURN_FAILURE( | |
3389 isolate, NewTypeError(MessageTemplate::kCalledNonCallable, name)); | |
3390 } | |
3391 RETURN_RESULT_OR_FAILURE( | |
3392 isolate, Execution::Call(isolate, function, receiver_obj, 0, NULL)); | |
3393 } | |
3394 } | |
3395 | |
3396 // static | |
3397 void Builtins::Generate_DatePrototypeGetDate(MacroAssembler* masm) { | |
3398 Generate_DatePrototype_GetField(masm, JSDate::kDay); | |
3399 } | |
3400 | |
3401 // static | |
3402 void Builtins::Generate_DatePrototypeGetDay(MacroAssembler* masm) { | |
3403 Generate_DatePrototype_GetField(masm, JSDate::kWeekday); | |
3404 } | |
3405 | |
3406 // static | |
3407 void Builtins::Generate_DatePrototypeGetFullYear(MacroAssembler* masm) { | |
3408 Generate_DatePrototype_GetField(masm, JSDate::kYear); | |
3409 } | |
3410 | |
3411 // static | |
3412 void Builtins::Generate_DatePrototypeGetHours(MacroAssembler* masm) { | |
3413 Generate_DatePrototype_GetField(masm, JSDate::kHour); | |
3414 } | |
3415 | |
3416 // static | |
3417 void Builtins::Generate_DatePrototypeGetMilliseconds(MacroAssembler* masm) { | |
3418 Generate_DatePrototype_GetField(masm, JSDate::kMillisecond); | |
3419 } | |
3420 | |
3421 // static | |
3422 void Builtins::Generate_DatePrototypeGetMinutes(MacroAssembler* masm) { | |
3423 Generate_DatePrototype_GetField(masm, JSDate::kMinute); | |
3424 } | |
3425 | |
3426 // static | |
3427 void Builtins::Generate_DatePrototypeGetMonth(MacroAssembler* masm) { | |
3428 Generate_DatePrototype_GetField(masm, JSDate::kMonth); | |
3429 } | |
3430 | |
3431 // static | |
3432 void Builtins::Generate_DatePrototypeGetSeconds(MacroAssembler* masm) { | |
3433 Generate_DatePrototype_GetField(masm, JSDate::kSecond); | |
3434 } | |
3435 | |
3436 // static | |
3437 void Builtins::Generate_DatePrototypeGetTime(MacroAssembler* masm) { | |
3438 Generate_DatePrototype_GetField(masm, JSDate::kDateValue); | |
3439 } | |
3440 | |
3441 // static | |
3442 void Builtins::Generate_DatePrototypeGetTimezoneOffset(MacroAssembler* masm) { | |
3443 Generate_DatePrototype_GetField(masm, JSDate::kTimezoneOffset); | |
3444 } | |
3445 | |
3446 // static | |
3447 void Builtins::Generate_DatePrototypeGetUTCDate(MacroAssembler* masm) { | |
3448 Generate_DatePrototype_GetField(masm, JSDate::kDayUTC); | |
3449 } | |
3450 | |
3451 // static | |
3452 void Builtins::Generate_DatePrototypeGetUTCDay(MacroAssembler* masm) { | |
3453 Generate_DatePrototype_GetField(masm, JSDate::kWeekdayUTC); | |
3454 } | |
3455 | |
3456 // static | |
3457 void Builtins::Generate_DatePrototypeGetUTCFullYear(MacroAssembler* masm) { | |
3458 Generate_DatePrototype_GetField(masm, JSDate::kYearUTC); | |
3459 } | |
3460 | |
3461 // static | |
3462 void Builtins::Generate_DatePrototypeGetUTCHours(MacroAssembler* masm) { | |
3463 Generate_DatePrototype_GetField(masm, JSDate::kHourUTC); | |
3464 } | |
3465 | |
3466 // static | |
3467 void Builtins::Generate_DatePrototypeGetUTCMilliseconds(MacroAssembler* masm) { | |
3468 Generate_DatePrototype_GetField(masm, JSDate::kMillisecondUTC); | |
3469 } | |
3470 | |
3471 // static | |
3472 void Builtins::Generate_DatePrototypeGetUTCMinutes(MacroAssembler* masm) { | |
3473 Generate_DatePrototype_GetField(masm, JSDate::kMinuteUTC); | |
3474 } | |
3475 | |
3476 // static | |
3477 void Builtins::Generate_DatePrototypeGetUTCMonth(MacroAssembler* masm) { | |
3478 Generate_DatePrototype_GetField(masm, JSDate::kMonthUTC); | |
3479 } | |
3480 | |
3481 // static | |
3482 void Builtins::Generate_DatePrototypeGetUTCSeconds(MacroAssembler* masm) { | |
3483 Generate_DatePrototype_GetField(masm, JSDate::kSecondUTC); | |
3484 } | |
3485 | |
3486 namespace { | |
3487 | |
3488 bool AllowDynamicFunction(Isolate* isolate, Handle<JSFunction> target, | |
3489 Handle<JSObject> target_global_proxy) { | |
3490 if (FLAG_allow_unsafe_function_constructor) return true; | |
3491 HandleScopeImplementer* impl = isolate->handle_scope_implementer(); | |
3492 Handle<Context> responsible_context = impl->LastEnteredContext(); | |
3493 if (responsible_context.is_null()) { | |
3494 responsible_context = impl->MicrotaskContext(); | |
3495 // TODO(jochen): Remove this. | |
3496 if (responsible_context.is_null()) { | |
3497 return true; | |
3498 } | |
3499 } | |
3500 if (*responsible_context == target->context()) return true; | |
3501 return isolate->MayAccess(responsible_context, target_global_proxy); | |
3502 } | |
3503 | |
3504 // ES6 section 19.2.1.1.1 CreateDynamicFunction | |
3505 MaybeHandle<Object> CreateDynamicFunction(Isolate* isolate, | |
3506 BuiltinArguments args, | |
3507 const char* token) { | |
3508 // Compute number of arguments, ignoring the receiver. | |
3509 DCHECK_LE(1, args.length()); | |
3510 int const argc = args.length() - 1; | |
3511 | |
3512 Handle<JSFunction> target = args.target<JSFunction>(); | |
3513 Handle<JSObject> target_global_proxy(target->global_proxy(), isolate); | |
3514 | |
3515 if (!AllowDynamicFunction(isolate, target, target_global_proxy)) { | |
3516 isolate->CountUsage(v8::Isolate::kFunctionConstructorReturnedUndefined); | |
3517 return isolate->factory()->undefined_value(); | |
3518 } | |
3519 | |
3520 // Build the source string. | |
3521 Handle<String> source; | |
3522 { | |
3523 IncrementalStringBuilder builder(isolate); | |
3524 builder.AppendCharacter('('); | |
3525 builder.AppendCString(token); | |
3526 builder.AppendCharacter('('); | |
3527 bool parenthesis_in_arg_string = false; | |
3528 if (argc > 1) { | |
3529 for (int i = 1; i < argc; ++i) { | |
3530 if (i > 1) builder.AppendCharacter(','); | |
3531 Handle<String> param; | |
3532 ASSIGN_RETURN_ON_EXCEPTION( | |
3533 isolate, param, Object::ToString(isolate, args.at<Object>(i)), | |
3534 Object); | |
3535 param = String::Flatten(param); | |
3536 builder.AppendString(param); | |
3537 // If the formal parameters string include ) - an illegal | |
3538 // character - it may make the combined function expression | |
3539 // compile. We avoid this problem by checking for this early on. | |
3540 DisallowHeapAllocation no_gc; // Ensure vectors stay valid. | |
3541 String::FlatContent param_content = param->GetFlatContent(); | |
3542 for (int i = 0, length = param->length(); i < length; ++i) { | |
3543 if (param_content.Get(i) == ')') { | |
3544 parenthesis_in_arg_string = true; | |
3545 break; | |
3546 } | |
3547 } | |
3548 } | |
3549 // If the formal parameters include an unbalanced block comment, the | |
3550 // function must be rejected. Since JavaScript does not allow nested | |
3551 // comments we can include a trailing block comment to catch this. | |
3552 builder.AppendCString("\n/**/"); | |
3553 } | |
3554 builder.AppendCString(") {\n"); | |
3555 if (argc > 0) { | |
3556 Handle<String> body; | |
3557 ASSIGN_RETURN_ON_EXCEPTION( | |
3558 isolate, body, Object::ToString(isolate, args.at<Object>(argc)), | |
3559 Object); | |
3560 builder.AppendString(body); | |
3561 } | |
3562 builder.AppendCString("\n})"); | |
3563 ASSIGN_RETURN_ON_EXCEPTION(isolate, source, builder.Finish(), Object); | |
3564 | |
3565 // The SyntaxError must be thrown after all the (observable) ToString | |
3566 // conversions are done. | |
3567 if (parenthesis_in_arg_string) { | |
3568 THROW_NEW_ERROR(isolate, | |
3569 NewSyntaxError(MessageTemplate::kParenthesisInArgString), | |
3570 Object); | |
3571 } | |
3572 } | |
3573 | |
3574 // Compile the string in the constructor and not a helper so that errors to | |
3575 // come from here. | |
3576 Handle<JSFunction> function; | |
3577 { | |
3578 ASSIGN_RETURN_ON_EXCEPTION( | |
3579 isolate, function, | |
3580 CompileString(handle(target->native_context(), isolate), source, | |
3581 ONLY_SINGLE_FUNCTION_LITERAL), | |
3582 Object); | |
3583 Handle<Object> result; | |
3584 ASSIGN_RETURN_ON_EXCEPTION( | |
3585 isolate, result, | |
3586 Execution::Call(isolate, function, target_global_proxy, 0, nullptr), | |
3587 Object); | |
3588 function = Handle<JSFunction>::cast(result); | |
3589 function->shared()->set_name_should_print_as_anonymous(true); | |
3590 } | |
3591 | |
3592 // If new.target is equal to target then the function created | |
3593 // is already correctly setup and nothing else should be done | |
3594 // here. But if new.target is not equal to target then we are | |
3595 // have a Function builtin subclassing case and therefore the | |
3596 // function has wrong initial map. To fix that we create a new | |
3597 // function object with correct initial map. | |
3598 Handle<Object> unchecked_new_target = args.new_target(); | |
3599 if (!unchecked_new_target->IsUndefined(isolate) && | |
3600 !unchecked_new_target.is_identical_to(target)) { | |
3601 Handle<JSReceiver> new_target = | |
3602 Handle<JSReceiver>::cast(unchecked_new_target); | |
3603 Handle<Map> initial_map; | |
3604 ASSIGN_RETURN_ON_EXCEPTION( | |
3605 isolate, initial_map, | |
3606 JSFunction::GetDerivedMap(isolate, target, new_target), Object); | |
3607 | |
3608 Handle<SharedFunctionInfo> shared_info(function->shared(), isolate); | |
3609 Handle<Map> map = Map::AsLanguageMode( | |
3610 initial_map, shared_info->language_mode(), shared_info->kind()); | |
3611 | |
3612 Handle<Context> context(function->context(), isolate); | |
3613 function = isolate->factory()->NewFunctionFromSharedFunctionInfo( | |
3614 map, shared_info, context, NOT_TENURED); | |
3615 } | |
3616 return function; | |
3617 } | |
3618 | |
3619 } // namespace | |
3620 | |
3621 // ES6 section 19.2.1.1 Function ( p1, p2, ... , pn, body ) | |
3622 BUILTIN(FunctionConstructor) { | |
3623 HandleScope scope(isolate); | |
3624 Handle<Object> result; | |
3625 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
3626 isolate, result, CreateDynamicFunction(isolate, args, "function")); | |
3627 return *result; | |
3628 } | |
3629 | |
3630 namespace { | |
3631 | |
3632 Object* DoFunctionBind(Isolate* isolate, BuiltinArguments args) { | |
3633 HandleScope scope(isolate); | |
3634 DCHECK_LE(1, args.length()); | |
3635 if (!args.receiver()->IsCallable()) { | |
3636 THROW_NEW_ERROR_RETURN_FAILURE( | |
3637 isolate, NewTypeError(MessageTemplate::kFunctionBind)); | |
3638 } | |
3639 | |
3640 // Allocate the bound function with the given {this_arg} and {args}. | |
3641 Handle<JSReceiver> target = args.at<JSReceiver>(0); | |
3642 Handle<Object> this_arg = isolate->factory()->undefined_value(); | |
3643 ScopedVector<Handle<Object>> argv(std::max(0, args.length() - 2)); | |
3644 if (args.length() > 1) { | |
3645 this_arg = args.at<Object>(1); | |
3646 for (int i = 2; i < args.length(); ++i) { | |
3647 argv[i - 2] = args.at<Object>(i); | |
3648 } | |
3649 } | |
3650 Handle<JSBoundFunction> function; | |
3651 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
3652 isolate, function, | |
3653 isolate->factory()->NewJSBoundFunction(target, this_arg, argv)); | |
3654 | |
3655 LookupIterator length_lookup(target, isolate->factory()->length_string(), | |
3656 target, LookupIterator::OWN); | |
3657 // Setup the "length" property based on the "length" of the {target}. | |
3658 // If the targets length is the default JSFunction accessor, we can keep the | |
3659 // accessor that's installed by default on the JSBoundFunction. It lazily | |
3660 // computes the value from the underlying internal length. | |
3661 if (!target->IsJSFunction() || | |
3662 length_lookup.state() != LookupIterator::ACCESSOR || | |
3663 !length_lookup.GetAccessors()->IsAccessorInfo()) { | |
3664 Handle<Object> length(Smi::FromInt(0), isolate); | |
3665 Maybe<PropertyAttributes> attributes = | |
3666 JSReceiver::GetPropertyAttributes(&length_lookup); | |
3667 if (!attributes.IsJust()) return isolate->heap()->exception(); | |
3668 if (attributes.FromJust() != ABSENT) { | |
3669 Handle<Object> target_length; | |
3670 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, target_length, | |
3671 Object::GetProperty(&length_lookup)); | |
3672 if (target_length->IsNumber()) { | |
3673 length = isolate->factory()->NewNumber(std::max( | |
3674 0.0, DoubleToInteger(target_length->Number()) - argv.length())); | |
3675 } | |
3676 } | |
3677 LookupIterator it(function, isolate->factory()->length_string(), function); | |
3678 DCHECK_EQ(LookupIterator::ACCESSOR, it.state()); | |
3679 RETURN_FAILURE_ON_EXCEPTION(isolate, | |
3680 JSObject::DefineOwnPropertyIgnoreAttributes( | |
3681 &it, length, it.property_attributes())); | |
3682 } | |
3683 | |
3684 // Setup the "name" property based on the "name" of the {target}. | |
3685 // If the targets name is the default JSFunction accessor, we can keep the | |
3686 // accessor that's installed by default on the JSBoundFunction. It lazily | |
3687 // computes the value from the underlying internal name. | |
3688 LookupIterator name_lookup(target, isolate->factory()->name_string(), target, | |
3689 LookupIterator::OWN); | |
3690 if (!target->IsJSFunction() || | |
3691 name_lookup.state() != LookupIterator::ACCESSOR || | |
3692 !name_lookup.GetAccessors()->IsAccessorInfo()) { | |
3693 Handle<Object> target_name; | |
3694 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, target_name, | |
3695 Object::GetProperty(&name_lookup)); | |
3696 Handle<String> name; | |
3697 if (target_name->IsString()) { | |
3698 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
3699 isolate, name, | |
3700 Name::ToFunctionName(Handle<String>::cast(target_name))); | |
3701 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
3702 isolate, name, isolate->factory()->NewConsString( | |
3703 isolate->factory()->bound__string(), name)); | |
3704 } else { | |
3705 name = isolate->factory()->bound__string(); | |
3706 } | |
3707 LookupIterator it(function, isolate->factory()->name_string()); | |
3708 DCHECK_EQ(LookupIterator::ACCESSOR, it.state()); | |
3709 RETURN_FAILURE_ON_EXCEPTION(isolate, | |
3710 JSObject::DefineOwnPropertyIgnoreAttributes( | |
3711 &it, name, it.property_attributes())); | |
3712 } | |
3713 return *function; | |
3714 } | |
3715 | |
3716 } // namespace | |
3717 | |
3718 // ES6 section 19.2.3.2 Function.prototype.bind ( thisArg, ...args ) | |
3719 BUILTIN(FunctionPrototypeBind) { return DoFunctionBind(isolate, args); } | |
3720 | |
3721 // TODO(verwaest): This is a temporary helper until the FastFunctionBind stub | |
3722 // can tailcall to the builtin directly. | |
3723 RUNTIME_FUNCTION(Runtime_FunctionBind) { | |
3724 DCHECK_EQ(2, args.length()); | |
3725 Arguments* incoming = reinterpret_cast<Arguments*>(args[0]); | |
3726 // Rewrap the arguments as builtins arguments. | |
3727 int argc = incoming->length() + BuiltinArguments::kNumExtraArgsWithReceiver; | |
3728 BuiltinArguments caller_args(argc, incoming->arguments() + 1); | |
3729 return DoFunctionBind(isolate, caller_args); | |
3730 } | |
3731 | |
3732 // ES6 section 19.2.3.5 Function.prototype.toString ( ) | |
3733 BUILTIN(FunctionPrototypeToString) { | |
3734 HandleScope scope(isolate); | |
3735 Handle<Object> receiver = args.receiver(); | |
3736 if (receiver->IsJSBoundFunction()) { | |
3737 return *JSBoundFunction::ToString(Handle<JSBoundFunction>::cast(receiver)); | |
3738 } else if (receiver->IsJSFunction()) { | |
3739 return *JSFunction::ToString(Handle<JSFunction>::cast(receiver)); | |
3740 } | |
3741 THROW_NEW_ERROR_RETURN_FAILURE( | |
3742 isolate, NewTypeError(MessageTemplate::kNotGeneric, | |
3743 isolate->factory()->NewStringFromAsciiChecked( | |
3744 "Function.prototype.toString"))); | |
3745 } | |
3746 | |
3747 // ES6 section 25.2.1.1 GeneratorFunction (p1, p2, ... , pn, body) | |
3748 BUILTIN(GeneratorFunctionConstructor) { | |
3749 HandleScope scope(isolate); | |
3750 RETURN_RESULT_OR_FAILURE(isolate, | |
3751 CreateDynamicFunction(isolate, args, "function*")); | |
3752 } | |
3753 | |
3754 BUILTIN(AsyncFunctionConstructor) { | |
3755 HandleScope scope(isolate); | |
3756 Handle<Object> maybe_func; | |
3757 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
3758 isolate, maybe_func, | |
3759 CreateDynamicFunction(isolate, args, "async function")); | |
3760 if (!maybe_func->IsJSFunction()) return *maybe_func; | |
3761 | |
3762 // Do not lazily compute eval position for AsyncFunction, as they may not be | |
3763 // determined after the function is resumed. | |
3764 Handle<JSFunction> func = Handle<JSFunction>::cast(maybe_func); | |
3765 Handle<Script> script = handle(Script::cast(func->shared()->script())); | |
3766 int position = script->GetEvalPosition(); | |
3767 USE(position); | |
3768 | |
3769 return *func; | |
3770 } | |
3771 | |
3772 // ----------------------------------------------------------------------------- | |
3773 // ES6 section 19.1 Object Objects | |
3774 | |
3775 // ES6 section 19.1.3.4 Object.prototype.propertyIsEnumerable ( V ) | |
3776 BUILTIN(ObjectPrototypePropertyIsEnumerable) { | |
3777 HandleScope scope(isolate); | |
3778 Handle<JSReceiver> object; | |
3779 Handle<Name> name; | |
3780 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
3781 isolate, name, Object::ToName(isolate, args.atOrUndefined(isolate, 1))); | |
3782 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
3783 isolate, object, JSReceiver::ToObject(isolate, args.receiver())); | |
3784 Maybe<PropertyAttributes> maybe = | |
3785 JSReceiver::GetOwnPropertyAttributes(object, name); | |
3786 if (!maybe.IsJust()) return isolate->heap()->exception(); | |
3787 if (maybe.FromJust() == ABSENT) return isolate->heap()->false_value(); | |
3788 return isolate->heap()->ToBoolean((maybe.FromJust() & DONT_ENUM) == 0); | |
3789 } | |
3790 | |
3791 // ----------------------------------------------------------------------------- | |
3792 // ES6 section 19.4 Symbol Objects | |
3793 | |
3794 // ES6 section 19.4.1.1 Symbol ( [ description ] ) for the [[Call]] case. | |
3795 BUILTIN(SymbolConstructor) { | |
3796 HandleScope scope(isolate); | |
3797 Handle<Symbol> result = isolate->factory()->NewSymbol(); | |
3798 Handle<Object> description = args.atOrUndefined(isolate, 1); | |
3799 if (!description->IsUndefined(isolate)) { | |
3800 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, description, | |
3801 Object::ToString(isolate, description)); | |
3802 result->set_name(*description); | |
3803 } | |
3804 return *result; | |
3805 } | |
3806 | |
3807 // ES6 section 19.4.1.1 Symbol ( [ description ] ) for the [[Construct]] case. | |
3808 BUILTIN(SymbolConstructor_ConstructStub) { | |
3809 HandleScope scope(isolate); | |
3810 THROW_NEW_ERROR_RETURN_FAILURE( | |
3811 isolate, NewTypeError(MessageTemplate::kNotConstructor, | |
3812 isolate->factory()->Symbol_string())); | |
3813 } | |
3814 | |
3815 // ES6 section 19.4.3.4 Symbol.prototype [ @@toPrimitive ] ( hint ) | |
3816 void Builtins::Generate_SymbolPrototypeToPrimitive( | |
3817 CodeStubAssembler* assembler) { | |
3818 typedef compiler::Node Node; | |
3819 | |
3820 Node* receiver = assembler->Parameter(0); | |
3821 Node* context = assembler->Parameter(4); | |
3822 | |
3823 Node* result = | |
3824 assembler->ToThisValue(context, receiver, PrimitiveType::kSymbol, | |
3825 "Symbol.prototype [ @@toPrimitive ]"); | |
3826 assembler->Return(result); | |
3827 } | |
3828 | |
3829 // ES6 section 19.4.3.2 Symbol.prototype.toString ( ) | |
3830 void Builtins::Generate_SymbolPrototypeToString(CodeStubAssembler* assembler) { | |
3831 typedef compiler::Node Node; | |
3832 | |
3833 Node* receiver = assembler->Parameter(0); | |
3834 Node* context = assembler->Parameter(3); | |
3835 | |
3836 Node* value = assembler->ToThisValue( | |
3837 context, receiver, PrimitiveType::kSymbol, "Symbol.prototype.toString"); | |
3838 Node* result = | |
3839 assembler->CallRuntime(Runtime::kSymbolDescriptiveString, context, value); | |
3840 assembler->Return(result); | |
3841 } | |
3842 | |
3843 // ES6 section 19.4.3.3 Symbol.prototype.valueOf ( ) | |
3844 void Builtins::Generate_SymbolPrototypeValueOf(CodeStubAssembler* assembler) { | |
3845 typedef compiler::Node Node; | |
3846 | |
3847 Node* receiver = assembler->Parameter(0); | |
3848 Node* context = assembler->Parameter(3); | |
3849 | |
3850 Node* result = assembler->ToThisValue( | |
3851 context, receiver, PrimitiveType::kSymbol, "Symbol.prototype.valueOf"); | |
3852 assembler->Return(result); | |
3853 } | |
3854 | |
3855 // ----------------------------------------------------------------------------- | |
3856 // ES6 section 21.1 String Objects | |
3857 | |
3858 // ES6 section 21.1.2.1 String.fromCharCode ( ...codeUnits ) | |
3859 void Builtins::Generate_StringFromCharCode(CodeStubAssembler* assembler) { | |
3860 typedef CodeStubAssembler::Label Label; | |
3861 typedef compiler::Node Node; | |
3862 typedef CodeStubAssembler::Variable Variable; | |
3863 | |
3864 Node* code = assembler->Parameter(1); | |
3865 Node* context = assembler->Parameter(4); | |
3866 | |
3867 // Check if we have exactly one argument (plus the implicit receiver), i.e. | |
3868 // if the parent frame is not an arguments adaptor frame. | |
3869 Label if_oneargument(assembler), if_notoneargument(assembler); | |
3870 Node* parent_frame_pointer = assembler->LoadParentFramePointer(); | |
3871 Node* parent_frame_type = | |
3872 assembler->Load(MachineType::Pointer(), parent_frame_pointer, | |
3873 assembler->IntPtrConstant( | |
3874 CommonFrameConstants::kContextOrFrameTypeOffset)); | |
3875 assembler->Branch( | |
3876 assembler->WordEqual( | |
3877 parent_frame_type, | |
3878 assembler->SmiConstant(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))), | |
3879 &if_notoneargument, &if_oneargument); | |
3880 | |
3881 assembler->Bind(&if_oneargument); | |
3882 { | |
3883 // Single argument case, perform fast single character string cache lookup | |
3884 // for one-byte code units, or fall back to creating a single character | |
3885 // string on the fly otherwise. | |
3886 Node* code32 = assembler->TruncateTaggedToWord32(context, code); | |
3887 Node* code16 = assembler->Word32And( | |
3888 code32, assembler->Int32Constant(String::kMaxUtf16CodeUnit)); | |
3889 Node* result = assembler->StringFromCharCode(code16); | |
3890 assembler->Return(result); | |
3891 } | |
3892 | |
3893 assembler->Bind(&if_notoneargument); | |
3894 { | |
3895 // Determine the resulting string length. | |
3896 Node* parent_frame_length = | |
3897 assembler->Load(MachineType::Pointer(), parent_frame_pointer, | |
3898 assembler->IntPtrConstant( | |
3899 ArgumentsAdaptorFrameConstants::kLengthOffset)); | |
3900 Node* length = assembler->SmiToWord(parent_frame_length); | |
3901 | |
3902 // Assume that the resulting string contains only one-byte characters. | |
3903 Node* result = assembler->AllocateSeqOneByteString(context, length); | |
3904 | |
3905 // Truncate all input parameters and append them to the resulting string. | |
3906 Variable var_offset(assembler, MachineType::PointerRepresentation()); | |
3907 Label loop(assembler, &var_offset), done_loop(assembler); | |
3908 var_offset.Bind(assembler->IntPtrConstant(0)); | |
3909 assembler->Goto(&loop); | |
3910 assembler->Bind(&loop); | |
3911 { | |
3912 // Load the current {offset}. | |
3913 Node* offset = var_offset.value(); | |
3914 | |
3915 // Check if we're done with the string. | |
3916 assembler->GotoIf(assembler->WordEqual(offset, length), &done_loop); | |
3917 | |
3918 // Load the next code point and truncate it to a 16-bit value. | |
3919 Node* code = assembler->Load( | |
3920 MachineType::AnyTagged(), parent_frame_pointer, | |
3921 assembler->IntPtrAdd( | |
3922 assembler->WordShl(assembler->IntPtrSub(length, offset), | |
3923 assembler->IntPtrConstant(kPointerSizeLog2)), | |
3924 assembler->IntPtrConstant( | |
3925 CommonFrameConstants::kFixedFrameSizeAboveFp - | |
3926 kPointerSize))); | |
3927 Node* code32 = assembler->TruncateTaggedToWord32(context, code); | |
3928 Node* code16 = assembler->Word32And( | |
3929 code32, assembler->Int32Constant(String::kMaxUtf16CodeUnit)); | |
3930 | |
3931 // Check if {code16} fits into a one-byte string. | |
3932 Label if_codeisonebyte(assembler), if_codeistwobyte(assembler); | |
3933 assembler->Branch( | |
3934 assembler->Int32LessThanOrEqual( | |
3935 code16, assembler->Int32Constant(String::kMaxOneByteCharCode)), | |
3936 &if_codeisonebyte, &if_codeistwobyte); | |
3937 | |
3938 assembler->Bind(&if_codeisonebyte); | |
3939 { | |
3940 // The {code16} fits into the SeqOneByteString {result}. | |
3941 assembler->StoreNoWriteBarrier( | |
3942 MachineRepresentation::kWord8, result, | |
3943 assembler->IntPtrAdd( | |
3944 assembler->IntPtrConstant(SeqOneByteString::kHeaderSize - | |
3945 kHeapObjectTag), | |
3946 offset), | |
3947 code16); | |
3948 var_offset.Bind( | |
3949 assembler->IntPtrAdd(offset, assembler->IntPtrConstant(1))); | |
3950 assembler->Goto(&loop); | |
3951 } | |
3952 | |
3953 assembler->Bind(&if_codeistwobyte); | |
3954 { | |
3955 // Allocate a SeqTwoByteString to hold the resulting string. | |
3956 Node* cresult = assembler->AllocateSeqTwoByteString(context, length); | |
3957 | |
3958 // Copy all characters that were previously written to the | |
3959 // SeqOneByteString in {result} over to the new {cresult}. | |
3960 Variable var_coffset(assembler, MachineType::PointerRepresentation()); | |
3961 Label cloop(assembler, &var_coffset), done_cloop(assembler); | |
3962 var_coffset.Bind(assembler->IntPtrConstant(0)); | |
3963 assembler->Goto(&cloop); | |
3964 assembler->Bind(&cloop); | |
3965 { | |
3966 Node* coffset = var_coffset.value(); | |
3967 assembler->GotoIf(assembler->WordEqual(coffset, offset), &done_cloop); | |
3968 Node* ccode = assembler->Load( | |
3969 MachineType::Uint8(), result, | |
3970 assembler->IntPtrAdd( | |
3971 assembler->IntPtrConstant(SeqOneByteString::kHeaderSize - | |
3972 kHeapObjectTag), | |
3973 coffset)); | |
3974 assembler->StoreNoWriteBarrier( | |
3975 MachineRepresentation::kWord16, cresult, | |
3976 assembler->IntPtrAdd( | |
3977 assembler->IntPtrConstant(SeqTwoByteString::kHeaderSize - | |
3978 kHeapObjectTag), | |
3979 assembler->WordShl(coffset, 1)), | |
3980 ccode); | |
3981 var_coffset.Bind( | |
3982 assembler->IntPtrAdd(coffset, assembler->IntPtrConstant(1))); | |
3983 assembler->Goto(&cloop); | |
3984 } | |
3985 | |
3986 // Write the pending {code16} to {offset}. | |
3987 assembler->Bind(&done_cloop); | |
3988 assembler->StoreNoWriteBarrier( | |
3989 MachineRepresentation::kWord16, cresult, | |
3990 assembler->IntPtrAdd( | |
3991 assembler->IntPtrConstant(SeqTwoByteString::kHeaderSize - | |
3992 kHeapObjectTag), | |
3993 assembler->WordShl(offset, 1)), | |
3994 code16); | |
3995 | |
3996 // Copy the remaining parameters to the SeqTwoByteString {cresult}. | |
3997 Label floop(assembler, &var_offset), done_floop(assembler); | |
3998 assembler->Goto(&floop); | |
3999 assembler->Bind(&floop); | |
4000 { | |
4001 // Compute the next {offset}. | |
4002 Node* offset = assembler->IntPtrAdd(var_offset.value(), | |
4003 assembler->IntPtrConstant(1)); | |
4004 | |
4005 // Check if we're done with the string. | |
4006 assembler->GotoIf(assembler->WordEqual(offset, length), &done_floop); | |
4007 | |
4008 // Load the next code point and truncate it to a 16-bit value. | |
4009 Node* code = assembler->Load( | |
4010 MachineType::AnyTagged(), parent_frame_pointer, | |
4011 assembler->IntPtrAdd( | |
4012 assembler->WordShl( | |
4013 assembler->IntPtrSub(length, offset), | |
4014 assembler->IntPtrConstant(kPointerSizeLog2)), | |
4015 assembler->IntPtrConstant( | |
4016 CommonFrameConstants::kFixedFrameSizeAboveFp - | |
4017 kPointerSize))); | |
4018 Node* code32 = assembler->TruncateTaggedToWord32(context, code); | |
4019 Node* code16 = assembler->Word32And( | |
4020 code32, assembler->Int32Constant(String::kMaxUtf16CodeUnit)); | |
4021 | |
4022 // Store the truncated {code} point at the next offset. | |
4023 assembler->StoreNoWriteBarrier( | |
4024 MachineRepresentation::kWord16, cresult, | |
4025 assembler->IntPtrAdd( | |
4026 assembler->IntPtrConstant(SeqTwoByteString::kHeaderSize - | |
4027 kHeapObjectTag), | |
4028 assembler->WordShl(offset, 1)), | |
4029 code16); | |
4030 var_offset.Bind(offset); | |
4031 assembler->Goto(&floop); | |
4032 } | |
4033 | |
4034 // Return the SeqTwoByteString. | |
4035 assembler->Bind(&done_floop); | |
4036 assembler->Return(cresult); | |
4037 } | |
4038 } | |
4039 | |
4040 assembler->Bind(&done_loop); | |
4041 assembler->Return(result); | |
4042 } | |
4043 } | |
4044 | |
4045 namespace { // for String.fromCodePoint | |
4046 | |
4047 bool IsValidCodePoint(Isolate* isolate, Handle<Object> value) { | |
4048 if (!value->IsNumber() && !Object::ToNumber(value).ToHandle(&value)) { | |
4049 return false; | |
4050 } | |
4051 | |
4052 if (Object::ToInteger(isolate, value).ToHandleChecked()->Number() != | |
4053 value->Number()) { | |
4054 return false; | |
4055 } | |
4056 | |
4057 if (value->Number() < 0 || value->Number() > 0x10FFFF) { | |
4058 return false; | |
4059 } | |
4060 | |
4061 return true; | |
4062 } | |
4063 | |
4064 uc32 NextCodePoint(Isolate* isolate, BuiltinArguments args, int index) { | |
4065 Handle<Object> value = args.at<Object>(1 + index); | |
4066 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, value, Object::ToNumber(value), -1); | |
4067 if (!IsValidCodePoint(isolate, value)) { | |
4068 isolate->Throw(*isolate->factory()->NewRangeError( | |
4069 MessageTemplate::kInvalidCodePoint, value)); | |
4070 return -1; | |
4071 } | |
4072 return DoubleToUint32(value->Number()); | |
4073 } | |
4074 | |
4075 } // namespace | |
4076 | |
4077 // ES6 section 21.1.2.2 String.fromCodePoint ( ...codePoints ) | |
4078 BUILTIN(StringFromCodePoint) { | |
4079 HandleScope scope(isolate); | |
4080 int const length = args.length() - 1; | |
4081 if (length == 0) return isolate->heap()->empty_string(); | |
4082 DCHECK_LT(0, length); | |
4083 | |
4084 // Optimistically assume that the resulting String contains only one byte | |
4085 // characters. | |
4086 List<uint8_t> one_byte_buffer(length); | |
4087 uc32 code = 0; | |
4088 int index; | |
4089 for (index = 0; index < length; index++) { | |
4090 code = NextCodePoint(isolate, args, index); | |
4091 if (code < 0) { | |
4092 return isolate->heap()->exception(); | |
4093 } | |
4094 if (code > String::kMaxOneByteCharCode) { | |
4095 break; | |
4096 } | |
4097 one_byte_buffer.Add(code); | |
4098 } | |
4099 | |
4100 if (index == length) { | |
4101 RETURN_RESULT_OR_FAILURE(isolate, isolate->factory()->NewStringFromOneByte( | |
4102 one_byte_buffer.ToConstVector())); | |
4103 } | |
4104 | |
4105 List<uc16> two_byte_buffer(length - index); | |
4106 | |
4107 while (true) { | |
4108 if (code <= unibrow::Utf16::kMaxNonSurrogateCharCode) { | |
4109 two_byte_buffer.Add(code); | |
4110 } else { | |
4111 two_byte_buffer.Add(unibrow::Utf16::LeadSurrogate(code)); | |
4112 two_byte_buffer.Add(unibrow::Utf16::TrailSurrogate(code)); | |
4113 } | |
4114 | |
4115 if (++index == length) { | |
4116 break; | |
4117 } | |
4118 code = NextCodePoint(isolate, args, index); | |
4119 if (code < 0) { | |
4120 return isolate->heap()->exception(); | |
4121 } | |
4122 } | |
4123 | |
4124 Handle<SeqTwoByteString> result; | |
4125 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
4126 isolate, result, | |
4127 isolate->factory()->NewRawTwoByteString(one_byte_buffer.length() + | |
4128 two_byte_buffer.length())); | |
4129 | |
4130 CopyChars(result->GetChars(), one_byte_buffer.ToConstVector().start(), | |
4131 one_byte_buffer.length()); | |
4132 CopyChars(result->GetChars() + one_byte_buffer.length(), | |
4133 two_byte_buffer.ToConstVector().start(), two_byte_buffer.length()); | |
4134 | |
4135 return *result; | |
4136 } | |
4137 | |
4138 // ES6 section 21.1.3.1 String.prototype.charAt ( pos ) | |
4139 void Builtins::Generate_StringPrototypeCharAt(CodeStubAssembler* assembler) { | |
4140 typedef CodeStubAssembler::Label Label; | |
4141 typedef compiler::Node Node; | |
4142 typedef CodeStubAssembler::Variable Variable; | |
4143 | |
4144 Node* receiver = assembler->Parameter(0); | |
4145 Node* position = assembler->Parameter(1); | |
4146 Node* context = assembler->Parameter(4); | |
4147 | |
4148 // Check that {receiver} is coercible to Object and convert it to a String. | |
4149 receiver = | |
4150 assembler->ToThisString(context, receiver, "String.prototype.charAt"); | |
4151 | |
4152 // Convert the {position} to a Smi and check that it's in bounds of the | |
4153 // {receiver}. | |
4154 // TODO(bmeurer): Find an abstraction for this! | |
4155 { | |
4156 // Check if the {position} is already a Smi. | |
4157 Variable var_position(assembler, MachineRepresentation::kTagged); | |
4158 var_position.Bind(position); | |
4159 Label if_positionissmi(assembler), | |
4160 if_positionisnotsmi(assembler, Label::kDeferred); | |
4161 assembler->Branch(assembler->WordIsSmi(position), &if_positionissmi, | |
4162 &if_positionisnotsmi); | |
4163 assembler->Bind(&if_positionisnotsmi); | |
4164 { | |
4165 // Convert the {position} to an Integer via the ToIntegerStub. | |
4166 Callable callable = CodeFactory::ToInteger(assembler->isolate()); | |
4167 Node* index = assembler->CallStub(callable, context, position); | |
4168 | |
4169 // Check if the resulting {index} is now a Smi. | |
4170 Label if_indexissmi(assembler, Label::kDeferred), | |
4171 if_indexisnotsmi(assembler, Label::kDeferred); | |
4172 assembler->Branch(assembler->WordIsSmi(index), &if_indexissmi, | |
4173 &if_indexisnotsmi); | |
4174 | |
4175 assembler->Bind(&if_indexissmi); | |
4176 { | |
4177 var_position.Bind(index); | |
4178 assembler->Goto(&if_positionissmi); | |
4179 } | |
4180 | |
4181 assembler->Bind(&if_indexisnotsmi); | |
4182 { | |
4183 // The ToIntegerStub canonicalizes everything in Smi range to Smi | |
4184 // representation, so any HeapNumber returned is not in Smi range. | |
4185 // The only exception here is -0.0, which we treat as 0. | |
4186 Node* index_value = assembler->LoadHeapNumberValue(index); | |
4187 Label if_indexiszero(assembler, Label::kDeferred), | |
4188 if_indexisnotzero(assembler, Label::kDeferred); | |
4189 assembler->Branch(assembler->Float64Equal( | |
4190 index_value, assembler->Float64Constant(0.0)), | |
4191 &if_indexiszero, &if_indexisnotzero); | |
4192 | |
4193 assembler->Bind(&if_indexiszero); | |
4194 { | |
4195 var_position.Bind(assembler->SmiConstant(Smi::FromInt(0))); | |
4196 assembler->Goto(&if_positionissmi); | |
4197 } | |
4198 | |
4199 assembler->Bind(&if_indexisnotzero); | |
4200 { | |
4201 // The {index} is some other integral Number, that is definitely | |
4202 // neither -0.0 nor in Smi range. | |
4203 assembler->Return(assembler->EmptyStringConstant()); | |
4204 } | |
4205 } | |
4206 } | |
4207 assembler->Bind(&if_positionissmi); | |
4208 position = var_position.value(); | |
4209 | |
4210 // Determine the actual length of the {receiver} String. | |
4211 Node* receiver_length = | |
4212 assembler->LoadObjectField(receiver, String::kLengthOffset); | |
4213 | |
4214 // Return "" if the Smi {position} is outside the bounds of the {receiver}. | |
4215 Label if_positioninbounds(assembler), | |
4216 if_positionnotinbounds(assembler, Label::kDeferred); | |
4217 assembler->Branch(assembler->SmiAboveOrEqual(position, receiver_length), | |
4218 &if_positionnotinbounds, &if_positioninbounds); | |
4219 assembler->Bind(&if_positionnotinbounds); | |
4220 assembler->Return(assembler->EmptyStringConstant()); | |
4221 assembler->Bind(&if_positioninbounds); | |
4222 } | |
4223 | |
4224 // Load the character code at the {position} from the {receiver}. | |
4225 Node* code = assembler->StringCharCodeAt(receiver, position); | |
4226 | |
4227 // And return the single character string with only that {code}. | |
4228 Node* result = assembler->StringFromCharCode(code); | |
4229 assembler->Return(result); | |
4230 } | |
4231 | |
4232 // ES6 section 21.1.3.2 String.prototype.charCodeAt ( pos ) | |
4233 void Builtins::Generate_StringPrototypeCharCodeAt( | |
4234 CodeStubAssembler* assembler) { | |
4235 typedef CodeStubAssembler::Label Label; | |
4236 typedef compiler::Node Node; | |
4237 typedef CodeStubAssembler::Variable Variable; | |
4238 | |
4239 Node* receiver = assembler->Parameter(0); | |
4240 Node* position = assembler->Parameter(1); | |
4241 Node* context = assembler->Parameter(4); | |
4242 | |
4243 // Check that {receiver} is coercible to Object and convert it to a String. | |
4244 receiver = | |
4245 assembler->ToThisString(context, receiver, "String.prototype.charCodeAt"); | |
4246 | |
4247 // Convert the {position} to a Smi and check that it's in bounds of the | |
4248 // {receiver}. | |
4249 // TODO(bmeurer): Find an abstraction for this! | |
4250 { | |
4251 // Check if the {position} is already a Smi. | |
4252 Variable var_position(assembler, MachineRepresentation::kTagged); | |
4253 var_position.Bind(position); | |
4254 Label if_positionissmi(assembler), | |
4255 if_positionisnotsmi(assembler, Label::kDeferred); | |
4256 assembler->Branch(assembler->WordIsSmi(position), &if_positionissmi, | |
4257 &if_positionisnotsmi); | |
4258 assembler->Bind(&if_positionisnotsmi); | |
4259 { | |
4260 // Convert the {position} to an Integer via the ToIntegerStub. | |
4261 Callable callable = CodeFactory::ToInteger(assembler->isolate()); | |
4262 Node* index = assembler->CallStub(callable, context, position); | |
4263 | |
4264 // Check if the resulting {index} is now a Smi. | |
4265 Label if_indexissmi(assembler, Label::kDeferred), | |
4266 if_indexisnotsmi(assembler, Label::kDeferred); | |
4267 assembler->Branch(assembler->WordIsSmi(index), &if_indexissmi, | |
4268 &if_indexisnotsmi); | |
4269 | |
4270 assembler->Bind(&if_indexissmi); | |
4271 { | |
4272 var_position.Bind(index); | |
4273 assembler->Goto(&if_positionissmi); | |
4274 } | |
4275 | |
4276 assembler->Bind(&if_indexisnotsmi); | |
4277 { | |
4278 // The ToIntegerStub canonicalizes everything in Smi range to Smi | |
4279 // representation, so any HeapNumber returned is not in Smi range. | |
4280 // The only exception here is -0.0, which we treat as 0. | |
4281 Node* index_value = assembler->LoadHeapNumberValue(index); | |
4282 Label if_indexiszero(assembler, Label::kDeferred), | |
4283 if_indexisnotzero(assembler, Label::kDeferred); | |
4284 assembler->Branch(assembler->Float64Equal( | |
4285 index_value, assembler->Float64Constant(0.0)), | |
4286 &if_indexiszero, &if_indexisnotzero); | |
4287 | |
4288 assembler->Bind(&if_indexiszero); | |
4289 { | |
4290 var_position.Bind(assembler->SmiConstant(Smi::FromInt(0))); | |
4291 assembler->Goto(&if_positionissmi); | |
4292 } | |
4293 | |
4294 assembler->Bind(&if_indexisnotzero); | |
4295 { | |
4296 // The {index} is some other integral Number, that is definitely | |
4297 // neither -0.0 nor in Smi range. | |
4298 assembler->Return(assembler->NaNConstant()); | |
4299 } | |
4300 } | |
4301 } | |
4302 assembler->Bind(&if_positionissmi); | |
4303 position = var_position.value(); | |
4304 | |
4305 // Determine the actual length of the {receiver} String. | |
4306 Node* receiver_length = | |
4307 assembler->LoadObjectField(receiver, String::kLengthOffset); | |
4308 | |
4309 // Return NaN if the Smi {position} is outside the bounds of the {receiver}. | |
4310 Label if_positioninbounds(assembler), | |
4311 if_positionnotinbounds(assembler, Label::kDeferred); | |
4312 assembler->Branch(assembler->SmiAboveOrEqual(position, receiver_length), | |
4313 &if_positionnotinbounds, &if_positioninbounds); | |
4314 assembler->Bind(&if_positionnotinbounds); | |
4315 assembler->Return(assembler->NaNConstant()); | |
4316 assembler->Bind(&if_positioninbounds); | |
4317 } | |
4318 | |
4319 // Load the character at the {position} from the {receiver}. | |
4320 Node* value = assembler->StringCharCodeAt(receiver, position); | |
4321 Node* result = assembler->SmiFromWord32(value); | |
4322 assembler->Return(result); | |
4323 } | |
4324 | |
4325 // ES6 section 21.1.3.25 String.prototype.toString () | |
4326 void Builtins::Generate_StringPrototypeToString(CodeStubAssembler* assembler) { | |
4327 typedef compiler::Node Node; | |
4328 | |
4329 Node* receiver = assembler->Parameter(0); | |
4330 Node* context = assembler->Parameter(3); | |
4331 | |
4332 Node* result = assembler->ToThisValue( | |
4333 context, receiver, PrimitiveType::kString, "String.prototype.toString"); | |
4334 assembler->Return(result); | |
4335 } | |
4336 | |
4337 // ES6 section 21.1.3.27 String.prototype.trim () | |
4338 BUILTIN(StringPrototypeTrim) { | |
4339 HandleScope scope(isolate); | |
4340 TO_THIS_STRING(string, "String.prototype.trim"); | |
4341 return *String::Trim(string, String::kTrim); | |
4342 } | |
4343 | |
4344 // Non-standard WebKit extension | |
4345 BUILTIN(StringPrototypeTrimLeft) { | |
4346 HandleScope scope(isolate); | |
4347 TO_THIS_STRING(string, "String.prototype.trimLeft"); | |
4348 return *String::Trim(string, String::kTrimLeft); | |
4349 } | |
4350 | |
4351 // Non-standard WebKit extension | |
4352 BUILTIN(StringPrototypeTrimRight) { | |
4353 HandleScope scope(isolate); | |
4354 TO_THIS_STRING(string, "String.prototype.trimRight"); | |
4355 return *String::Trim(string, String::kTrimRight); | |
4356 } | |
4357 | |
4358 // ES6 section 21.1.3.28 String.prototype.valueOf ( ) | |
4359 void Builtins::Generate_StringPrototypeValueOf(CodeStubAssembler* assembler) { | |
4360 typedef compiler::Node Node; | |
4361 | |
4362 Node* receiver = assembler->Parameter(0); | |
4363 Node* context = assembler->Parameter(3); | |
4364 | |
4365 Node* result = assembler->ToThisValue( | |
4366 context, receiver, PrimitiveType::kString, "String.prototype.valueOf"); | |
4367 assembler->Return(result); | |
4368 } | |
4369 | |
4370 // ----------------------------------------------------------------------------- | |
4371 // ES6 section 21.1 ArrayBuffer Objects | |
4372 | |
4373 // ES6 section 24.1.2.1 ArrayBuffer ( length ) for the [[Call]] case. | |
4374 BUILTIN(ArrayBufferConstructor) { | |
4375 HandleScope scope(isolate); | |
4376 Handle<JSFunction> target = args.target<JSFunction>(); | |
4377 DCHECK(*target == target->native_context()->array_buffer_fun() || | |
4378 *target == target->native_context()->shared_array_buffer_fun()); | |
4379 THROW_NEW_ERROR_RETURN_FAILURE( | |
4380 isolate, NewTypeError(MessageTemplate::kConstructorNotFunction, | |
4381 handle(target->shared()->name(), isolate))); | |
4382 } | |
4383 | |
4384 // ES6 section 24.1.2.1 ArrayBuffer ( length ) for the [[Construct]] case. | |
4385 BUILTIN(ArrayBufferConstructor_ConstructStub) { | |
4386 HandleScope scope(isolate); | |
4387 Handle<JSFunction> target = args.target<JSFunction>(); | |
4388 Handle<JSReceiver> new_target = Handle<JSReceiver>::cast(args.new_target()); | |
4389 Handle<Object> length = args.atOrUndefined(isolate, 1); | |
4390 DCHECK(*target == target->native_context()->array_buffer_fun() || | |
4391 *target == target->native_context()->shared_array_buffer_fun()); | |
4392 Handle<Object> number_length; | |
4393 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, number_length, | |
4394 Object::ToInteger(isolate, length)); | |
4395 if (number_length->Number() < 0.0) { | |
4396 THROW_NEW_ERROR_RETURN_FAILURE( | |
4397 isolate, NewRangeError(MessageTemplate::kInvalidArrayBufferLength)); | |
4398 } | |
4399 Handle<JSObject> result; | |
4400 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, | |
4401 JSObject::New(target, new_target)); | |
4402 size_t byte_length; | |
4403 if (!TryNumberToSize(isolate, *number_length, &byte_length)) { | |
4404 THROW_NEW_ERROR_RETURN_FAILURE( | |
4405 isolate, NewRangeError(MessageTemplate::kInvalidArrayBufferLength)); | |
4406 } | |
4407 SharedFlag shared_flag = | |
4408 (*target == target->native_context()->array_buffer_fun()) | |
4409 ? SharedFlag::kNotShared | |
4410 : SharedFlag::kShared; | |
4411 if (!JSArrayBuffer::SetupAllocatingData(Handle<JSArrayBuffer>::cast(result), | |
4412 isolate, byte_length, true, | |
4413 shared_flag)) { | |
4414 THROW_NEW_ERROR_RETURN_FAILURE( | |
4415 isolate, NewRangeError(MessageTemplate::kArrayBufferAllocationFailed)); | |
4416 } | |
4417 return *result; | |
4418 } | |
4419 | |
4420 // ES6 section 24.1.4.1 get ArrayBuffer.prototype.byteLength | |
4421 BUILTIN(ArrayBufferPrototypeGetByteLength) { | |
4422 HandleScope scope(isolate); | |
4423 CHECK_RECEIVER(JSArrayBuffer, array_buffer, | |
4424 "get ArrayBuffer.prototype.byteLength"); | |
4425 | |
4426 if (array_buffer->is_shared()) { | |
4427 THROW_NEW_ERROR_RETURN_FAILURE( | |
4428 isolate, NewTypeError(MessageTemplate::kIncompatibleMethodReceiver, | |
4429 isolate->factory()->NewStringFromAsciiChecked( | |
4430 "get ArrayBuffer.prototype.byteLength"), | |
4431 args.receiver())); | |
4432 } | |
4433 // TODO(franzih): According to the ES6 spec, we should throw a TypeError | |
4434 // here if the JSArrayBuffer is detached. | |
4435 return array_buffer->byte_length(); | |
4436 } | |
4437 | |
4438 // ES6 section 24.1.3.1 ArrayBuffer.isView ( arg ) | |
4439 BUILTIN(ArrayBufferIsView) { | |
4440 SealHandleScope shs(isolate); | |
4441 DCHECK_EQ(2, args.length()); | |
4442 Object* arg = args[1]; | |
4443 return isolate->heap()->ToBoolean(arg->IsJSArrayBufferView()); | |
4444 } | |
4445 | |
4446 // ES7 sharedmem 6.3.4.1 get SharedArrayBuffer.prototype.byteLength | |
4447 BUILTIN(SharedArrayBufferPrototypeGetByteLength) { | |
4448 HandleScope scope(isolate); | |
4449 CHECK_RECEIVER(JSArrayBuffer, array_buffer, | |
4450 "get SharedArrayBuffer.prototype.byteLength"); | |
4451 if (!array_buffer->is_shared()) { | |
4452 THROW_NEW_ERROR_RETURN_FAILURE( | |
4453 isolate, NewTypeError(MessageTemplate::kIncompatibleMethodReceiver, | |
4454 isolate->factory()->NewStringFromAsciiChecked( | |
4455 "get SharedArrayBuffer.prototype.byteLength"), | |
4456 args.receiver())); | |
4457 } | |
4458 return array_buffer->byte_length(); | |
4459 } | |
4460 | |
4461 // ES6 section 26.2.1.1 Proxy ( target, handler ) for the [[Call]] case. | |
4462 BUILTIN(ProxyConstructor) { | |
4463 HandleScope scope(isolate); | |
4464 THROW_NEW_ERROR_RETURN_FAILURE( | |
4465 isolate, | |
4466 NewTypeError(MessageTemplate::kConstructorNotFunction, | |
4467 isolate->factory()->NewStringFromAsciiChecked("Proxy"))); | |
4468 } | |
4469 | |
4470 // ES6 section 26.2.1.1 Proxy ( target, handler ) for the [[Construct]] case. | |
4471 BUILTIN(ProxyConstructor_ConstructStub) { | |
4472 HandleScope scope(isolate); | |
4473 DCHECK(isolate->proxy_function()->IsConstructor()); | |
4474 Handle<Object> target = args.atOrUndefined(isolate, 1); | |
4475 Handle<Object> handler = args.atOrUndefined(isolate, 2); | |
4476 RETURN_RESULT_OR_FAILURE(isolate, JSProxy::New(isolate, target, handler)); | |
4477 } | |
4478 | |
4479 // ----------------------------------------------------------------------------- | |
4480 // Throwers for restricted function properties and strict arguments object | |
4481 // properties | |
4482 | |
4483 BUILTIN(RestrictedFunctionPropertiesThrower) { | |
4484 HandleScope scope(isolate); | |
4485 THROW_NEW_ERROR_RETURN_FAILURE( | |
4486 isolate, NewTypeError(MessageTemplate::kRestrictedFunctionProperties)); | |
4487 } | |
4488 | |
4489 BUILTIN(RestrictedStrictArgumentsPropertiesThrower) { | |
4490 HandleScope scope(isolate); | |
4491 THROW_NEW_ERROR_RETURN_FAILURE( | |
4492 isolate, NewTypeError(MessageTemplate::kStrictPoisonPill)); | |
4493 } | |
4494 | |
4495 // ----------------------------------------------------------------------------- | |
4496 // | 145 // |
4497 | 146 |
4498 namespace { | 147 namespace { |
4499 | 148 |
4500 // Returns the holder JSObject if the function can legally be called with this | 149 // Returns the holder JSObject if the function can legally be called with this |
4501 // receiver. Returns nullptr if the call is illegal. | 150 // receiver. Returns nullptr if the call is illegal. |
4502 // TODO(dcarney): CallOptimization duplicates this logic, merge. | 151 // TODO(dcarney): CallOptimization duplicates this logic, merge. |
4503 JSObject* GetCompatibleReceiver(Isolate* isolate, FunctionTemplateInfo* info, | 152 JSObject* GetCompatibleReceiver(Isolate* isolate, FunctionTemplateInfo* info, |
4504 JSObject* receiver) { | 153 JSObject* receiver) { |
4505 Object* recv_type = info->signature(); | 154 Object* recv_type = info->signature(); |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4615 RETURN_RESULT_OR_FAILURE( | 264 RETURN_RESULT_OR_FAILURE( |
4616 isolate, HandleApiCallHelper<true>(isolate, function, new_target, | 265 isolate, HandleApiCallHelper<true>(isolate, function, new_target, |
4617 fun_data, receiver, args)); | 266 fun_data, receiver, args)); |
4618 } else { | 267 } else { |
4619 RETURN_RESULT_OR_FAILURE( | 268 RETURN_RESULT_OR_FAILURE( |
4620 isolate, HandleApiCallHelper<false>(isolate, function, new_target, | 269 isolate, HandleApiCallHelper<false>(isolate, function, new_target, |
4621 fun_data, receiver, args)); | 270 fun_data, receiver, args)); |
4622 } | 271 } |
4623 } | 272 } |
4624 | 273 |
| 274 namespace { |
| 275 |
| 276 bool CodeGenerationFromStringsAllowed(Isolate* isolate, |
| 277 Handle<Context> context) { |
| 278 DCHECK(context->allow_code_gen_from_strings()->IsFalse(isolate)); |
| 279 // Check with callback if set. |
| 280 AllowCodeGenerationFromStringsCallback callback = |
| 281 isolate->allow_code_gen_callback(); |
| 282 if (callback == NULL) { |
| 283 // No callback set and code generation disallowed. |
| 284 return false; |
| 285 } else { |
| 286 // Callback set. Let it decide if code generation is allowed. |
| 287 VMState<EXTERNAL> state(isolate); |
| 288 return callback(v8::Utils::ToLocal(context)); |
| 289 } |
| 290 } |
| 291 |
| 292 } // namespace |
| 293 |
| 294 MaybeHandle<JSFunction> Builtins::CompileString(Handle<Context> context, |
| 295 Handle<String> source, |
| 296 ParseRestriction restriction) { |
| 297 Isolate* const isolate = context->GetIsolate(); |
| 298 Handle<Context> native_context(context->native_context(), isolate); |
| 299 |
| 300 // Check if native context allows code generation from |
| 301 // strings. Throw an exception if it doesn't. |
| 302 if (native_context->allow_code_gen_from_strings()->IsFalse(isolate) && |
| 303 !CodeGenerationFromStringsAllowed(isolate, native_context)) { |
| 304 Handle<Object> error_message = |
| 305 native_context->ErrorMessageForCodeGenerationFromStrings(); |
| 306 THROW_NEW_ERROR(isolate, NewEvalError(MessageTemplate::kCodeGenFromStrings, |
| 307 error_message), |
| 308 JSFunction); |
| 309 } |
| 310 |
| 311 // Compile source string in the native context. |
| 312 int eval_scope_position = 0; |
| 313 int eval_position = kNoSourcePosition; |
| 314 Handle<SharedFunctionInfo> outer_info(native_context->closure()->shared()); |
| 315 return Compiler::GetFunctionFromEval(source, outer_info, native_context, |
| 316 SLOPPY, restriction, eval_scope_position, |
| 317 eval_position); |
| 318 } |
| 319 |
4625 Handle<Code> Builtins::CallFunction(ConvertReceiverMode mode, | 320 Handle<Code> Builtins::CallFunction(ConvertReceiverMode mode, |
4626 TailCallMode tail_call_mode) { | 321 TailCallMode tail_call_mode) { |
4627 switch (tail_call_mode) { | 322 switch (tail_call_mode) { |
4628 case TailCallMode::kDisallow: | 323 case TailCallMode::kDisallow: |
4629 switch (mode) { | 324 switch (mode) { |
4630 case ConvertReceiverMode::kNullOrUndefined: | 325 case ConvertReceiverMode::kNullOrUndefined: |
4631 return CallFunction_ReceiverIsNullOrUndefined(); | 326 return CallFunction_ReceiverIsNullOrUndefined(); |
4632 case ConvertReceiverMode::kNotNullOrUndefined: | 327 case ConvertReceiverMode::kNotNullOrUndefined: |
4633 return CallFunction_ReceiverIsNotNullOrUndefined(); | 328 return CallFunction_ReceiverIsNotNullOrUndefined(); |
4634 case ConvertReceiverMode::kAny: | 329 case ConvertReceiverMode::kAny: |
(...skipping 866 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5501 } | 1196 } |
5502 | 1197 |
5503 void Builtins::Generate_InterruptCheck(MacroAssembler* masm) { | 1198 void Builtins::Generate_InterruptCheck(MacroAssembler* masm) { |
5504 masm->TailCallRuntime(Runtime::kInterrupt); | 1199 masm->TailCallRuntime(Runtime::kInterrupt); |
5505 } | 1200 } |
5506 | 1201 |
5507 void Builtins::Generate_StackCheck(MacroAssembler* masm) { | 1202 void Builtins::Generate_StackCheck(MacroAssembler* masm) { |
5508 masm->TailCallRuntime(Runtime::kStackGuard); | 1203 masm->TailCallRuntime(Runtime::kStackGuard); |
5509 } | 1204 } |
5510 | 1205 |
5511 namespace { | |
5512 | |
5513 void ValidateSharedTypedArray(CodeStubAssembler* a, compiler::Node* tagged, | |
5514 compiler::Node* context, | |
5515 compiler::Node** out_instance_type, | |
5516 compiler::Node** out_backing_store) { | |
5517 using namespace compiler; | |
5518 CodeStubAssembler::Label is_smi(a), not_smi(a), is_typed_array(a), | |
5519 not_typed_array(a), is_shared(a), not_shared(a), is_float_or_clamped(a), | |
5520 not_float_or_clamped(a), invalid(a); | |
5521 | |
5522 // Fail if it is not a heap object. | |
5523 a->Branch(a->WordIsSmi(tagged), &is_smi, ¬_smi); | |
5524 a->Bind(&is_smi); | |
5525 a->Goto(&invalid); | |
5526 | |
5527 // Fail if the array's instance type is not JSTypedArray. | |
5528 a->Bind(¬_smi); | |
5529 a->Branch(a->WordEqual(a->LoadInstanceType(tagged), | |
5530 a->Int32Constant(JS_TYPED_ARRAY_TYPE)), | |
5531 &is_typed_array, ¬_typed_array); | |
5532 a->Bind(¬_typed_array); | |
5533 a->Goto(&invalid); | |
5534 | |
5535 // Fail if the array's JSArrayBuffer is not shared. | |
5536 a->Bind(&is_typed_array); | |
5537 Node* array_buffer = a->LoadObjectField(tagged, JSTypedArray::kBufferOffset); | |
5538 Node* is_buffer_shared = a->BitFieldDecode<JSArrayBuffer::IsShared>( | |
5539 a->LoadObjectField(array_buffer, JSArrayBuffer::kBitFieldSlot)); | |
5540 a->Branch(is_buffer_shared, &is_shared, ¬_shared); | |
5541 a->Bind(¬_shared); | |
5542 a->Goto(&invalid); | |
5543 | |
5544 // Fail if the array's element type is float32, float64 or clamped. | |
5545 a->Bind(&is_shared); | |
5546 Node* elements_instance_type = a->LoadInstanceType( | |
5547 a->LoadObjectField(tagged, JSObject::kElementsOffset)); | |
5548 STATIC_ASSERT(FIXED_INT8_ARRAY_TYPE < FIXED_FLOAT32_ARRAY_TYPE); | |
5549 STATIC_ASSERT(FIXED_INT16_ARRAY_TYPE < FIXED_FLOAT32_ARRAY_TYPE); | |
5550 STATIC_ASSERT(FIXED_INT32_ARRAY_TYPE < FIXED_FLOAT32_ARRAY_TYPE); | |
5551 STATIC_ASSERT(FIXED_UINT8_ARRAY_TYPE < FIXED_FLOAT32_ARRAY_TYPE); | |
5552 STATIC_ASSERT(FIXED_UINT16_ARRAY_TYPE < FIXED_FLOAT32_ARRAY_TYPE); | |
5553 STATIC_ASSERT(FIXED_UINT32_ARRAY_TYPE < FIXED_FLOAT32_ARRAY_TYPE); | |
5554 a->Branch(a->Int32LessThan(elements_instance_type, | |
5555 a->Int32Constant(FIXED_FLOAT32_ARRAY_TYPE)), | |
5556 ¬_float_or_clamped, &is_float_or_clamped); | |
5557 a->Bind(&is_float_or_clamped); | |
5558 a->Goto(&invalid); | |
5559 | |
5560 a->Bind(&invalid); | |
5561 a->CallRuntime(Runtime::kThrowNotIntegerSharedTypedArrayError, context, | |
5562 tagged); | |
5563 a->Return(a->UndefinedConstant()); | |
5564 | |
5565 a->Bind(¬_float_or_clamped); | |
5566 *out_instance_type = elements_instance_type; | |
5567 | |
5568 Node* backing_store = | |
5569 a->LoadObjectField(array_buffer, JSArrayBuffer::kBackingStoreOffset); | |
5570 Node* byte_offset = a->ChangeUint32ToWord(a->TruncateTaggedToWord32( | |
5571 context, | |
5572 a->LoadObjectField(tagged, JSArrayBufferView::kByteOffsetOffset))); | |
5573 *out_backing_store = a->IntPtrAdd(backing_store, byte_offset); | |
5574 } | |
5575 | |
5576 // https://tc39.github.io/ecmascript_sharedmem/shmem.html#Atomics.ValidateAtomic
Access | |
5577 compiler::Node* ConvertTaggedAtomicIndexToWord32(CodeStubAssembler* a, | |
5578 compiler::Node* tagged, | |
5579 compiler::Node* context) { | |
5580 using namespace compiler; | |
5581 CodeStubAssembler::Variable var_result(a, MachineRepresentation::kWord32); | |
5582 | |
5583 Callable to_number = CodeFactory::ToNumber(a->isolate()); | |
5584 Node* number_index = a->CallStub(to_number, context, tagged); | |
5585 CodeStubAssembler::Label done(a, &var_result); | |
5586 | |
5587 CodeStubAssembler::Label if_numberissmi(a), if_numberisnotsmi(a); | |
5588 a->Branch(a->WordIsSmi(number_index), &if_numberissmi, &if_numberisnotsmi); | |
5589 | |
5590 a->Bind(&if_numberissmi); | |
5591 { | |
5592 var_result.Bind(a->SmiToWord32(number_index)); | |
5593 a->Goto(&done); | |
5594 } | |
5595 | |
5596 a->Bind(&if_numberisnotsmi); | |
5597 { | |
5598 Node* number_index_value = a->LoadHeapNumberValue(number_index); | |
5599 Node* access_index = a->TruncateFloat64ToWord32(number_index_value); | |
5600 Node* test_index = a->ChangeInt32ToFloat64(access_index); | |
5601 | |
5602 CodeStubAssembler::Label if_indexesareequal(a), if_indexesarenotequal(a); | |
5603 a->Branch(a->Float64Equal(number_index_value, test_index), | |
5604 &if_indexesareequal, &if_indexesarenotequal); | |
5605 | |
5606 a->Bind(&if_indexesareequal); | |
5607 { | |
5608 var_result.Bind(access_index); | |
5609 a->Goto(&done); | |
5610 } | |
5611 | |
5612 a->Bind(&if_indexesarenotequal); | |
5613 a->Return( | |
5614 a->CallRuntime(Runtime::kThrowInvalidAtomicAccessIndexError, context)); | |
5615 } | |
5616 | |
5617 a->Bind(&done); | |
5618 return var_result.value(); | |
5619 } | |
5620 | |
5621 void ValidateAtomicIndex(CodeStubAssembler* a, compiler::Node* index_word, | |
5622 compiler::Node* array_length_word, | |
5623 compiler::Node* context) { | |
5624 using namespace compiler; | |
5625 // Check if the index is in bounds. If not, throw RangeError. | |
5626 CodeStubAssembler::Label if_inbounds(a), if_notinbounds(a); | |
5627 a->Branch( | |
5628 a->WordOr(a->Int32LessThan(index_word, a->Int32Constant(0)), | |
5629 a->Int32GreaterThanOrEqual(index_word, array_length_word)), | |
5630 &if_notinbounds, &if_inbounds); | |
5631 a->Bind(&if_notinbounds); | |
5632 a->Return( | |
5633 a->CallRuntime(Runtime::kThrowInvalidAtomicAccessIndexError, context)); | |
5634 a->Bind(&if_inbounds); | |
5635 } | |
5636 | |
5637 } // anonymous namespace | |
5638 | |
5639 void Builtins::Generate_AtomicsLoad(CodeStubAssembler* a) { | |
5640 using namespace compiler; | |
5641 Node* array = a->Parameter(1); | |
5642 Node* index = a->Parameter(2); | |
5643 Node* context = a->Parameter(3 + 2); | |
5644 | |
5645 Node* instance_type; | |
5646 Node* backing_store; | |
5647 ValidateSharedTypedArray(a, array, context, &instance_type, &backing_store); | |
5648 | |
5649 Node* index_word32 = ConvertTaggedAtomicIndexToWord32(a, index, context); | |
5650 Node* array_length_word32 = a->TruncateTaggedToWord32( | |
5651 context, a->LoadObjectField(array, JSTypedArray::kLengthOffset)); | |
5652 ValidateAtomicIndex(a, index_word32, array_length_word32, context); | |
5653 Node* index_word = a->ChangeUint32ToWord(index_word32); | |
5654 | |
5655 CodeStubAssembler::Label i8(a), u8(a), i16(a), u16(a), i32(a), u32(a), | |
5656 other(a); | |
5657 int32_t case_values[] = { | |
5658 FIXED_INT8_ARRAY_TYPE, FIXED_UINT8_ARRAY_TYPE, FIXED_INT16_ARRAY_TYPE, | |
5659 FIXED_UINT16_ARRAY_TYPE, FIXED_INT32_ARRAY_TYPE, FIXED_UINT32_ARRAY_TYPE, | |
5660 }; | |
5661 CodeStubAssembler::Label* case_labels[] = { | |
5662 &i8, &u8, &i16, &u16, &i32, &u32, | |
5663 }; | |
5664 a->Switch(instance_type, &other, case_values, case_labels, | |
5665 arraysize(case_labels)); | |
5666 | |
5667 a->Bind(&i8); | |
5668 a->Return( | |
5669 a->SmiTag(a->AtomicLoad(MachineType::Int8(), backing_store, index_word))); | |
5670 | |
5671 a->Bind(&u8); | |
5672 a->Return(a->SmiTag( | |
5673 a->AtomicLoad(MachineType::Uint8(), backing_store, index_word))); | |
5674 | |
5675 a->Bind(&i16); | |
5676 a->Return(a->SmiTag(a->AtomicLoad(MachineType::Int16(), backing_store, | |
5677 a->WordShl(index_word, 1)))); | |
5678 | |
5679 a->Bind(&u16); | |
5680 a->Return(a->SmiTag(a->AtomicLoad(MachineType::Uint16(), backing_store, | |
5681 a->WordShl(index_word, 1)))); | |
5682 | |
5683 a->Bind(&i32); | |
5684 a->Return(a->ChangeInt32ToTagged(a->AtomicLoad( | |
5685 MachineType::Int32(), backing_store, a->WordShl(index_word, 2)))); | |
5686 | |
5687 a->Bind(&u32); | |
5688 a->Return(a->ChangeUint32ToTagged(a->AtomicLoad( | |
5689 MachineType::Uint32(), backing_store, a->WordShl(index_word, 2)))); | |
5690 | |
5691 // This shouldn't happen, we've already validated the type. | |
5692 a->Bind(&other); | |
5693 a->Return(a->Int32Constant(0)); | |
5694 } | |
5695 | |
5696 void Builtins::Generate_AtomicsStore(CodeStubAssembler* a) { | |
5697 using namespace compiler; | |
5698 Node* array = a->Parameter(1); | |
5699 Node* index = a->Parameter(2); | |
5700 Node* value = a->Parameter(3); | |
5701 Node* context = a->Parameter(4 + 2); | |
5702 | |
5703 Node* instance_type; | |
5704 Node* backing_store; | |
5705 ValidateSharedTypedArray(a, array, context, &instance_type, &backing_store); | |
5706 | |
5707 Node* index_word32 = ConvertTaggedAtomicIndexToWord32(a, index, context); | |
5708 Node* array_length_word32 = a->TruncateTaggedToWord32( | |
5709 context, a->LoadObjectField(array, JSTypedArray::kLengthOffset)); | |
5710 ValidateAtomicIndex(a, index_word32, array_length_word32, context); | |
5711 Node* index_word = a->ChangeUint32ToWord(index_word32); | |
5712 | |
5713 Callable to_integer = CodeFactory::ToInteger(a->isolate()); | |
5714 Node* value_integer = a->CallStub(to_integer, context, value); | |
5715 Node* value_word32 = a->TruncateTaggedToWord32(context, value_integer); | |
5716 | |
5717 CodeStubAssembler::Label u8(a), u16(a), u32(a), other(a); | |
5718 int32_t case_values[] = { | |
5719 FIXED_INT8_ARRAY_TYPE, FIXED_UINT8_ARRAY_TYPE, FIXED_INT16_ARRAY_TYPE, | |
5720 FIXED_UINT16_ARRAY_TYPE, FIXED_INT32_ARRAY_TYPE, FIXED_UINT32_ARRAY_TYPE, | |
5721 }; | |
5722 CodeStubAssembler::Label* case_labels[] = { | |
5723 &u8, &u8, &u16, &u16, &u32, &u32, | |
5724 }; | |
5725 a->Switch(instance_type, &other, case_values, case_labels, | |
5726 arraysize(case_labels)); | |
5727 | |
5728 a->Bind(&u8); | |
5729 a->AtomicStore(MachineRepresentation::kWord8, backing_store, index_word, | |
5730 value_word32); | |
5731 a->Return(value_integer); | |
5732 | |
5733 a->Bind(&u16); | |
5734 a->SmiTag(a->AtomicStore(MachineRepresentation::kWord16, backing_store, | |
5735 a->WordShl(index_word, 1), value_word32)); | |
5736 a->Return(value_integer); | |
5737 | |
5738 a->Bind(&u32); | |
5739 a->AtomicStore(MachineRepresentation::kWord32, backing_store, | |
5740 a->WordShl(index_word, 2), value_word32); | |
5741 a->Return(value_integer); | |
5742 | |
5743 // This shouldn't happen, we've already validated the type. | |
5744 a->Bind(&other); | |
5745 a->Return(a->Int32Constant(0)); | |
5746 } | |
5747 | |
5748 void Builtins::Generate_CallFunction_ReceiverIsNullOrUndefined( | 1206 void Builtins::Generate_CallFunction_ReceiverIsNullOrUndefined( |
5749 MacroAssembler* masm) { | 1207 MacroAssembler* masm) { |
5750 Generate_CallFunction(masm, ConvertReceiverMode::kNullOrUndefined, | 1208 Generate_CallFunction(masm, ConvertReceiverMode::kNullOrUndefined, |
5751 TailCallMode::kDisallow); | 1209 TailCallMode::kDisallow); |
5752 } | 1210 } |
5753 | 1211 |
5754 void Builtins::Generate_CallFunction_ReceiverIsNotNullOrUndefined( | 1212 void Builtins::Generate_CallFunction_ReceiverIsNotNullOrUndefined( |
5755 MacroAssembler* masm) { | 1213 MacroAssembler* masm) { |
5756 Generate_CallFunction(masm, ConvertReceiverMode::kNotNullOrUndefined, | 1214 Generate_CallFunction(masm, ConvertReceiverMode::kNotNullOrUndefined, |
5757 TailCallMode::kDisallow); | 1215 TailCallMode::kDisallow); |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5831 return Generate_InterpreterPushArgsAndCallImpl(masm, TailCallMode::kDisallow, | 1289 return Generate_InterpreterPushArgsAndCallImpl(masm, TailCallMode::kDisallow, |
5832 CallableType::kJSFunction); | 1290 CallableType::kJSFunction); |
5833 } | 1291 } |
5834 | 1292 |
5835 void Builtins::Generate_InterpreterPushArgsAndTailCallFunction( | 1293 void Builtins::Generate_InterpreterPushArgsAndTailCallFunction( |
5836 MacroAssembler* masm) { | 1294 MacroAssembler* masm) { |
5837 return Generate_InterpreterPushArgsAndCallImpl(masm, TailCallMode::kAllow, | 1295 return Generate_InterpreterPushArgsAndCallImpl(masm, TailCallMode::kAllow, |
5838 CallableType::kJSFunction); | 1296 CallableType::kJSFunction); |
5839 } | 1297 } |
5840 | 1298 |
5841 void Builtins::Generate_MathMax(MacroAssembler* masm) { | |
5842 Generate_MathMaxMin(masm, MathMaxMinKind::kMax); | |
5843 } | |
5844 | |
5845 void Builtins::Generate_MathMin(MacroAssembler* masm) { | |
5846 Generate_MathMaxMin(masm, MathMaxMinKind::kMin); | |
5847 } | |
5848 | |
5849 #define DEFINE_BUILTIN_ACCESSOR(Name, ...) \ | 1299 #define DEFINE_BUILTIN_ACCESSOR(Name, ...) \ |
5850 Handle<Code> Builtins::Name() { \ | 1300 Handle<Code> Builtins::Name() { \ |
5851 Code** code_address = reinterpret_cast<Code**>(builtin_address(k##Name)); \ | 1301 Code** code_address = reinterpret_cast<Code**>(builtin_address(k##Name)); \ |
5852 return Handle<Code>(code_address); \ | 1302 return Handle<Code>(code_address); \ |
5853 } | 1303 } |
5854 BUILTIN_LIST_ALL(DEFINE_BUILTIN_ACCESSOR) | 1304 BUILTIN_LIST_ALL(DEFINE_BUILTIN_ACCESSOR) |
5855 #undef DEFINE_BUILTIN_ACCESSOR | 1305 #undef DEFINE_BUILTIN_ACCESSOR |
5856 | 1306 |
5857 } // namespace internal | 1307 } // namespace internal |
5858 } // namespace v8 | 1308 } // namespace v8 |
OLD | NEW |