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 3 // found in the LICENSE file. 4 5 #include "src/builtins.h" 6 7 #include "src/api-arguments.h" 8 #include "src/api-natives.h" 9 #include "src/api.h" 10 #include "src/base/ieee754.h" 11 #include "src/base/once.h" 12 #include "src/bootstrapper.h" 13 #include "src/code-factory.h" 14 #include "src/code-stub-assembler.h" 15 #include "src/dateparser-inl.h" 16 #include "src/elements.h" 17 #include "src/frames-inl.h" 18 #include "src/gdb-jit.h" 19 #include "src/ic/handler-compiler.h" 20 #include "src/ic/ic.h" 21 #include "src/isolate-inl.h" 22 #include "src/json-parser.h" 23 #include "src/json-stringifier.h" 24 #include "src/messages.h" 25 #include "src/property-descriptor.h" 26 #include "src/prototype.h" 27 #include "src/string-builder.h" 28 #include "src/uri.h" 29 #include "src/vm-state-inl.h" 30 31 namespace v8 { 32 namespace internal { 33 34 namespace { 35 36 // Arguments object passed to C++ builtins. 37 class BuiltinArguments : public Arguments { 38 public: 39 BuiltinArguments(int length, Object** arguments) 40 : Arguments(length, arguments) { 41 // Check we have at least the receiver. 42 DCHECK_LE(1, this->length()); 43 } 44 45 Object*& operator[] (int index) { 46 DCHECK_LT(index, length()); 47 return Arguments::operator[](index); 48 } 49 50 template <class S> Handle<S> at(int index) { 51 DCHECK_LT(index, length()); 52 return Arguments::at<S>(index); 53 } 54 55 Handle<Object> atOrUndefined(Isolate* isolate, int index) { 56 if (index >= length()) { 57 return isolate->factory()->undefined_value(); 58 } 59 return at<Object>(index); 60 } 61 62 Handle<Object> receiver() { 63 return Arguments::at<Object>(0); 64 } 65 66 template <class S> 67 Handle<S> target() { 68 return Arguments::at<S>(Arguments::length() - 2); 69 } 70 Handle<HeapObject> new_target() { 71 return Arguments::at<HeapObject>(Arguments::length() - 1); 72 } 73 74 // Gets the total number of arguments including the receiver (but 75 // excluding extra arguments). 76 int length() const { return Arguments::length() - 2; } 77 }; 78 79 80 // ---------------------------------------------------------------------------- 81 // Support macro for defining builtins in C++. 82 // ---------------------------------------------------------------------------- 83 // 84 // A builtin function is defined by writing: 85 // 86 // BUILTIN(name) { 87 // ... 88 // } 89 // 90 // In the body of the builtin function the arguments can be accessed 91 // through the BuiltinArguments object args. 92 // TODO(cbruni): add global flag to check whether any tracing events have been 93 // enabled. 94 #define BUILTIN(name) \ 95 MUST_USE_RESULT static Object* Builtin_Impl_##name(BuiltinArguments args, \ 96 Isolate* isolate); \ 97 \ 98 V8_NOINLINE static Object* Builtin_Impl_Stats_##name( \ 99 int args_length, Object** args_object, Isolate* isolate) { \ 100 BuiltinArguments args(args_length, args_object); \ 101 RuntimeCallTimerScope timer(isolate, &RuntimeCallStats::Builtin_##name); \ 102 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.runtime"), \ 103 "V8.Builtin_" #name); \ 104 return Builtin_Impl_##name(args, isolate); \ 105 } \ 106 \ 107 MUST_USE_RESULT static Object* Builtin_##name( \ 108 int args_length, Object** args_object, Isolate* isolate) { \ 109 if (FLAG_runtime_call_stats) { \ 110 return Builtin_Impl_Stats_##name(args_length, args_object, isolate); \ 111 } \ 112 BuiltinArguments args(args_length, args_object); \ 113 return Builtin_Impl_##name(args, isolate); \ 114 } \ 115 \ 116 MUST_USE_RESULT static Object* Builtin_Impl_##name(BuiltinArguments args, \ 117 Isolate* isolate) 118 119 // ---------------------------------------------------------------------------- 120 121 #define CHECK_RECEIVER(Type, name, method) \ 122 if (!args.receiver()->Is##Type()) { \ 123 THROW_NEW_ERROR_RETURN_FAILURE( \ 124 isolate, \ 125 NewTypeError(MessageTemplate::kIncompatibleMethodReceiver, \ 126 isolate->factory()->NewStringFromAsciiChecked(method), \ 127 args.receiver())); \ 128 } \ 129 Handle<Type> name = Handle<Type>::cast(args.receiver()) 130 131 // Throws a TypeError for {method} if the receiver is not coercible to Object, 132 // or converts the receiver to a String otherwise and assigns it to a new var 133 // with the given {name}. 134 #define TO_THIS_STRING(name, method) \ 135 if (args.receiver()->IsNull(isolate) || \ 136 args.receiver()->IsUndefined(isolate)) { \ 137 THROW_NEW_ERROR_RETURN_FAILURE( \ 138 isolate, \ 139 NewTypeError(MessageTemplate::kCalledOnNullOrUndefined, \ 140 isolate->factory()->NewStringFromAsciiChecked(method))); \ 141 } \ 142 Handle<String> name; \ 143 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( \ 144 isolate, name, Object::ToString(isolate, args.receiver())) 145 146 inline bool ClampedToInteger(Isolate* isolate, Object* object, int* out) { 147 // This is an extended version of ECMA-262 7.1.11 handling signed values 148 // Try to convert object to a number and clamp values to [kMinInt, kMaxInt] 149 if (object->IsSmi()) { 150 *out = Smi::cast(object)->value(); 151 return true; 152 } else if (object->IsHeapNumber()) { 153 double value = HeapNumber::cast(object)->value(); 154 if (std::isnan(value)) { 155 *out = 0; 156 } else if (value > kMaxInt) { 157 *out = kMaxInt; 158 } else if (value < kMinInt) { 159 *out = kMinInt; 160 } else { 161 *out = static_cast<int>(value); 162 } 163 return true; 164 } else if (object->IsUndefined(isolate) || object->IsNull(isolate)) { 165 *out = 0; 166 return true; 167 } else if (object->IsBoolean()) { 168 *out = object->IsTrue(isolate); 169 return true; 170 } 171 return false; 172 } 173 174 175 inline bool GetSloppyArgumentsLength(Isolate* isolate, Handle<JSObject> object, 176 int* out) { 177 Context* context = *isolate->native_context(); 178 Map* map = object->map(); 179 if (map != context->sloppy_arguments_map() && 180 map != context->strict_arguments_map() && 181 map != context->fast_aliased_arguments_map()) { 182 return false; 183 } 184 DCHECK(object->HasFastElements() || object->HasFastArgumentsElements()); 185 Object* len_obj = object->InObjectPropertyAt(JSArgumentsObject::kLengthIndex); 186 if (!len_obj->IsSmi()) return false; 187 *out = Max(0, Smi::cast(len_obj)->value()); 188 return *out <= object->elements()->length(); 189 } 190 191 inline bool PrototypeHasNoElements(Isolate* isolate, JSObject* object) { 192 DisallowHeapAllocation no_gc; 193 HeapObject* prototype = HeapObject::cast(object->map()->prototype()); 194 HeapObject* null = isolate->heap()->null_value(); 195 HeapObject* empty = isolate->heap()->empty_fixed_array(); 196 while (prototype != null) { 197 Map* map = prototype->map(); 198 if (map->instance_type() <= LAST_CUSTOM_ELEMENTS_RECEIVER) return false; 199 if (JSObject::cast(prototype)->elements() != empty) return false; 200 prototype = HeapObject::cast(map->prototype()); 201 } 202 return true; 203 } 204 205 inline bool IsJSArrayFastElementMovingAllowed(Isolate* isolate, 206 JSArray* receiver) { 207 return PrototypeHasNoElements(isolate, receiver); 208 } 209 210 inline bool HasSimpleElements(JSObject* current) { 211 return current->map()->instance_type() > LAST_CUSTOM_ELEMENTS_RECEIVER && 212 !current->GetElementsAccessor()->HasAccessors(current); 213 } 214 215 inline bool HasOnlySimpleReceiverElements(Isolate* isolate, 216 JSObject* receiver) { 217 // Check that we have no accessors on the receiver's elements. 218 if (!HasSimpleElements(receiver)) return false; 219 return PrototypeHasNoElements(isolate, receiver); 220 } 221 222 inline bool HasOnlySimpleElements(Isolate* isolate, JSReceiver* receiver) { 223 DisallowHeapAllocation no_gc; 224 PrototypeIterator iter(isolate, receiver, kStartAtReceiver); 225 for (; !iter.IsAtEnd(); iter.Advance()) { 226 if (iter.GetCurrent()->IsJSProxy()) return false; 227 JSObject* current = iter.GetCurrent<JSObject>(); 228 if (!HasSimpleElements(current)) return false; 229 } 230 return true; 231 } 232 233 // Returns |false| if not applicable. 234 MUST_USE_RESULT 235 inline bool EnsureJSArrayWithWritableFastElements(Isolate* isolate, 236 Handle<Object> receiver, 237 BuiltinArguments* args, 238 int first_added_arg) { 239 if (!receiver->IsJSArray()) return false; 240 Handle<JSArray> array = Handle<JSArray>::cast(receiver); 241 ElementsKind origin_kind = array->GetElementsKind(); 242 if (IsDictionaryElementsKind(origin_kind)) return false; 243 if (!array->map()->is_extensible()) return false; 244 if (args == nullptr) return true; 245 246 // If there may be elements accessors in the prototype chain, the fast path 247 // cannot be used if there arguments to add to the array. 248 if (!IsJSArrayFastElementMovingAllowed(isolate, *array)) return false; 249 250 // Adding elements to the array prototype would break code that makes sure 251 // it has no elements. Handle that elsewhere. 252 if (isolate->IsAnyInitialArrayPrototype(array)) return false; 253 254 // Need to ensure that the arguments passed in args can be contained in 255 // the array. 256 int args_length = args->length(); 257 if (first_added_arg >= args_length) return true; 258 259 if (IsFastObjectElementsKind(origin_kind)) return true; 260 ElementsKind target_kind = origin_kind; 261 { 262 DisallowHeapAllocation no_gc; 263 for (int i = first_added_arg; i < args_length; i++) { 264 Object* arg = (*args)[i]; 265 if (arg->IsHeapObject()) { 266 if (arg->IsHeapNumber()) { 267 target_kind = FAST_DOUBLE_ELEMENTS; 268 } else { 269 target_kind = FAST_ELEMENTS; 270 break; 271 } 272 } 273 } 274 } 275 if (target_kind != origin_kind) { 276 // Use a short-lived HandleScope to avoid creating several copies of the 277 // elements handle which would cause issues when left-trimming later-on. 278 HandleScope scope(isolate); 279 JSObject::TransitionElementsKind(array, target_kind); 280 } 281 return true; 282 } 283 284 MUST_USE_RESULT static Object* CallJsIntrinsic(Isolate* isolate, 285 Handle<JSFunction> function, 286 BuiltinArguments args) { 287 HandleScope handleScope(isolate); 288 int argc = args.length() - 1; 289 ScopedVector<Handle<Object> > argv(argc); 290 for (int i = 0; i < argc; ++i) { 291 argv[i] = args.at<Object>(i + 1); 292 } 293 RETURN_RESULT_OR_FAILURE( 294 isolate, 295 Execution::Call(isolate, function, args.receiver(), argc, argv.start())); 296 } 297 298 299 } // namespace 300 301 302 BUILTIN(Illegal) { 303 UNREACHABLE(); 304 return isolate->heap()->undefined_value(); // Make compiler happy. 305 } 306 307 308 BUILTIN(EmptyFunction) { return isolate->heap()->undefined_value(); } 309 310 void Builtins::Generate_ArrayIsArray(CodeStubAssembler* assembler) { 311 typedef compiler::Node Node; 312 typedef CodeStubAssembler::Label Label; 313 314 Node* object = assembler->Parameter(1); 315 Node* context = assembler->Parameter(4); 316 317 Label call_runtime(assembler), return_true(assembler), 318 return_false(assembler); 319 320 assembler->GotoIf(assembler->WordIsSmi(object), &return_false); 321 Node* instance_type = assembler->LoadInstanceType(object); 322 323 assembler->GotoIf(assembler->Word32Equal( 324 instance_type, assembler->Int32Constant(JS_ARRAY_TYPE)), 325 &return_true); 326 327 // TODO(verwaest): Handle proxies in-place. 328 assembler->Branch(assembler->Word32Equal( 329 instance_type, assembler->Int32Constant(JS_PROXY_TYPE)), 330 &call_runtime, &return_false); 331 332 assembler->Bind(&return_true); 333 assembler->Return(assembler->BooleanConstant(true)); 334 335 assembler->Bind(&return_false); 336 assembler->Return(assembler->BooleanConstant(false)); 337 338 assembler->Bind(&call_runtime); 339 assembler->Return( 340 assembler->CallRuntime(Runtime::kArrayIsArray, context, object)); 341 } 342 343 void Builtins::Generate_ObjectHasOwnProperty(CodeStubAssembler* assembler) { 344 typedef compiler::Node Node; 345 typedef CodeStubAssembler::Label Label; 346 typedef CodeStubAssembler::Variable Variable; 347 348 Node* object = assembler->Parameter(0); 349 Node* key = assembler->Parameter(1); 350 Node* context = assembler->Parameter(4); 351 352 Label call_runtime(assembler), return_true(assembler), 353 return_false(assembler); 354 355 // Smi receivers do not have own properties. 356 Label if_objectisnotsmi(assembler); 357 assembler->Branch(assembler->WordIsSmi(object), &return_false, 358 &if_objectisnotsmi); 359 assembler->Bind(&if_objectisnotsmi); 360 361 Node* map = assembler->LoadMap(object); 362 Node* instance_type = assembler->LoadMapInstanceType(map); 363 364 Variable var_index(assembler, MachineRepresentation::kWord32); 365 366 Label keyisindex(assembler), if_iskeyunique(assembler); 367 assembler->TryToName(key, &keyisindex, &var_index, &if_iskeyunique, 368 &call_runtime); 369 370 assembler->Bind(&if_iskeyunique); 371 assembler->TryHasOwnProperty(object, map, instance_type, key, &return_true, 372 &return_false, &call_runtime); 373 374 assembler->Bind(&keyisindex); 375 assembler->TryLookupElement(object, map, instance_type, var_index.value(), 376 &return_true, &return_false, &call_runtime); 377 378 assembler->Bind(&return_true); 379 assembler->Return(assembler->BooleanConstant(true)); 380 381 assembler->Bind(&return_false); 382 assembler->Return(assembler->BooleanConstant(false)); 383 384 assembler->Bind(&call_runtime); 385 assembler->Return(assembler->CallRuntime(Runtime::kObjectHasOwnProperty, 386 context, object, key)); 387 } 388 389 namespace { 390 391 Object* DoArrayPush(Isolate* isolate, BuiltinArguments args) { 392 HandleScope scope(isolate); 393 Handle<Object> receiver = args.receiver(); 394 if (!EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 1)) { 395 return CallJsIntrinsic(isolate, isolate->array_push(), args); 396 } 397 // Fast Elements Path 398 int to_add = args.length() - 1; 399 Handle<JSArray> array = Handle<JSArray>::cast(receiver); 400 int len = Smi::cast(array->length())->value(); 401 if (to_add == 0) return Smi::FromInt(len); 402 403 // Currently fixed arrays cannot grow too big, so we should never hit this. 404 DCHECK_LE(to_add, Smi::kMaxValue - Smi::cast(array->length())->value()); 405 406 if (JSArray::HasReadOnlyLength(array)) { 407 return CallJsIntrinsic(isolate, isolate->array_push(), args); 408 } 409 410 ElementsAccessor* accessor = array->GetElementsAccessor(); 411 int new_length = accessor->Push(array, &args, to_add); 412 return Smi::FromInt(new_length); 413 } 414 415 } // namespace 416 417 BUILTIN(ArrayPush) { return DoArrayPush(isolate, args); } 418 419 // TODO(verwaest): This is a temporary helper until the FastArrayPush stub can 420 // tailcall to the builtin directly. 421 RUNTIME_FUNCTION(Runtime_ArrayPush) { 422 DCHECK_EQ(2, args.length()); 423 Arguments* incoming = reinterpret_cast<Arguments*>(args[0]); 424 // Rewrap the arguments as builtins arguments. 425 BuiltinArguments caller_args(incoming->length() + 3, 426 incoming->arguments() + 1); 427 return DoArrayPush(isolate, caller_args); 428 } 429 430 BUILTIN(ArrayPop) { 431 HandleScope scope(isolate); 432 Handle<Object> receiver = args.receiver(); 433 if (!EnsureJSArrayWithWritableFastElements(isolate, receiver, nullptr, 0)) { 434 return CallJsIntrinsic(isolate, isolate->array_pop(), args); 435 } 436 437 Handle<JSArray> array = Handle<JSArray>::cast(receiver); 438 439 uint32_t len = static_cast<uint32_t>(Smi::cast(array->length())->value()); 440 if (len == 0) return isolate->heap()->undefined_value(); 441 442 if (JSArray::HasReadOnlyLength(array)) { 443 return CallJsIntrinsic(isolate, isolate->array_pop(), args); 444 } 445 446 Handle<Object> result; 447 if (IsJSArrayFastElementMovingAllowed(isolate, JSArray::cast(*receiver))) { 448 // Fast Elements Path 449 result = array->GetElementsAccessor()->Pop(array); 450 } else { 451 // Use Slow Lookup otherwise 452 uint32_t new_length = len - 1; 453 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 454 isolate, result, JSReceiver::GetElement(isolate, array, new_length)); 455 JSArray::SetLength(array, new_length); 456 } 457 return *result; 458 } 459 460 461 BUILTIN(ArrayShift) { 462 HandleScope scope(isolate); 463 Heap* heap = isolate->heap(); 464 Handle<Object> receiver = args.receiver(); 465 if (!EnsureJSArrayWithWritableFastElements(isolate, receiver, nullptr, 0) || 466 !IsJSArrayFastElementMovingAllowed(isolate, JSArray::cast(*receiver))) { 467 return CallJsIntrinsic(isolate, isolate->array_shift(), args); 468 } 469 Handle<JSArray> array = Handle<JSArray>::cast(receiver); 470 471 int len = Smi::cast(array->length())->value(); 472 if (len == 0) return heap->undefined_value(); 473 474 if (JSArray::HasReadOnlyLength(array)) { 475 return CallJsIntrinsic(isolate, isolate->array_shift(), args); 476 } 477 478 Handle<Object> first = array->GetElementsAccessor()->Shift(array); 479 return *first; 480 } 481 482 483 BUILTIN(ArrayUnshift) { 484 HandleScope scope(isolate); 485 Handle<Object> receiver = args.receiver(); 486 if (!EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 1)) { 487 return CallJsIntrinsic(isolate, isolate->array_unshift(), args); 488 } 489 Handle<JSArray> array = Handle<JSArray>::cast(receiver); 490 int to_add = args.length() - 1; 491 if (to_add == 0) return array->length(); 492 493 // Currently fixed arrays cannot grow too big, so we should never hit this. 494 DCHECK_LE(to_add, Smi::kMaxValue - Smi::cast(array->length())->value()); 495 496 if (JSArray::HasReadOnlyLength(array)) { 497 return CallJsIntrinsic(isolate, isolate->array_unshift(), args); 498 } 499 500 ElementsAccessor* accessor = array->GetElementsAccessor(); 501 int new_length = accessor->Unshift(array, &args, to_add); 502 return Smi::FromInt(new_length); 503 } 504 505 506 BUILTIN(ArraySlice) { 507 HandleScope scope(isolate); 508 Handle<Object> receiver = args.receiver(); 509 int len = -1; 510 int relative_start = 0; 511 int relative_end = 0; 512 513 if (receiver->IsJSArray()) { 514 DisallowHeapAllocation no_gc; 515 JSArray* array = JSArray::cast(*receiver); 516 if (V8_UNLIKELY(!array->HasFastElements() || 517 !IsJSArrayFastElementMovingAllowed(isolate, array) || 518 !isolate->IsArraySpeciesLookupChainIntact() || 519 // If this is a subclass of Array, then call out to JS 520 !array->HasArrayPrototype(isolate))) { 521 AllowHeapAllocation allow_allocation; 522 return CallJsIntrinsic(isolate, isolate->array_slice(), args); 523 } 524 len = Smi::cast(array->length())->value(); 525 } else if (receiver->IsJSObject() && 526 GetSloppyArgumentsLength(isolate, Handle<JSObject>::cast(receiver), 527 &len)) { 528 // Array.prototype.slice.call(arguments, ...) is quite a common idiom 529 // (notably more than 50% of invocations in Web apps). 530 // Treat it in C++ as well. 531 DCHECK(JSObject::cast(*receiver)->HasFastElements() || 532 JSObject::cast(*receiver)->HasFastArgumentsElements()); 533 } else { 534 AllowHeapAllocation allow_allocation; 535 return CallJsIntrinsic(isolate, isolate->array_slice(), args); 536 } 537 DCHECK_LE(0, len); 538 int argument_count = args.length() - 1; 539 // Note carefully chosen defaults---if argument is missing, 540 // it's undefined which gets converted to 0 for relative_start 541 // and to len for relative_end. 542 relative_start = 0; 543 relative_end = len; 544 if (argument_count > 0) { 545 DisallowHeapAllocation no_gc; 546 if (!ClampedToInteger(isolate, args[1], &relative_start)) { 547 AllowHeapAllocation allow_allocation; 548 return CallJsIntrinsic(isolate, isolate->array_slice(), args); 549 } 550 if (argument_count > 1) { 551 Object* end_arg = args[2]; 552 // slice handles the end_arg specially 553 if (end_arg->IsUndefined(isolate)) { 554 relative_end = len; 555 } else if (!ClampedToInteger(isolate, end_arg, &relative_end)) { 556 AllowHeapAllocation allow_allocation; 557 return CallJsIntrinsic(isolate, isolate->array_slice(), args); 558 } 559 } 560 } 561 562 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 6. 563 uint32_t actual_start = (relative_start < 0) ? Max(len + relative_start, 0) 564 : Min(relative_start, len); 565 566 // ECMAScript 232, 3rd Edition, Section 15.4.4.10, step 8. 567 uint32_t actual_end = 568 (relative_end < 0) ? Max(len + relative_end, 0) : Min(relative_end, len); 569 570 Handle<JSObject> object = Handle<JSObject>::cast(receiver); 571 ElementsAccessor* accessor = object->GetElementsAccessor(); 572 return *accessor->Slice(object, actual_start, actual_end); 573 } 574 575 576 BUILTIN(ArraySplice) { 577 HandleScope scope(isolate); 578 Handle<Object> receiver = args.receiver(); 579 if (V8_UNLIKELY( 580 !EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 3) || 581 // If this is a subclass of Array, then call out to JS. 582 !Handle<JSArray>::cast(receiver)->HasArrayPrototype(isolate) || 583 // If anything with @@species has been messed with, call out to JS. 584 !isolate->IsArraySpeciesLookupChainIntact())) { 585 return CallJsIntrinsic(isolate, isolate->array_splice(), args); 586 } 587 Handle<JSArray> array = Handle<JSArray>::cast(receiver); 588 589 int argument_count = args.length() - 1; 590 int relative_start = 0; 591 if (argument_count > 0) { 592 DisallowHeapAllocation no_gc; 593 if (!ClampedToInteger(isolate, args[1], &relative_start)) { 594 AllowHeapAllocation allow_allocation; 595 return CallJsIntrinsic(isolate, isolate->array_splice(), args); 596 } 597 } 598 int len = Smi::cast(array->length())->value(); 599 // clip relative start to [0, len] 600 int actual_start = (relative_start < 0) ? Max(len + relative_start, 0) 601 : Min(relative_start, len); 602 603 int actual_delete_count; 604 if (argument_count == 1) { 605 // SpiderMonkey, TraceMonkey and JSC treat the case where no delete count is 606 // given as a request to delete all the elements from the start. 607 // And it differs from the case of undefined delete count. 608 // This does not follow ECMA-262, but we do the same for compatibility. 609 DCHECK(len - actual_start >= 0); 610 actual_delete_count = len - actual_start; 611 } else { 612 int delete_count = 0; 613 DisallowHeapAllocation no_gc; 614 if (argument_count > 1) { 615 if (!ClampedToInteger(isolate, args[2], &delete_count)) { 616 AllowHeapAllocation allow_allocation; 617 return CallJsIntrinsic(isolate, isolate->array_splice(), args); 618 } 619 } 620 actual_delete_count = Min(Max(delete_count, 0), len - actual_start); 621 } 622 623 int add_count = (argument_count > 1) ? (argument_count - 2) : 0; 624 int new_length = len - actual_delete_count + add_count; 625 626 if (new_length != len && JSArray::HasReadOnlyLength(array)) { 627 AllowHeapAllocation allow_allocation; 628 return CallJsIntrinsic(isolate, isolate->array_splice(), args); 629 } 630 ElementsAccessor* accessor = array->GetElementsAccessor(); 631 Handle<JSArray> result_array = accessor->Splice( 632 array, actual_start, actual_delete_count, &args, add_count); 633 return *result_array; 634 } 635 636 637 // Array Concat ------------------------------------------------------------- 638 639 namespace { 640 641 /** 642 * A simple visitor visits every element of Array's. 643 * The backend storage can be a fixed array for fast elements case, 644 * or a dictionary for sparse array. Since Dictionary is a subtype 645 * of FixedArray, the class can be used by both fast and slow cases. 646 * The second parameter of the constructor, fast_elements, specifies 647 * whether the storage is a FixedArray or Dictionary. 648 * 649 * An index limit is used to deal with the situation that a result array 650 * length overflows 32-bit non-negative integer. 651 */ 652 class ArrayConcatVisitor { 653 public: 654 ArrayConcatVisitor(Isolate* isolate, Handle<Object> storage, 655 bool fast_elements) 656 : isolate_(isolate), 657 storage_(isolate->global_handles()->Create(*storage)), 658 index_offset_(0u), 659 bit_field_(FastElementsField::encode(fast_elements) | 660 ExceedsLimitField::encode(false) | 661 IsFixedArrayField::encode(storage->IsFixedArray())) { 662 DCHECK(!(this->fast_elements() && !is_fixed_array())); 663 } 664 665 ~ArrayConcatVisitor() { clear_storage(); } 666 667 MUST_USE_RESULT bool visit(uint32_t i, Handle<Object> elm) { 668 uint32_t index = index_offset_ + i; 669 670 if (i >= JSObject::kMaxElementCount - index_offset_) { 671 set_exceeds_array_limit(true); 672 // Exception hasn't been thrown at this point. Return true to 673 // break out, and caller will throw. !visit would imply that 674 // there is already a pending exception. 675 return true; 676 } 677 678 if (!is_fixed_array()) { 679 LookupIterator it(isolate_, storage_, index, LookupIterator::OWN); 680 MAYBE_RETURN( 681 JSReceiver::CreateDataProperty(&it, elm, Object::THROW_ON_ERROR), 682 false); 683 return true; 684 } 685 686 if (fast_elements()) { 687 if (index < static_cast<uint32_t>(storage_fixed_array()->length())) { 688 storage_fixed_array()->set(index, *elm); 689 return true; 690 } 691 // Our initial estimate of length was foiled, possibly by 692 // getters on the arrays increasing the length of later arrays 693 // during iteration. 694 // This shouldn't happen in anything but pathological cases. 695 SetDictionaryMode(); 696 // Fall-through to dictionary mode. 697 } 698 DCHECK(!fast_elements()); 699 Handle<SeededNumberDictionary> dict( 700 SeededNumberDictionary::cast(*storage_)); 701 // The object holding this backing store has just been allocated, so 702 // it cannot yet be used as a prototype. 703 Handle<SeededNumberDictionary> result = 704 SeededNumberDictionary::AtNumberPut(dict, index, elm, false); 705 if (!result.is_identical_to(dict)) { 706 // Dictionary needed to grow. 707 clear_storage(); 708 set_storage(*result); 709 } 710 return true; 711 } 712 713 void increase_index_offset(uint32_t delta) { 714 if (JSObject::kMaxElementCount - index_offset_ < delta) { 715 index_offset_ = JSObject::kMaxElementCount; 716 } else { 717 index_offset_ += delta; 718 } 719 // If the initial length estimate was off (see special case in visit()), 720 // but the array blowing the limit didn't contain elements beyond the 721 // provided-for index range, go to dictionary mode now. 722 if (fast_elements() && 723 index_offset_ > 724 static_cast<uint32_t>(FixedArrayBase::cast(*storage_)->length())) { 725 SetDictionaryMode(); 726 } 727 } 728 729 bool exceeds_array_limit() const { 730 return ExceedsLimitField::decode(bit_field_); 731 } 732 733 Handle<JSArray> ToArray() { 734 DCHECK(is_fixed_array()); 735 Handle<JSArray> array = isolate_->factory()->NewJSArray(0); 736 Handle<Object> length = 737 isolate_->factory()->NewNumber(static_cast<double>(index_offset_)); 738 Handle<Map> map = JSObject::GetElementsTransitionMap( 739 array, fast_elements() ? FAST_HOLEY_ELEMENTS : DICTIONARY_ELEMENTS); 740 array->set_map(*map); 741 array->set_length(*length); 742 array->set_elements(*storage_fixed_array()); 743 return array; 744 } 745 746 // Storage is either a FixedArray (if is_fixed_array()) or a JSReciever 747 // (otherwise) 748 Handle<FixedArray> storage_fixed_array() { 749 DCHECK(is_fixed_array()); 750 return Handle<FixedArray>::cast(storage_); 751 } 752 Handle<JSReceiver> storage_jsreceiver() { 753 DCHECK(!is_fixed_array()); 754 return Handle<JSReceiver>::cast(storage_); 755 } 756 757 private: 758 // Convert storage to dictionary mode. 759 void SetDictionaryMode() { 760 DCHECK(fast_elements() && is_fixed_array()); 761 Handle<FixedArray> current_storage = storage_fixed_array(); 762 Handle<SeededNumberDictionary> slow_storage( 763 SeededNumberDictionary::New(isolate_, current_storage->length())); 764 uint32_t current_length = static_cast<uint32_t>(current_storage->length()); 765 FOR_WITH_HANDLE_SCOPE( 766 isolate_, uint32_t, i = 0, i, i < current_length, i++, { 767 Handle<Object> element(current_storage->get(i), isolate_); 768 if (!element->IsTheHole(isolate_)) { 769 // The object holding this backing store has just been allocated, so 770 // it cannot yet be used as a prototype. 771 Handle<SeededNumberDictionary> new_storage = 772 SeededNumberDictionary::AtNumberPut(slow_storage, i, element, 773 false); 774 if (!new_storage.is_identical_to(slow_storage)) { 775 slow_storage = loop_scope.CloseAndEscape(new_storage); 776 } 777 } 778 }); 779 clear_storage(); 780 set_storage(*slow_storage); 781 set_fast_elements(false); 782 } 783 784 inline void clear_storage() { GlobalHandles::Destroy(storage_.location()); } 785 786 inline void set_storage(FixedArray* storage) { 787 DCHECK(is_fixed_array()); 788 storage_ = isolate_->global_handles()->Create(storage); 789 } 790 791 class FastElementsField : public BitField<bool, 0, 1> {}; 792 class ExceedsLimitField : public BitField<bool, 1, 1> {}; 793 class IsFixedArrayField : public BitField<bool, 2, 1> {}; 794 795 bool fast_elements() const { return FastElementsField::decode(bit_field_); } 796 void set_fast_elements(bool fast) { 797 bit_field_ = FastElementsField::update(bit_field_, fast); 798 } 799 void set_exceeds_array_limit(bool exceeds) { 800 bit_field_ = ExceedsLimitField::update(bit_field_, exceeds); 801 } 802 bool is_fixed_array() const { return IsFixedArrayField::decode(bit_field_); } 803 804 Isolate* isolate_; 805 Handle<Object> storage_; // Always a global handle. 806 // Index after last seen index. Always less than or equal to 807 // JSObject::kMaxElementCount. 808 uint32_t index_offset_; 809 uint32_t bit_field_; 810 }; 811 812 813 uint32_t EstimateElementCount(Handle<JSArray> array) { 814 DisallowHeapAllocation no_gc; 815 uint32_t length = static_cast<uint32_t>(array->length()->Number()); 816 int element_count = 0; 817 switch (array->GetElementsKind()) { 818 case FAST_SMI_ELEMENTS: 819 case FAST_HOLEY_SMI_ELEMENTS: 820 case FAST_ELEMENTS: 821 case FAST_HOLEY_ELEMENTS: { 822 // Fast elements can't have lengths that are not representable by 823 // a 32-bit signed integer. 824 DCHECK(static_cast<int32_t>(FixedArray::kMaxLength) >= 0); 825 int fast_length = static_cast<int>(length); 826 Isolate* isolate = array->GetIsolate(); 827 FixedArray* elements = FixedArray::cast(array->elements()); 828 for (int i = 0; i < fast_length; i++) { 829 if (!elements->get(i)->IsTheHole(isolate)) element_count++; 830 } 831 break; 832 } 833 case FAST_DOUBLE_ELEMENTS: 834 case FAST_HOLEY_DOUBLE_ELEMENTS: { 835 // Fast elements can't have lengths that are not representable by 836 // a 32-bit signed integer. 837 DCHECK(static_cast<int32_t>(FixedDoubleArray::kMaxLength) >= 0); 838 int fast_length = static_cast<int>(length); 839 if (array->elements()->IsFixedArray()) { 840 DCHECK(FixedArray::cast(array->elements())->length() == 0); 841 break; 842 } 843 FixedDoubleArray* elements = FixedDoubleArray::cast(array->elements()); 844 for (int i = 0; i < fast_length; i++) { 845 if (!elements->is_the_hole(i)) element_count++; 846 } 847 break; 848 } 849 case DICTIONARY_ELEMENTS: { 850 SeededNumberDictionary* dictionary = 851 SeededNumberDictionary::cast(array->elements()); 852 Isolate* isolate = dictionary->GetIsolate(); 853 int capacity = dictionary->Capacity(); 854 for (int i = 0; i < capacity; i++) { 855 Object* key = dictionary->KeyAt(i); 856 if (dictionary->IsKey(isolate, key)) { 857 element_count++; 858 } 859 } 860 break; 861 } 862 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) case TYPE##_ELEMENTS: 863 864 TYPED_ARRAYS(TYPED_ARRAY_CASE) 865 #undef TYPED_ARRAY_CASE 866 // External arrays are always dense. 867 return length; 868 case NO_ELEMENTS: 869 return 0; 870 case FAST_SLOPPY_ARGUMENTS_ELEMENTS: 871 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: 872 case FAST_STRING_WRAPPER_ELEMENTS: 873 case SLOW_STRING_WRAPPER_ELEMENTS: 874 UNREACHABLE(); 875 return 0; 876 } 877 // As an estimate, we assume that the prototype doesn't contain any 878 // inherited elements. 879 return element_count; 880 } 881 882 883 // Used for sorting indices in a List<uint32_t>. 884 int compareUInt32(const uint32_t* ap, const uint32_t* bp) { 885 uint32_t a = *ap; 886 uint32_t b = *bp; 887 return (a == b) ? 0 : (a < b) ? -1 : 1; 888 } 889 890 891 void CollectElementIndices(Handle<JSObject> object, uint32_t range, 892 List<uint32_t>* indices) { 893 Isolate* isolate = object->GetIsolate(); 894 ElementsKind kind = object->GetElementsKind(); 895 switch (kind) { 896 case FAST_SMI_ELEMENTS: 897 case FAST_ELEMENTS: 898 case FAST_HOLEY_SMI_ELEMENTS: 899 case FAST_HOLEY_ELEMENTS: { 900 DisallowHeapAllocation no_gc; 901 FixedArray* elements = FixedArray::cast(object->elements()); 902 uint32_t length = static_cast<uint32_t>(elements->length()); 903 if (range < length) length = range; 904 for (uint32_t i = 0; i < length; i++) { 905 if (!elements->get(i)->IsTheHole(isolate)) { 906 indices->Add(i); 907 } 908 } 909 break; 910 } 911 case FAST_HOLEY_DOUBLE_ELEMENTS: 912 case FAST_DOUBLE_ELEMENTS: { 913 if (object->elements()->IsFixedArray()) { 914 DCHECK(object->elements()->length() == 0); 915 break; 916 } 917 Handle<FixedDoubleArray> elements( 918 FixedDoubleArray::cast(object->elements())); 919 uint32_t length = static_cast<uint32_t>(elements->length()); 920 if (range < length) length = range; 921 for (uint32_t i = 0; i < length; i++) { 922 if (!elements->is_the_hole(i)) { 923 indices->Add(i); 924 } 925 } 926 break; 927 } 928 case DICTIONARY_ELEMENTS: { 929 DisallowHeapAllocation no_gc; 930 SeededNumberDictionary* dict = 931 SeededNumberDictionary::cast(object->elements()); 932 uint32_t capacity = dict->Capacity(); 933 FOR_WITH_HANDLE_SCOPE(isolate, uint32_t, j = 0, j, j < capacity, j++, { 934 Object* k = dict->KeyAt(j); 935 if (!dict->IsKey(isolate, k)) continue; 936 DCHECK(k->IsNumber()); 937 uint32_t index = static_cast<uint32_t>(k->Number()); 938 if (index < range) { 939 indices->Add(index); 940 } 941 }); 942 break; 943 } 944 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) case TYPE##_ELEMENTS: 945 946 TYPED_ARRAYS(TYPED_ARRAY_CASE) 947 #undef TYPED_ARRAY_CASE 948 { 949 uint32_t length = static_cast<uint32_t>( 950 FixedArrayBase::cast(object->elements())->length()); 951 if (range <= length) { 952 length = range; 953 // We will add all indices, so we might as well clear it first 954 // and avoid duplicates. 955 indices->Clear(); 956 } 957 for (uint32_t i = 0; i < length; i++) { 958 indices->Add(i); 959 } 960 if (length == range) return; // All indices accounted for already. 961 break; 962 } 963 case FAST_SLOPPY_ARGUMENTS_ELEMENTS: 964 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: { 965 ElementsAccessor* accessor = object->GetElementsAccessor(); 966 for (uint32_t i = 0; i < range; i++) { 967 if (accessor->HasElement(object, i)) { 968 indices->Add(i); 969 } 970 } 971 break; 972 } 973 case FAST_STRING_WRAPPER_ELEMENTS: 974 case SLOW_STRING_WRAPPER_ELEMENTS: { 975 DCHECK(object->IsJSValue()); 976 Handle<JSValue> js_value = Handle<JSValue>::cast(object); 977 DCHECK(js_value->value()->IsString()); 978 Handle<String> string(String::cast(js_value->value()), isolate); 979 uint32_t length = static_cast<uint32_t>(string->length()); 980 uint32_t i = 0; 981 uint32_t limit = Min(length, range); 982 for (; i < limit; i++) { 983 indices->Add(i); 984 } 985 ElementsAccessor* accessor = object->GetElementsAccessor(); 986 for (; i < range; i++) { 987 if (accessor->HasElement(object, i)) { 988 indices->Add(i); 989 } 990 } 991 break; 992 } 993 case NO_ELEMENTS: 994 break; 995 } 996 997 PrototypeIterator iter(isolate, object); 998 if (!iter.IsAtEnd()) { 999 // The prototype will usually have no inherited element indices, 1000 // but we have to check. 1001 CollectElementIndices(PrototypeIterator::GetCurrent<JSObject>(iter), range, 1002 indices); 1003 } 1004 } 1005 1006 1007 bool IterateElementsSlow(Isolate* isolate, Handle<JSReceiver> receiver, 1008 uint32_t length, ArrayConcatVisitor* visitor) { 1009 FOR_WITH_HANDLE_SCOPE(isolate, uint32_t, i = 0, i, i < length, ++i, { 1010 Maybe<bool> maybe = JSReceiver::HasElement(receiver, i); 1011 if (!maybe.IsJust()) return false; 1012 if (maybe.FromJust()) { 1013 Handle<Object> element_value; 1014 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 1015 isolate, element_value, JSReceiver::GetElement(isolate, receiver, i), 1016 false); 1017 if (!visitor->visit(i, element_value)) return false; 1018 } 1019 }); 1020 visitor->increase_index_offset(length); 1021 return true; 1022 } 1023 1024 1025 /** 1026 * A helper function that visits "array" elements of a JSReceiver in numerical 1027 * order. 1028 * 1029 * The visitor argument called for each existing element in the array 1030 * with the element index and the element's value. 1031 * Afterwards it increments the base-index of the visitor by the array 1032 * length. 1033 * Returns false if any access threw an exception, otherwise true. 1034 */ 1035 bool IterateElements(Isolate* isolate, Handle<JSReceiver> receiver, 1036 ArrayConcatVisitor* visitor) { 1037 uint32_t length = 0; 1038 1039 if (receiver->IsJSArray()) { 1040 Handle<JSArray> array = Handle<JSArray>::cast(receiver); 1041 length = static_cast<uint32_t>(array->length()->Number()); 1042 } else { 1043 Handle<Object> val; 1044 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 1045 isolate, val, Object::GetLengthFromArrayLike(isolate, receiver), false); 1046 // TODO(caitp): Support larger element indexes (up to 2^53-1). 1047 if (!val->ToUint32(&length)) { 1048 length = 0; 1049 } 1050 // TODO(cbruni): handle other element kind as well 1051 return IterateElementsSlow(isolate, receiver, length, visitor); 1052 } 1053 1054 if (!HasOnlySimpleElements(isolate, *receiver)) { 1055 return IterateElementsSlow(isolate, receiver, length, visitor); 1056 } 1057 Handle<JSObject> array = Handle<JSObject>::cast(receiver); 1058 1059 switch (array->GetElementsKind()) { 1060 case FAST_SMI_ELEMENTS: 1061 case FAST_ELEMENTS: 1062 case FAST_HOLEY_SMI_ELEMENTS: 1063 case FAST_HOLEY_ELEMENTS: { 1064 // Run through the elements FixedArray and use HasElement and GetElement 1065 // to check the prototype for missing elements. 1066 Handle<FixedArray> elements(FixedArray::cast(array->elements())); 1067 int fast_length = static_cast<int>(length); 1068 DCHECK(fast_length <= elements->length()); 1069 FOR_WITH_HANDLE_SCOPE(isolate, int, j = 0, j, j < fast_length, j++, { 1070 Handle<Object> element_value(elements->get(j), isolate); 1071 if (!element_value->IsTheHole(isolate)) { 1072 if (!visitor->visit(j, element_value)) return false; 1073 } else { 1074 Maybe<bool> maybe = JSReceiver::HasElement(array, j); 1075 if (!maybe.IsJust()) return false; 1076 if (maybe.FromJust()) { 1077 // Call GetElement on array, not its prototype, or getters won't 1078 // have the correct receiver. 1079 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 1080 isolate, element_value, 1081 JSReceiver::GetElement(isolate, array, j), false); 1082 if (!visitor->visit(j, element_value)) return false; 1083 } 1084 } 1085 }); 1086 break; 1087 } 1088 case FAST_HOLEY_DOUBLE_ELEMENTS: 1089 case FAST_DOUBLE_ELEMENTS: { 1090 // Empty array is FixedArray but not FixedDoubleArray. 1091 if (length == 0) break; 1092 // Run through the elements FixedArray and use HasElement and GetElement 1093 // to check the prototype for missing elements. 1094 if (array->elements()->IsFixedArray()) { 1095 DCHECK(array->elements()->length() == 0); 1096 break; 1097 } 1098 Handle<FixedDoubleArray> elements( 1099 FixedDoubleArray::cast(array->elements())); 1100 int fast_length = static_cast<int>(length); 1101 DCHECK(fast_length <= elements->length()); 1102 FOR_WITH_HANDLE_SCOPE(isolate, int, j = 0, j, j < fast_length, j++, { 1103 if (!elements->is_the_hole(j)) { 1104 double double_value = elements->get_scalar(j); 1105 Handle<Object> element_value = 1106 isolate->factory()->NewNumber(double_value); 1107 if (!visitor->visit(j, element_value)) return false; 1108 } else { 1109 Maybe<bool> maybe = JSReceiver::HasElement(array, j); 1110 if (!maybe.IsJust()) return false; 1111 if (maybe.FromJust()) { 1112 // Call GetElement on array, not its prototype, or getters won't 1113 // have the correct receiver. 1114 Handle<Object> element_value; 1115 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 1116 isolate, element_value, 1117 JSReceiver::GetElement(isolate, array, j), false); 1118 if (!visitor->visit(j, element_value)) return false; 1119 } 1120 } 1121 }); 1122 break; 1123 } 1124 1125 case DICTIONARY_ELEMENTS: { 1126 Handle<SeededNumberDictionary> dict(array->element_dictionary()); 1127 List<uint32_t> indices(dict->Capacity() / 2); 1128 // Collect all indices in the object and the prototypes less 1129 // than length. This might introduce duplicates in the indices list. 1130 CollectElementIndices(array, length, &indices); 1131 indices.Sort(&compareUInt32); 1132 int n = indices.length(); 1133 FOR_WITH_HANDLE_SCOPE(isolate, int, j = 0, j, j < n, (void)0, { 1134 uint32_t index = indices[j]; 1135 Handle<Object> element; 1136 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 1137 isolate, element, JSReceiver::GetElement(isolate, array, index), 1138 false); 1139 if (!visitor->visit(index, element)) return false; 1140 // Skip to next different index (i.e., omit duplicates). 1141 do { 1142 j++; 1143 } while (j < n && indices[j] == index); 1144 }); 1145 break; 1146 } 1147 case FAST_SLOPPY_ARGUMENTS_ELEMENTS: 1148 case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: { 1149 FOR_WITH_HANDLE_SCOPE( 1150 isolate, uint32_t, index = 0, index, index < length, index++, { 1151 Handle<Object> element; 1152 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 1153 isolate, element, JSReceiver::GetElement(isolate, array, index), 1154 false); 1155 if (!visitor->visit(index, element)) return false; 1156 }); 1157 break; 1158 } 1159 case NO_ELEMENTS: 1160 break; 1161 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) case TYPE##_ELEMENTS: 1162 TYPED_ARRAYS(TYPED_ARRAY_CASE) 1163 #undef TYPED_ARRAY_CASE 1164 return IterateElementsSlow(isolate, receiver, length, visitor); 1165 case FAST_STRING_WRAPPER_ELEMENTS: 1166 case SLOW_STRING_WRAPPER_ELEMENTS: 1167 // |array| is guaranteed to be an array or typed array. 1168 UNREACHABLE(); 1169 break; 1170 } 1171 visitor->increase_index_offset(length); 1172 return true; 1173 } 1174 1175 static Maybe<bool> IsConcatSpreadable(Isolate* isolate, Handle<Object> obj) { 1176 HandleScope handle_scope(isolate); 1177 if (!obj->IsJSReceiver()) return Just(false); 1178 if (!isolate->IsIsConcatSpreadableLookupChainIntact()) { 1179 // Slow path if @@isConcatSpreadable has been used. 1180 Handle<Symbol> key(isolate->factory()->is_concat_spreadable_symbol()); 1181 Handle<Object> value; 1182 MaybeHandle<Object> maybeValue = 1183 i::Runtime::GetObjectProperty(isolate, obj, key); 1184 if (!maybeValue.ToHandle(&value)) return Nothing<bool>(); 1185 if (!value->IsUndefined(isolate)) return Just(value->BooleanValue()); 1186 } 1187 return Object::IsArray(obj); 1188 } 1189 1190 Object* Slow_ArrayConcat(BuiltinArguments* args, Handle<Object> species, 1191 Isolate* isolate) { 1192 int argument_count = args->length(); 1193 1194 bool is_array_species = *species == isolate->context()->array_function(); 1195 1196 // Pass 1: estimate the length and number of elements of the result. 1197 // The actual length can be larger if any of the arguments have getters 1198 // that mutate other arguments (but will otherwise be precise). 1199 // The number of elements is precise if there are no inherited elements. 1200 1201 ElementsKind kind = FAST_SMI_ELEMENTS; 1202 1203 uint32_t estimate_result_length = 0; 1204 uint32_t estimate_nof_elements = 0; 1205 FOR_WITH_HANDLE_SCOPE(isolate, int, i = 0, i, i < argument_count, i++, { 1206 Handle<Object> obj((*args)[i], isolate); 1207 uint32_t length_estimate; 1208 uint32_t element_estimate; 1209 if (obj->IsJSArray()) { 1210 Handle<JSArray> array(Handle<JSArray>::cast(obj)); 1211 length_estimate = static_cast<uint32_t>(array->length()->Number()); 1212 if (length_estimate != 0) { 1213 ElementsKind array_kind = 1214 GetPackedElementsKind(array->GetElementsKind()); 1215 kind = GetMoreGeneralElementsKind(kind, array_kind); 1216 } 1217 element_estimate = EstimateElementCount(array); 1218 } else { 1219 if (obj->IsHeapObject()) { 1220 kind = GetMoreGeneralElementsKind( 1221 kind, obj->IsNumber() ? FAST_DOUBLE_ELEMENTS : FAST_ELEMENTS); 1222 } 1223 length_estimate = 1; 1224 element_estimate = 1; 1225 } 1226 // Avoid overflows by capping at kMaxElementCount. 1227 if (JSObject::kMaxElementCount - estimate_result_length < length_estimate) { 1228 estimate_result_length = JSObject::kMaxElementCount; 1229 } else { 1230 estimate_result_length += length_estimate; 1231 } 1232 if (JSObject::kMaxElementCount - estimate_nof_elements < element_estimate) { 1233 estimate_nof_elements = JSObject::kMaxElementCount; 1234 } else { 1235 estimate_nof_elements += element_estimate; 1236 } 1237 }); 1238 1239 // If estimated number of elements is more than half of length, a 1240 // fixed array (fast case) is more time and space-efficient than a 1241 // dictionary. 1242 bool fast_case = 1243 is_array_species && (estimate_nof_elements * 2) >= estimate_result_length; 1244 1245 if (fast_case && kind == FAST_DOUBLE_ELEMENTS) { 1246 Handle<FixedArrayBase> storage = 1247 isolate->factory()->NewFixedDoubleArray(estimate_result_length); 1248 int j = 0; 1249 bool failure = false; 1250 if (estimate_result_length > 0) { 1251 Handle<FixedDoubleArray> double_storage = 1252 Handle<FixedDoubleArray>::cast(storage); 1253 for (int i = 0; i < argument_count; i++) { 1254 Handle<Object> obj((*args)[i], isolate); 1255 if (obj->IsSmi()) { 1256 double_storage->set(j, Smi::cast(*obj)->value()); 1257 j++; 1258 } else if (obj->IsNumber()) { 1259 double_storage->set(j, obj->Number()); 1260 j++; 1261 } else { 1262 DisallowHeapAllocation no_gc; 1263 JSArray* array = JSArray::cast(*obj); 1264 uint32_t length = static_cast<uint32_t>(array->length()->Number()); 1265 switch (array->GetElementsKind()) { 1266 case FAST_HOLEY_DOUBLE_ELEMENTS: 1267 case FAST_DOUBLE_ELEMENTS: { 1268 // Empty array is FixedArray but not FixedDoubleArray. 1269 if (length == 0) break; 1270 FixedDoubleArray* elements = 1271 FixedDoubleArray::cast(array->elements()); 1272 for (uint32_t i = 0; i < length; i++) { 1273 if (elements->is_the_hole(i)) { 1274 // TODO(jkummerow/verwaest): We could be a bit more clever 1275 // here: Check if there are no elements/getters on the 1276 // prototype chain, and if so, allow creation of a holey 1277 // result array. 1278 // Same thing below (holey smi case). 1279 failure = true; 1280 break; 1281 } 1282 double double_value = elements->get_scalar(i); 1283 double_storage->set(j, double_value); 1284 j++; 1285 } 1286 break; 1287 } 1288 case FAST_HOLEY_SMI_ELEMENTS: 1289 case FAST_SMI_ELEMENTS: { 1290 Object* the_hole = isolate->heap()->the_hole_value(); 1291 FixedArray* elements(FixedArray::cast(array->elements())); 1292 for (uint32_t i = 0; i < length; i++) { 1293 Object* element = elements->get(i); 1294 if (element == the_hole) { 1295 failure = true; 1296 break; 1297 } 1298 int32_t int_value = Smi::cast(element)->value(); 1299 double_storage->set(j, int_value); 1300 j++; 1301 } 1302 break; 1303 } 1304 case FAST_HOLEY_ELEMENTS: 1305 case FAST_ELEMENTS: 1306 case DICTIONARY_ELEMENTS: 1307 case NO_ELEMENTS: 1308 DCHECK_EQ(0u, length); 1309 break; 1310 default: 1311 UNREACHABLE(); 1312 } 1313 } 1314 if (failure) break; 1315 } 1316 } 1317 if (!failure) { 1318 return *isolate->factory()->NewJSArrayWithElements(storage, kind, j); 1319 } 1320 // In case of failure, fall through. 1321 } 1322 1323 Handle<Object> storage; 1324 if (fast_case) { 1325 // The backing storage array must have non-existing elements to preserve 1326 // holes across concat operations. 1327 storage = 1328 isolate->factory()->NewFixedArrayWithHoles(estimate_result_length); 1329 } else if (is_array_species) { 1330 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate 1331 uint32_t at_least_space_for = 1332 estimate_nof_elements + (estimate_nof_elements >> 2); 1333 storage = SeededNumberDictionary::New(isolate, at_least_space_for); 1334 } else { 1335 DCHECK(species->IsConstructor()); 1336 Handle<Object> length(Smi::FromInt(0), isolate); 1337 Handle<Object> storage_object; 1338 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 1339 isolate, storage_object, 1340 Execution::New(isolate, species, species, 1, &length)); 1341 storage = storage_object; 1342 } 1343 1344 ArrayConcatVisitor visitor(isolate, storage, fast_case); 1345 1346 for (int i = 0; i < argument_count; i++) { 1347 Handle<Object> obj((*args)[i], isolate); 1348 Maybe<bool> spreadable = IsConcatSpreadable(isolate, obj); 1349 MAYBE_RETURN(spreadable, isolate->heap()->exception()); 1350 if (spreadable.FromJust()) { 1351 Handle<JSReceiver> object = Handle<JSReceiver>::cast(obj); 1352 if (!IterateElements(isolate, object, &visitor)) { 1353 return isolate->heap()->exception(); 1354 } 1355 } else { 1356 if (!visitor.visit(0, obj)) return isolate->heap()->exception(); 1357 visitor.increase_index_offset(1); 1358 } 1359 } 1360 1361 if (visitor.exceeds_array_limit()) { 1362 THROW_NEW_ERROR_RETURN_FAILURE( 1363 isolate, NewRangeError(MessageTemplate::kInvalidArrayLength)); 1364 } 1365 1366 if (is_array_species) { 1367 return *visitor.ToArray(); 1368 } else { 1369 return *visitor.storage_jsreceiver(); 1370 } 1371 } 1372 1373 bool IsSimpleArray(Isolate* isolate, Handle<JSArray> obj) { 1374 DisallowHeapAllocation no_gc; 1375 Map* map = obj->map(); 1376 // If there is only the 'length' property we are fine. 1377 if (map->prototype() == 1378 isolate->native_context()->initial_array_prototype() && 1379 map->NumberOfOwnDescriptors() == 1) { 1380 return true; 1381 } 1382 // TODO(cbruni): slower lookup for array subclasses and support slow 1383 // @@IsConcatSpreadable lookup. 1384 return false; 1385 } 1386 1387 MaybeHandle<JSArray> Fast_ArrayConcat(Isolate* isolate, 1388 BuiltinArguments* args) { 1389 if (!isolate->IsIsConcatSpreadableLookupChainIntact()) { 1390 return MaybeHandle<JSArray>(); 1391 } 1392 // We shouldn't overflow when adding another len. 1393 const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2); 1394 STATIC_ASSERT(FixedArray::kMaxLength < kHalfOfMaxInt); 1395 STATIC_ASSERT(FixedDoubleArray::kMaxLength < kHalfOfMaxInt); 1396 USE(kHalfOfMaxInt); 1397 1398 int n_arguments = args->length(); 1399 int result_len = 0; 1400 { 1401 DisallowHeapAllocation no_gc; 1402 // Iterate through all the arguments performing checks 1403 // and calculating total length. 1404 for (int i = 0; i < n_arguments; i++) { 1405 Object* arg = (*args)[i]; 1406 if (!arg->IsJSArray()) return MaybeHandle<JSArray>(); 1407 if (!HasOnlySimpleReceiverElements(isolate, JSObject::cast(arg))) { 1408 return MaybeHandle<JSArray>(); 1409 } 1410 // TODO(cbruni): support fast concatenation of DICTIONARY_ELEMENTS. 1411 if (!JSObject::cast(arg)->HasFastElements()) { 1412 return MaybeHandle<JSArray>(); 1413 } 1414 Handle<JSArray> array(JSArray::cast(arg), isolate); 1415 if (!IsSimpleArray(isolate, array)) { 1416 return MaybeHandle<JSArray>(); 1417 } 1418 // The Array length is guaranted to be <= kHalfOfMaxInt thus we won't 1419 // overflow. 1420 result_len += Smi::cast(array->length())->value(); 1421 DCHECK(result_len >= 0); 1422 // Throw an Error if we overflow the FixedArray limits 1423 if (FixedDoubleArray::kMaxLength < result_len || 1424 FixedArray::kMaxLength < result_len) { 1425 AllowHeapAllocation gc; 1426 THROW_NEW_ERROR(isolate, 1427 NewRangeError(MessageTemplate::kInvalidArrayLength), 1428 JSArray); 1429 } 1430 } 1431 } 1432 return ElementsAccessor::Concat(isolate, args, n_arguments, result_len); 1433 } 1434 1435 } // namespace 1436 1437 1438 // ES6 22.1.3.1 Array.prototype.concat 1439 BUILTIN(ArrayConcat) { 1440 HandleScope scope(isolate); 1441 1442 Handle<Object> receiver = args.receiver(); 1443 // TODO(bmeurer): Do we really care about the exact exception message here? 1444 if (receiver->IsNull(isolate) || receiver->IsUndefined(isolate)) { 1445 THROW_NEW_ERROR_RETURN_FAILURE( 1446 isolate, NewTypeError(MessageTemplate::kCalledOnNullOrUndefined, 1447 isolate->factory()->NewStringFromAsciiChecked( 1448 "Array.prototype.concat"))); 1449 } 1450 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 1451 isolate, receiver, Object::ToObject(isolate, args.receiver())); 1452 args[0] = *receiver; 1453 1454 Handle<JSArray> result_array; 1455 1456 // Avoid a real species read to avoid extra lookups to the array constructor 1457 if (V8_LIKELY(receiver->IsJSArray() && 1458 Handle<JSArray>::cast(receiver)->HasArrayPrototype(isolate) && 1459 isolate->IsArraySpeciesLookupChainIntact())) { 1460 if (Fast_ArrayConcat(isolate, &args).ToHandle(&result_array)) { 1461 return *result_array; 1462 } 1463 if (isolate->has_pending_exception()) return isolate->heap()->exception(); 1464 } 1465 // Reading @@species happens before anything else with a side effect, so 1466 // we can do it here to determine whether to take the fast path. 1467 Handle<Object> species; 1468 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 1469 isolate, species, Object::ArraySpeciesConstructor(isolate, receiver)); 1470 if (*species == *isolate->array_function()) { 1471 if (Fast_ArrayConcat(isolate, &args).ToHandle(&result_array)) { 1472 return *result_array; 1473 } 1474 if (isolate->has_pending_exception()) return isolate->heap()->exception(); 1475 } 1476 return Slow_ArrayConcat(&args, species, isolate); 1477 } 1478 1479 1480 namespace { 1481 1482 MUST_USE_RESULT Maybe<bool> FastAssign(Handle<JSReceiver> to, 1483 Handle<Object> next_source) { 1484 // Non-empty strings are the only non-JSReceivers that need to be handled 1485 // explicitly by Object.assign. 1486 if (!next_source->IsJSReceiver()) { 1487 return Just(!next_source->IsString() || 1488 String::cast(*next_source)->length() == 0); 1489 } 1490 1491 // If the target is deprecated, the object will be updated on first store. If 1492 // the source for that store equals the target, this will invalidate the 1493 // cached representation of the source. Preventively upgrade the target. 1494 // Do this on each iteration since any property load could cause deprecation. 1495 if (to->map()->is_deprecated()) { 1496 JSObject::MigrateInstance(Handle<JSObject>::cast(to)); 1497 } 1498 1499 Isolate* isolate = to->GetIsolate(); 1500 Handle<Map> map(JSReceiver::cast(*next_source)->map(), isolate); 1501 1502 if (!map->IsJSObjectMap()) return Just(false); 1503 if (!map->OnlyHasSimpleProperties()) return Just(false); 1504 1505 Handle<JSObject> from = Handle<JSObject>::cast(next_source); 1506 if (from->elements() != isolate->heap()->empty_fixed_array()) { 1507 return Just(false); 1508 } 1509 1510 Handle<DescriptorArray> descriptors(map->instance_descriptors(), isolate); 1511 int length = map->NumberOfOwnDescriptors(); 1512 1513 bool stable = true; 1514 1515 for (int i = 0; i < length; i++) { 1516 Handle<Name> next_key(descriptors->GetKey(i), isolate); 1517 Handle<Object> prop_value; 1518 // Directly decode from the descriptor array if |from| did not change shape. 1519 if (stable) { 1520 PropertyDetails details = descriptors->GetDetails(i); 1521 if (!details.IsEnumerable()) continue; 1522 if (details.kind() == kData) { 1523 if (details.location() == kDescriptor) { 1524 prop_value = handle(descriptors->GetValue(i), isolate); 1525 } else { 1526 Representation representation = details.representation(); 1527 FieldIndex index = FieldIndex::ForDescriptor(*map, i); 1528 prop_value = JSObject::FastPropertyAt(from, representation, index); 1529 } 1530 } else { 1531 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 1532 isolate, prop_value, JSReceiver::GetProperty(from, next_key), 1533 Nothing<bool>()); 1534 stable = from->map() == *map; 1535 } 1536 } else { 1537 // If the map did change, do a slower lookup. We are still guaranteed that 1538 // the object has a simple shape, and that the key is a name. 1539 LookupIterator it(from, next_key, from, 1540 LookupIterator::OWN_SKIP_INTERCEPTOR); 1541 if (!it.IsFound()) continue; 1542 DCHECK(it.state() == LookupIterator::DATA || 1543 it.state() == LookupIterator::ACCESSOR); 1544 if (!it.IsEnumerable()) continue; 1545 ASSIGN_RETURN_ON_EXCEPTION_VALUE( 1546 isolate, prop_value, Object::GetProperty(&it), Nothing<bool>()); 1547 } 1548 LookupIterator it(to, next_key, to); 1549 bool call_to_js = it.IsFound() && it.state() != LookupIterator::DATA; 1550 Maybe<bool> result = Object::SetProperty( 1551 &it, prop_value, STRICT, Object::CERTAINLY_NOT_STORE_FROM_KEYED); 1552 if (result.IsNothing()) return result; 1553 if (stable && call_to_js) stable = from->map() == *map; 1554 } 1555 1556 return Just(true); 1557 } 1558 1559 } // namespace 1560 1561 // ES6 19.1.2.1 Object.assign 1562 BUILTIN(ObjectAssign) { 1563 HandleScope scope(isolate); 1564 Handle<Object> target = args.atOrUndefined(isolate, 1); 1565 1566 // 1. Let to be ? ToObject(target). 1567 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, target, 1568 Object::ToObject(isolate, target)); 1569 Handle<JSReceiver> to = Handle<JSReceiver>::cast(target); 1570 // 2. If only one argument was passed, return to. 1571 if (args.length() == 2) return *to; 1572 // 3. Let sources be the List of argument values starting with the 1573 // second argument. 1574 // 4. For each element nextSource of sources, in ascending index order, 1575 for (int i = 2; i < args.length(); ++i) { 1576 Handle<Object> next_source = args.at<Object>(i); 1577 Maybe<bool> fast_assign = FastAssign(to, next_source); 1578 if (fast_assign.IsNothing()) return isolate->heap()->exception(); 1579 if (fast_assign.FromJust()) continue; 1580 // 4a. If nextSource is undefined or null, let keys be an empty List. 1581 // 4b. Else, 1582 // 4b i. Let from be ToObject(nextSource). 1583 // Only non-empty strings and JSReceivers have enumerable properties. 1584 Handle<JSReceiver> from = 1585 Object::ToObject(isolate, next_source).ToHandleChecked(); 1586 // 4b ii. Let keys be ? from.[[OwnPropertyKeys]](). 1587 Handle<FixedArray> keys; 1588 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 1589 isolate, keys, KeyAccumulator::GetKeys( 1590 from, KeyCollectionMode::kOwnOnly, ALL_PROPERTIES, 1591 GetKeysConversion::kKeepNumbers)); 1592 // 4c. Repeat for each element nextKey of keys in List order, 1593 for (int j = 0; j < keys->length(); ++j) { 1594 Handle<Object> next_key(keys->get(j), isolate); 1595 // 4c i. Let desc be ? from.[[GetOwnProperty]](nextKey). 1596 PropertyDescriptor desc; 1597 Maybe<bool> found = 1598 JSReceiver::GetOwnPropertyDescriptor(isolate, from, next_key, &desc); 1599 if (found.IsNothing()) return isolate->heap()->exception(); 1600 // 4c ii. If desc is not undefined and desc.[[Enumerable]] is true, then 1601 if (found.FromJust() && desc.enumerable()) { 1602 // 4c ii 1. Let propValue be ? Get(from, nextKey). 1603 Handle<Object> prop_value; 1604 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 1605 isolate, prop_value, 1606 Runtime::GetObjectProperty(isolate, from, next_key)); 1607 // 4c ii 2. Let status be ? Set(to, nextKey, propValue, true). 1608 Handle<Object> status; 1609 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 1610 isolate, status, Runtime::SetObjectProperty(isolate, to, next_key, 1611 prop_value, STRICT)); 1612 } 1613 } 1614 } 1615 // 5. Return to. 1616 return *to; 1617 } 1618 1619 1620 // ES6 section 19.1.2.2 Object.create ( O [ , Properties ] ) 1621 // TODO(verwaest): Support the common cases with precached map directly in 1622 // an Object.create stub. 1623 BUILTIN(ObjectCreate) { 1624 HandleScope scope(isolate); 1625 Handle<Object> prototype = args.atOrUndefined(isolate, 1); 1626 if (!prototype->IsNull(isolate) && !prototype->IsJSReceiver()) { 1627 THROW_NEW_ERROR_RETURN_FAILURE( 1628 isolate, NewTypeError(MessageTemplate::kProtoObjectOrNull, prototype)); 1629 } 1630 1631 // Generate the map with the specified {prototype} based on the Object 1632 // function's initial map from the current native context. 1633 // TODO(bmeurer): Use a dedicated cache for Object.create; think about 1634 // slack tracking for Object.create. 1635 Handle<Map> map(isolate->native_context()->object_function()->initial_map(), 1636 isolate); 1637 if (map->prototype() != *prototype) { 1638 if (prototype->IsNull(isolate)) { 1639 map = isolate->object_with_null_prototype_map(); 1640 } else if (prototype->IsJSObject()) { 1641 Handle<JSObject> js_prototype = Handle<JSObject>::cast(prototype); 1642 if (!js_prototype->map()->is_prototype_map()) { 1643 JSObject::OptimizeAsPrototype(js_prototype, FAST_PROTOTYPE); 1644 } 1645 Handle<PrototypeInfo> info = 1646 Map::GetOrCreatePrototypeInfo(js_prototype, isolate); 1647 // TODO(verwaest): Use inobject slack tracking for this map. 1648 if (info->HasObjectCreateMap()) { 1649 map = handle(info->ObjectCreateMap(), isolate); 1650 } else { 1651 map = Map::CopyInitialMap(map); 1652 Map::SetPrototype(map, prototype, FAST_PROTOTYPE); 1653 PrototypeInfo::SetObjectCreateMap(info, map); 1654 } 1655 } else { 1656 map = Map::TransitionToPrototype(map, prototype, REGULAR_PROTOTYPE); 1657 } 1658 } 1659 1660 // Actually allocate the object. 1661 Handle<JSObject> object = isolate->factory()->NewJSObjectFromMap(map); 1662 1663 // Define the properties if properties was specified and is not undefined. 1664 Handle<Object> properties = args.atOrUndefined(isolate, 2); 1665 if (!properties->IsUndefined(isolate)) { 1666 RETURN_FAILURE_ON_EXCEPTION( 1667 isolate, JSReceiver::DefineProperties(isolate, object, properties)); 1668 } 1669 1670 return *object; 1671 } 1672 1673 // ES6 section 19.1.2.3 Object.defineProperties 1674 BUILTIN(ObjectDefineProperties) { 1675 HandleScope scope(isolate); 1676 DCHECK_EQ(3, args.length()); 1677 Handle<Object> target = args.at<Object>(1); 1678 Handle<Object> properties = args.at<Object>(2); 1679 1680 RETURN_RESULT_OR_FAILURE( 1681 isolate, JSReceiver::DefineProperties(isolate, target, properties)); 1682 } 1683 1684 // ES6 section 19.1.2.4 Object.defineProperty 1685 BUILTIN(ObjectDefineProperty) { 1686 HandleScope scope(isolate); 1687 DCHECK_EQ(4, args.length()); 1688 Handle<Object> target = args.at<Object>(1); 1689 Handle<Object> key = args.at<Object>(2); 1690 Handle<Object> attributes = args.at<Object>(3); 1691 1692 return JSReceiver::DefineProperty(isolate, target, key, attributes); 1693 } 1694 1695 namespace { 1696 1697 template <AccessorComponent which_accessor> 1698 Object* ObjectDefineAccessor(Isolate* isolate, Handle<Object> object, 1699 Handle<Object> name, Handle<Object> accessor) { 1700 // 1. Let O be ? ToObject(this value). 1701 Handle<JSReceiver> receiver; 1702 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver, 1703 Object::ConvertReceiver(isolate, object)); 1704 // 2. If IsCallable(getter) is false, throw a TypeError exception. 1705 if (!accessor->IsCallable()) { 1706 MessageTemplate::Template message = 1707 which_accessor == ACCESSOR_GETTER 1708 ? MessageTemplate::kObjectGetterExpectingFunction 1709 : MessageTemplate::kObjectSetterExpectingFunction; 1710 THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewTypeError(message)); 1711 } 1712 // 3. Let desc be PropertyDescriptor{[[Get]]: getter, [[Enumerable]]: true, 1713 // [[Configurable]]: true}. 1714 PropertyDescriptor desc; 1715 if (which_accessor == ACCESSOR_GETTER) { 1716 desc.set_get(accessor); 1717 } else { 1718 DCHECK(which_accessor == ACCESSOR_SETTER); 1719 desc.set_set(accessor); 1720 } 1721 desc.set_enumerable(true); 1722 desc.set_configurable(true); 1723 // 4. Let key be ? ToPropertyKey(P). 1724 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name, 1725 Object::ToPropertyKey(isolate, name)); 1726 // 5. Perform ? DefinePropertyOrThrow(O, key, desc). 1727 // To preserve legacy behavior, we ignore errors silently rather than 1728 // throwing an exception. 1729 Maybe<bool> success = JSReceiver::DefineOwnProperty( 1730 isolate, receiver, name, &desc, Object::DONT_THROW); 1731 MAYBE_RETURN(success, isolate->heap()->exception()); 1732 if (!success.FromJust()) { 1733 isolate->CountUsage(v8::Isolate::kDefineGetterOrSetterWouldThrow); 1734 } 1735 // 6. Return undefined. 1736 return isolate->heap()->undefined_value(); 1737 } 1738 1739 Object* ObjectLookupAccessor(Isolate* isolate, Handle<Object> object, 1740 Handle<Object> key, AccessorComponent component) { 1741 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, object, 1742 Object::ConvertReceiver(isolate, object)); 1743 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, key, 1744 Object::ToPropertyKey(isolate, key)); 1745 bool success = false; 1746 LookupIterator it = LookupIterator::PropertyOrElement( 1747 isolate, object, key, &success, 1748 LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR); 1749 DCHECK(success); 1750 1751 for (; it.IsFound(); it.Next()) { 1752 switch (it.state()) { 1753 case LookupIterator::INTERCEPTOR: 1754 case LookupIterator::NOT_FOUND: 1755 case LookupIterator::TRANSITION: 1756 UNREACHABLE(); 1757 1758 case LookupIterator::ACCESS_CHECK: 1759 if (it.HasAccess()) continue; 1760 isolate->ReportFailedAccessCheck(it.GetHolder<JSObject>()); 1761 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); 1762 return isolate->heap()->undefined_value(); 1763 1764 case LookupIterator::JSPROXY: 1765 return isolate->heap()->undefined_value(); 1766 1767 case LookupIterator::INTEGER_INDEXED_EXOTIC: 1768 return isolate->heap()->undefined_value(); 1769 case LookupIterator::DATA: 1770 continue; 1771 case LookupIterator::ACCESSOR: { 1772 Handle<Object> maybe_pair = it.GetAccessors(); 1773 if (maybe_pair->IsAccessorPair()) { 1774 return *AccessorPair::GetComponent( 1775 Handle<AccessorPair>::cast(maybe_pair), component); 1776 } 1777 } 1778 } 1779 } 1780 1781 return isolate->heap()->undefined_value(); 1782 } 1783 1784 } // namespace 1785 1786 // ES6 B.2.2.2 a.k.a. 1787 // https://tc39.github.io/ecma262/#sec-object.prototype.__defineGetter__ 1788 BUILTIN(ObjectDefineGetter) { 1789 HandleScope scope(isolate); 1790 Handle<Object> object = args.at<Object>(0); // Receiver. 1791 Handle<Object> name = args.at<Object>(1); 1792 Handle<Object> getter = args.at<Object>(2); 1793 return ObjectDefineAccessor<ACCESSOR_GETTER>(isolate, object, name, getter); 1794 } 1795 1796 // ES6 B.2.2.3 a.k.a. 1797 // https://tc39.github.io/ecma262/#sec-object.prototype.__defineSetter__ 1798 BUILTIN(ObjectDefineSetter) { 1799 HandleScope scope(isolate); 1800 Handle<Object> object = args.at<Object>(0); // Receiver. 1801 Handle<Object> name = args.at<Object>(1); 1802 Handle<Object> setter = args.at<Object>(2); 1803 return ObjectDefineAccessor<ACCESSOR_SETTER>(isolate, object, name, setter); 1804 } 1805 1806 // ES6 B.2.2.4 a.k.a. 1807 // https://tc39.github.io/ecma262/#sec-object.prototype.__lookupGetter__ 1808 BUILTIN(ObjectLookupGetter) { 1809 HandleScope scope(isolate); 1810 Handle<Object> object = args.at<Object>(0); 1811 Handle<Object> name = args.at<Object>(1); 1812 return ObjectLookupAccessor(isolate, object, name, ACCESSOR_GETTER); 1813 } 1814 1815 // ES6 B.2.2.5 a.k.a. 1816 // https://tc39.github.io/ecma262/#sec-object.prototype.__lookupSetter__ 1817 BUILTIN(ObjectLookupSetter) { 1818 HandleScope scope(isolate); 1819 Handle<Object> object = args.at<Object>(0); 1820 Handle<Object> name = args.at<Object>(1); 1821 return ObjectLookupAccessor(isolate, object, name, ACCESSOR_SETTER); 1822 } 1823 1824 // ES6 section 19.1.2.5 Object.freeze ( O ) 1825 BUILTIN(ObjectFreeze) { 1826 HandleScope scope(isolate); 1827 Handle<Object> object = args.atOrUndefined(isolate, 1); 1828 if (object->IsJSReceiver()) { 1829 MAYBE_RETURN(JSReceiver::SetIntegrityLevel(Handle<JSReceiver>::cast(object), 1830 FROZEN, Object::THROW_ON_ERROR), 1831 isolate->heap()->exception()); 1832 } 1833 return *object; 1834 } 1835 1836 1837 // ES section 19.1.2.9 Object.getPrototypeOf ( O ) 1838 BUILTIN(ObjectGetPrototypeOf) { 1839 HandleScope scope(isolate); 1840 Handle<Object> object = args.atOrUndefined(isolate, 1); 1841 1842 Handle<JSReceiver> receiver; 1843 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 1844 isolate, receiver, Object::ToObject(isolate, object)); 1845 1846 RETURN_RESULT_OR_FAILURE(isolate, 1847 JSReceiver::GetPrototype(isolate, receiver)); 1848 } 1849 1850 1851 // ES6 section 19.1.2.6 Object.getOwnPropertyDescriptor ( O, P ) 1852 BUILTIN(ObjectGetOwnPropertyDescriptor) { 1853 HandleScope scope(isolate); 1854 // 1. Let obj be ? ToObject(O). 1855 Handle<Object> object = args.atOrUndefined(isolate, 1); 1856 Handle<JSReceiver> receiver; 1857 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver, 1858 Object::ToObject(isolate, object)); 1859 // 2. Let key be ? ToPropertyKey(P). 1860 Handle<Object> property = args.atOrUndefined(isolate, 2); 1861 Handle<Name> key; 1862 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, key, 1863 Object::ToName(isolate, property)); 1864 // 3. Let desc be ? obj.[[GetOwnProperty]](key). 1865 PropertyDescriptor desc; 1866 Maybe<bool> found = 1867 JSReceiver::GetOwnPropertyDescriptor(isolate, receiver, key, &desc); 1868 MAYBE_RETURN(found, isolate->heap()->exception()); 1869 // 4. Return FromPropertyDescriptor(desc). 1870 if (!found.FromJust()) return isolate->heap()->undefined_value(); 1871 return *desc.ToObject(isolate); 1872 } 1873 1874 1875 namespace { 1876 1877 Object* GetOwnPropertyKeys(Isolate* isolate, BuiltinArguments args, 1878 PropertyFilter filter) { 1879 HandleScope scope(isolate); 1880 Handle<Object> object = args.atOrUndefined(isolate, 1); 1881 Handle<JSReceiver> receiver; 1882 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver, 1883 Object::ToObject(isolate, object)); 1884 Handle<FixedArray> keys; 1885 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 1886 isolate, keys, 1887 KeyAccumulator::GetKeys(receiver, KeyCollectionMode::kOwnOnly, filter, 1888 GetKeysConversion::kConvertToString)); 1889 return *isolate->factory()->NewJSArrayWithElements(keys); 1890 } 1891 1892 } // namespace 1893 1894 1895 // ES6 section 19.1.2.7 Object.getOwnPropertyNames ( O ) 1896 BUILTIN(ObjectGetOwnPropertyNames) { 1897 return GetOwnPropertyKeys(isolate, args, SKIP_SYMBOLS); 1898 } 1899 1900 1901 // ES6 section 19.1.2.8 Object.getOwnPropertySymbols ( O ) 1902 BUILTIN(ObjectGetOwnPropertySymbols) { 1903 return GetOwnPropertyKeys(isolate, args, SKIP_STRINGS); 1904 } 1905 1906 1907 // ES#sec-object.is Object.is ( value1, value2 ) 1908 BUILTIN(ObjectIs) { 1909 SealHandleScope shs(isolate); 1910 DCHECK_EQ(3, args.length()); 1911 Handle<Object> value1 = args.at<Object>(1); 1912 Handle<Object> value2 = args.at<Object>(2); 1913 return isolate->heap()->ToBoolean(value1->SameValue(*value2)); 1914 } 1915 1916 1917 // ES6 section 19.1.2.11 Object.isExtensible ( O ) 1918 BUILTIN(ObjectIsExtensible) { 1919 HandleScope scope(isolate); 1920 Handle<Object> object = args.atOrUndefined(isolate, 1); 1921 Maybe<bool> result = 1922 object->IsJSReceiver() 1923 ? JSReceiver::IsExtensible(Handle<JSReceiver>::cast(object)) 1924 : Just(false); 1925 MAYBE_RETURN(result, isolate->heap()->exception()); 1926 return isolate->heap()->ToBoolean(result.FromJust()); 1927 } 1928 1929 1930 // ES6 section 19.1.2.12 Object.isFrozen ( O ) 1931 BUILTIN(ObjectIsFrozen) { 1932 HandleScope scope(isolate); 1933 Handle<Object> object = args.atOrUndefined(isolate, 1); 1934 Maybe<bool> result = object->IsJSReceiver() 1935 ? JSReceiver::TestIntegrityLevel( 1936 Handle<JSReceiver>::cast(object), FROZEN) 1937 : Just(true); 1938 MAYBE_RETURN(result, isolate->heap()->exception()); 1939 return isolate->heap()->ToBoolean(result.FromJust()); 1940 } 1941 1942 1943 // ES6 section 19.1.2.13 Object.isSealed ( O ) 1944 BUILTIN(ObjectIsSealed) { 1945 HandleScope scope(isolate); 1946 Handle<Object> object = args.atOrUndefined(isolate, 1); 1947 Maybe<bool> result = object->IsJSReceiver() 1948 ? JSReceiver::TestIntegrityLevel( 1949 Handle<JSReceiver>::cast(object), SEALED) 1950 : Just(true); 1951 MAYBE_RETURN(result, isolate->heap()->exception()); 1952 return isolate->heap()->ToBoolean(result.FromJust()); 1953 } 1954 1955 1956 // ES6 section 19.1.2.14 Object.keys ( O ) 1957 BUILTIN(ObjectKeys) { 1958 HandleScope scope(isolate); 1959 Handle<Object> object = args.atOrUndefined(isolate, 1); 1960 Handle<JSReceiver> receiver; 1961 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver, 1962 Object::ToObject(isolate, object)); 1963 1964 Handle<FixedArray> keys; 1965 int enum_length = receiver->map()->EnumLength(); 1966 if (enum_length != kInvalidEnumCacheSentinel && 1967 JSObject::cast(*receiver)->elements() == 1968 isolate->heap()->empty_fixed_array()) { 1969 DCHECK(receiver->IsJSObject()); 1970 DCHECK(!JSObject::cast(*receiver)->HasNamedInterceptor()); 1971 DCHECK(!JSObject::cast(*receiver)->IsAccessCheckNeeded()); 1972 DCHECK(!receiver->map()->has_hidden_prototype()); 1973 DCHECK(JSObject::cast(*receiver)->HasFastProperties()); 1974 if (enum_length == 0) { 1975 keys = isolate->factory()->empty_fixed_array(); 1976 } else { 1977 Handle<FixedArray> cache( 1978 receiver->map()->instance_descriptors()->GetEnumCache()); 1979 keys = isolate->factory()->CopyFixedArrayUpTo(cache, enum_length); 1980 } 1981 } else { 1982 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 1983 isolate, keys, 1984 KeyAccumulator::GetKeys(receiver, KeyCollectionMode::kOwnOnly, 1985 ENUMERABLE_STRINGS, 1986 GetKeysConversion::kConvertToString)); 1987 } 1988 return *isolate->factory()->NewJSArrayWithElements(keys, FAST_ELEMENTS); 1989 } 1990 1991 BUILTIN(ObjectValues) { 1992 HandleScope scope(isolate); 1993 Handle<Object> object = args.atOrUndefined(isolate, 1); 1994 Handle<JSReceiver> receiver; 1995 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver, 1996 Object::ToObject(isolate, object)); 1997 Handle<FixedArray> values; 1998 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 1999 isolate, values, JSReceiver::GetOwnValues(receiver, ENUMERABLE_STRINGS)); 2000 return *isolate->factory()->NewJSArrayWithElements(values); 2001 } 2002 2003 2004 BUILTIN(ObjectEntries) { 2005 HandleScope scope(isolate); 2006 Handle<Object> object = args.atOrUndefined(isolate, 1); 2007 Handle<JSReceiver> receiver; 2008 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver, 2009 Object::ToObject(isolate, object)); 2010 Handle<FixedArray> entries; 2011 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 2012 isolate, entries, 2013 JSReceiver::GetOwnEntries(receiver, ENUMERABLE_STRINGS)); 2014 return *isolate->factory()->NewJSArrayWithElements(entries); 2015 } 2016 2017 BUILTIN(ObjectGetOwnPropertyDescriptors) { 2018 HandleScope scope(isolate); 2019 Handle<Object> object = args.atOrUndefined(isolate, 1); 2020 Handle<Object> undefined = isolate->factory()->undefined_value(); 2021 2022 Handle<JSReceiver> receiver; 2023 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver, 2024 Object::ToObject(isolate, object)); 2025 2026 Handle<FixedArray> keys; 2027 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 2028 isolate, keys, KeyAccumulator::GetKeys( 2029 receiver, KeyCollectionMode::kOwnOnly, ALL_PROPERTIES, 2030 GetKeysConversion::kConvertToString)); 2031 2032 Handle<JSObject> descriptors = 2033 isolate->factory()->NewJSObject(isolate->object_function()); 2034 2035 for (int i = 0; i < keys->length(); ++i) { 2036 Handle<Name> key = Handle<Name>::cast(FixedArray::get(*keys, i, isolate)); 2037 PropertyDescriptor descriptor; 2038 Maybe<bool> did_get_descriptor = JSReceiver::GetOwnPropertyDescriptor( 2039 isolate, receiver, key, &descriptor); 2040 MAYBE_RETURN(did_get_descriptor, isolate->heap()->exception()); 2041 2042 Handle<Object> from_descriptor = did_get_descriptor.FromJust() 2043 ? descriptor.ToObject(isolate) 2044 : undefined; 2045 2046 LookupIterator it = LookupIterator::PropertyOrElement( 2047 isolate, descriptors, key, descriptors, LookupIterator::OWN); 2048 Maybe<bool> success = JSReceiver::CreateDataProperty(&it, from_descriptor, 2049 Object::DONT_THROW); 2050 CHECK(success.FromJust()); 2051 } 2052 2053 return *descriptors; 2054 } 2055 2056 // ES6 section 19.1.2.15 Object.preventExtensions ( O ) 2057 BUILTIN(ObjectPreventExtensions) { 2058 HandleScope scope(isolate); 2059 Handle<Object> object = args.atOrUndefined(isolate, 1); 2060 if (object->IsJSReceiver()) { 2061 MAYBE_RETURN(JSReceiver::PreventExtensions(Handle<JSReceiver>::cast(object), 2062 Object::THROW_ON_ERROR), 2063 isolate->heap()->exception()); 2064 } 2065 return *object; 2066 } 2067 2068 2069 // ES6 section 19.1.2.17 Object.seal ( O ) 2070 BUILTIN(ObjectSeal) { 2071 HandleScope scope(isolate); 2072 Handle<Object> object = args.atOrUndefined(isolate, 1); 2073 if (object->IsJSReceiver()) { 2074 MAYBE_RETURN(JSReceiver::SetIntegrityLevel(Handle<JSReceiver>::cast(object), 2075 SEALED, Object::THROW_ON_ERROR), 2076 isolate->heap()->exception()); 2077 } 2078 return *object; 2079 } 2080 2081 // ES6 section 18.2.6.2 decodeURI (encodedURI) 2082 BUILTIN(GlobalDecodeURI) { 2083 HandleScope scope(isolate); 2084 Handle<String> encoded_uri; 2085 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 2086 isolate, encoded_uri, 2087 Object::ToString(isolate, args.atOrUndefined(isolate, 1))); 2088 2089 RETURN_RESULT_OR_FAILURE(isolate, Uri::DecodeUri(isolate, encoded_uri)); 2090 } 2091 2092 // ES6 section 18.2.6.3 decodeURIComponent (encodedURIComponent) 2093 BUILTIN(GlobalDecodeURIComponent) { 2094 HandleScope scope(isolate); 2095 Handle<String> encoded_uri_component; 2096 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 2097 isolate, encoded_uri_component, 2098 Object::ToString(isolate, args.atOrUndefined(isolate, 1))); 2099 2100 RETURN_RESULT_OR_FAILURE( 2101 isolate, Uri::DecodeUriComponent(isolate, encoded_uri_component)); 2102 } 2103 2104 // ES6 section 18.2.6.4 encodeURI (uri) 2105 BUILTIN(GlobalEncodeURI) { 2106 HandleScope scope(isolate); 2107 Handle<String> uri; 2108 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 2109 isolate, uri, Object::ToString(isolate, args.atOrUndefined(isolate, 1))); 2110 2111 RETURN_RESULT_OR_FAILURE(isolate, Uri::EncodeUri(isolate, uri)); 2112 } 2113 2114 // ES6 section 18.2.6.5 encodeURIComponenet (uriComponent) 2115 BUILTIN(GlobalEncodeURIComponent) { 2116 HandleScope scope(isolate); 2117 Handle<String> uri_component; 2118 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 2119 isolate, uri_component, 2120 Object::ToString(isolate, args.atOrUndefined(isolate, 1))); 2121 2122 RETURN_RESULT_OR_FAILURE(isolate, 2123 Uri::EncodeUriComponent(isolate, uri_component)); 2124 } 2125 2126 // ES6 section B.2.1.1 escape (string) 2127 BUILTIN(GlobalEscape) { 2128 HandleScope scope(isolate); 2129 Handle<String> string; 2130 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 2131 isolate, string, 2132 Object::ToString(isolate, args.atOrUndefined(isolate, 1))); 2133 2134 RETURN_RESULT_OR_FAILURE(isolate, Uri::Escape(isolate, string)); 2135 } 2136 2137 // ES6 section B.2.1.2 unescape (string) 2138 BUILTIN(GlobalUnescape) { 2139 HandleScope scope(isolate); 2140 Handle<String> string; 2141 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 2142 isolate, string, 2143 Object::ToString(isolate, args.atOrUndefined(isolate, 1))); 2144 2145 RETURN_RESULT_OR_FAILURE(isolate, Uri::Unescape(isolate, string)); 2146 } 2147 2148 namespace { 2149 2150 bool CodeGenerationFromStringsAllowed(Isolate* isolate, 2151 Handle<Context> context) { 2152 DCHECK(context->allow_code_gen_from_strings()->IsFalse(isolate)); 2153 // Check with callback if set. 2154 AllowCodeGenerationFromStringsCallback callback = 2155 isolate->allow_code_gen_callback(); 2156 if (callback == NULL) { 2157 // No callback set and code generation disallowed. 2158 return false; 2159 } else { 2160 // Callback set. Let it decide if code generation is allowed. 2161 VMState<EXTERNAL> state(isolate); 2162 return callback(v8::Utils::ToLocal(context)); 2163 } 2164 } 2165 2166 2167 MaybeHandle<JSFunction> CompileString(Handle<Context> context, 2168 Handle<String> source, 2169 ParseRestriction restriction) { 2170 Isolate* const isolate = context->GetIsolate(); 2171 Handle<Context> native_context(context->native_context(), isolate); 2172 2173 // Check if native context allows code generation from 2174 // strings. Throw an exception if it doesn't. 2175 if (native_context->allow_code_gen_from_strings()->IsFalse(isolate) && 2176 !CodeGenerationFromStringsAllowed(isolate, native_context)) { 2177 Handle<Object> error_message = 2178 native_context->ErrorMessageForCodeGenerationFromStrings(); 2179 THROW_NEW_ERROR(isolate, NewEvalError(MessageTemplate::kCodeGenFromStrings, 2180 error_message), 2181 JSFunction); 2182 } 2183 2184 // Compile source string in the native context. 2185 int eval_scope_position = 0; 2186 int eval_position = RelocInfo::kNoPosition; 2187 Handle<SharedFunctionInfo> outer_info(native_context->closure()->shared()); 2188 return Compiler::GetFunctionFromEval(source, outer_info, native_context, 2189 SLOPPY, restriction, eval_scope_position, 2190 eval_position); 2191 } 2192 2193 } // namespace 2194 2195 2196 // ES6 section 18.2.1 eval (x) 2197 BUILTIN(GlobalEval) { 2198 HandleScope scope(isolate); 2199 Handle<Object> x = args.atOrUndefined(isolate, 1); 2200 Handle<JSFunction> target = args.target<JSFunction>(); 2201 Handle<JSObject> target_global_proxy(target->global_proxy(), isolate); 2202 if (!x->IsString()) return *x; 2203 Handle<JSFunction> function; 2204 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 2205 isolate, function, 2206 CompileString(handle(target->native_context(), isolate), 2207 Handle<String>::cast(x), NO_PARSE_RESTRICTION)); 2208 RETURN_RESULT_OR_FAILURE( 2209 isolate, 2210 Execution::Call(isolate, function, target_global_proxy, 0, nullptr)); 2211 } 2212 2213 // ES6 section 24.3.1 JSON.parse. 2214 BUILTIN(JsonParse) { 2215 HandleScope scope(isolate); 2216 Handle<Object> source = args.atOrUndefined(isolate, 1); 2217 Handle<Object> reviver = args.atOrUndefined(isolate, 2); 2218 Handle<String> string; 2219 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, string, 2220 Object::ToString(isolate, source)); 2221 string = String::Flatten(string); 2222 RETURN_RESULT_OR_FAILURE( 2223 isolate, string->IsSeqOneByteString() 2224 ? JsonParser<true>::Parse(isolate, string, reviver) 2225 : JsonParser<false>::Parse(isolate, string, reviver)); 2226 } 2227 2228 // ES6 section 24.3.2 JSON.stringify. 2229 BUILTIN(JsonStringify) { 2230 HandleScope scope(isolate); 2231 JsonStringifier stringifier(isolate); 2232 Handle<Object> object = args.atOrUndefined(isolate, 1); 2233 Handle<Object> replacer = args.atOrUndefined(isolate, 2); 2234 Handle<Object> indent = args.atOrUndefined(isolate, 3); 2235 RETURN_RESULT_OR_FAILURE(isolate, 2236 stringifier.Stringify(object, replacer, indent)); 2237 } 2238 2239 // ----------------------------------------------------------------------------- 2240 // ES6 section 20.2.2 Function Properties of the Math Object 2241 2242 2243 // ES6 section 20.2.2.2 Math.acos ( x ) 2244 BUILTIN(MathAcos) { 2245 HandleScope scope(isolate); 2246 DCHECK_EQ(2, args.length()); 2247 Handle<Object> x = args.at<Object>(1); 2248 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, x, Object::ToNumber(x)); 2249 return *isolate->factory()->NewHeapNumber(std::acos(x->Number())); 2250 } 2251 2252 2253 // ES6 section 20.2.2.4 Math.asin ( x ) 2254 BUILTIN(MathAsin) { 2255 HandleScope scope(isolate); 2256 DCHECK_EQ(2, args.length()); 2257 Handle<Object> x = args.at<Object>(1); 2258 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, x, Object::ToNumber(x)); 2259 return *isolate->factory()->NewHeapNumber(std::asin(x->Number())); 2260 } 2261 2262 // ES6 section 20.2.2.6 Math.atan ( x ) 2263 void Builtins::Generate_MathAtan(CodeStubAssembler* assembler) { 2264 using compiler::Node; 2265 2266 Node* x = assembler->Parameter(1); 2267 Node* context = assembler->Parameter(4); 2268 Node* x_value = assembler->TruncateTaggedToFloat64(context, x); 2269 Node* value = assembler->Float64Atan(x_value); 2270 Node* result = assembler->ChangeFloat64ToTagged(value); 2271 assembler->Return(result); 2272 } 2273 2274 // ES6 section 20.2.2.8 Math.atan2 ( y, x ) 2275 void Builtins::Generate_MathAtan2(CodeStubAssembler* assembler) { 2276 using compiler::Node; 2277 2278 Node* y = assembler->Parameter(1); 2279 Node* x = assembler->Parameter(2); 2280 Node* context = assembler->Parameter(5); 2281 Node* y_value = assembler->TruncateTaggedToFloat64(context, y); 2282 Node* x_value = assembler->TruncateTaggedToFloat64(context, x); 2283 Node* value = assembler->Float64Atan2(y_value, x_value); 2284 Node* result = assembler->ChangeFloat64ToTagged(value); 2285 assembler->Return(result); 2286 } 2287 2288 // ES6 section 20.2.2.7 Math.atanh ( x ) 2289 void Builtins::Generate_MathAtanh(CodeStubAssembler* assembler) { 2290 using compiler::Node; 2291 2292 Node* x = assembler->Parameter(1); 2293 Node* context = assembler->Parameter(4); 2294 Node* x_value = assembler->TruncateTaggedToFloat64(context, x); 2295 Node* value = assembler->Float64Atanh(x_value); 2296 Node* result = assembler->ChangeFloat64ToTagged(value); 2297 assembler->Return(result); 2298 } 2299 2300 namespace { 2301 2302 void Generate_MathRoundingOperation( 2303 CodeStubAssembler* assembler, 2304 compiler::Node* (CodeStubAssembler::*float64op)(compiler::Node*)) { 2305 typedef CodeStubAssembler::Label Label; 2306 typedef compiler::Node Node; 2307 typedef CodeStubAssembler::Variable Variable; 2308 2309 Node* context = assembler->Parameter(4); 2310 2311 // We might need to loop once for ToNumber conversion. 2312 Variable var_x(assembler, MachineRepresentation::kTagged); 2313 Label loop(assembler, &var_x); 2314 var_x.Bind(assembler->Parameter(1)); 2315 assembler->Goto(&loop); 2316 assembler->Bind(&loop); 2317 { 2318 // Load the current {x} value. 2319 Node* x = var_x.value(); 2320 2321 // Check if {x} is a Smi or a HeapObject. 2322 Label if_xissmi(assembler), if_xisnotsmi(assembler); 2323 assembler->Branch(assembler->WordIsSmi(x), &if_xissmi, &if_xisnotsmi); 2324 2325 assembler->Bind(&if_xissmi); 2326 { 2327 // Nothing to do when {x} is a Smi. 2328 assembler->Return(x); 2329 } 2330 2331 assembler->Bind(&if_xisnotsmi); 2332 { 2333 // Check if {x} is a HeapNumber. 2334 Label if_xisheapnumber(assembler), 2335 if_xisnotheapnumber(assembler, Label::kDeferred); 2336 assembler->Branch( 2337 assembler->WordEqual(assembler->LoadMap(x), 2338 assembler->HeapNumberMapConstant()), 2339 &if_xisheapnumber, &if_xisnotheapnumber); 2340 2341 assembler->Bind(&if_xisheapnumber); 2342 { 2343 Node* x_value = assembler->LoadHeapNumberValue(x); 2344 Node* value = (assembler->*float64op)(x_value); 2345 Node* result = assembler->ChangeFloat64ToTagged(value); 2346 assembler->Return(result); 2347 } 2348 2349 assembler->Bind(&if_xisnotheapnumber); 2350 { 2351 // Need to convert {x} to a Number first. 2352 Callable callable = 2353 CodeFactory::NonNumberToNumber(assembler->isolate()); 2354 var_x.Bind(assembler->CallStub(callable, context, x)); 2355 assembler->Goto(&loop); 2356 } 2357 } 2358 } 2359 } 2360 2361 } // namespace 2362 2363 // ES6 section 20.2.2.10 Math.ceil ( x ) 2364 void Builtins::Generate_MathCeil(CodeStubAssembler* assembler) { 2365 Generate_MathRoundingOperation(assembler, &CodeStubAssembler::Float64Ceil); 2366 } 2367 2368 // ES6 section 20.2.2.9 Math.cbrt ( x ) 2369 void Builtins::Generate_MathCbrt(CodeStubAssembler* assembler) { 2370 using compiler::Node; 2371 2372 Node* x = assembler->Parameter(1); 2373 Node* context = assembler->Parameter(4); 2374 Node* x_value = assembler->TruncateTaggedToFloat64(context, x); 2375 Node* value = assembler->Float64Cbrt(x_value); 2376 Node* result = assembler->ChangeFloat64ToTagged(value); 2377 assembler->Return(result); 2378 } 2379 2380 // ES6 section 20.2.2.11 Math.clz32 ( x ) 2381 void Builtins::Generate_MathClz32(CodeStubAssembler* assembler) { 2382 typedef CodeStubAssembler::Label Label; 2383 typedef compiler::Node Node; 2384 typedef CodeStubAssembler::Variable Variable; 2385 2386 Node* context = assembler->Parameter(4); 2387 2388 // Shared entry point for the clz32 operation. 2389 Variable var_clz32_x(assembler, MachineRepresentation::kWord32); 2390 Label do_clz32(assembler); 2391 2392 // We might need to loop once for ToNumber conversion. 2393 Variable var_x(assembler, MachineRepresentation::kTagged); 2394 Label loop(assembler, &var_x); 2395 var_x.Bind(assembler->Parameter(1)); 2396 assembler->Goto(&loop); 2397 assembler->Bind(&loop); 2398 { 2399 // Load the current {x} value. 2400 Node* x = var_x.value(); 2401 2402 // Check if {x} is a Smi or a HeapObject. 2403 Label if_xissmi(assembler), if_xisnotsmi(assembler); 2404 assembler->Branch(assembler->WordIsSmi(x), &if_xissmi, &if_xisnotsmi); 2405 2406 assembler->Bind(&if_xissmi); 2407 { 2408 var_clz32_x.Bind(assembler->SmiToWord32(x)); 2409 assembler->Goto(&do_clz32); 2410 } 2411 2412 assembler->Bind(&if_xisnotsmi); 2413 { 2414 // Check if {x} is a HeapNumber. 2415 Label if_xisheapnumber(assembler), 2416 if_xisnotheapnumber(assembler, Label::kDeferred); 2417 assembler->Branch( 2418 assembler->WordEqual(assembler->LoadMap(x), 2419 assembler->HeapNumberMapConstant()), 2420 &if_xisheapnumber, &if_xisnotheapnumber); 2421 2422 assembler->Bind(&if_xisheapnumber); 2423 { 2424 var_clz32_x.Bind(assembler->TruncateHeapNumberValueToWord32(x)); 2425 assembler->Goto(&do_clz32); 2426 } 2427 2428 assembler->Bind(&if_xisnotheapnumber); 2429 { 2430 // Need to convert {x} to a Number first. 2431 Callable callable = 2432 CodeFactory::NonNumberToNumber(assembler->isolate()); 2433 var_x.Bind(assembler->CallStub(callable, context, x)); 2434 assembler->Goto(&loop); 2435 } 2436 } 2437 } 2438 2439 assembler->Bind(&do_clz32); 2440 { 2441 Node* x_value = var_clz32_x.value(); 2442 Node* value = assembler->Word32Clz(x_value); 2443 Node* result = assembler->ChangeInt32ToTagged(value); 2444 assembler->Return(result); 2445 } 2446 } 2447 2448 // ES6 section 20.2.2.12 Math.cos ( x ) 2449 void Builtins::Generate_MathCos(CodeStubAssembler* assembler) { 2450 using compiler::Node; 2451 2452 Node* x = assembler->Parameter(1); 2453 Node* context = assembler->Parameter(4); 2454 Node* x_value = assembler->TruncateTaggedToFloat64(context, x); 2455 Node* value = assembler->Float64Cos(x_value); 2456 Node* result = assembler->ChangeFloat64ToTagged(value); 2457 assembler->Return(result); 2458 } 2459 2460 // ES6 section 20.2.2.14 Math.exp ( x ) 2461 void Builtins::Generate_MathExp(CodeStubAssembler* assembler) { 2462 using compiler::Node; 2463 2464 Node* x = assembler->Parameter(1); 2465 Node* context = assembler->Parameter(4); 2466 Node* x_value = assembler->TruncateTaggedToFloat64(context, x); 2467 Node* value = assembler->Float64Exp(x_value); 2468 Node* result = assembler->ChangeFloat64ToTagged(value); 2469 assembler->Return(result); 2470 } 2471 2472 // ES6 section 20.2.2.16 Math.floor ( x ) 2473 void Builtins::Generate_MathFloor(CodeStubAssembler* assembler) { 2474 Generate_MathRoundingOperation(assembler, &CodeStubAssembler::Float64Floor); 2475 } 2476 2477 // ES6 section 20.2.2.17 Math.fround ( x ) 2478 BUILTIN(MathFround) { 2479 HandleScope scope(isolate); 2480 DCHECK_EQ(2, args.length()); 2481 Handle<Object> x = args.at<Object>(1); 2482 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, x, Object::ToNumber(x)); 2483 float x32 = DoubleToFloat32(x->Number()); 2484 return *isolate->factory()->NewNumber(x32); 2485 } 2486 2487 // ES6 section 20.2.2.19 Math.imul ( x, y ) 2488 BUILTIN(MathImul) { 2489 HandleScope scope(isolate); 2490 DCHECK_EQ(3, args.length()); 2491 Handle<Object> x = args.at<Object>(1); 2492 Handle<Object> y = args.at<Object>(2); 2493 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, x, Object::ToNumber(x)); 2494 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, y, Object::ToNumber(y)); 2495 int product = static_cast<int>(NumberToUint32(*x) * NumberToUint32(*y)); 2496 return *isolate->factory()->NewNumberFromInt(product); 2497 } 2498 2499 // ES6 section 20.2.2.20 Math.log ( x ) 2500 void Builtins::Generate_MathLog(CodeStubAssembler* assembler) { 2501 using compiler::Node; 2502 2503 Node* x = assembler->Parameter(1); 2504 Node* context = assembler->Parameter(4); 2505 Node* x_value = assembler->TruncateTaggedToFloat64(context, x); 2506 Node* value = assembler->Float64Log(x_value); 2507 Node* result = assembler->ChangeFloat64ToTagged(value); 2508 assembler->Return(result); 2509 } 2510 2511 // ES6 section 20.2.2.21 Math.log1p ( x ) 2512 void Builtins::Generate_MathLog1p(CodeStubAssembler* assembler) { 2513 using compiler::Node; 2514 2515 Node* x = assembler->Parameter(1); 2516 Node* context = assembler->Parameter(4); 2517 Node* x_value = assembler->TruncateTaggedToFloat64(context, x); 2518 Node* value = assembler->Float64Log1p(x_value); 2519 Node* result = assembler->ChangeFloat64ToTagged(value); 2520 assembler->Return(result); 2521 } 2522 2523 // ES6 section 20.2.2.23 Math.log2 ( x ) 2524 void Builtins::Generate_MathLog2(CodeStubAssembler* assembler) { 2525 using compiler::Node; 2526 2527 Node* x = assembler->Parameter(1); 2528 Node* context = assembler->Parameter(4); 2529 Node* x_value = assembler->TruncateTaggedToFloat64(context, x); 2530 Node* value = assembler->Float64Log2(x_value); 2531 Node* result = assembler->ChangeFloat64ToTagged(value); 2532 assembler->Return(result); 2533 } 2534 2535 // ES6 section 20.2.2.22 Math.log10 ( x ) 2536 void Builtins::Generate_MathLog10(CodeStubAssembler* assembler) { 2537 using compiler::Node; 2538 2539 Node* x = assembler->Parameter(1); 2540 Node* context = assembler->Parameter(4); 2541 Node* x_value = assembler->TruncateTaggedToFloat64(context, x); 2542 Node* value = assembler->Float64Log10(x_value); 2543 Node* result = assembler->ChangeFloat64ToTagged(value); 2544 assembler->Return(result); 2545 } 2546 2547 // ES6 section 20.2.2.15 Math.expm1 ( x ) 2548 void Builtins::Generate_MathExpm1(CodeStubAssembler* assembler) { 2549 using compiler::Node; 2550 2551 Node* x = assembler->Parameter(1); 2552 Node* context = assembler->Parameter(4); 2553 Node* x_value = assembler->TruncateTaggedToFloat64(context, x); 2554 Node* value = assembler->Float64Expm1(x_value); 2555 Node* result = assembler->ChangeFloat64ToTagged(value); 2556 assembler->Return(result); 2557 } 2558 2559 // ES6 section 20.2.2.28 Math.round ( x ) 2560 void Builtins::Generate_MathRound(CodeStubAssembler* assembler) { 2561 Generate_MathRoundingOperation(assembler, &CodeStubAssembler::Float64Round); 2562 } 2563 2564 // ES6 section 20.2.2.30 Math.sin ( x ) 2565 void Builtins::Generate_MathSin(CodeStubAssembler* assembler) { 2566 using compiler::Node; 2567 2568 Node* x = assembler->Parameter(1); 2569 Node* context = assembler->Parameter(4); 2570 Node* x_value = assembler->TruncateTaggedToFloat64(context, x); 2571 Node* value = assembler->Float64Sin(x_value); 2572 Node* result = assembler->ChangeFloat64ToTagged(value); 2573 assembler->Return(result); 2574 } 2575 2576 // ES6 section 20.2.2.32 Math.sqrt ( x ) 2577 void Builtins::Generate_MathSqrt(CodeStubAssembler* assembler) { 2578 using compiler::Node; 2579 2580 Node* x = assembler->Parameter(1); 2581 Node* context = assembler->Parameter(4); 2582 Node* x_value = assembler->TruncateTaggedToFloat64(context, x); 2583 Node* value = assembler->Float64Sqrt(x_value); 2584 Node* result = assembler->ChangeFloat64ToTagged(value); 2585 assembler->Return(result); 2586 } 2587 2588 // ES6 section 20.2.2.33 Math.tan ( x ) 2589 void Builtins::Generate_MathTan(CodeStubAssembler* assembler) { 2590 using compiler::Node; 2591 2592 Node* x = assembler->Parameter(1); 2593 Node* context = assembler->Parameter(4); 2594 Node* x_value = assembler->TruncateTaggedToFloat64(context, x); 2595 Node* value = assembler->Float64Tan(x_value); 2596 Node* result = assembler->ChangeFloat64ToTagged(value); 2597 assembler->Return(result); 2598 } 2599 2600 // ES6 section 20.2.2.35 Math.trunc ( x ) 2601 void Builtins::Generate_MathTrunc(CodeStubAssembler* assembler) { 2602 Generate_MathRoundingOperation(assembler, &CodeStubAssembler::Float64Trunc); 2603 } 2604 2605 // ----------------------------------------------------------------------------- 2606 // ES6 section 19.2 Function Objects 2607 2608 // ES6 section 19.2.3.6 Function.prototype [ @@hasInstance ] ( V ) 2609 void Builtins::Generate_FunctionPrototypeHasInstance( 2610 CodeStubAssembler* assembler) { 2611 using compiler::Node; 2612 2613 Node* f = assembler->Parameter(0); 2614 Node* v = assembler->Parameter(1); 2615 Node* context = assembler->Parameter(4); 2616 Node* result = assembler->OrdinaryHasInstance(context, f, v); 2617 assembler->Return(result); 2618 } 2619 2620 // ----------------------------------------------------------------------------- 2621 // ES6 section 25.3 Generator Objects 2622 2623 namespace { 2624 2625 void Generate_GeneratorPrototypeResume( 2626 CodeStubAssembler* assembler, JSGeneratorObject::ResumeMode resume_mode, 2627 char const* const method_name) { 2628 typedef CodeStubAssembler::Label Label; 2629 typedef compiler::Node Node; 2630 2631 Node* receiver = assembler->Parameter(0); 2632 Node* value = assembler->Parameter(1); 2633 Node* context = assembler->Parameter(4); 2634 Node* closed = assembler->SmiConstant( 2635 Smi::FromInt(JSGeneratorObject::kGeneratorClosed)); 2636 2637 // Check if the {receiver} is actually a JSGeneratorObject. 2638 Label if_receiverisincompatible(assembler, Label::kDeferred); 2639 assembler->GotoIf(assembler->WordIsSmi(receiver), &if_receiverisincompatible); 2640 Node* receiver_instance_type = assembler->LoadInstanceType(receiver); 2641 assembler->GotoUnless(assembler->Word32Equal( 2642 receiver_instance_type, 2643 assembler->Int32Constant(JS_GENERATOR_OBJECT_TYPE)), 2644 &if_receiverisincompatible); 2645 2646 // Check if the {receiver} is running or already closed. 2647 Node* receiver_continuation = assembler->LoadObjectField( 2648 receiver, JSGeneratorObject::kContinuationOffset); 2649 Label if_receiverisclosed(assembler, Label::kDeferred), 2650 if_receiverisrunning(assembler, Label::kDeferred); 2651 assembler->GotoIf(assembler->SmiEqual(receiver_continuation, closed), 2652 &if_receiverisclosed); 2653 DCHECK_LT(JSGeneratorObject::kGeneratorExecuting, 2654 JSGeneratorObject::kGeneratorClosed); 2655 assembler->GotoIf(assembler->SmiLessThan(receiver_continuation, closed), 2656 &if_receiverisrunning); 2657 2658 // Resume the {receiver} using our trampoline. 2659 Node* result = assembler->CallStub( 2660 CodeFactory::ResumeGenerator(assembler->isolate()), context, value, 2661 receiver, assembler->SmiConstant(Smi::FromInt(resume_mode))); 2662 assembler->Return(result); 2663 2664 assembler->Bind(&if_receiverisincompatible); 2665 { 2666 // The {receiver} is not a valid JSGeneratorObject. 2667 Node* result = assembler->CallRuntime( 2668 Runtime::kThrowIncompatibleMethodReceiver, context, 2669 assembler->HeapConstant(assembler->factory()->NewStringFromAsciiChecked( 2670 method_name, TENURED)), 2671 receiver); 2672 assembler->Return(result); // Never reached. 2673 } 2674 2675 assembler->Bind(&if_receiverisclosed); 2676 { 2677 // The {receiver} is closed already. 2678 Node* result = nullptr; 2679 switch (resume_mode) { 2680 case JSGeneratorObject::kNext: 2681 result = assembler->CallRuntime(Runtime::kCreateIterResultObject, 2682 context, assembler->UndefinedConstant(), 2683 assembler->BooleanConstant(true)); 2684 break; 2685 case JSGeneratorObject::kReturn: 2686 result = 2687 assembler->CallRuntime(Runtime::kCreateIterResultObject, context, 2688 value, assembler->BooleanConstant(true)); 2689 break; 2690 case JSGeneratorObject::kThrow: 2691 result = assembler->CallRuntime(Runtime::kThrow, context, value); 2692 break; 2693 } 2694 assembler->Return(result); 2695 } 2696 2697 assembler->Bind(&if_receiverisrunning); 2698 { 2699 Node* result = 2700 assembler->CallRuntime(Runtime::kThrowGeneratorRunning, context); 2701 assembler->Return(result); // Never reached. 2702 } 2703 } 2704 2705 } // namespace 2706 2707 // ES6 section 25.3.1.2 Generator.prototype.next ( value ) 2708 void Builtins::Generate_GeneratorPrototypeNext(CodeStubAssembler* assembler) { 2709 Generate_GeneratorPrototypeResume(assembler, JSGeneratorObject::kNext, 2710 "[Generator].prototype.next"); 2711 } 2712 2713 // ES6 section 25.3.1.3 Generator.prototype.return ( value ) 2714 void Builtins::Generate_GeneratorPrototypeReturn(CodeStubAssembler* assembler) { 2715 Generate_GeneratorPrototypeResume(assembler, JSGeneratorObject::kReturn, 2716 "[Generator].prototype.return"); 2717 } 2718 2719 // ES6 section 25.3.1.4 Generator.prototype.throw ( exception ) 2720 void Builtins::Generate_GeneratorPrototypeThrow(CodeStubAssembler* assembler) { 2721 Generate_GeneratorPrototypeResume(assembler, JSGeneratorObject::kThrow, 2722 "[Generator].prototype.throw"); 2723 } 2724 2725 // ----------------------------------------------------------------------------- 2726 // ES6 section 26.1 The Reflect Object 2727 2728 // ES6 section 26.1.3 Reflect.defineProperty 2729 BUILTIN(ReflectDefineProperty) { 2730 HandleScope scope(isolate); 2731 DCHECK_EQ(4, args.length()); 2732 Handle<Object> target = args.at<Object>(1); 2733 Handle<Object> key = args.at<Object>(2); 2734 Handle<Object> attributes = args.at<Object>(3); 2735 2736 if (!target->IsJSReceiver()) { 2737 THROW_NEW_ERROR_RETURN_FAILURE( 2738 isolate, NewTypeError(MessageTemplate::kCalledOnNonObject, 2739 isolate->factory()->NewStringFromAsciiChecked( 2740 "Reflect.defineProperty"))); 2741 } 2742 2743 Handle<Name> name; 2744 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name, 2745 Object::ToName(isolate, key)); 2746 2747 PropertyDescriptor desc; 2748 if (!PropertyDescriptor::ToPropertyDescriptor(isolate, attributes, &desc)) { 2749 return isolate->heap()->exception(); 2750 } 2751 2752 Maybe<bool> result = 2753 JSReceiver::DefineOwnProperty(isolate, Handle<JSReceiver>::cast(target), 2754 name, &desc, Object::DONT_THROW); 2755 MAYBE_RETURN(result, isolate->heap()->exception()); 2756 return *isolate->factory()->ToBoolean(result.FromJust()); 2757 } 2758 2759 2760 // ES6 section 26.1.4 Reflect.deleteProperty 2761 BUILTIN(ReflectDeleteProperty) { 2762 HandleScope scope(isolate); 2763 DCHECK_EQ(3, args.length()); 2764 Handle<Object> target = args.at<Object>(1); 2765 Handle<Object> key = args.at<Object>(2); 2766 2767 if (!target->IsJSReceiver()) { 2768 THROW_NEW_ERROR_RETURN_FAILURE( 2769 isolate, NewTypeError(MessageTemplate::kCalledOnNonObject, 2770 isolate->factory()->NewStringFromAsciiChecked( 2771 "Reflect.deleteProperty"))); 2772 } 2773 2774 Handle<Name> name; 2775 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name, 2776 Object::ToName(isolate, key)); 2777 2778 Maybe<bool> result = JSReceiver::DeletePropertyOrElement( 2779 Handle<JSReceiver>::cast(target), name, SLOPPY); 2780 MAYBE_RETURN(result, isolate->heap()->exception()); 2781 return *isolate->factory()->ToBoolean(result.FromJust()); 2782 } 2783 2784 2785 // ES6 section 26.1.6 Reflect.get 2786 BUILTIN(ReflectGet) { 2787 HandleScope scope(isolate); 2788 Handle<Object> target = args.atOrUndefined(isolate, 1); 2789 Handle<Object> key = args.atOrUndefined(isolate, 2); 2790 Handle<Object> receiver = args.length() > 3 ? args.at<Object>(3) : target; 2791 2792 if (!target->IsJSReceiver()) { 2793 THROW_NEW_ERROR_RETURN_FAILURE( 2794 isolate, NewTypeError(MessageTemplate::kCalledOnNonObject, 2795 isolate->factory()->NewStringFromAsciiChecked( 2796 "Reflect.get"))); 2797 } 2798 2799 Handle<Name> name; 2800 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name, 2801 Object::ToName(isolate, key)); 2802 2803 RETURN_RESULT_OR_FAILURE( 2804 isolate, Object::GetPropertyOrElement(receiver, name, 2805 Handle<JSReceiver>::cast(target))); 2806 } 2807 2808 2809 // ES6 section 26.1.7 Reflect.getOwnPropertyDescriptor 2810 BUILTIN(ReflectGetOwnPropertyDescriptor) { 2811 HandleScope scope(isolate); 2812 DCHECK_EQ(3, args.length()); 2813 Handle<Object> target = args.at<Object>(1); 2814 Handle<Object> key = args.at<Object>(2); 2815 2816 if (!target->IsJSReceiver()) { 2817 THROW_NEW_ERROR_RETURN_FAILURE( 2818 isolate, NewTypeError(MessageTemplate::kCalledOnNonObject, 2819 isolate->factory()->NewStringFromAsciiChecked( 2820 "Reflect.getOwnPropertyDescriptor"))); 2821 } 2822 2823 Handle<Name> name; 2824 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name, 2825 Object::ToName(isolate, key)); 2826 2827 PropertyDescriptor desc; 2828 Maybe<bool> found = JSReceiver::GetOwnPropertyDescriptor( 2829 isolate, Handle<JSReceiver>::cast(target), name, &desc); 2830 MAYBE_RETURN(found, isolate->heap()->exception()); 2831 if (!found.FromJust()) return isolate->heap()->undefined_value(); 2832 return *desc.ToObject(isolate); 2833 } 2834 2835 2836 // ES6 section 26.1.8 Reflect.getPrototypeOf 2837 BUILTIN(ReflectGetPrototypeOf) { 2838 HandleScope scope(isolate); 2839 DCHECK_EQ(2, args.length()); 2840 Handle<Object> target = args.at<Object>(1); 2841 2842 if (!target->IsJSReceiver()) { 2843 THROW_NEW_ERROR_RETURN_FAILURE( 2844 isolate, NewTypeError(MessageTemplate::kCalledOnNonObject, 2845 isolate->factory()->NewStringFromAsciiChecked( 2846 "Reflect.getPrototypeOf"))); 2847 } 2848 Handle<JSReceiver> receiver = Handle<JSReceiver>::cast(target); 2849 RETURN_RESULT_OR_FAILURE(isolate, 2850 JSReceiver::GetPrototype(isolate, receiver)); 2851 } 2852 2853 2854 // ES6 section 26.1.9 Reflect.has 2855 BUILTIN(ReflectHas) { 2856 HandleScope scope(isolate); 2857 DCHECK_EQ(3, args.length()); 2858 Handle<Object> target = args.at<Object>(1); 2859 Handle<Object> key = args.at<Object>(2); 2860 2861 if (!target->IsJSReceiver()) { 2862 THROW_NEW_ERROR_RETURN_FAILURE( 2863 isolate, NewTypeError(MessageTemplate::kCalledOnNonObject, 2864 isolate->factory()->NewStringFromAsciiChecked( 2865 "Reflect.has"))); 2866 } 2867 2868 Handle<Name> name; 2869 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name, 2870 Object::ToName(isolate, key)); 2871 2872 Maybe<bool> result = 2873 JSReceiver::HasProperty(Handle<JSReceiver>::cast(target), name); 2874 return result.IsJust() ? *isolate->factory()->ToBoolean(result.FromJust()) 2875 : isolate->heap()->exception(); 2876 } 2877 2878 2879 // ES6 section 26.1.10 Reflect.isExtensible 2880 BUILTIN(ReflectIsExtensible) { 2881 HandleScope scope(isolate); 2882 DCHECK_EQ(2, args.length()); 2883 Handle<Object> target = args.at<Object>(1); 2884 2885 if (!target->IsJSReceiver()) { 2886 THROW_NEW_ERROR_RETURN_FAILURE( 2887 isolate, NewTypeError(MessageTemplate::kCalledOnNonObject, 2888 isolate->factory()->NewStringFromAsciiChecked( 2889 "Reflect.isExtensible"))); 2890 } 2891 2892 Maybe<bool> result = 2893 JSReceiver::IsExtensible(Handle<JSReceiver>::cast(target)); 2894 MAYBE_RETURN(result, isolate->heap()->exception()); 2895 return *isolate->factory()->ToBoolean(result.FromJust()); 2896 } 2897 2898 2899 // ES6 section 26.1.11 Reflect.ownKeys 2900 BUILTIN(ReflectOwnKeys) { 2901 HandleScope scope(isolate); 2902 DCHECK_EQ(2, args.length()); 2903 Handle<Object> target = args.at<Object>(1); 2904 2905 if (!target->IsJSReceiver()) { 2906 THROW_NEW_ERROR_RETURN_FAILURE( 2907 isolate, NewTypeError(MessageTemplate::kCalledOnNonObject, 2908 isolate->factory()->NewStringFromAsciiChecked( 2909 "Reflect.ownKeys"))); 2910 } 2911 2912 Handle<FixedArray> keys; 2913 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 2914 isolate, keys, 2915 KeyAccumulator::GetKeys(Handle<JSReceiver>::cast(target), 2916 KeyCollectionMode::kOwnOnly, ALL_PROPERTIES, 2917 GetKeysConversion::kConvertToString)); 2918 return *isolate->factory()->NewJSArrayWithElements(keys); 2919 } 2920 2921 2922 // ES6 section 26.1.12 Reflect.preventExtensions 2923 BUILTIN(ReflectPreventExtensions) { 2924 HandleScope scope(isolate); 2925 DCHECK_EQ(2, args.length()); 2926 Handle<Object> target = args.at<Object>(1); 2927 2928 if (!target->IsJSReceiver()) { 2929 THROW_NEW_ERROR_RETURN_FAILURE( 2930 isolate, NewTypeError(MessageTemplate::kCalledOnNonObject, 2931 isolate->factory()->NewStringFromAsciiChecked( 2932 "Reflect.preventExtensions"))); 2933 } 2934 2935 Maybe<bool> result = JSReceiver::PreventExtensions( 2936 Handle<JSReceiver>::cast(target), Object::DONT_THROW); 2937 MAYBE_RETURN(result, isolate->heap()->exception()); 2938 return *isolate->factory()->ToBoolean(result.FromJust()); 2939 } 2940 2941 2942 // ES6 section 26.1.13 Reflect.set 2943 BUILTIN(ReflectSet) { 2944 HandleScope scope(isolate); 2945 Handle<Object> target = args.atOrUndefined(isolate, 1); 2946 Handle<Object> key = args.atOrUndefined(isolate, 2); 2947 Handle<Object> value = args.atOrUndefined(isolate, 3); 2948 Handle<Object> receiver = args.length() > 4 ? args.at<Object>(4) : target; 2949 2950 if (!target->IsJSReceiver()) { 2951 THROW_NEW_ERROR_RETURN_FAILURE( 2952 isolate, NewTypeError(MessageTemplate::kCalledOnNonObject, 2953 isolate->factory()->NewStringFromAsciiChecked( 2954 "Reflect.set"))); 2955 } 2956 2957 Handle<Name> name; 2958 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, name, 2959 Object::ToName(isolate, key)); 2960 2961 LookupIterator it = LookupIterator::PropertyOrElement( 2962 isolate, receiver, name, Handle<JSReceiver>::cast(target)); 2963 Maybe<bool> result = Object::SetSuperProperty( 2964 &it, value, SLOPPY, Object::MAY_BE_STORE_FROM_KEYED); 2965 MAYBE_RETURN(result, isolate->heap()->exception()); 2966 return *isolate->factory()->ToBoolean(result.FromJust()); 2967 } 2968 2969 2970 // ES6 section 26.1.14 Reflect.setPrototypeOf 2971 BUILTIN(ReflectSetPrototypeOf) { 2972 HandleScope scope(isolate); 2973 DCHECK_EQ(3, args.length()); 2974 Handle<Object> target = args.at<Object>(1); 2975 Handle<Object> proto = args.at<Object>(2); 2976 2977 if (!target->IsJSReceiver()) { 2978 THROW_NEW_ERROR_RETURN_FAILURE( 2979 isolate, NewTypeError(MessageTemplate::kCalledOnNonObject, 2980 isolate->factory()->NewStringFromAsciiChecked( 2981 "Reflect.setPrototypeOf"))); 2982 } 2983 2984 if (!proto->IsJSReceiver() && !proto->IsNull(isolate)) { 2985 THROW_NEW_ERROR_RETURN_FAILURE( 2986 isolate, NewTypeError(MessageTemplate::kProtoObjectOrNull, proto)); 2987 } 2988 2989 Maybe<bool> result = JSReceiver::SetPrototype( 2990 Handle<JSReceiver>::cast(target), proto, true, Object::DONT_THROW); 2991 MAYBE_RETURN(result, isolate->heap()->exception()); 2992 return *isolate->factory()->ToBoolean(result.FromJust()); 2993 } 2994 2995 2996 // ----------------------------------------------------------------------------- 2997 // ES6 section 19.3 Boolean Objects 2998 2999 3000 // ES6 section 19.3.1.1 Boolean ( value ) for the [[Call]] case. 3001 BUILTIN(BooleanConstructor) { 3002 HandleScope scope(isolate); 3003 Handle<Object> value = args.atOrUndefined(isolate, 1); 3004 return isolate->heap()->ToBoolean(value->BooleanValue()); 3005 } 3006 3007 3008 // ES6 section 19.3.1.1 Boolean ( value ) for the [[Construct]] case. 3009 BUILTIN(BooleanConstructor_ConstructStub) { 3010 HandleScope scope(isolate); 3011 Handle<Object> value = args.atOrUndefined(isolate, 1); 3012 Handle<JSFunction> target = args.target<JSFunction>(); 3013 Handle<JSReceiver> new_target = Handle<JSReceiver>::cast(args.new_target()); 3014 DCHECK(*target == target->native_context()->boolean_function()); 3015 Handle<JSObject> result; 3016 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, 3017 JSObject::New(target, new_target)); 3018 Handle<JSValue>::cast(result)->set_value( 3019 isolate->heap()->ToBoolean(value->BooleanValue())); 3020 return *result; 3021 } 3022 3023 3024 // ES6 section 19.3.3.2 Boolean.prototype.toString ( ) 3025 BUILTIN(BooleanPrototypeToString) { 3026 HandleScope scope(isolate); 3027 Handle<Object> receiver = args.receiver(); 3028 if (receiver->IsJSValue()) { 3029 receiver = handle(Handle<JSValue>::cast(receiver)->value(), isolate); 3030 } 3031 if (!receiver->IsBoolean()) { 3032 THROW_NEW_ERROR_RETURN_FAILURE( 3033 isolate, NewTypeError(MessageTemplate::kNotGeneric, 3034 isolate->factory()->NewStringFromAsciiChecked( 3035 "Boolean.prototype.toString"))); 3036 } 3037 return Handle<Oddball>::cast(receiver)->to_string(); 3038 } 3039 3040 3041 // ES6 section 19.3.3.3 Boolean.prototype.valueOf ( ) 3042 BUILTIN(BooleanPrototypeValueOf) { 3043 HandleScope scope(isolate); 3044 Handle<Object> receiver = args.receiver(); 3045 if (receiver->IsJSValue()) { 3046 receiver = handle(Handle<JSValue>::cast(receiver)->value(), isolate); 3047 } 3048 if (!receiver->IsBoolean()) { 3049 THROW_NEW_ERROR_RETURN_FAILURE( 3050 isolate, NewTypeError(MessageTemplate::kNotGeneric, 3051 isolate->factory()->NewStringFromAsciiChecked( 3052 "Boolean.prototype.valueOf"))); 3053 } 3054 return *receiver; 3055 } 3056 3057 3058 // ----------------------------------------------------------------------------- 3059 // ES6 section 24.2 DataView Objects 3060 3061 3062 // ES6 section 24.2.2 The DataView Constructor for the [[Call]] case. 3063 BUILTIN(DataViewConstructor) { 3064 HandleScope scope(isolate); 3065 THROW_NEW_ERROR_RETURN_FAILURE( 3066 isolate, 3067 NewTypeError(MessageTemplate::kConstructorNotFunction, 3068 isolate->factory()->NewStringFromAsciiChecked("DataView"))); 3069 } 3070 3071 3072 // ES6 section 24.2.2 The DataView Constructor for the [[Construct]] case. 3073 BUILTIN(DataViewConstructor_ConstructStub) { 3074 HandleScope scope(isolate); 3075 Handle<JSFunction> target = args.target<JSFunction>(); 3076 Handle<JSReceiver> new_target = Handle<JSReceiver>::cast(args.new_target()); 3077 Handle<Object> buffer = args.atOrUndefined(isolate, 1); 3078 Handle<Object> byte_offset = args.atOrUndefined(isolate, 2); 3079 Handle<Object> byte_length = args.atOrUndefined(isolate, 3); 3080 3081 // 2. If Type(buffer) is not Object, throw a TypeError exception. 3082 // 3. If buffer does not have an [[ArrayBufferData]] internal slot, throw a 3083 // TypeError exception. 3084 if (!buffer->IsJSArrayBuffer()) { 3085 THROW_NEW_ERROR_RETURN_FAILURE( 3086 isolate, NewTypeError(MessageTemplate::kDataViewNotArrayBuffer)); 3087 } 3088 Handle<JSArrayBuffer> array_buffer = Handle<JSArrayBuffer>::cast(buffer); 3089 3090 // 4. Let numberOffset be ? ToNumber(byteOffset). 3091 Handle<Object> number_offset; 3092 if (byte_offset->IsUndefined(isolate)) { 3093 // We intentionally violate the specification at this point to allow 3094 // for new DataView(buffer) invocations to be equivalent to the full 3095 // new DataView(buffer, 0) invocation. 3096 number_offset = handle(Smi::FromInt(0), isolate); 3097 } else { 3098 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, number_offset, 3099 Object::ToNumber(byte_offset)); 3100 } 3101 3102 // 5. Let offset be ToInteger(numberOffset). 3103 Handle<Object> offset; 3104 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, offset, 3105 Object::ToInteger(isolate, number_offset)); 3106 3107 // 6. If numberOffset offset or offset < 0, throw a RangeError exception. 3108 if (number_offset->Number() != offset->Number() || offset->Number() < 0.0) { 3109 THROW_NEW_ERROR_RETURN_FAILURE( 3110 isolate, NewRangeError(MessageTemplate::kInvalidDataViewOffset)); 3111 } 3112 3113 // 7. If IsDetachedBuffer(buffer) is true, throw a TypeError exception. 3114 // We currently violate the specification at this point. 3115 3116 // 8. Let bufferByteLength be the value of buffer's [[ArrayBufferByteLength]] 3117 // internal slot. 3118 double const buffer_byte_length = array_buffer->byte_length()->Number(); 3119 3120 // 9. If offset > bufferByteLength, throw a RangeError exception 3121 if (offset->Number() > buffer_byte_length) { 3122 THROW_NEW_ERROR_RETURN_FAILURE( 3123 isolate, NewRangeError(MessageTemplate::kInvalidDataViewOffset)); 3124 } 3125 3126 Handle<Object> view_byte_length; 3127 if (byte_length->IsUndefined(isolate)) { 3128 // 10. If byteLength is undefined, then 3129 // a. Let viewByteLength be bufferByteLength - offset. 3130 view_byte_length = 3131 isolate->factory()->NewNumber(buffer_byte_length - offset->Number()); 3132 } else { 3133 // 11. Else, 3134 // a. Let viewByteLength be ? ToLength(byteLength). 3135 // b. If offset+viewByteLength > bufferByteLength, throw a RangeError 3136 // exception 3137 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 3138 isolate, view_byte_length, Object::ToLength(isolate, byte_length)); 3139 if (offset->Number() + view_byte_length->Number() > buffer_byte_length) { 3140 THROW_NEW_ERROR_RETURN_FAILURE( 3141 isolate, NewRangeError(MessageTemplate::kInvalidDataViewLength)); 3142 } 3143 } 3144 3145 // 12. Let O be ? OrdinaryCreateFromConstructor(NewTarget, 3146 // "%DataViewPrototype%", [[DataView]], [[ViewedArrayBuffer]], 3147 // [[ByteLength]], [[ByteOffset]]). 3148 // 13. Set O's [[DataView]] internal slot to true. 3149 Handle<JSObject> result; 3150 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, 3151 JSObject::New(target, new_target)); 3152 for (int i = 0; i < ArrayBufferView::kInternalFieldCount; ++i) { 3153 Handle<JSDataView>::cast(result)->SetInternalField(i, Smi::FromInt(0)); 3154 } 3155 3156 // 14. Set O's [[ViewedArrayBuffer]] internal slot to buffer. 3157 Handle<JSDataView>::cast(result)->set_buffer(*array_buffer); 3158 3159 // 15. Set O's [[ByteLength]] internal slot to viewByteLength. 3160 Handle<JSDataView>::cast(result)->set_byte_length(*view_byte_length); 3161 3162 // 16. Set O's [[ByteOffset]] internal slot to offset. 3163 Handle<JSDataView>::cast(result)->set_byte_offset(*offset); 3164 3165 // 17. Return O. 3166 return *result; 3167 } 3168 3169 // ES6 section 24.2.4.1 get DataView.prototype.buffer 3170 BUILTIN(DataViewPrototypeGetBuffer) { 3171 HandleScope scope(isolate); 3172 CHECK_RECEIVER(JSDataView, data_view, "get DataView.prototype.buffer"); 3173 return data_view->buffer(); 3174 } 3175 3176 // ES6 section 24.2.4.2 get DataView.prototype.byteLength 3177 BUILTIN(DataViewPrototypeGetByteLength) { 3178 HandleScope scope(isolate); 3179 CHECK_RECEIVER(JSDataView, data_view, "get DataView.prototype.byteLength"); 3180 // TODO(bmeurer): According to the ES6 spec, we should throw a TypeError 3181 // here if the JSArrayBuffer of the {data_view} was neutered. 3182 return data_view->byte_length(); 3183 } 3184 3185 // ES6 section 24.2.4.3 get DataView.prototype.byteOffset 3186 BUILTIN(DataViewPrototypeGetByteOffset) { 3187 HandleScope scope(isolate); 3188 CHECK_RECEIVER(JSDataView, data_view, "get DataView.prototype.byteOffset"); 3189 // TODO(bmeurer): According to the ES6 spec, we should throw a TypeError 3190 // here if the JSArrayBuffer of the {data_view} was neutered. 3191 return data_view->byte_offset(); 3192 } 3193 3194 // ----------------------------------------------------------------------------- 3195 // ES6 section 22.2 TypedArray Objects 3196 3197 // ES6 section 22.2.3.1 get %TypedArray%.prototype.buffer 3198 BUILTIN(TypedArrayPrototypeBuffer) { 3199 HandleScope scope(isolate); 3200 CHECK_RECEIVER(JSTypedArray, typed_array, "get TypedArray.prototype.buffer"); 3201 return *typed_array->GetBuffer(); 3202 } 3203 3204 namespace { 3205 3206 void Generate_TypedArrayProtoypeGetter(CodeStubAssembler* assembler, 3207 const char* method_name, 3208 int object_offset) { 3209 typedef CodeStubAssembler::Label Label; 3210 typedef compiler::Node Node; 3211 3212 Node* receiver = assembler->Parameter(0); 3213 Node* context = assembler->Parameter(3); 3214 3215 // Check if the {receiver} is actually a JSTypedArray. 3216 Label if_receiverisincompatible(assembler, Label::kDeferred); 3217 assembler->GotoIf(assembler->WordIsSmi(receiver), &if_receiverisincompatible); 3218 Node* receiver_instance_type = assembler->LoadInstanceType(receiver); 3219 assembler->GotoUnless( 3220 assembler->Word32Equal(receiver_instance_type, 3221 assembler->Int32Constant(JS_TYPED_ARRAY_TYPE)), 3222 &if_receiverisincompatible); 3223 3224 // Check if the {receiver}'s JSArrayBuffer was neutered. 3225 Node* receiver_buffer = 3226 assembler->LoadObjectField(receiver, JSTypedArray::kBufferOffset); 3227 Node* receiver_buffer_bit_field = assembler->LoadObjectField( 3228 receiver_buffer, JSArrayBuffer::kBitFieldOffset, MachineType::Uint32()); 3229 Label if_receiverisneutered(assembler, Label::kDeferred); 3230 assembler->GotoUnless( 3231 assembler->Word32Equal( 3232 assembler->Word32And( 3233 receiver_buffer_bit_field, 3234 assembler->Int32Constant(JSArrayBuffer::WasNeutered::kMask)), 3235 assembler->Int32Constant(0)), 3236 &if_receiverisneutered); 3237 assembler->Return(assembler->LoadObjectField(receiver, object_offset)); 3238 3239 assembler->Bind(&if_receiverisneutered); 3240 { 3241 // The {receiver}s buffer was neutered, default to zero. 3242 assembler->Return(assembler->SmiConstant(0)); 3243 } 3244 3245 assembler->Bind(&if_receiverisincompatible); 3246 { 3247 // The {receiver} is not a valid JSGeneratorObject. 3248 Node* result = assembler->CallRuntime( 3249 Runtime::kThrowIncompatibleMethodReceiver, context, 3250 assembler->HeapConstant(assembler->factory()->NewStringFromAsciiChecked( 3251 method_name, TENURED)), 3252 receiver); 3253 assembler->Return(result); // Never reached. 3254 } 3255 } 3256 3257 } // namespace 3258 3259 // ES6 section 22.2.3.2 get %TypedArray%.prototype.byteLength 3260 void Builtins::Generate_TypedArrayPrototypeByteLength( 3261 CodeStubAssembler* assembler) { 3262 Generate_TypedArrayProtoypeGetter(assembler, 3263 "get TypedArray.prototype.byteLength", 3264 JSTypedArray::kByteLengthOffset); 3265 } 3266 3267 // ES6 section 22.2.3.3 get %TypedArray%.prototype.byteOffset 3268 void Builtins::Generate_TypedArrayPrototypeByteOffset( 3269 CodeStubAssembler* assembler) { 3270 Generate_TypedArrayProtoypeGetter(assembler, 3271 "get TypedArray.prototype.byteOffset", 3272 JSTypedArray::kByteOffsetOffset); 3273 } 3274 3275 // ES6 section 22.2.3.18 get %TypedArray%.prototype.length 3276 void Builtins::Generate_TypedArrayPrototypeLength( 3277 CodeStubAssembler* assembler) { 3278 Generate_TypedArrayProtoypeGetter(assembler, 3279 "get TypedArray.prototype.length", 3280 JSTypedArray::kLengthOffset); 3281 } 3282 3283 // ----------------------------------------------------------------------------- 3284 // ES6 section 20.3 Date Objects 3285 3286 3287 namespace { 3288 3289 // ES6 section 20.3.1.1 Time Values and Time Range 3290 const double kMinYear = -1000000.0; 3291 const double kMaxYear = -kMinYear; 3292 const double kMinMonth = -10000000.0; 3293 const double kMaxMonth = -kMinMonth; 3294 3295 3296 // 20.3.1.2 Day Number and Time within Day 3297 const double kMsPerDay = 86400000.0; 3298 3299 3300 // ES6 section 20.3.1.11 Hours, Minutes, Second, and Milliseconds 3301 const double kMsPerSecond = 1000.0; 3302 const double kMsPerMinute = 60000.0; 3303 const double kMsPerHour = 3600000.0; 3304 3305 3306 // ES6 section 20.3.1.14 MakeDate (day, time) 3307 double MakeDate(double day, double time) { 3308 if (std::isfinite(day) && std::isfinite(time)) { 3309 return time + day * kMsPerDay; 3310 } 3311 return std::numeric_limits<double>::quiet_NaN(); 3312 } 3313 3314 3315 // ES6 section 20.3.1.13 MakeDay (year, month, date) 3316 double MakeDay(double year, double month, double date) { 3317 if ((kMinYear <= year && year <= kMaxYear) && 3318 (kMinMonth <= month && month <= kMaxMonth) && std::isfinite(date)) { 3319 int y = FastD2I(year); 3320 int m = FastD2I(month); 3321 y += m / 12; 3322 m %= 12; 3323 if (m < 0) { 3324 m += 12; 3325 y -= 1; 3326 } 3327 DCHECK_LE(0, m); 3328 DCHECK_LT(m, 12); 3329 3330 // kYearDelta is an arbitrary number such that: 3331 // a) kYearDelta = -1 (mod 400) 3332 // b) year + kYearDelta > 0 for years in the range defined by 3333 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of 3334 // Jan 1 1970. This is required so that we don't run into integer 3335 // division of negative numbers. 3336 // c) there shouldn't be an overflow for 32-bit integers in the following 3337 // operations. 3338 static const int kYearDelta = 399999; 3339 static const int kBaseDay = 3340 365 * (1970 + kYearDelta) + (1970 + kYearDelta) / 4 - 3341 (1970 + kYearDelta) / 100 + (1970 + kYearDelta) / 400; 3342 int day_from_year = 365 * (y + kYearDelta) + (y + kYearDelta) / 4 - 3343 (y + kYearDelta) / 100 + (y + kYearDelta) / 400 - 3344 kBaseDay; 3345 if ((y % 4 != 0) || (y % 100 == 0 && y % 400 != 0)) { 3346 static const int kDayFromMonth[] = {0, 31, 59, 90, 120, 151, 3347 181, 212, 243, 273, 304, 334}; 3348 day_from_year += kDayFromMonth[m]; 3349 } else { 3350 static const int kDayFromMonth[] = {0, 31, 60, 91, 121, 152, 3351 182, 213, 244, 274, 305, 335}; 3352 day_from_year += kDayFromMonth[m]; 3353 } 3354 return static_cast<double>(day_from_year - 1) + date; 3355 } 3356 return std::numeric_limits<double>::quiet_NaN(); 3357 } 3358 3359 3360 // ES6 section 20.3.1.12 MakeTime (hour, min, sec, ms) 3361 double MakeTime(double hour, double min, double sec, double ms) { 3362 if (std::isfinite(hour) && std::isfinite(min) && std::isfinite(sec) && 3363 std::isfinite(ms)) { 3364 double const h = DoubleToInteger(hour); 3365 double const m = DoubleToInteger(min); 3366 double const s = DoubleToInteger(sec); 3367 double const milli = DoubleToInteger(ms); 3368 return h * kMsPerHour + m * kMsPerMinute + s * kMsPerSecond + milli; 3369 } 3370 return std::numeric_limits<double>::quiet_NaN(); 3371 } 3372 3373 3374 // ES6 section 20.3.1.15 TimeClip (time) 3375 double TimeClip(double time) { 3376 if (-DateCache::kMaxTimeInMs <= time && time <= DateCache::kMaxTimeInMs) { 3377 return DoubleToInteger(time) + 0.0; 3378 } 3379 return std::numeric_limits<double>::quiet_NaN(); 3380 } 3381 3382 3383 const char* kShortWeekDays[] = {"Sun", "Mon", "Tue", "Wed", 3384 "Thu", "Fri", "Sat"}; 3385 const char* kShortMonths[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", 3386 "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; 3387 3388 3389 // ES6 section 20.3.1.16 Date Time String Format 3390 double ParseDateTimeString(Handle<String> str) { 3391 Isolate* const isolate = str->GetIsolate(); 3392 str = String::Flatten(str); 3393 // TODO(bmeurer): Change DateParser to not use the FixedArray. 3394 Handle<FixedArray> tmp = 3395 isolate->factory()->NewFixedArray(DateParser::OUTPUT_SIZE); 3396 DisallowHeapAllocation no_gc; 3397 String::FlatContent str_content = str->GetFlatContent(); 3398 bool result; 3399 if (str_content.IsOneByte()) { 3400 result = DateParser::Parse(isolate, str_content.ToOneByteVector(), *tmp); 3401 } else { 3402 result = DateParser::Parse(isolate, str_content.ToUC16Vector(), *tmp); 3403 } 3404 if (!result) return std::numeric_limits<double>::quiet_NaN(); 3405 double const day = MakeDay(tmp->get(0)->Number(), tmp->get(1)->Number(), 3406 tmp->get(2)->Number()); 3407 double const time = MakeTime(tmp->get(3)->Number(), tmp->get(4)->Number(), 3408 tmp->get(5)->Number(), tmp->get(6)->Number()); 3409 double date = MakeDate(day, time); 3410 if (tmp->get(7)->IsNull(isolate)) { 3411 if (!std::isnan(date)) { 3412 date = isolate->date_cache()->ToUTC(static_cast<int64_t>(date)); 3413 } 3414 } else { 3415 date -= tmp->get(7)->Number() * 1000.0; 3416 } 3417 return date; 3418 } 3419 3420 3421 enum ToDateStringMode { kDateOnly, kTimeOnly, kDateAndTime }; 3422 3423 3424 // ES6 section 20.3.4.41.1 ToDateString(tv) 3425 void ToDateString(double time_val, Vector<char> str, DateCache* date_cache, 3426 ToDateStringMode mode = kDateAndTime) { 3427 if (std::isnan(time_val)) { 3428 SNPrintF(str, "Invalid Date"); 3429 return; 3430 } 3431 int64_t time_ms = static_cast<int64_t>(time_val); 3432 int64_t local_time_ms = date_cache->ToLocal(time_ms); 3433 int year, month, day, weekday, hour, min, sec, ms; 3434 date_cache->BreakDownTime(local_time_ms, &year, &month, &day, &weekday, &hour, 3435 &min, &sec, &ms); 3436 int timezone_offset = -date_cache->TimezoneOffset(time_ms); 3437 int timezone_hour = std::abs(timezone_offset) / 60; 3438 int timezone_min = std::abs(timezone_offset) % 60; 3439 const char* local_timezone = date_cache->LocalTimezone(time_ms); 3440 switch (mode) { 3441 case kDateOnly: 3442 SNPrintF(str, "%s %s %02d %4d", kShortWeekDays[weekday], 3443 kShortMonths[month], day, year); 3444 return; 3445 case kTimeOnly: 3446 SNPrintF(str, "%02d:%02d:%02d GMT%c%02d%02d (%s)", hour, min, sec, 3447 (timezone_offset < 0) ? '-' : '+', timezone_hour, timezone_min, 3448 local_timezone); 3449 return; 3450 case kDateAndTime: 3451 SNPrintF(str, "%s %s %02d %4d %02d:%02d:%02d GMT%c%02d%02d (%s)", 3452 kShortWeekDays[weekday], kShortMonths[month], day, year, hour, 3453 min, sec, (timezone_offset < 0) ? '-' : '+', timezone_hour, 3454 timezone_min, local_timezone); 3455 return; 3456 } 3457 UNREACHABLE(); 3458 } 3459 3460 3461 Object* SetLocalDateValue(Handle<JSDate> date, double time_val) { 3462 if (time_val >= -DateCache::kMaxTimeBeforeUTCInMs && 3463 time_val <= DateCache::kMaxTimeBeforeUTCInMs) { 3464 Isolate* const isolate = date->GetIsolate(); 3465 time_val = isolate->date_cache()->ToUTC(static_cast<int64_t>(time_val)); 3466 } else { 3467 time_val = std::numeric_limits<double>::quiet_NaN(); 3468 } 3469 return *JSDate::SetValue(date, TimeClip(time_val)); 3470 } 3471 3472 } // namespace 3473 3474 3475 // ES6 section 20.3.2 The Date Constructor for the [[Call]] case. 3476 BUILTIN(DateConstructor) { 3477 HandleScope scope(isolate); 3478 double const time_val = JSDate::CurrentTimeValue(isolate); 3479 char buffer[128]; 3480 ToDateString(time_val, ArrayVector(buffer), isolate->date_cache()); 3481 RETURN_RESULT_OR_FAILURE( 3482 isolate, isolate->factory()->NewStringFromUtf8(CStrVector(buffer))); 3483 } 3484 3485 3486 // ES6 section 20.3.2 The Date Constructor for the [[Construct]] case. 3487 BUILTIN(DateConstructor_ConstructStub) { 3488 HandleScope scope(isolate); 3489 int const argc = args.length() - 1; 3490 Handle<JSFunction> target = args.target<JSFunction>(); 3491 Handle<JSReceiver> new_target = Handle<JSReceiver>::cast(args.new_target()); 3492 double time_val; 3493 if (argc == 0) { 3494 time_val = JSDate::CurrentTimeValue(isolate); 3495 } else if (argc == 1) { 3496 Handle<Object> value = args.at<Object>(1); 3497 if (value->IsJSDate()) { 3498 time_val = Handle<JSDate>::cast(value)->value()->Number(); 3499 } else { 3500 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value, 3501 Object::ToPrimitive(value)); 3502 if (value->IsString()) { 3503 time_val = ParseDateTimeString(Handle<String>::cast(value)); 3504 } else { 3505 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value, 3506 Object::ToNumber(value)); 3507 time_val = value->Number(); 3508 } 3509 } 3510 } else { 3511 Handle<Object> year_object; 3512 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, year_object, 3513 Object::ToNumber(args.at<Object>(1))); 3514 Handle<Object> month_object; 3515 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, month_object, 3516 Object::ToNumber(args.at<Object>(2))); 3517 double year = year_object->Number(); 3518 double month = month_object->Number(); 3519 double date = 1.0, hours = 0.0, minutes = 0.0, seconds = 0.0, ms = 0.0; 3520 if (argc >= 3) { 3521 Handle<Object> date_object; 3522 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, date_object, 3523 Object::ToNumber(args.at<Object>(3))); 3524 date = date_object->Number(); 3525 if (argc >= 4) { 3526 Handle<Object> hours_object; 3527 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 3528 isolate, hours_object, Object::ToNumber(args.at<Object>(4))); 3529 hours = hours_object->Number(); 3530 if (argc >= 5) { 3531 Handle<Object> minutes_object; 3532 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 3533 isolate, minutes_object, Object::ToNumber(args.at<Object>(5))); 3534 minutes = minutes_object->Number(); 3535 if (argc >= 6) { 3536 Handle<Object> seconds_object; 3537 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 3538 isolate, seconds_object, Object::ToNumber(args.at<Object>(6))); 3539 seconds = seconds_object->Number(); 3540 if (argc >= 7) { 3541 Handle<Object> ms_object; 3542 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 3543 isolate, ms_object, Object::ToNumber(args.at<Object>(7))); 3544 ms = ms_object->Number(); 3545 } 3546 } 3547 } 3548 } 3549 } 3550 if (!std::isnan(year)) { 3551 double const y = DoubleToInteger(year); 3552 if (0.0 <= y && y <= 99) year = 1900 + y; 3553 } 3554 double const day = MakeDay(year, month, date); 3555 double const time = MakeTime(hours, minutes, seconds, ms); 3556 time_val = MakeDate(day, time); 3557 if (time_val >= -DateCache::kMaxTimeBeforeUTCInMs && 3558 time_val <= DateCache::kMaxTimeBeforeUTCInMs) { 3559 time_val = isolate->date_cache()->ToUTC(static_cast<int64_t>(time_val)); 3560 } else { 3561 time_val = std::numeric_limits<double>::quiet_NaN(); 3562 } 3563 } 3564 RETURN_RESULT_OR_FAILURE(isolate, JSDate::New(target, new_target, time_val)); 3565 } 3566 3567 3568 // ES6 section 20.3.3.1 Date.now ( ) 3569 BUILTIN(DateNow) { 3570 HandleScope scope(isolate); 3571 return *isolate->factory()->NewNumber(JSDate::CurrentTimeValue(isolate)); 3572 } 3573 3574 3575 // ES6 section 20.3.3.2 Date.parse ( string ) 3576 BUILTIN(DateParse) { 3577 HandleScope scope(isolate); 3578 Handle<String> string; 3579 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 3580 isolate, string, 3581 Object::ToString(isolate, args.atOrUndefined(isolate, 1))); 3582 return *isolate->factory()->NewNumber(ParseDateTimeString(string)); 3583 } 3584 3585 3586 // ES6 section 20.3.3.4 Date.UTC (year,month,date,hours,minutes,seconds,ms) 3587 BUILTIN(DateUTC) { 3588 HandleScope scope(isolate); 3589 int const argc = args.length() - 1; 3590 double year = std::numeric_limits<double>::quiet_NaN(); 3591 double month = std::numeric_limits<double>::quiet_NaN(); 3592 double date = 1.0, hours = 0.0, minutes = 0.0, seconds = 0.0, ms = 0.0; 3593 if (argc >= 1) { 3594 Handle<Object> year_object; 3595 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, year_object, 3596 Object::ToNumber(args.at<Object>(1))); 3597 year = year_object->Number(); 3598 if (argc >= 2) { 3599 Handle<Object> month_object; 3600 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, month_object, 3601 Object::ToNumber(args.at<Object>(2))); 3602 month = month_object->Number(); 3603 if (argc >= 3) { 3604 Handle<Object> date_object; 3605 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 3606 isolate, date_object, Object::ToNumber(args.at<Object>(3))); 3607 date = date_object->Number(); 3608 if (argc >= 4) { 3609 Handle<Object> hours_object; 3610 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 3611 isolate, hours_object, Object::ToNumber(args.at<Object>(4))); 3612 hours = hours_object->Number(); 3613 if (argc >= 5) { 3614 Handle<Object> minutes_object; 3615 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 3616 isolate, minutes_object, Object::ToNumber(args.at<Object>(5))); 3617 minutes = minutes_object->Number(); 3618 if (argc >= 6) { 3619 Handle<Object> seconds_object; 3620 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 3621 isolate, seconds_object, 3622 Object::ToNumber(args.at<Object>(6))); 3623 seconds = seconds_object->Number(); 3624 if (argc >= 7) { 3625 Handle<Object> ms_object; 3626 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 3627 isolate, ms_object, Object::ToNumber(args.at<Object>(7))); 3628 ms = ms_object->Number(); 3629 } 3630 } 3631 } 3632 } 3633 } 3634 } 3635 } 3636 if (!std::isnan(year)) { 3637 double const y = DoubleToInteger(year); 3638 if (0.0 <= y && y <= 99) year = 1900 + y; 3639 } 3640 double const day = MakeDay(year, month, date); 3641 double const time = MakeTime(hours, minutes, seconds, ms); 3642 return *isolate->factory()->NewNumber(TimeClip(MakeDate(day, time))); 3643 } 3644 3645 3646 // ES6 section 20.3.4.20 Date.prototype.setDate ( date ) 3647 BUILTIN(DatePrototypeSetDate) { 3648 HandleScope scope(isolate); 3649 CHECK_RECEIVER(JSDate, date, "Date.prototype.setDate"); 3650 Handle<Object> value = args.atOrUndefined(isolate, 1); 3651 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value, Object::ToNumber(value)); 3652 double time_val = date->value()->Number(); 3653 if (!std::isnan(time_val)) { 3654 int64_t const time_ms = static_cast<int64_t>(time_val); 3655 int64_t local_time_ms = isolate->date_cache()->ToLocal(time_ms); 3656 int const days = isolate->date_cache()->DaysFromTime(local_time_ms); 3657 int time_within_day = isolate->date_cache()->TimeInDay(local_time_ms, days); 3658 int year, month, day; 3659 isolate->date_cache()->YearMonthDayFromDays(days, &year, &month, &day); 3660 time_val = MakeDate(MakeDay(year, month, value->Number()), time_within_day); 3661 } 3662 return SetLocalDateValue(date, time_val); 3663 } 3664 3665 3666 // ES6 section 20.3.4.21 Date.prototype.setFullYear (year, month, date) 3667 BUILTIN(DatePrototypeSetFullYear) { 3668 HandleScope scope(isolate); 3669 CHECK_RECEIVER(JSDate, date, "Date.prototype.setFullYear"); 3670 int const argc = args.length() - 1; 3671 Handle<Object> year = args.atOrUndefined(isolate, 1); 3672 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, year, Object::ToNumber(year)); 3673 double y = year->Number(), m = 0.0, dt = 1.0; 3674 int time_within_day = 0; 3675 if (!std::isnan(date->value()->Number())) { 3676 int64_t const time_ms = static_cast<int64_t>(date->value()->Number()); 3677 int64_t local_time_ms = isolate->date_cache()->ToLocal(time_ms); 3678 int const days = isolate->date_cache()->DaysFromTime(local_time_ms); 3679 time_within_day = isolate->date_cache()->TimeInDay(local_time_ms, days); 3680 int year, month, day; 3681 isolate->date_cache()->YearMonthDayFromDays(days, &year, &month, &day); 3682 m = month; 3683 dt = day; 3684 } 3685 if (argc >= 2) { 3686 Handle<Object> month = args.at<Object>(2); 3687 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, month, Object::ToNumber(month)); 3688 m = month->Number(); 3689 if (argc >= 3) { 3690 Handle<Object> date = args.at<Object>(3); 3691 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, date, Object::ToNumber(date)); 3692 dt = date->Number(); 3693 } 3694 } 3695 double time_val = MakeDate(MakeDay(y, m, dt), time_within_day); 3696 return SetLocalDateValue(date, time_val); 3697 } 3698 3699 3700 // ES6 section 20.3.4.22 Date.prototype.setHours(hour, min, sec, ms) 3701 BUILTIN(DatePrototypeSetHours) { 3702 HandleScope scope(isolate); 3703 CHECK_RECEIVER(JSDate, date, "Date.prototype.setHours"); 3704 int const argc = args.length() - 1; 3705 Handle<Object> hour = args.atOrUndefined(isolate, 1); 3706 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, hour, Object::ToNumber(hour)); 3707 double h = hour->Number(); 3708 double time_val = date->value()->Number(); 3709 if (!std::isnan(time_val)) { 3710 int64_t const time_ms = static_cast<int64_t>(time_val); 3711 int64_t local_time_ms = isolate->date_cache()->ToLocal(time_ms); 3712 int day = isolate->date_cache()->DaysFromTime(local_time_ms); 3713 int time_within_day = isolate->date_cache()->TimeInDay(local_time_ms, day); 3714 double m = (time_within_day / (60 * 1000)) % 60; 3715 double s = (time_within_day / 1000) % 60; 3716 double milli = time_within_day % 1000; 3717 if (argc >= 2) { 3718 Handle<Object> min = args.at<Object>(2); 3719 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, min, Object::ToNumber(min)); 3720 m = min->Number(); 3721 if (argc >= 3) { 3722 Handle<Object> sec = args.at<Object>(3); 3723 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, sec, Object::ToNumber(sec)); 3724 s = sec->Number(); 3725 if (argc >= 4) { 3726 Handle<Object> ms = args.at<Object>(4); 3727 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, ms, Object::ToNumber(ms)); 3728 milli = ms->Number(); 3729 } 3730 } 3731 } 3732 time_val = MakeDate(day, MakeTime(h, m, s, milli)); 3733 } 3734 return SetLocalDateValue(date, time_val); 3735 } 3736 3737 3738 // ES6 section 20.3.4.23 Date.prototype.setMilliseconds(ms) 3739 BUILTIN(DatePrototypeSetMilliseconds) { 3740 HandleScope scope(isolate); 3741 CHECK_RECEIVER(JSDate, date, "Date.prototype.setMilliseconds"); 3742 Handle<Object> ms = args.atOrUndefined(isolate, 1); 3743 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, ms, Object::ToNumber(ms)); 3744 double time_val = date->value()->Number(); 3745 if (!std::isnan(time_val)) { 3746 int64_t const time_ms = static_cast<int64_t>(time_val); 3747 int64_t local_time_ms = isolate->date_cache()->ToLocal(time_ms); 3748 int day = isolate->date_cache()->DaysFromTime(local_time_ms); 3749 int time_within_day = isolate->date_cache()->TimeInDay(local_time_ms, day); 3750 int h = time_within_day / (60 * 60 * 1000); 3751 int m = (time_within_day / (60 * 1000)) % 60; 3752 int s = (time_within_day / 1000) % 60; 3753 time_val = MakeDate(day, MakeTime(h, m, s, ms->Number())); 3754 } 3755 return SetLocalDateValue(date, time_val); 3756 } 3757 3758 3759 // ES6 section 20.3.4.24 Date.prototype.setMinutes ( min, sec, ms ) 3760 BUILTIN(DatePrototypeSetMinutes) { 3761 HandleScope scope(isolate); 3762 CHECK_RECEIVER(JSDate, date, "Date.prototype.setMinutes"); 3763 int const argc = args.length() - 1; 3764 Handle<Object> min = args.atOrUndefined(isolate, 1); 3765 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, min, Object::ToNumber(min)); 3766 double time_val = date->value()->Number(); 3767 if (!std::isnan(time_val)) { 3768 int64_t const time_ms = static_cast<int64_t>(time_val); 3769 int64_t local_time_ms = isolate->date_cache()->ToLocal(time_ms); 3770 int day = isolate->date_cache()->DaysFromTime(local_time_ms); 3771 int time_within_day = isolate->date_cache()->TimeInDay(local_time_ms, day); 3772 int h = time_within_day / (60 * 60 * 1000); 3773 double m = min->Number(); 3774 double s = (time_within_day / 1000) % 60; 3775 double milli = time_within_day % 1000; 3776 if (argc >= 2) { 3777 Handle<Object> sec = args.at<Object>(2); 3778 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, sec, Object::ToNumber(sec)); 3779 s = sec->Number(); 3780 if (argc >= 3) { 3781 Handle<Object> ms = args.at<Object>(3); 3782 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, ms, Object::ToNumber(ms)); 3783 milli = ms->Number(); 3784 } 3785 } 3786 time_val = MakeDate(day, MakeTime(h, m, s, milli)); 3787 } 3788 return SetLocalDateValue(date, time_val); 3789 } 3790 3791 3792 // ES6 section 20.3.4.25 Date.prototype.setMonth ( month, date ) 3793 BUILTIN(DatePrototypeSetMonth) { 3794 HandleScope scope(isolate); 3795 CHECK_RECEIVER(JSDate, date, "Date.prototype.setMonth"); 3796 int const argc = args.length() - 1; 3797 Handle<Object> month = args.atOrUndefined(isolate, 1); 3798 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, month, Object::ToNumber(month)); 3799 double time_val = date->value()->Number(); 3800 if (!std::isnan(time_val)) { 3801 int64_t const time_ms = static_cast<int64_t>(time_val); 3802 int64_t local_time_ms = isolate->date_cache()->ToLocal(time_ms); 3803 int days = isolate->date_cache()->DaysFromTime(local_time_ms); 3804 int time_within_day = isolate->date_cache()->TimeInDay(local_time_ms, days); 3805 int year, unused, day; 3806 isolate->date_cache()->YearMonthDayFromDays(days, &year, &unused, &day); 3807 double m = month->Number(); 3808 double dt = day; 3809 if (argc >= 2) { 3810 Handle<Object> date = args.at<Object>(2); 3811 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, date, Object::ToNumber(date)); 3812 dt = date->Number(); 3813 } 3814 time_val = MakeDate(MakeDay(year, m, dt), time_within_day); 3815 } 3816 return SetLocalDateValue(date, time_val); 3817 } 3818 3819 3820 // ES6 section 20.3.4.26 Date.prototype.setSeconds ( sec, ms ) 3821 BUILTIN(DatePrototypeSetSeconds) { 3822 HandleScope scope(isolate); 3823 CHECK_RECEIVER(JSDate, date, "Date.prototype.setSeconds"); 3824 int const argc = args.length() - 1; 3825 Handle<Object> sec = args.atOrUndefined(isolate, 1); 3826 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, sec, Object::ToNumber(sec)); 3827 double time_val = date->value()->Number(); 3828 if (!std::isnan(time_val)) { 3829 int64_t const time_ms = static_cast<int64_t>(time_val); 3830 int64_t local_time_ms = isolate->date_cache()->ToLocal(time_ms); 3831 int day = isolate->date_cache()->DaysFromTime(local_time_ms); 3832 int time_within_day = isolate->date_cache()->TimeInDay(local_time_ms, day); 3833 int h = time_within_day / (60 * 60 * 1000); 3834 double m = (time_within_day / (60 * 1000)) % 60; 3835 double s = sec->Number(); 3836 double milli = time_within_day % 1000; 3837 if (argc >= 2) { 3838 Handle<Object> ms = args.at<Object>(2); 3839 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, ms, Object::ToNumber(ms)); 3840 milli = ms->Number(); 3841 } 3842 time_val = MakeDate(day, MakeTime(h, m, s, milli)); 3843 } 3844 return SetLocalDateValue(date, time_val); 3845 } 3846 3847 3848 // ES6 section 20.3.4.27 Date.prototype.setTime ( time ) 3849 BUILTIN(DatePrototypeSetTime) { 3850 HandleScope scope(isolate); 3851 CHECK_RECEIVER(JSDate, date, "Date.prototype.setTime"); 3852 Handle<Object> value = args.atOrUndefined(isolate, 1); 3853 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value, Object::ToNumber(value)); 3854 return *JSDate::SetValue(date, TimeClip(value->Number())); 3855 } 3856 3857 3858 // ES6 section 20.3.4.28 Date.prototype.setUTCDate ( date ) 3859 BUILTIN(DatePrototypeSetUTCDate) { 3860 HandleScope scope(isolate); 3861 CHECK_RECEIVER(JSDate, date, "Date.prototype.setUTCDate"); 3862 Handle<Object> value = args.atOrUndefined(isolate, 1); 3863 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, value, Object::ToNumber(value)); 3864 if (std::isnan(date->value()->Number())) return date->value(); 3865 int64_t const time_ms = static_cast<int64_t>(date->value()->Number()); 3866 int const days = isolate->date_cache()->DaysFromTime(time_ms); 3867 int const time_within_day = isolate->date_cache()->TimeInDay(time_ms, days); 3868 int year, month, day; 3869 isolate->date_cache()->YearMonthDayFromDays(days, &year, &month, &day); 3870 double const time_val = 3871 MakeDate(MakeDay(year, month, value->Number()), time_within_day); 3872 return *JSDate::SetValue(date, TimeClip(time_val)); 3873 } 3874 3875 3876 // ES6 section 20.3.4.29 Date.prototype.setUTCFullYear (year, month, date) 3877 BUILTIN(DatePrototypeSetUTCFullYear) { 3878 HandleScope scope(isolate); 3879 CHECK_RECEIVER(JSDate, date, "Date.prototype.setUTCFullYear"); 3880 int const argc = args.length() - 1; 3881 Handle<Object> year = args.atOrUndefined(isolate, 1); 3882 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, year, Object::ToNumber(year)); 3883 double y = year->Number(), m = 0.0, dt = 1.0; 3884 int time_within_day = 0; 3885 if (!std::isnan(date->value()->Number())) { 3886 int64_t const time_ms = static_cast<int64_t>(date->value()->Number()); 3887 int const days = isolate->date_cache()->DaysFromTime(time_ms); 3888 time_within_day = isolate->date_cache()->TimeInDay(time_ms, days); 3889 int year, month, day; 3890 isolate->date_cache()->YearMonthDayFromDays(days, &year, &month, &day); 3891 m = month; 3892 dt = day; 3893 } 3894 if (argc >= 2) { 3895 Handle<Object> month = args.at<Object>(2); 3896 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, month, Object::ToNumber(month)); 3897 m = month->Number(); 3898 if (argc >= 3) { 3899 Handle<Object> date = args.at<Object>(3); 3900 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, date, Object::ToNumber(date)); 3901 dt = date->Number(); 3902 } 3903 } 3904 double const time_val = MakeDate(MakeDay(y, m, dt), time_within_day); 3905 return *JSDate::SetValue(date, TimeClip(time_val)); 3906 } 3907 3908 3909 // ES6 section 20.3.4.30 Date.prototype.setUTCHours(hour, min, sec, ms) 3910 BUILTIN(DatePrototypeSetUTCHours) { 3911 HandleScope scope(isolate); 3912 CHECK_RECEIVER(JSDate, date, "Date.prototype.setUTCHours"); 3913 int const argc = args.length() - 1; 3914 Handle<Object> hour = args.atOrUndefined(isolate, 1); 3915 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, hour, Object::ToNumber(hour)); 3916 double h = hour->Number(); 3917 double time_val = date->value()->Number(); 3918 if (!std::isnan(time_val)) { 3919 int64_t const time_ms = static_cast<int64_t>(time_val); 3920 int day = isolate->date_cache()->DaysFromTime(time_ms); 3921 int time_within_day = isolate->date_cache()->TimeInDay(time_ms, day); 3922 double m = (time_within_day / (60 * 1000)) % 60; 3923 double s = (time_within_day / 1000) % 60; 3924 double milli = time_within_day % 1000; 3925 if (argc >= 2) { 3926 Handle<Object> min = args.at<Object>(2); 3927 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, min, Object::ToNumber(min)); 3928 m = min->Number(); 3929 if (argc >= 3) { 3930 Handle<Object> sec = args.at<Object>(3); 3931 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, sec, Object::ToNumber(sec)); 3932 s = sec->Number(); 3933 if (argc >= 4) { 3934 Handle<Object> ms = args.at<Object>(4); 3935 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, ms, Object::ToNumber(ms)); 3936 milli = ms->Number(); 3937 } 3938 } 3939 } 3940 time_val = MakeDate(day, MakeTime(h, m, s, milli)); 3941 } 3942 return *JSDate::SetValue(date, TimeClip(time_val)); 3943 } 3944 3945 3946 // ES6 section 20.3.4.31 Date.prototype.setUTCMilliseconds(ms) 3947 BUILTIN(DatePrototypeSetUTCMilliseconds) { 3948 HandleScope scope(isolate); 3949 CHECK_RECEIVER(JSDate, date, "Date.prototype.setUTCMilliseconds"); 3950 Handle<Object> ms = args.atOrUndefined(isolate, 1); 3951 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, ms, Object::ToNumber(ms)); 3952 double time_val = date->value()->Number(); 3953 if (!std::isnan(time_val)) { 3954 int64_t const time_ms = static_cast<int64_t>(time_val); 3955 int day = isolate->date_cache()->DaysFromTime(time_ms); 3956 int time_within_day = isolate->date_cache()->TimeInDay(time_ms, day); 3957 int h = time_within_day / (60 * 60 * 1000); 3958 int m = (time_within_day / (60 * 1000)) % 60; 3959 int s = (time_within_day / 1000) % 60; 3960 time_val = MakeDate(day, MakeTime(h, m, s, ms->Number())); 3961 } 3962 return *JSDate::SetValue(date, TimeClip(time_val)); 3963 } 3964 3965 3966 // ES6 section 20.3.4.32 Date.prototype.setUTCMinutes ( min, sec, ms ) 3967 BUILTIN(DatePrototypeSetUTCMinutes) { 3968 HandleScope scope(isolate); 3969 CHECK_RECEIVER(JSDate, date, "Date.prototype.setUTCMinutes"); 3970 int const argc = args.length() - 1; 3971 Handle<Object> min = args.atOrUndefined(isolate, 1); 3972 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, min, Object::ToNumber(min)); 3973 double time_val = date->value()->Number(); 3974 if (!std::isnan(time_val)) { 3975 int64_t const time_ms = static_cast<int64_t>(time_val); 3976 int day = isolate->date_cache()->DaysFromTime(time_ms); 3977 int time_within_day = isolate->date_cache()->TimeInDay(time_ms, day); 3978 int h = time_within_day / (60 * 60 * 1000); 3979 double m = min->Number(); 3980 double s = (time_within_day / 1000) % 60; 3981 double milli = time_within_day % 1000; 3982 if (argc >= 2) { 3983 Handle<Object> sec = args.at<Object>(2); 3984 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, sec, Object::ToNumber(sec)); 3985 s = sec->Number(); 3986 if (argc >= 3) { 3987 Handle<Object> ms = args.at<Object>(3); 3988 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, ms, Object::ToNumber(ms)); 3989 milli = ms->Number(); 3990 } 3991 } 3992 time_val = MakeDate(day, MakeTime(h, m, s, milli)); 3993 } 3994 return *JSDate::SetValue(date, TimeClip(time_val)); 3995 } 3996 3997 3998 // ES6 section 20.3.4.31 Date.prototype.setUTCMonth ( month, date ) 3999 BUILTIN(DatePrototypeSetUTCMonth) { 4000 HandleScope scope(isolate); 4001 CHECK_RECEIVER(JSDate, date, "Date.prototype.setUTCMonth"); 4002 int const argc = args.length() - 1; 4003 Handle<Object> month = args.atOrUndefined(isolate, 1); 4004 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, month, Object::ToNumber(month)); 4005 double time_val = date->value()->Number(); 4006 if (!std::isnan(time_val)) { 4007 int64_t const time_ms = static_cast<int64_t>(time_val); 4008 int days = isolate->date_cache()->DaysFromTime(time_ms); 4009 int time_within_day = isolate->date_cache()->TimeInDay(time_ms, days); 4010 int year, unused, day; 4011 isolate->date_cache()->YearMonthDayFromDays(days, &year, &unused, &day); 4012 double m = month->Number(); 4013 double dt = day; 4014 if (argc >= 2) { 4015 Handle<Object> date = args.at<Object>(2); 4016 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, date, Object::ToNumber(date)); 4017 dt = date->Number(); 4018 } 4019 time_val = MakeDate(MakeDay(year, m, dt), time_within_day); 4020 } 4021 return *JSDate::SetValue(date, TimeClip(time_val)); 4022 } 4023 4024 4025 // ES6 section 20.3.4.34 Date.prototype.setUTCSeconds ( sec, ms ) 4026 BUILTIN(DatePrototypeSetUTCSeconds) { 4027 HandleScope scope(isolate); 4028 CHECK_RECEIVER(JSDate, date, "Date.prototype.setUTCSeconds"); 4029 int const argc = args.length() - 1; 4030 Handle<Object> sec = args.atOrUndefined(isolate, 1); 4031 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, sec, Object::ToNumber(sec)); 4032 double time_val = date->value()->Number(); 4033 if (!std::isnan(time_val)) { 4034 int64_t const time_ms = static_cast<int64_t>(time_val); 4035 int day = isolate->date_cache()->DaysFromTime(time_ms); 4036 int time_within_day = isolate->date_cache()->TimeInDay(time_ms, day); 4037 int h = time_within_day / (60 * 60 * 1000); 4038 double m = (time_within_day / (60 * 1000)) % 60; 4039 double s = sec->Number(); 4040 double milli = time_within_day % 1000; 4041 if (argc >= 2) { 4042 Handle<Object> ms = args.at<Object>(2); 4043 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, ms, Object::ToNumber(ms)); 4044 milli = ms->Number(); 4045 } 4046 time_val = MakeDate(day, MakeTime(h, m, s, milli)); 4047 } 4048 return *JSDate::SetValue(date, TimeClip(time_val)); 4049 } 4050 4051 4052 // ES6 section 20.3.4.35 Date.prototype.toDateString ( ) 4053 BUILTIN(DatePrototypeToDateString) { 4054 HandleScope scope(isolate); 4055 CHECK_RECEIVER(JSDate, date, "Date.prototype.toDateString"); 4056 char buffer[128]; 4057 ToDateString(date->value()->Number(), ArrayVector(buffer), 4058 isolate->date_cache(), kDateOnly); 4059 RETURN_RESULT_OR_FAILURE( 4060 isolate, isolate->factory()->NewStringFromUtf8(CStrVector(buffer))); 4061 } 4062 4063 4064 // ES6 section 20.3.4.36 Date.prototype.toISOString ( ) 4065 BUILTIN(DatePrototypeToISOString) { 4066 HandleScope scope(isolate); 4067 CHECK_RECEIVER(JSDate, date, "Date.prototype.toISOString"); 4068 double const time_val = date->value()->Number(); 4069 if (std::isnan(time_val)) { 4070 THROW_NEW_ERROR_RETURN_FAILURE( 4071 isolate, NewRangeError(MessageTemplate::kInvalidTimeValue)); 4072 } 4073 int64_t const time_ms = static_cast<int64_t>(time_val); 4074 int year, month, day, weekday, hour, min, sec, ms; 4075 isolate->date_cache()->BreakDownTime(time_ms, &year, &month, &day, &weekday, 4076 &hour, &min, &sec, &ms); 4077 char buffer[128]; 4078 if (year >= 0 && year <= 9999) { 4079 SNPrintF(ArrayVector(buffer), "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", year, 4080 month + 1, day, hour, min, sec, ms); 4081 } else if (year < 0) { 4082 SNPrintF(ArrayVector(buffer), "-%06d-%02d-%02dT%02d:%02d:%02d.%03dZ", -year, 4083 month + 1, day, hour, min, sec, ms); 4084 } else { 4085 SNPrintF(ArrayVector(buffer), "+%06d-%02d-%02dT%02d:%02d:%02d.%03dZ", year, 4086 month + 1, day, hour, min, sec, ms); 4087 } 4088 return *isolate->factory()->NewStringFromAsciiChecked(buffer); 4089 } 4090 4091 4092 // ES6 section 20.3.4.41 Date.prototype.toString ( ) 4093 BUILTIN(DatePrototypeToString) { 4094 HandleScope scope(isolate); 4095 CHECK_RECEIVER(JSDate, date, "Date.prototype.toString"); 4096 char buffer[128]; 4097 ToDateString(date->value()->Number(), ArrayVector(buffer), 4098 isolate->date_cache()); 4099 RETURN_RESULT_OR_FAILURE( 4100 isolate, isolate->factory()->NewStringFromUtf8(CStrVector(buffer))); 4101 } 4102 4103 4104 // ES6 section 20.3.4.42 Date.prototype.toTimeString ( ) 4105 BUILTIN(DatePrototypeToTimeString) { 4106 HandleScope scope(isolate); 4107 CHECK_RECEIVER(JSDate, date, "Date.prototype.toTimeString"); 4108 char buffer[128]; 4109 ToDateString(date->value()->Number(), ArrayVector(buffer), 4110 isolate->date_cache(), kTimeOnly); 4111 RETURN_RESULT_OR_FAILURE( 4112 isolate, isolate->factory()->NewStringFromUtf8(CStrVector(buffer))); 4113 } 4114 4115 4116 // ES6 section 20.3.4.43 Date.prototype.toUTCString ( ) 4117 BUILTIN(DatePrototypeToUTCString) { 4118 HandleScope scope(isolate); 4119 CHECK_RECEIVER(JSDate, date, "Date.prototype.toUTCString"); 4120 double const time_val = date->value()->Number(); 4121 if (std::isnan(time_val)) { 4122 return *isolate->factory()->NewStringFromAsciiChecked("Invalid Date"); 4123 } 4124 char buffer[128]; 4125 int64_t time_ms = static_cast<int64_t>(time_val); 4126 int year, month, day, weekday, hour, min, sec, ms; 4127 isolate->date_cache()->BreakDownTime(time_ms, &year, &month, &day, &weekday, 4128 &hour, &min, &sec, &ms); 4129 SNPrintF(ArrayVector(buffer), "%s, %02d %s %4d %02d:%02d:%02d GMT", 4130 kShortWeekDays[weekday], day, kShortMonths[month], year, hour, min, 4131 sec); 4132 return *isolate->factory()->NewStringFromAsciiChecked(buffer); 4133 } 4134 4135 4136 // ES6 section 20.3.4.44 Date.prototype.valueOf ( ) 4137 BUILTIN(DatePrototypeValueOf) { 4138 HandleScope scope(isolate); 4139 CHECK_RECEIVER(JSDate, date, "Date.prototype.valueOf"); 4140 return date->value(); 4141 } 4142 4143 4144 // ES6 section 20.3.4.45 Date.prototype [ @@toPrimitive ] ( hint ) 4145 BUILTIN(DatePrototypeToPrimitive) { 4146 HandleScope scope(isolate); 4147 DCHECK_EQ(2, args.length()); 4148 CHECK_RECEIVER(JSReceiver, receiver, "Date.prototype [ @@toPrimitive ]"); 4149 Handle<Object> hint = args.at<Object>(1); 4150 RETURN_RESULT_OR_FAILURE(isolate, JSDate::ToPrimitive(receiver, hint)); 4151 } 4152 4153 4154 // ES6 section B.2.4.1 Date.prototype.getYear ( ) 4155 BUILTIN(DatePrototypeGetYear) { 4156 HandleScope scope(isolate); 4157 CHECK_RECEIVER(JSDate, date, "Date.prototype.getYear"); 4158 double time_val = date->value()->Number(); 4159 if (std::isnan(time_val)) return date->value(); 4160 int64_t time_ms = static_cast<int64_t>(time_val); 4161 int64_t local_time_ms = isolate->date_cache()->ToLocal(time_ms); 4162 int days = isolate->date_cache()->DaysFromTime(local_time_ms); 4163 int year, month, day; 4164 isolate->date_cache()->YearMonthDayFromDays(days, &year, &month, &day); 4165 return Smi::FromInt(year - 1900); 4166 } 4167 4168 4169 // ES6 section B.2.4.2 Date.prototype.setYear ( year ) 4170 BUILTIN(DatePrototypeSetYear) { 4171 HandleScope scope(isolate); 4172 CHECK_RECEIVER(JSDate, date, "Date.prototype.setYear"); 4173 Handle<Object> year = args.atOrUndefined(isolate, 1); 4174 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, year, Object::ToNumber(year)); 4175 double m = 0.0, dt = 1.0, y = year->Number(); 4176 if (0.0 <= y && y <= 99.0) { 4177 y = 1900.0 + DoubleToInteger(y); 4178 } 4179 int time_within_day = 0; 4180 if (!std::isnan(date->value()->Number())) { 4181 int64_t const time_ms = static_cast<int64_t>(date->value()->Number()); 4182 int64_t local_time_ms = isolate->date_cache()->ToLocal(time_ms); 4183 int const days = isolate->date_cache()->DaysFromTime(local_time_ms); 4184 time_within_day = isolate->date_cache()->TimeInDay(local_time_ms, days); 4185 int year, month, day; 4186 isolate->date_cache()->YearMonthDayFromDays(days, &year, &month, &day); 4187 m = month; 4188 dt = day; 4189 } 4190 double time_val = MakeDate(MakeDay(y, m, dt), time_within_day); 4191 return SetLocalDateValue(date, time_val); 4192 } 4193 4194 // ES6 section 20.3.4.37 Date.prototype.toJSON ( key ) 4195 BUILTIN(DatePrototypeToJson) { 4196 HandleScope scope(isolate); 4197 Handle<Object> receiver = args.atOrUndefined(isolate, 0); 4198 Handle<JSReceiver> receiver_obj; 4199 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, receiver_obj, 4200 Object::ToObject(isolate, receiver)); 4201 Handle<Object> primitive; 4202 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 4203 isolate, primitive, 4204 Object::ToPrimitive(receiver_obj, ToPrimitiveHint::kNumber)); 4205 if (primitive->IsNumber() && !std::isfinite(primitive->Number())) { 4206 return isolate->heap()->null_value(); 4207 } else { 4208 Handle<String> name = 4209 isolate->factory()->NewStringFromAsciiChecked("toISOString"); 4210 Handle<Object> function; 4211 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, function, 4212 Object::GetProperty(receiver_obj, name)); 4213 if (!function->IsCallable()) { 4214 THROW_NEW_ERROR_RETURN_FAILURE( 4215 isolate, NewTypeError(MessageTemplate::kCalledNonCallable, name)); 4216 } 4217 RETURN_RESULT_OR_FAILURE( 4218 isolate, Execution::Call(isolate, function, receiver_obj, 0, NULL)); 4219 } 4220 } 4221 4222 // static 4223 void Builtins::Generate_DatePrototypeGetDate(MacroAssembler* masm) { 4224 Generate_DatePrototype_GetField(masm, JSDate::kDay); 4225 } 4226 4227 4228 // static 4229 void Builtins::Generate_DatePrototypeGetDay(MacroAssembler* masm) { 4230 Generate_DatePrototype_GetField(masm, JSDate::kWeekday); 4231 } 4232 4233 4234 // static 4235 void Builtins::Generate_DatePrototypeGetFullYear(MacroAssembler* masm) { 4236 Generate_DatePrototype_GetField(masm, JSDate::kYear); 4237 } 4238 4239 4240 // static 4241 void Builtins::Generate_DatePrototypeGetHours(MacroAssembler* masm) { 4242 Generate_DatePrototype_GetField(masm, JSDate::kHour); 4243 } 4244 4245 4246 // static 4247 void Builtins::Generate_DatePrototypeGetMilliseconds(MacroAssembler* masm) { 4248 Generate_DatePrototype_GetField(masm, JSDate::kMillisecond); 4249 } 4250 4251 4252 // static 4253 void Builtins::Generate_DatePrototypeGetMinutes(MacroAssembler* masm) { 4254 Generate_DatePrototype_GetField(masm, JSDate::kMinute); 4255 } 4256 4257 4258 // static 4259 void Builtins::Generate_DatePrototypeGetMonth(MacroAssembler* masm) { 4260 Generate_DatePrototype_GetField(masm, JSDate::kMonth); 4261 } 4262 4263 4264 // static 4265 void Builtins::Generate_DatePrototypeGetSeconds(MacroAssembler* masm) { 4266 Generate_DatePrototype_GetField(masm, JSDate::kSecond); 4267 } 4268 4269 4270 // static 4271 void Builtins::Generate_DatePrototypeGetTime(MacroAssembler* masm) { 4272 Generate_DatePrototype_GetField(masm, JSDate::kDateValue); 4273 } 4274 4275 4276 // static 4277 void Builtins::Generate_DatePrototypeGetTimezoneOffset(MacroAssembler* masm) { 4278 Generate_DatePrototype_GetField(masm, JSDate::kTimezoneOffset); 4279 } 4280 4281 4282 // static 4283 void Builtins::Generate_DatePrototypeGetUTCDate(MacroAssembler* masm) { 4284 Generate_DatePrototype_GetField(masm, JSDate::kDayUTC); 4285 } 4286 4287 4288 // static 4289 void Builtins::Generate_DatePrototypeGetUTCDay(MacroAssembler* masm) { 4290 Generate_DatePrototype_GetField(masm, JSDate::kWeekdayUTC); 4291 } 4292 4293 4294 // static 4295 void Builtins::Generate_DatePrototypeGetUTCFullYear(MacroAssembler* masm) { 4296 Generate_DatePrototype_GetField(masm, JSDate::kYearUTC); 4297 } 4298 4299 4300 // static 4301 void Builtins::Generate_DatePrototypeGetUTCHours(MacroAssembler* masm) { 4302 Generate_DatePrototype_GetField(masm, JSDate::kHourUTC); 4303 } 4304 4305 4306 // static 4307 void Builtins::Generate_DatePrototypeGetUTCMilliseconds(MacroAssembler* masm) { 4308 Generate_DatePrototype_GetField(masm, JSDate::kMillisecondUTC); 4309 } 4310 4311 4312 // static 4313 void Builtins::Generate_DatePrototypeGetUTCMinutes(MacroAssembler* masm) { 4314 Generate_DatePrototype_GetField(masm, JSDate::kMinuteUTC); 4315 } 4316 4317 4318 // static 4319 void Builtins::Generate_DatePrototypeGetUTCMonth(MacroAssembler* masm) { 4320 Generate_DatePrototype_GetField(masm, JSDate::kMonthUTC); 4321 } 4322 4323 4324 // static 4325 void Builtins::Generate_DatePrototypeGetUTCSeconds(MacroAssembler* masm) { 4326 Generate_DatePrototype_GetField(masm, JSDate::kSecondUTC); 4327 } 4328 4329 4330 namespace { 4331 4332 // ES6 section 19.2.1.1.1 CreateDynamicFunction 4333 MaybeHandle<JSFunction> CreateDynamicFunction(Isolate* isolate, 4334 BuiltinArguments args, 4335 const char* token) { 4336 // Compute number of arguments, ignoring the receiver. 4337 DCHECK_LE(1, args.length()); 4338 int const argc = args.length() - 1; 4339 4340 // Build the source string. 4341 Handle<String> source; 4342 { 4343 IncrementalStringBuilder builder(isolate); 4344 builder.AppendCharacter('('); 4345 builder.AppendCString(token); 4346 builder.AppendCharacter('('); 4347 bool parenthesis_in_arg_string = false; 4348 if (argc > 1) { 4349 for (int i = 1; i < argc; ++i) { 4350 if (i > 1) builder.AppendCharacter(','); 4351 Handle<String> param; 4352 ASSIGN_RETURN_ON_EXCEPTION( 4353 isolate, param, Object::ToString(isolate, args.at<Object>(i)), 4354 JSFunction); 4355 param = String::Flatten(param); 4356 builder.AppendString(param); 4357 // If the formal parameters string include ) - an illegal 4358 // character - it may make the combined function expression 4359 // compile. We avoid this problem by checking for this early on. 4360 DisallowHeapAllocation no_gc; // Ensure vectors stay valid. 4361 String::FlatContent param_content = param->GetFlatContent(); 4362 for (int i = 0, length = param->length(); i < length; ++i) { 4363 if (param_content.Get(i) == ')') { 4364 parenthesis_in_arg_string = true; 4365 break; 4366 } 4367 } 4368 } 4369 // If the formal parameters include an unbalanced block comment, the 4370 // function must be rejected. Since JavaScript does not allow nested 4371 // comments we can include a trailing block comment to catch this. 4372 builder.AppendCString("\n/**/"); 4373 } 4374 builder.AppendCString(") {\n"); 4375 if (argc > 0) { 4376 Handle<String> body; 4377 ASSIGN_RETURN_ON_EXCEPTION( 4378 isolate, body, Object::ToString(isolate, args.at<Object>(argc)), 4379 JSFunction); 4380 builder.AppendString(body); 4381 } 4382 builder.AppendCString("\n})"); 4383 ASSIGN_RETURN_ON_EXCEPTION(isolate, source, builder.Finish(), JSFunction); 4384 4385 // The SyntaxError must be thrown after all the (observable) ToString 4386 // conversions are done. 4387 if (parenthesis_in_arg_string) { 4388 THROW_NEW_ERROR(isolate, 4389 NewSyntaxError(MessageTemplate::kParenthesisInArgString), 4390 JSFunction); 4391 } 4392 } 4393 4394 // Compile the string in the constructor and not a helper so that errors to 4395 // come from here. 4396 Handle<JSFunction> target = args.target<JSFunction>(); 4397 Handle<JSObject> target_global_proxy(target->global_proxy(), isolate); 4398 Handle<JSFunction> function; 4399 { 4400 ASSIGN_RETURN_ON_EXCEPTION( 4401 isolate, function, 4402 CompileString(handle(target->native_context(), isolate), source, 4403 ONLY_SINGLE_FUNCTION_LITERAL), 4404 JSFunction); 4405 Handle<Object> result; 4406 ASSIGN_RETURN_ON_EXCEPTION( 4407 isolate, result, 4408 Execution::Call(isolate, function, target_global_proxy, 0, nullptr), 4409 JSFunction); 4410 function = Handle<JSFunction>::cast(result); 4411 function->shared()->set_name_should_print_as_anonymous(true); 4412 } 4413 4414 // If new.target is equal to target then the function created 4415 // is already correctly setup and nothing else should be done 4416 // here. But if new.target is not equal to target then we are 4417 // have a Function builtin subclassing case and therefore the 4418 // function has wrong initial map. To fix that we create a new 4419 // function object with correct initial map. 4420 Handle<Object> unchecked_new_target = args.new_target(); 4421 if (!unchecked_new_target->IsUndefined(isolate) && 4422 !unchecked_new_target.is_identical_to(target)) { 4423 Handle<JSReceiver> new_target = 4424 Handle<JSReceiver>::cast(unchecked_new_target); 4425 Handle<Map> initial_map; 4426 ASSIGN_RETURN_ON_EXCEPTION( 4427 isolate, initial_map, 4428 JSFunction::GetDerivedMap(isolate, target, new_target), JSFunction); 4429 4430 Handle<SharedFunctionInfo> shared_info(function->shared(), isolate); 4431 Handle<Map> map = Map::AsLanguageMode( 4432 initial_map, shared_info->language_mode(), shared_info->kind()); 4433 4434 Handle<Context> context(function->context(), isolate); 4435 function = isolate->factory()->NewFunctionFromSharedFunctionInfo( 4436 map, shared_info, context, NOT_TENURED); 4437 } 4438 return function; 4439 } 4440 4441 } // namespace 4442 4443 4444 // ES6 section 19.2.1.1 Function ( p1, p2, ... , pn, body ) 4445 BUILTIN(FunctionConstructor) { 4446 HandleScope scope(isolate); 4447 Handle<JSFunction> result; 4448 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 4449 isolate, result, CreateDynamicFunction(isolate, args, "function")); 4450 return *result; 4451 } 4452 4453 namespace { 4454 4455 Object* DoFunctionBind(Isolate* isolate, BuiltinArguments args) { 4456 HandleScope scope(isolate); 4457 DCHECK_LE(1, args.length()); 4458 if (!args.receiver()->IsCallable()) { 4459 THROW_NEW_ERROR_RETURN_FAILURE( 4460 isolate, NewTypeError(MessageTemplate::kFunctionBind)); 4461 } 4462 4463 // Allocate the bound function with the given {this_arg} and {args}. 4464 Handle<JSReceiver> target = args.at<JSReceiver>(0); 4465 Handle<Object> this_arg = isolate->factory()->undefined_value(); 4466 ScopedVector<Handle<Object>> argv(std::max(0, args.length() - 2)); 4467 if (args.length() > 1) { 4468 this_arg = args.at<Object>(1); 4469 for (int i = 2; i < args.length(); ++i) { 4470 argv[i - 2] = args.at<Object>(i); 4471 } 4472 } 4473 Handle<JSBoundFunction> function; 4474 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 4475 isolate, function, 4476 isolate->factory()->NewJSBoundFunction(target, this_arg, argv)); 4477 4478 LookupIterator length_lookup(target, isolate->factory()->length_string(), 4479 target, LookupIterator::OWN); 4480 // Setup the "length" property based on the "length" of the {target}. 4481 // If the targets length is the default JSFunction accessor, we can keep the 4482 // accessor that's installed by default on the JSBoundFunction. It lazily 4483 // computes the value from the underlying internal length. 4484 if (!target->IsJSFunction() || 4485 length_lookup.state() != LookupIterator::ACCESSOR || 4486 !length_lookup.GetAccessors()->IsAccessorInfo()) { 4487 Handle<Object> length(Smi::FromInt(0), isolate); 4488 Maybe<PropertyAttributes> attributes = 4489 JSReceiver::GetPropertyAttributes(&length_lookup); 4490 if (!attributes.IsJust()) return isolate->heap()->exception(); 4491 if (attributes.FromJust() != ABSENT) { 4492 Handle<Object> target_length; 4493 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, target_length, 4494 Object::GetProperty(&length_lookup)); 4495 if (target_length->IsNumber()) { 4496 length = isolate->factory()->NewNumber(std::max( 4497 0.0, DoubleToInteger(target_length->Number()) - argv.length())); 4498 } 4499 } 4500 LookupIterator it(function, isolate->factory()->length_string(), function); 4501 DCHECK_EQ(LookupIterator::ACCESSOR, it.state()); 4502 RETURN_FAILURE_ON_EXCEPTION(isolate, 4503 JSObject::DefineOwnPropertyIgnoreAttributes( 4504 &it, length, it.property_attributes())); 4505 } 4506 4507 // Setup the "name" property based on the "name" of the {target}. 4508 // If the targets name is the default JSFunction accessor, we can keep the 4509 // accessor that's installed by default on the JSBoundFunction. It lazily 4510 // computes the value from the underlying internal name. 4511 LookupIterator name_lookup(target, isolate->factory()->name_string(), target, 4512 LookupIterator::OWN); 4513 if (!target->IsJSFunction() || 4514 name_lookup.state() != LookupIterator::ACCESSOR || 4515 !name_lookup.GetAccessors()->IsAccessorInfo()) { 4516 Handle<Object> target_name; 4517 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, target_name, 4518 Object::GetProperty(&name_lookup)); 4519 Handle<String> name; 4520 if (target_name->IsString()) { 4521 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 4522 isolate, name, 4523 Name::ToFunctionName(Handle<String>::cast(target_name))); 4524 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 4525 isolate, name, isolate->factory()->NewConsString( 4526 isolate->factory()->bound__string(), name)); 4527 } else { 4528 name = isolate->factory()->bound__string(); 4529 } 4530 LookupIterator it(function, isolate->factory()->name_string()); 4531 DCHECK_EQ(LookupIterator::ACCESSOR, it.state()); 4532 RETURN_FAILURE_ON_EXCEPTION(isolate, 4533 JSObject::DefineOwnPropertyIgnoreAttributes( 4534 &it, name, it.property_attributes())); 4535 } 4536 return *function; 4537 } 4538 4539 } // namespace 4540 4541 // ES6 section 19.2.3.2 Function.prototype.bind ( thisArg, ...args ) 4542 BUILTIN(FunctionPrototypeBind) { return DoFunctionBind(isolate, args); } 4543 4544 // TODO(verwaest): This is a temporary helper until the FastFunctionBind stub 4545 // can tailcall to the builtin directly. 4546 RUNTIME_FUNCTION(Runtime_FunctionBind) { 4547 DCHECK_EQ(2, args.length()); 4548 Arguments* incoming = reinterpret_cast<Arguments*>(args[0]); 4549 // Rewrap the arguments as builtins arguments. 4550 BuiltinArguments caller_args(incoming->length() + 3, 4551 incoming->arguments() + 1); 4552 return DoFunctionBind(isolate, caller_args); 4553 } 4554 4555 // ES6 section 19.2.3.5 Function.prototype.toString ( ) 4556 BUILTIN(FunctionPrototypeToString) { 4557 HandleScope scope(isolate); 4558 Handle<Object> receiver = args.receiver(); 4559 if (receiver->IsJSBoundFunction()) { 4560 return *JSBoundFunction::ToString(Handle<JSBoundFunction>::cast(receiver)); 4561 } else if (receiver->IsJSFunction()) { 4562 return *JSFunction::ToString(Handle<JSFunction>::cast(receiver)); 4563 } 4564 THROW_NEW_ERROR_RETURN_FAILURE( 4565 isolate, NewTypeError(MessageTemplate::kNotGeneric, 4566 isolate->factory()->NewStringFromAsciiChecked( 4567 "Function.prototype.toString"))); 4568 } 4569 4570 4571 // ES6 section 25.2.1.1 GeneratorFunction (p1, p2, ... , pn, body) 4572 BUILTIN(GeneratorFunctionConstructor) { 4573 HandleScope scope(isolate); 4574 RETURN_RESULT_OR_FAILURE(isolate, 4575 CreateDynamicFunction(isolate, args, "function*")); 4576 } 4577 4578 BUILTIN(AsyncFunctionConstructor) { 4579 HandleScope scope(isolate); 4580 Handle<JSFunction> func; 4581 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 4582 isolate, func, CreateDynamicFunction(isolate, args, "async function")); 4583 4584 // Do not lazily compute eval position for AsyncFunction, as they may not be 4585 // determined after the function is resumed. 4586 Handle<Script> script = handle(Script::cast(func->shared()->script())); 4587 int position = script->GetEvalPosition(); 4588 USE(position); 4589 4590 return *func; 4591 } 4592 4593 // ES6 section 19.4.1.1 Symbol ( [ description ] ) for the [[Call]] case. 4594 BUILTIN(SymbolConstructor) { 4595 HandleScope scope(isolate); 4596 Handle<Symbol> result = isolate->factory()->NewSymbol(); 4597 Handle<Object> description = args.atOrUndefined(isolate, 1); 4598 if (!description->IsUndefined(isolate)) { 4599 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, description, 4600 Object::ToString(isolate, description)); 4601 result->set_name(*description); 4602 } 4603 return *result; 4604 } 4605 4606 4607 // ES6 section 19.4.1.1 Symbol ( [ description ] ) for the [[Construct]] case. 4608 BUILTIN(SymbolConstructor_ConstructStub) { 4609 HandleScope scope(isolate); 4610 THROW_NEW_ERROR_RETURN_FAILURE( 4611 isolate, NewTypeError(MessageTemplate::kNotConstructor, 4612 isolate->factory()->Symbol_string())); 4613 } 4614 4615 4616 // ES6 19.1.3.6 Object.prototype.toString 4617 BUILTIN(ObjectProtoToString) { 4618 HandleScope scope(isolate); 4619 Handle<Object> object = args.at<Object>(0); 4620 RETURN_RESULT_OR_FAILURE(isolate, 4621 Object::ObjectProtoToString(isolate, object)); 4622 } 4623 4624 // ----------------------------------------------------------------------------- 4625 // ES6 section 21.1 String Objects 4626 4627 // ES6 section 21.1.2.1 String.fromCharCode ( ...codeUnits ) 4628 void Builtins::Generate_StringFromCharCode(CodeStubAssembler* assembler) { 4629 typedef CodeStubAssembler::Label Label; 4630 typedef compiler::Node Node; 4631 typedef CodeStubAssembler::Variable Variable; 4632 4633 Node* code = assembler->Parameter(1); 4634 Node* context = assembler->Parameter(4); 4635 4636 // Check if we have exactly one argument (plus the implicit receiver), i.e. 4637 // if the parent frame is not an arguments adaptor frame. 4638 Label if_oneargument(assembler), if_notoneargument(assembler); 4639 Node* parent_frame_pointer = assembler->LoadParentFramePointer(); 4640 Node* parent_frame_type = 4641 assembler->Load(MachineType::Pointer(), parent_frame_pointer, 4642 assembler->IntPtrConstant( 4643 CommonFrameConstants::kContextOrFrameTypeOffset)); 4644 assembler->Branch( 4645 assembler->WordEqual( 4646 parent_frame_type, 4647 assembler->SmiConstant(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR))), 4648 &if_notoneargument, &if_oneargument); 4649 4650 assembler->Bind(&if_oneargument); 4651 { 4652 // Single argument case, perform fast single character string cache lookup 4653 // for one-byte code units, or fall back to creating a single character 4654 // string on the fly otherwise. 4655 Node* code32 = assembler->TruncateTaggedToWord32(context, code); 4656 Node* code16 = assembler->Word32And( 4657 code32, assembler->Int32Constant(String::kMaxUtf16CodeUnit)); 4658 Node* result = assembler->StringFromCharCode(code16); 4659 assembler->Return(result); 4660 } 4661 4662 assembler->Bind(&if_notoneargument); 4663 { 4664 // Determine the resulting string length. 4665 Node* parent_frame_length = 4666 assembler->Load(MachineType::Pointer(), parent_frame_pointer, 4667 assembler->IntPtrConstant( 4668 ArgumentsAdaptorFrameConstants::kLengthOffset)); 4669 Node* length = assembler->SmiToWord(parent_frame_length); 4670 4671 // Assume that the resulting string contains only one-byte characters. 4672 Node* result = assembler->AllocateSeqOneByteString(context, length); 4673 4674 // Truncate all input parameters and append them to the resulting string. 4675 Variable var_offset(assembler, MachineType::PointerRepresentation()); 4676 Label loop(assembler, &var_offset), done_loop(assembler); 4677 var_offset.Bind(assembler->IntPtrConstant(0)); 4678 assembler->Goto(&loop); 4679 assembler->Bind(&loop); 4680 { 4681 // Load the current {offset}. 4682 Node* offset = var_offset.value(); 4683 4684 // Check if we're done with the string. 4685 assembler->GotoIf(assembler->WordEqual(offset, length), &done_loop); 4686 4687 // Load the next code point and truncate it to a 16-bit value. 4688 Node* code = assembler->Load( 4689 MachineType::AnyTagged(), parent_frame_pointer, 4690 assembler->IntPtrAdd( 4691 assembler->WordShl(assembler->IntPtrSub(length, offset), 4692 assembler->IntPtrConstant(kPointerSizeLog2)), 4693 assembler->IntPtrConstant( 4694 CommonFrameConstants::kFixedFrameSizeAboveFp - 4695 kPointerSize))); 4696 Node* code32 = assembler->TruncateTaggedToWord32(context, code); 4697 Node* code16 = assembler->Word32And( 4698 code32, assembler->Int32Constant(String::kMaxUtf16CodeUnit)); 4699 4700 // Check if {code16} fits into a one-byte string. 4701 Label if_codeisonebyte(assembler), if_codeistwobyte(assembler); 4702 assembler->Branch( 4703 assembler->Int32LessThanOrEqual( 4704 code16, assembler->Int32Constant(String::kMaxOneByteCharCode)), 4705 &if_codeisonebyte, &if_codeistwobyte); 4706 4707 assembler->Bind(&if_codeisonebyte); 4708 { 4709 // The {code16} fits into the SeqOneByteString {result}. 4710 assembler->StoreNoWriteBarrier( 4711 MachineRepresentation::kWord8, result, 4712 assembler->IntPtrAdd( 4713 assembler->IntPtrConstant(SeqOneByteString::kHeaderSize - 4714 kHeapObjectTag), 4715 offset), 4716 code16); 4717 var_offset.Bind( 4718 assembler->IntPtrAdd(offset, assembler->IntPtrConstant(1))); 4719 assembler->Goto(&loop); 4720 } 4721 4722 assembler->Bind(&if_codeistwobyte); 4723 { 4724 // Allocate a SeqTwoByteString to hold the resulting string. 4725 Node* cresult = assembler->AllocateSeqTwoByteString(context, length); 4726 4727 // Copy all characters that were previously written to the 4728 // SeqOneByteString in {result} over to the new {cresult}. 4729 Variable var_coffset(assembler, MachineType::PointerRepresentation()); 4730 Label cloop(assembler, &var_coffset), done_cloop(assembler); 4731 var_coffset.Bind(assembler->IntPtrConstant(0)); 4732 assembler->Goto(&cloop); 4733 assembler->Bind(&cloop); 4734 { 4735 Node* coffset = var_coffset.value(); 4736 assembler->GotoIf(assembler->WordEqual(coffset, offset), &done_cloop); 4737 Node* ccode = assembler->Load( 4738 MachineType::Uint8(), result, 4739 assembler->IntPtrAdd( 4740 assembler->IntPtrConstant(SeqOneByteString::kHeaderSize - 4741 kHeapObjectTag), 4742 coffset)); 4743 assembler->StoreNoWriteBarrier( 4744 MachineRepresentation::kWord16, cresult, 4745 assembler->IntPtrAdd( 4746 assembler->IntPtrConstant(SeqTwoByteString::kHeaderSize - 4747 kHeapObjectTag), 4748 assembler->WordShl(coffset, 1)), 4749 ccode); 4750 var_coffset.Bind( 4751 assembler->IntPtrAdd(coffset, assembler->IntPtrConstant(1))); 4752 assembler->Goto(&cloop); 4753 } 4754 4755 // Write the pending {code16} to {offset}. 4756 assembler->Bind(&done_cloop); 4757 assembler->StoreNoWriteBarrier( 4758 MachineRepresentation::kWord16, cresult, 4759 assembler->IntPtrAdd( 4760 assembler->IntPtrConstant(SeqTwoByteString::kHeaderSize - 4761 kHeapObjectTag), 4762 assembler->WordShl(offset, 1)), 4763 code16); 4764 4765 // Copy the remaining parameters to the SeqTwoByteString {cresult}. 4766 Label floop(assembler, &var_offset), done_floop(assembler); 4767 assembler->Goto(&floop); 4768 assembler->Bind(&floop); 4769 { 4770 // Compute the next {offset}. 4771 Node* offset = assembler->IntPtrAdd(var_offset.value(), 4772 assembler->IntPtrConstant(1)); 4773 4774 // Check if we're done with the string. 4775 assembler->GotoIf(assembler->WordEqual(offset, length), &done_floop); 4776 4777 // Load the next code point and truncate it to a 16-bit value. 4778 Node* code = assembler->Load( 4779 MachineType::AnyTagged(), parent_frame_pointer, 4780 assembler->IntPtrAdd( 4781 assembler->WordShl( 4782 assembler->IntPtrSub(length, offset), 4783 assembler->IntPtrConstant(kPointerSizeLog2)), 4784 assembler->IntPtrConstant( 4785 CommonFrameConstants::kFixedFrameSizeAboveFp - 4786 kPointerSize))); 4787 Node* code32 = assembler->TruncateTaggedToWord32(context, code); 4788 Node* code16 = assembler->Word32And( 4789 code32, assembler->Int32Constant(String::kMaxUtf16CodeUnit)); 4790 4791 // Store the truncated {code} point at the next offset. 4792 assembler->StoreNoWriteBarrier( 4793 MachineRepresentation::kWord16, cresult, 4794 assembler->IntPtrAdd( 4795 assembler->IntPtrConstant(SeqTwoByteString::kHeaderSize - 4796 kHeapObjectTag), 4797 assembler->WordShl(offset, 1)), 4798 code16); 4799 var_offset.Bind(offset); 4800 assembler->Goto(&floop); 4801 } 4802 4803 // Return the SeqTwoByteString. 4804 assembler->Bind(&done_floop); 4805 assembler->Return(cresult); 4806 } 4807 } 4808 4809 assembler->Bind(&done_loop); 4810 assembler->Return(result); 4811 } 4812 } 4813 4814 namespace { // for String.fromCodePoint 4815 4816 bool IsValidCodePoint(Isolate* isolate, Handle<Object> value) { 4817 if (!value->IsNumber() && !Object::ToNumber(value).ToHandle(&value)) { 4818 return false; 4819 } 4820 4821 if (Object::ToInteger(isolate, value).ToHandleChecked()->Number() != 4822 value->Number()) { 4823 return false; 4824 } 4825 4826 if (value->Number() < 0 || value->Number() > 0x10FFFF) { 4827 return false; 4828 } 4829 4830 return true; 4831 } 4832 4833 uc32 NextCodePoint(Isolate* isolate, BuiltinArguments args, int index) { 4834 Handle<Object> value = args.at<Object>(1 + index); 4835 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, value, Object::ToNumber(value), -1); 4836 if (!IsValidCodePoint(isolate, value)) { 4837 isolate->Throw(*isolate->factory()->NewRangeError( 4838 MessageTemplate::kInvalidCodePoint, value)); 4839 return -1; 4840 } 4841 return DoubleToUint32(value->Number()); 4842 } 4843 4844 } // namespace 4845 4846 // ES6 section 21.1.2.2 String.fromCodePoint ( ...codePoints ) 4847 BUILTIN(StringFromCodePoint) { 4848 HandleScope scope(isolate); 4849 int const length = args.length() - 1; 4850 if (length == 0) return isolate->heap()->empty_string(); 4851 DCHECK_LT(0, length); 4852 4853 // Optimistically assume that the resulting String contains only one byte 4854 // characters. 4855 List<uint8_t> one_byte_buffer(length); 4856 uc32 code = 0; 4857 int index; 4858 for (index = 0; index < length; index++) { 4859 code = NextCodePoint(isolate, args, index); 4860 if (code < 0) { 4861 return isolate->heap()->exception(); 4862 } 4863 if (code > String::kMaxOneByteCharCode) { 4864 break; 4865 } 4866 one_byte_buffer.Add(code); 4867 } 4868 4869 if (index == length) { 4870 RETURN_RESULT_OR_FAILURE(isolate, isolate->factory()->NewStringFromOneByte( 4871 one_byte_buffer.ToConstVector())); 4872 } 4873 4874 List<uc16> two_byte_buffer(length - index); 4875 4876 while (true) { 4877 if (code <= unibrow::Utf16::kMaxNonSurrogateCharCode) { 4878 two_byte_buffer.Add(code); 4879 } else { 4880 two_byte_buffer.Add(unibrow::Utf16::LeadSurrogate(code)); 4881 two_byte_buffer.Add(unibrow::Utf16::TrailSurrogate(code)); 4882 } 4883 4884 if (++index == length) { 4885 break; 4886 } 4887 code = NextCodePoint(isolate, args, index); 4888 if (code < 0) { 4889 return isolate->heap()->exception(); 4890 } 4891 } 4892 4893 Handle<SeqTwoByteString> result; 4894 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( 4895 isolate, result, 4896 isolate->factory()->NewRawTwoByteString(one_byte_buffer.length() + 4897 two_byte_buffer.length())); 4898 4899 CopyChars(result->GetChars(), one_byte_buffer.ToConstVector().start(), 4900 one_byte_buffer.length()); 4901 CopyChars(result->GetChars() + one_byte_buffer.length(), 4902 two_byte_buffer.ToConstVector().start(), two_byte_buffer.length()); 4903 4904 return *result; 4905 } 4906 4907 // ES6 section 21.1.3.1 String.prototype.charAt ( pos ) 4908 void Builtins::Generate_StringPrototypeCharAt(CodeStubAssembler* assembler) { 4909 typedef CodeStubAssembler::Label Label; 4910 typedef compiler::Node Node; 4911 typedef CodeStubAssembler::Variable Variable; 4912 4913 Node* receiver = assembler->Parameter(0); 4914 Node* position = assembler->Parameter(1); 4915 Node* context = assembler->Parameter(4); 4916 4917 // Check that {receiver} is coercible to Object and convert it to a String. 4918 receiver = 4919 assembler->ToThisString(context, receiver, "String.prototype.charAt"); 4920 4921 // Convert the {position} to a Smi and check that it's in bounds of the 4922 // {receiver}. 4923 // TODO(bmeurer): Find an abstraction for this! 4924 { 4925 // Check if the {position} is already a Smi. 4926 Variable var_position(assembler, MachineRepresentation::kTagged); 4927 var_position.Bind(position); 4928 Label if_positionissmi(assembler), 4929 if_positionisnotsmi(assembler, Label::kDeferred); 4930 assembler->Branch(assembler->WordIsSmi(position), &if_positionissmi, 4931 &if_positionisnotsmi); 4932 assembler->Bind(&if_positionisnotsmi); 4933 { 4934 // Convert the {position} to an Integer via the ToIntegerStub. 4935 Callable callable = CodeFactory::ToInteger(assembler->isolate()); 4936 Node* index = assembler->CallStub(callable, context, position); 4937 4938 // Check if the resulting {index} is now a Smi. 4939 Label if_indexissmi(assembler, Label::kDeferred), 4940 if_indexisnotsmi(assembler, Label::kDeferred); 4941 assembler->Branch(assembler->WordIsSmi(index), &if_indexissmi, 4942 &if_indexisnotsmi); 4943 4944 assembler->Bind(&if_indexissmi); 4945 { 4946 var_position.Bind(index); 4947 assembler->Goto(&if_positionissmi); 4948 } 4949 4950 assembler->Bind(&if_indexisnotsmi); 4951 { 4952 // The ToIntegerStub canonicalizes everything in Smi range to Smi 4953 // representation, so any HeapNumber returned is not in Smi range. 4954 // The only exception here is -0.0, which we treat as 0. 4955 Node* index_value = assembler->LoadHeapNumberValue(index); 4956 Label if_indexiszero(assembler, Label::kDeferred), 4957 if_indexisnotzero(assembler, Label::kDeferred); 4958 assembler->Branch(assembler->Float64Equal( 4959 index_value, assembler->Float64Constant(0.0)), 4960 &if_indexiszero, &if_indexisnotzero); 4961 4962 assembler->Bind(&if_indexiszero); 4963 { 4964 var_position.Bind(assembler->SmiConstant(Smi::FromInt(0))); 4965 assembler->Goto(&if_positionissmi); 4966 } 4967 4968 assembler->Bind(&if_indexisnotzero); 4969 { 4970 // The {index} is some other integral Number, that is definitely 4971 // neither -0.0 nor in Smi range. 4972 assembler->Return(assembler->EmptyStringConstant()); 4973 } 4974 } 4975 } 4976 assembler->Bind(&if_positionissmi); 4977 position = var_position.value(); 4978 4979 // Determine the actual length of the {receiver} String. 4980 Node* receiver_length = 4981 assembler->LoadObjectField(receiver, String::kLengthOffset); 4982 4983 // Return "" if the Smi {position} is outside the bounds of the {receiver}. 4984 Label if_positioninbounds(assembler), 4985 if_positionnotinbounds(assembler, Label::kDeferred); 4986 assembler->Branch(assembler->SmiAboveOrEqual(position, receiver_length), 4987 &if_positionnotinbounds, &if_positioninbounds); 4988 assembler->Bind(&if_positionnotinbounds); 4989 assembler->Return(assembler->EmptyStringConstant()); 4990 assembler->Bind(&if_positioninbounds); 4991 } 4992 4993 // Load the character code at the {position} from the {receiver}. 4994 Node* code = assembler->StringCharCodeAt(receiver, position); 4995 4996 // And return the single character string with only that {code}. 4997 Node* result = assembler->StringFromCharCode(code); 4998 assembler->Return(result); 4999 } 5000 5001 // ES6 section 21.1.3.2 String.prototype.charCodeAt ( pos ) 5002 void Builtins::Generate_StringPrototypeCharCodeAt( 5003 CodeStubAssembler* assembler) { 5004 typedef CodeStubAssembler::Label Label; 5005 typedef compiler::Node Node; 5006 typedef CodeStubAssembler::Variable Variable; 5007 5008 Node* receiver = assembler->Parameter(0); 5009 Node* position = assembler->Parameter(1); 5010 Node* context = assembler->Parameter(4); 5011 5012 // Check that {receiver} is coercible to Object and convert it to a String. 5013 receiver = 5014 assembler->ToThisString(context, receiver, "String.prototype.charCodeAt"); 5015 5016 // Convert the {position} to a Smi and check that it's in bounds of the 5017 // {receiver}. 5018 // TODO(bmeurer): Find an abstraction for this! 5019 { 5020 // Check if the {position} is already a Smi. 5021 Variable var_position(assembler, MachineRepresentation::kTagged); 5022 var_position.Bind(position); 5023 Label if_positionissmi(assembler), 5024 if_positionisnotsmi(assembler, Label::kDeferred); 5025 assembler->Branch(assembler->WordIsSmi(position), &if_positionissmi, 5026 &if_positionisnotsmi); 5027 assembler->Bind(&if_positionisnotsmi); 5028 { 5029 // Convert the {position} to an Integer via the ToIntegerStub. 5030 Callable callable = CodeFactory::ToInteger(assembler->isolate()); 5031 Node* index = assembler->CallStub(callable, context, position); 5032 5033 // Check if the resulting {index} is now a Smi. 5034 Label if_indexissmi(assembler, Label::kDeferred), 5035 if_indexisnotsmi(assembler, Label::kDeferred); 5036 assembler->Branch(assembler->WordIsSmi(index), &if_indexissmi, 5037 &if_indexisnotsmi); 5038 5039 assembler->Bind(&if_indexissmi); 5040 { 5041 var_position.Bind(index); 5042 assembler->Goto(&if_positionissmi); 5043 } 5044 5045 assembler->Bind(&if_indexisnotsmi); 5046 { 5047 // The ToIntegerStub canonicalizes everything in Smi range to Smi 5048 // representation, so any HeapNumber returned is not in Smi range. 5049 // The only exception here is -0.0, which we treat as 0. 5050 Node* index_value = assembler->LoadHeapNumberValue(index); 5051 Label if_indexiszero(assembler, Label::kDeferred), 5052 if_indexisnotzero(assembler, Label::kDeferred); 5053 assembler->Branch(assembler->Float64Equal( 5054 index_value, assembler->Float64Constant(0.0)), 5055 &if_indexiszero, &if_indexisnotzero); 5056 5057 assembler->Bind(&if_indexiszero); 5058 { 5059 var_position.Bind(assembler->SmiConstant(Smi::FromInt(0))); 5060 assembler->Goto(&if_positionissmi); 5061 } 5062 5063 assembler->Bind(&if_indexisnotzero); 5064 { 5065 // The {index} is some other integral Number, that is definitely 5066 // neither -0.0 nor in Smi range. 5067 assembler->Return(assembler->NaNConstant()); 5068 } 5069 } 5070 } 5071 assembler->Bind(&if_positionissmi); 5072 position = var_position.value(); 5073 5074 // Determine the actual length of the {receiver} String. 5075 Node* receiver_length = 5076 assembler->LoadObjectField(receiver, String::kLengthOffset); 5077 5078 // Return NaN if the Smi {position} is outside the bounds of the {receiver}. 5079 Label if_positioninbounds(assembler), 5080 if_positionnotinbounds(assembler, Label::kDeferred); 5081 assembler->Branch(assembler->SmiAboveOrEqual(position, receiver_length), 5082 &if_positionnotinbounds, &if_positioninbounds); 5083 assembler->Bind(&if_positionnotinbounds); 5084 assembler->Return(assembler->NaNConstant()); 5085 assembler->Bind(&if_positioninbounds); 5086 } 5087 5088 // Load the character at the {position} from the {receiver}. 5089 Node* value = assembler->StringCharCodeAt(receiver, position); 5090 Node* result = assembler->SmiFromWord32(value); 5091 assembler->Return(result); 5092 } 5093 5094 // ES6 section 21.1.3.25 String.prototype.trim () 5095 BUILTIN(StringPrototypeTrim) { 5096 HandleScope scope(isolate); 5097 TO_THIS_STRING(string, "String.prototype.trim"); 5098 return *String::Trim(string, String::kTrim); 5099 } 5100 5101 // Non-standard WebKit extension 5102 BUILTIN(StringPrototypeTrimLeft) { 5103 HandleScope scope(isolate); 5104 TO_THIS_STRING(string, "String.prototype.trimLeft"); 5105 return *String::Trim(string, String::kTrimLeft); 5106 } 5107 5108 // Non-standard WebKit extension 5109 BUILTIN(StringPrototypeTrimRight) { 5110 HandleScope scope(isolate); 5111 TO_THIS_STRING(string, "String.prototype.trimRight"); 5112 return *String::Trim(string, String::kTrimRight); 5113 } 5114 5115 // ----------------------------------------------------------------------------- 5116 // ES6 section 21.1 ArrayBuffer Objects 5117 5118 // ES6 section 24.1.2.1 ArrayBuffer ( length ) for the [[Call]] case. 5119 BUILTIN(ArrayBufferConstructor) { 5120 HandleScope scope(isolate); 5121 Handle<JSFunction> target = args.target<JSFunction>(); 5122 DCHECK(*target == target->native_context()->array_buffer_fun() || 5123 *target == target->native_context()->shared_array_buffer_fun()); 5124 THROW_NEW_ERROR_RETURN_FAILURE( 5125 isolate, NewTypeError(MessageTemplate::kConstructorNotFunction, 5126 handle(target->shared()->name(), isolate))); 5127 } 5128 5129 5130 // ES6 section 24.1.2.1 ArrayBuffer ( length ) for the [[Construct]] case. 5131 BUILTIN(ArrayBufferConstructor_ConstructStub) { 5132 HandleScope scope(isolate); 5133 Handle<JSFunction> target = args.target<JSFunction>(); 5134 Handle<JSReceiver> new_target = Handle<JSReceiver>::cast(args.new_target()); 5135 Handle<Object> length = args.atOrUndefined(isolate, 1); 5136 DCHECK(*target == target->native_context()->array_buffer_fun() || 5137 *target == target->native_context()->shared_array_buffer_fun()); 5138 Handle<Object> number_length; 5139 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, number_length, 5140 Object::ToInteger(isolate, length)); 5141 if (number_length->Number() < 0.0) { 5142 THROW_NEW_ERROR_RETURN_FAILURE( 5143 isolate, NewRangeError(MessageTemplate::kInvalidArrayBufferLength)); 5144 } 5145 Handle<JSObject> result; 5146 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, 5147 JSObject::New(target, new_target)); 5148 size_t byte_length; 5149 if (!TryNumberToSize(isolate, *number_length, &byte_length)) { 5150 THROW_NEW_ERROR_RETURN_FAILURE( 5151 isolate, NewRangeError(MessageTemplate::kInvalidArrayBufferLength)); 5152 } 5153 SharedFlag shared_flag = 5154 (*target == target->native_context()->array_buffer_fun()) 5155 ? SharedFlag::kNotShared 5156 : SharedFlag::kShared; 5157 if (!JSArrayBuffer::SetupAllocatingData(Handle<JSArrayBuffer>::cast(result), 5158 isolate, byte_length, true, 5159 shared_flag)) { 5160 THROW_NEW_ERROR_RETURN_FAILURE( 5161 isolate, NewRangeError(MessageTemplate::kArrayBufferAllocationFailed)); 5162 } 5163 return *result; 5164 } 5165 5166 5167 // ES6 section 24.1.3.1 ArrayBuffer.isView ( arg ) 5168 BUILTIN(ArrayBufferIsView) { 5169 SealHandleScope shs(isolate); 5170 DCHECK_EQ(2, args.length()); 5171 Object* arg = args[1]; 5172 return isolate->heap()->ToBoolean(arg->IsJSArrayBufferView()); 5173 } 5174 5175 5176 // ES6 section 26.2.1.1 Proxy ( target, handler ) for the [[Call]] case. 5177 BUILTIN(ProxyConstructor) { 5178 HandleScope scope(isolate); 5179 THROW_NEW_ERROR_RETURN_FAILURE( 5180 isolate, 5181 NewTypeError(MessageTemplate::kConstructorNotFunction, 5182 isolate->factory()->NewStringFromAsciiChecked("Proxy"))); 5183 } 5184 5185 5186 // ES6 section 26.2.1.1 Proxy ( target, handler ) for the [[Construct]] case. 5187 BUILTIN(ProxyConstructor_ConstructStub) { 5188 HandleScope scope(isolate); 5189 DCHECK(isolate->proxy_function()->IsConstructor()); 5190 Handle<Object> target = args.atOrUndefined(isolate, 1); 5191 Handle<Object> handler = args.atOrUndefined(isolate, 2); 5192 RETURN_RESULT_OR_FAILURE(isolate, JSProxy::New(isolate, target, handler)); 5193 } 5194 5195 5196 // ----------------------------------------------------------------------------- 5197 // Throwers for restricted function properties and strict arguments object 5198 // properties 5199 5200 5201 BUILTIN(RestrictedFunctionPropertiesThrower) { 5202 HandleScope scope(isolate); 5203 THROW_NEW_ERROR_RETURN_FAILURE( 5204 isolate, NewTypeError(MessageTemplate::kRestrictedFunctionProperties)); 5205 } 5206 5207 5208 BUILTIN(RestrictedStrictArgumentsPropertiesThrower) { 5209 HandleScope scope(isolate); 5210 THROW_NEW_ERROR_RETURN_FAILURE( 5211 isolate, NewTypeError(MessageTemplate::kStrictPoisonPill)); 5212 } 5213 5214 5215 // ----------------------------------------------------------------------------- 5216 // 5217 5218 5219 namespace { 5220 5221 // Returns the holder JSObject if the function can legally be called with this 5222 // receiver. Returns nullptr if the call is illegal. 5223 // TODO(dcarney): CallOptimization duplicates this logic, merge. 5224 JSObject* GetCompatibleReceiver(Isolate* isolate, FunctionTemplateInfo* info, 5225 JSObject* receiver) { 5226 Object* recv_type = info->signature(); 5227 // No signature, return holder. 5228 if (!recv_type->IsFunctionTemplateInfo()) return receiver; 5229 FunctionTemplateInfo* signature = FunctionTemplateInfo::cast(recv_type); 5230 5231 // Check the receiver. Fast path for receivers with no hidden prototypes. 5232 if (signature->IsTemplateFor(receiver)) return receiver; 5233 if (!receiver->map()->has_hidden_prototype()) return nullptr; 5234 for (PrototypeIterator iter(isolate, receiver, kStartAtPrototype, 5235 PrototypeIterator::END_AT_NON_HIDDEN); 5236 !iter.IsAtEnd(); iter.Advance()) { 5237 JSObject* current = iter.GetCurrent<JSObject>(); 5238 if (signature->IsTemplateFor(current)) return current; 5239 } 5240 return nullptr; 5241 } 5242 5243 template <bool is_construct> 5244 MUST_USE_RESULT MaybeHandle<Object> HandleApiCallHelper( 5245 Isolate* isolate, Handle<HeapObject> function, 5246 Handle<HeapObject> new_target, Handle<FunctionTemplateInfo> fun_data, 5247 Handle<Object> receiver, BuiltinArguments args) { 5248 Handle<JSObject> js_receiver; 5249 JSObject* raw_holder; 5250 if (is_construct) { 5251 DCHECK(args.receiver()->IsTheHole(isolate)); 5252 if (fun_data->instance_template()->IsUndefined(isolate)) { 5253 v8::Local<ObjectTemplate> templ = 5254 ObjectTemplate::New(reinterpret_cast<v8::Isolate*>(isolate), 5255 ToApiHandle<v8::FunctionTemplate>(fun_data)); 5256 fun_data->set_instance_template(*Utils::OpenHandle(*templ)); 5257 } 5258 Handle<ObjectTemplateInfo> instance_template( 5259 ObjectTemplateInfo::cast(fun_data->instance_template()), isolate); 5260 ASSIGN_RETURN_ON_EXCEPTION( 5261 isolate, js_receiver, 5262 ApiNatives::InstantiateObject(instance_template, 5263 Handle<JSReceiver>::cast(new_target)), 5264 Object); 5265 args[0] = *js_receiver; 5266 DCHECK_EQ(*js_receiver, *args.receiver()); 5267 5268 raw_holder = *js_receiver; 5269 } else { 5270 DCHECK(receiver->IsJSReceiver()); 5271 5272 if (!receiver->IsJSObject()) { 5273 // This function cannot be called with the given receiver. Abort! 5274 THROW_NEW_ERROR( 5275 isolate, NewTypeError(MessageTemplate::kIllegalInvocation), Object); 5276 } 5277 5278 js_receiver = Handle<JSObject>::cast(receiver); 5279 5280 if (!fun_data->accept_any_receiver() && 5281 js_receiver->IsAccessCheckNeeded() && 5282 !isolate->MayAccess(handle(isolate->context()), js_receiver)) { 5283 isolate->ReportFailedAccessCheck(js_receiver); 5284 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); 5285 } 5286 5287 raw_holder = GetCompatibleReceiver(isolate, *fun_data, *js_receiver); 5288 5289 if (raw_holder == nullptr) { 5290 // This function cannot be called with the given receiver. Abort! 5291 THROW_NEW_ERROR( 5292 isolate, NewTypeError(MessageTemplate::kIllegalInvocation), Object); 5293 } 5294 } 5295 5296 Object* raw_call_data = fun_data->call_code(); 5297 if (!raw_call_data->IsUndefined(isolate)) { 5298 DCHECK(raw_call_data->IsCallHandlerInfo()); 5299 CallHandlerInfo* call_data = CallHandlerInfo::cast(raw_call_data); 5300 Object* callback_obj = call_data->callback(); 5301 v8::FunctionCallback callback = 5302 v8::ToCData<v8::FunctionCallback>(callback_obj); 5303 Object* data_obj = call_data->data(); 5304 5305 LOG(isolate, ApiObjectAccess("call", JSObject::cast(*js_receiver))); 5306 5307 FunctionCallbackArguments custom(isolate, data_obj, *function, raw_holder, 5308 *new_target, &args[0] - 1, 5309 args.length() - 1); 5310 5311 Handle<Object> result = custom.Call(callback); 5312 5313 RETURN_EXCEPTION_IF_SCHEDULED_EXCEPTION(isolate, Object); 5314 if (result.is_null()) { 5315 if (is_construct) return js_receiver; 5316 return isolate->factory()->undefined_value(); 5317 } 5318 // Rebox the result. 5319 result->VerifyApiCallResultType(); 5320 if (!is_construct || result->IsJSObject()) return handle(*result, isolate); 5321 } 5322 5323 return js_receiver; 5324 } 5325 5326 } // namespace 5327 5328 5329 BUILTIN(HandleApiCall) { 5330 HandleScope scope(isolate); 5331 Handle<JSFunction> function = args.target<JSFunction>(); 5332 Handle<Object> receiver = args.receiver(); 5333 Handle<HeapObject> new_target = args.new_target(); 5334 Handle<FunctionTemplateInfo> fun_data(function->shared()->get_api_func_data(), 5335 isolate); 5336 if (new_target->IsJSReceiver()) { 5337 RETURN_RESULT_OR_FAILURE( 5338 isolate, HandleApiCallHelper<true>(isolate, function, new_target, 5339 fun_data, receiver, args)); 5340 } else { 5341 RETURN_RESULT_OR_FAILURE( 5342 isolate, HandleApiCallHelper<false>(isolate, function, new_target, 5343 fun_data, receiver, args)); 5344 } 5345 } 5346 5347 5348 Handle<Code> Builtins::CallFunction(ConvertReceiverMode mode, 5349 TailCallMode tail_call_mode) { 5350 switch (tail_call_mode) { 5351 case TailCallMode::kDisallow: 5352 switch (mode) { 5353 case ConvertReceiverMode::kNullOrUndefined: 5354 return CallFunction_ReceiverIsNullOrUndefined(); 5355 case ConvertReceiverMode::kNotNullOrUndefined: 5356 return CallFunction_ReceiverIsNotNullOrUndefined(); 5357 case ConvertReceiverMode::kAny: 5358 return CallFunction_ReceiverIsAny(); 5359 } 5360 break; 5361 case TailCallMode::kAllow: 5362 switch (mode) { 5363 case ConvertReceiverMode::kNullOrUndefined: 5364 return TailCallFunction_ReceiverIsNullOrUndefined(); 5365 case ConvertReceiverMode::kNotNullOrUndefined: 5366 return TailCallFunction_ReceiverIsNotNullOrUndefined(); 5367 case ConvertReceiverMode::kAny: 5368 return TailCallFunction_ReceiverIsAny(); 5369 } 5370 break; 5371 } 5372 UNREACHABLE(); 5373 return Handle<Code>::null(); 5374 } 5375 5376 Handle<Code> Builtins::Call(ConvertReceiverMode mode, 5377 TailCallMode tail_call_mode) { 5378 switch (tail_call_mode) { 5379 case TailCallMode::kDisallow: 5380 switch (mode) { 5381 case ConvertReceiverMode::kNullOrUndefined: 5382 return Call_ReceiverIsNullOrUndefined(); 5383 case ConvertReceiverMode::kNotNullOrUndefined: 5384 return Call_ReceiverIsNotNullOrUndefined(); 5385 case ConvertReceiverMode::kAny: 5386 return Call_ReceiverIsAny(); 5387 } 5388 break; 5389 case TailCallMode::kAllow: 5390 switch (mode) { 5391 case ConvertReceiverMode::kNullOrUndefined: 5392 return TailCall_ReceiverIsNullOrUndefined(); 5393 case ConvertReceiverMode::kNotNullOrUndefined: 5394 return TailCall_ReceiverIsNotNullOrUndefined(); 5395 case ConvertReceiverMode::kAny: 5396 return TailCall_ReceiverIsAny(); 5397 } 5398 break; 5399 } 5400 UNREACHABLE(); 5401 return Handle<Code>::null(); 5402 } 5403 5404 Handle<Code> Builtins::CallBoundFunction(TailCallMode tail_call_mode) { 5405 switch (tail_call_mode) { 5406 case TailCallMode::kDisallow: 5407 return CallBoundFunction(); 5408 case TailCallMode::kAllow: 5409 return TailCallBoundFunction(); 5410 } 5411 UNREACHABLE(); 5412 return Handle<Code>::null(); 5413 } 5414 5415 Handle<Code> Builtins::InterpreterPushArgsAndCall(TailCallMode tail_call_mode) { 5416 switch (tail_call_mode) { 5417 case TailCallMode::kDisallow: 5418 return InterpreterPushArgsAndCall(); 5419 case TailCallMode::kAllow: 5420 return InterpreterPushArgsAndTailCall(); 5421 } 5422 UNREACHABLE(); 5423 return Handle<Code>::null(); 5424 } 5425 5426 namespace { 5427 5428 class RelocatableArguments : public BuiltinArguments, public Relocatable { 5429 public: 5430 RelocatableArguments(Isolate* isolate, int length, Object** arguments) 5431 : BuiltinArguments(length, arguments), Relocatable(isolate) {} 5432 5433 virtual inline void IterateInstance(ObjectVisitor* v) { 5434 if (length() == 0) return; 5435 v->VisitPointers(lowest_address(), highest_address() + 1); 5436 } 5437 5438 private: 5439 DISALLOW_COPY_AND_ASSIGN(RelocatableArguments); 5440 }; 5441 5442 } // namespace 5443 5444 MaybeHandle<Object> Builtins::InvokeApiFunction(Isolate* isolate, 5445 Handle<HeapObject> function, 5446 Handle<Object> receiver, 5447 int argc, 5448 Handle<Object> args[]) { 5449 DCHECK(function->IsFunctionTemplateInfo() || 5450 (function->IsJSFunction() && 5451 JSFunction::cast(*function)->shared()->IsApiFunction())); 5452 5453 // Do proper receiver conversion for non-strict mode api functions. 5454 if (!receiver->IsJSReceiver()) { 5455 if (function->IsFunctionTemplateInfo() || 5456 is_sloppy(JSFunction::cast(*function)->shared()->language_mode())) { 5457 ASSIGN_RETURN_ON_EXCEPTION(isolate, receiver, 5458 Object::ConvertReceiver(isolate, receiver), 5459 Object); 5460 } 5461 } 5462 5463 Handle<FunctionTemplateInfo> fun_data = 5464 function->IsFunctionTemplateInfo() 5465 ? Handle<FunctionTemplateInfo>::cast(function) 5466 : handle(JSFunction::cast(*function)->shared()->get_api_func_data(), 5467 isolate); 5468 Handle<HeapObject> new_target = isolate->factory()->undefined_value(); 5469 // Construct BuiltinArguments object: 5470 // new target, function, arguments reversed, receiver. 5471 const int kBufferSize = 32; 5472 Object* small_argv[kBufferSize]; 5473 Object** argv; 5474 if (argc + 3 <= kBufferSize) { 5475 argv = small_argv; 5476 } else { 5477 argv = new Object*[argc + 3]; 5478 } 5479 argv[argc + 2] = *receiver; 5480 for (int i = 0; i < argc; ++i) { 5481 argv[argc - i + 1] = *args[i]; 5482 } 5483 argv[1] = *function; 5484 argv[0] = *new_target; 5485 MaybeHandle<Object> result; 5486 { 5487 RelocatableArguments arguments(isolate, argc + 3, &argv[argc] + 2); 5488 result = HandleApiCallHelper<false>(isolate, function, new_target, fun_data, 5489 receiver, arguments); 5490 } 5491 if (argv != small_argv) delete[] argv; 5492 return result; 5493 } 5494 5495 5496 // Helper function to handle calls to non-function objects created through the 5497 // API. The object can be called as either a constructor (using new) or just as 5498 // a function (without new). 5499 MUST_USE_RESULT static Object* HandleApiCallAsFunctionOrConstructor( 5500 Isolate* isolate, bool is_construct_call, BuiltinArguments args) { 5501 Handle<Object> receiver = args.receiver(); 5502 5503 // Get the object called. 5504 JSObject* obj = JSObject::cast(*receiver); 5505 5506 // Set the new target. 5507 HeapObject* new_target; 5508 if (is_construct_call) { 5509 // TODO(adamk): This should be passed through in args instead of 5510 // being patched in here. We need to set a non-undefined value 5511 // for v8::FunctionCallbackInfo::IsConstructCall() to get the 5512 // right answer. 5513 new_target = obj; 5514 } else { 5515 new_target = isolate->heap()->undefined_value(); 5516 } 5517 5518 // Get the invocation callback from the function descriptor that was 5519 // used to create the called object. 5520 DCHECK(obj->map()->is_callable()); 5521 JSFunction* constructor = JSFunction::cast(obj->map()->GetConstructor()); 5522 // TODO(ishell): turn this back to a DCHECK. 5523 CHECK(constructor->shared()->IsApiFunction()); 5524 Object* handler = 5525 constructor->shared()->get_api_func_data()->instance_call_handler(); 5526 DCHECK(!handler->IsUndefined(isolate)); 5527 // TODO(ishell): remove this debugging code. 5528 CHECK(handler->IsCallHandlerInfo()); 5529 CallHandlerInfo* call_data = CallHandlerInfo::cast(handler); 5530 Object* callback_obj = call_data->callback(); 5531 v8::FunctionCallback callback = 5532 v8::ToCData<v8::FunctionCallback>(callback_obj); 5533 5534 // Get the data for the call and perform the callback. 5535 Object* result; 5536 { 5537 HandleScope scope(isolate); 5538 LOG(isolate, ApiObjectAccess("call non-function", obj)); 5539 5540 FunctionCallbackArguments custom(isolate, call_data->data(), constructor, 5541 obj, new_target, &args[0] - 1, 5542 args.length() - 1); 5543 Handle<Object> result_handle = custom.Call(callback); 5544 if (result_handle.is_null()) { 5545 result = isolate->heap()->undefined_value(); 5546 } else { 5547 result = *result_handle; 5548 } 5549 } 5550 // Check for exceptions and return result. 5551 RETURN_FAILURE_IF_SCHEDULED_EXCEPTION(isolate); 5552 return result; 5553 } 5554 5555 5556 // Handle calls to non-function objects created through the API. This delegate 5557 // function is used when the call is a normal function call. 5558 BUILTIN(HandleApiCallAsFunction) { 5559 return HandleApiCallAsFunctionOrConstructor(isolate, false, args); 5560 } 5561 5562 5563 // Handle calls to non-function objects created through the API. This delegate 5564 // function is used when the call is a construct call. 5565 BUILTIN(HandleApiCallAsConstructor) { 5566 return HandleApiCallAsFunctionOrConstructor(isolate, true, args); 5567 } 5568 5569 namespace { 5570 5571 void Generate_LoadIC_Miss(CodeStubAssembler* assembler) { 5572 typedef compiler::Node Node; 5573 5574 Node* receiver = assembler->Parameter(0); 5575 Node* name = assembler->Parameter(1); 5576 Node* slot = assembler->Parameter(2); 5577 Node* vector = assembler->Parameter(3); 5578 Node* context = assembler->Parameter(4); 5579 5580 assembler->TailCallRuntime(Runtime::kLoadIC_Miss, context, receiver, name, 5581 slot, vector); 5582 } 5583 5584 void Generate_LoadGlobalIC_Miss(CodeStubAssembler* assembler) { 5585 typedef compiler::Node Node; 5586 5587 Node* slot = assembler->Parameter(0); 5588 Node* vector = assembler->Parameter(1); 5589 Node* context = assembler->Parameter(2); 5590 5591 assembler->TailCallRuntime(Runtime::kLoadGlobalIC_Miss, context, slot, 5592 vector); 5593 } 5594 5595 void Generate_LoadIC_Normal(MacroAssembler* masm) { 5596 LoadIC::GenerateNormal(masm); 5597 } 5598 5599 void Generate_LoadIC_Getter_ForDeopt(MacroAssembler* masm) { 5600 NamedLoadHandlerCompiler::GenerateLoadViaGetterForDeopt(masm); 5601 } 5602 5603 void Generate_LoadIC_Slow(CodeStubAssembler* assembler) { 5604 typedef compiler::Node Node; 5605 5606 Node* receiver = assembler->Parameter(0); 5607 Node* name = assembler->Parameter(1); 5608 // Node* slot = assembler->Parameter(2); 5609 // Node* vector = assembler->Parameter(3); 5610 Node* context = assembler->Parameter(4); 5611 5612 assembler->TailCallRuntime(Runtime::kGetProperty, context, receiver, name); 5613 } 5614 5615 void Generate_LoadGlobalIC_Slow(CodeStubAssembler* assembler) { 5616 typedef compiler::Node Node; 5617 5618 Node* slot = assembler->Parameter(0); 5619 Node* vector = assembler->Parameter(1); 5620 Node* context = assembler->Parameter(2); 5621 5622 assembler->TailCallRuntime(Runtime::kLoadGlobalIC_Slow, context, slot, 5623 vector); 5624 } 5625 5626 void Generate_KeyedLoadIC_Slow(MacroAssembler* masm) { 5627 KeyedLoadIC::GenerateRuntimeGetProperty(masm); 5628 } 5629 5630 void Generate_KeyedLoadIC_Miss(MacroAssembler* masm) { 5631 KeyedLoadIC::GenerateMiss(masm); 5632 } 5633 5634 void Generate_KeyedLoadIC_Megamorphic(MacroAssembler* masm) { 5635 KeyedLoadIC::GenerateMegamorphic(masm); 5636 } 5637 5638 void Generate_StoreIC_Miss(MacroAssembler* masm) { 5639 StoreIC::GenerateMiss(masm); 5640 } 5641 5642 void Generate_StoreIC_Normal(MacroAssembler* masm) { 5643 StoreIC::GenerateNormal(masm); 5644 } 5645 5646 void Generate_StoreIC_Slow(MacroAssembler* masm) { 5647 NamedStoreHandlerCompiler::GenerateSlow(masm); 5648 } 5649 5650 void Generate_KeyedStoreIC_Slow(MacroAssembler* masm) { 5651 ElementHandlerCompiler::GenerateStoreSlow(masm); 5652 } 5653 5654 void Generate_StoreIC_Setter_ForDeopt(MacroAssembler* masm) { 5655 NamedStoreHandlerCompiler::GenerateStoreViaSetterForDeopt(masm); 5656 } 5657 5658 void Generate_KeyedStoreIC_Megamorphic(MacroAssembler* masm) { 5659 KeyedStoreIC::GenerateMegamorphic(masm, SLOPPY); 5660 } 5661 5662 void Generate_KeyedStoreIC_Megamorphic_Strict(MacroAssembler* masm) { 5663 KeyedStoreIC::GenerateMegamorphic(masm, STRICT); 5664 } 5665 5666 void Generate_KeyedStoreIC_Miss(MacroAssembler* masm) { 5667 KeyedStoreIC::GenerateMiss(masm); 5668 } 5669 5670 void Generate_Return_DebugBreak(MacroAssembler* masm) { 5671 DebugCodegen::GenerateDebugBreakStub(masm, 5672 DebugCodegen::SAVE_RESULT_REGISTER); 5673 } 5674 5675 void Generate_Slot_DebugBreak(MacroAssembler* masm) { 5676 DebugCodegen::GenerateDebugBreakStub(masm, 5677 DebugCodegen::IGNORE_RESULT_REGISTER); 5678 } 5679 5680 void Generate_FrameDropper_LiveEdit(MacroAssembler* masm) { 5681 DebugCodegen::GenerateFrameDropperLiveEdit(masm); 5682 } 5683 5684 } // namespace 5685 5686 Builtins::Builtins() : initialized_(false) { 5687 memset(builtins_, 0, sizeof(builtins_[0]) * builtin_count); 5688 memset(names_, 0, sizeof(names_[0]) * builtin_count); 5689 } 5690 5691 5692 Builtins::~Builtins() { 5693 } 5694 5695 #define DEF_ENUM_C(name) FUNCTION_ADDR(Builtin_##name), 5696 Address const Builtins::c_functions_[cfunction_count] = { 5697 BUILTIN_LIST_C(DEF_ENUM_C) 5698 }; 5699 #undef DEF_ENUM_C 5700 5701 5702 struct BuiltinDesc { 5703 Handle<Code> (*builder)(Isolate*, struct BuiltinDesc const*); 5704 byte* generator; 5705 byte* c_code; 5706 const char* s_name; // name is only used for generating log information. 5707 int name; 5708 Code::Flags flags; 5709 int argc; 5710 }; 5711 5712 #define BUILTIN_FUNCTION_TABLE_INIT { V8_ONCE_INIT, {} } 5713 5714 class BuiltinFunctionTable { 5715 public: 5716 BuiltinDesc* functions() { 5717 base::CallOnce(&once_, &Builtins::InitBuiltinFunctionTable); 5718 return functions_; 5719 } 5720 5721 base::OnceType once_; 5722 BuiltinDesc functions_[Builtins::builtin_count + 1]; 5723 5724 friend class Builtins; 5725 }; 5726 5727 namespace { 5728 5729 BuiltinFunctionTable builtin_function_table = BUILTIN_FUNCTION_TABLE_INIT; 5730 5731 Handle<Code> MacroAssemblerBuilder(Isolate* isolate, 5732 BuiltinDesc const* builtin_desc) { 5733 // For now we generate builtin adaptor code into a stack-allocated 5734 // buffer, before copying it into individual code objects. Be careful 5735 // with alignment, some platforms don't like unaligned code. 5736 #ifdef DEBUG 5737 // We can generate a lot of debug code on Arm64. 5738 const size_t buffer_size = 32 * KB; 5739 #elif V8_TARGET_ARCH_PPC64 5740 // 8 KB is insufficient on PPC64 when FLAG_debug_code is on. 5741 const size_t buffer_size = 10 * KB; 5742 #else 5743 const size_t buffer_size = 8 * KB; 5744 #endif 5745 union { 5746 int force_alignment; 5747 byte buffer[buffer_size]; // NOLINT(runtime/arrays) 5748 } u; 5749 5750 MacroAssembler masm(isolate, u.buffer, sizeof(u.buffer), 5751 CodeObjectRequired::kYes); 5752 // Generate the code/adaptor. 5753 typedef void (*Generator)(MacroAssembler*, int); 5754 Generator g = FUNCTION_CAST<Generator>(builtin_desc->generator); 5755 // We pass all arguments to the generator, but it may not use all of 5756 // them. This works because the first arguments are on top of the 5757 // stack. 5758 DCHECK(!masm.has_frame()); 5759 g(&masm, builtin_desc->name); 5760 // Move the code into the object heap. 5761 CodeDesc desc; 5762 masm.GetCode(&desc); 5763 Code::Flags flags = builtin_desc->flags; 5764 return isolate->factory()->NewCode(desc, flags, masm.CodeObject()); 5765 } 5766 5767 // Builder for builtins implemented in TurboFan with JS linkage. 5768 Handle<Code> CodeStubAssemblerBuilderJS(Isolate* isolate, 5769 BuiltinDesc const* builtin_desc) { 5770 Zone zone(isolate->allocator()); 5771 CodeStubAssembler assembler(isolate, &zone, builtin_desc->argc, 5772 builtin_desc->flags, builtin_desc->s_name); 5773 // Generate the code/adaptor. 5774 typedef void (*Generator)(CodeStubAssembler*); 5775 Generator g = FUNCTION_CAST<Generator>(builtin_desc->generator); 5776 g(&assembler); 5777 return assembler.GenerateCode(); 5778 } 5779 5780 // Builder for builtins implemented in TurboFan with CallStub linkage. 5781 Handle<Code> CodeStubAssemblerBuilderCS(Isolate* isolate, 5782 BuiltinDesc const* builtin_desc) { 5783 Zone zone(isolate->allocator()); 5784 // The interface descriptor with given key must be initialized at this point 5785 // and this construction just queries the details from the descriptors table. 5786 CallInterfaceDescriptor descriptor( 5787 isolate, static_cast<CallDescriptors::Key>(builtin_desc->argc)); 5788 // Ensure descriptor is already initialized. 5789 DCHECK_NOT_NULL(descriptor.GetFunctionType()); 5790 CodeStubAssembler assembler(isolate, &zone, descriptor, builtin_desc->flags, 5791 builtin_desc->s_name); 5792 // Generate the code/adaptor. 5793 typedef void (*Generator)(CodeStubAssembler*); 5794 Generator g = FUNCTION_CAST<Generator>(builtin_desc->generator); 5795 g(&assembler); 5796 return assembler.GenerateCode(); 5797 } 5798 5799 } // namespace 5800 5801 // Define array of pointers to generators and C builtin functions. 5802 // We do this in a sort of roundabout way so that we can do the initialization 5803 // within the lexical scope of Builtins:: and within a context where 5804 // Code::Flags names a non-abstract type. 5805 void Builtins::InitBuiltinFunctionTable() { 5806 BuiltinDesc* functions = builtin_function_table.functions_; 5807 functions[builtin_count].builder = nullptr; 5808 functions[builtin_count].generator = nullptr; 5809 functions[builtin_count].c_code = nullptr; 5810 functions[builtin_count].s_name = nullptr; 5811 functions[builtin_count].name = builtin_count; 5812 functions[builtin_count].flags = static_cast<Code::Flags>(0); 5813 functions[builtin_count].argc = 0; 5814 5815 #define DEF_FUNCTION_PTR_C(aname) \ 5816 functions->builder = &MacroAssemblerBuilder; \ 5817 functions->generator = FUNCTION_ADDR(Generate_Adaptor); \ 5818 functions->c_code = FUNCTION_ADDR(Builtin_##aname); \ 5819 functions->s_name = #aname; \ 5820 functions->name = c_##aname; \ 5821 functions->flags = Code::ComputeFlags(Code::BUILTIN); \ 5822 functions->argc = 0; \ 5823 ++functions; 5824 5825 #define DEF_FUNCTION_PTR_A(aname, kind, extra) \ 5826 functions->builder = &MacroAssemblerBuilder; \ 5827 functions->generator = FUNCTION_ADDR(Generate_##aname); \ 5828 functions->c_code = NULL; \ 5829 functions->s_name = #aname; \ 5830 functions->name = k##aname; \ 5831 functions->flags = Code::ComputeFlags(Code::kind, extra); \ 5832 functions->argc = 0; \ 5833 ++functions; 5834 5835 #define DEF_FUNCTION_PTR_T(aname, aargc) \ 5836 functions->builder = &CodeStubAssemblerBuilderJS; \ 5837 functions->generator = FUNCTION_ADDR(Generate_##aname); \ 5838 functions->c_code = NULL; \ 5839 functions->s_name = #aname; \ 5840 functions->name = k##aname; \ 5841 functions->flags = Code::ComputeFlags(Code::BUILTIN); \ 5842 functions->argc = aargc; \ 5843 ++functions; 5844 5845 #define DEF_FUNCTION_PTR_S(aname, kind, extra, interface_descriptor) \ 5846 functions->builder = &CodeStubAssemblerBuilderCS; \ 5847 functions->generator = FUNCTION_ADDR(Generate_##aname); \ 5848 functions->c_code = NULL; \ 5849 functions->s_name = #aname; \ 5850 functions->name = k##aname; \ 5851 functions->flags = Code::ComputeFlags(Code::kind, extra); \ 5852 functions->argc = CallDescriptors::interface_descriptor; \ 5853 ++functions; 5854 5855 #define DEF_FUNCTION_PTR_H(aname, kind) \ 5856 functions->builder = &MacroAssemblerBuilder; \ 5857 functions->generator = FUNCTION_ADDR(Generate_##aname); \ 5858 functions->c_code = NULL; \ 5859 functions->s_name = #aname; \ 5860 functions->name = k##aname; \ 5861 functions->flags = Code::ComputeHandlerFlags(Code::kind); \ 5862 functions->argc = 0; \ 5863 ++functions; 5864 5865 BUILTIN_LIST_C(DEF_FUNCTION_PTR_C) 5866 BUILTIN_LIST_A(DEF_FUNCTION_PTR_A) 5867 BUILTIN_LIST_T(DEF_FUNCTION_PTR_T) 5868 BUILTIN_LIST_S(DEF_FUNCTION_PTR_S) 5869 BUILTIN_LIST_H(DEF_FUNCTION_PTR_H) 5870 BUILTIN_LIST_DEBUG_A(DEF_FUNCTION_PTR_A) 5871 5872 #undef DEF_FUNCTION_PTR_C 5873 #undef DEF_FUNCTION_PTR_A 5874 #undef DEF_FUNCTION_PTR_T 5875 #undef DEF_FUNCTION_PTR_S 5876 #undef DEF_FUNCTION_PTR_H 5877 } 5878 5879 5880 void Builtins::SetUp(Isolate* isolate, bool create_heap_objects) { 5881 DCHECK(!initialized_); 5882 5883 // Create a scope for the handles in the builtins. 5884 HandleScope scope(isolate); 5885 5886 #define INITIALIZE_CALL_DESCRIPTOR(name, kind, extra, interface_descriptor) \ 5887 { interface_descriptor##Descriptor descriptor(isolate); } 5888 BUILTIN_LIST_S(INITIALIZE_CALL_DESCRIPTOR) 5889 #undef INITIALIZE_CALL_DESCRIPTOR 5890 5891 const BuiltinDesc* functions = builtin_function_table.functions(); 5892 5893 // Traverse the list of builtins and generate an adaptor in a 5894 // separate code object for each one. 5895 for (int i = 0; i < builtin_count; i++) { 5896 if (create_heap_objects) { 5897 Handle<Code> code = (*functions[i].builder)(isolate, functions + i); 5898 // Log the event and add the code to the builtins array. 5899 PROFILE(isolate, 5900 CodeCreateEvent(CodeEventListener::BUILTIN_TAG, 5901 AbstractCode::cast(*code), functions[i].s_name)); 5902 builtins_[i] = *code; 5903 code->set_builtin_index(i); 5904 #ifdef ENABLE_DISASSEMBLER 5905 if (FLAG_print_builtin_code) { 5906 CodeTracer::Scope trace_scope(isolate->GetCodeTracer()); 5907 OFStream os(trace_scope.file()); 5908 os << "Builtin: " << functions[i].s_name << "\n"; 5909 code->Disassemble(functions[i].s_name, os); 5910 os << "\n"; 5911 } 5912 #endif 5913 } else { 5914 // Deserializing. The values will be filled in during IterateBuiltins. 5915 builtins_[i] = NULL; 5916 } 5917 names_[i] = functions[i].s_name; 5918 } 5919 5920 // Mark as initialized. 5921 initialized_ = true; 5922 } 5923 5924 5925 void Builtins::TearDown() { 5926 initialized_ = false; 5927 } 5928 5929 5930 void Builtins::IterateBuiltins(ObjectVisitor* v) { 5931 v->VisitPointers(&builtins_[0], &builtins_[0] + builtin_count); 5932 } 5933 5934 5935 const char* Builtins::Lookup(byte* pc) { 5936 // may be called during initialization (disassembler!) 5937 if (initialized_) { 5938 for (int i = 0; i < builtin_count; i++) { 5939 Code* entry = Code::cast(builtins_[i]); 5940 if (entry->contains(pc)) { 5941 return names_[i]; 5942 } 5943 } 5944 } 5945 return NULL; 5946 } 5947 5948 5949 void Builtins::Generate_InterruptCheck(MacroAssembler* masm) { 5950 masm->TailCallRuntime(Runtime::kInterrupt); 5951 } 5952 5953 5954 void Builtins::Generate_StackCheck(MacroAssembler* masm) { 5955 masm->TailCallRuntime(Runtime::kStackGuard); 5956 } 5957 5958 namespace { 5959 5960 void ValidateSharedTypedArray(CodeStubAssembler* a, compiler::Node* tagged, 5961 compiler::Node* context, 5962 compiler::Node** out_instance_type, 5963 compiler::Node** out_backing_store) { 5964 using namespace compiler; 5965 CodeStubAssembler::Label is_smi(a), not_smi(a), is_typed_array(a), 5966 not_typed_array(a), is_shared(a), not_shared(a), is_float_or_clamped(a), 5967 not_float_or_clamped(a), invalid(a); 5968 5969 // Fail if it is not a heap object. 5970 a->Branch(a->WordIsSmi(tagged), &is_smi, ¬_smi); 5971 a->Bind(&is_smi); 5972 a->Goto(&invalid); 5973 5974 // Fail if the array's instance type is not JSTypedArray. 5975 a->Bind(¬_smi); 5976 a->Branch(a->WordEqual(a->LoadInstanceType(tagged), 5977 a->Int32Constant(JS_TYPED_ARRAY_TYPE)), 5978 &is_typed_array, ¬_typed_array); 5979 a->Bind(¬_typed_array); 5980 a->Goto(&invalid); 5981 5982 // Fail if the array's JSArrayBuffer is not shared. 5983 a->Bind(&is_typed_array); 5984 Node* array_buffer = a->LoadObjectField(tagged, JSTypedArray::kBufferOffset); 5985 Node* is_buffer_shared = a->BitFieldDecode<JSArrayBuffer::IsShared>( 5986 a->LoadObjectField(array_buffer, JSArrayBuffer::kBitFieldSlot)); 5987 a->Branch(is_buffer_shared, &is_shared, ¬_shared); 5988 a->Bind(¬_shared); 5989 a->Goto(&invalid); 5990 5991 // Fail if the array's element type is float32, float64 or clamped. 5992 a->Bind(&is_shared); 5993 Node* elements_instance_type = a->LoadInstanceType( 5994 a->LoadObjectField(tagged, JSObject::kElementsOffset)); 5995 STATIC_ASSERT(FIXED_INT8_ARRAY_TYPE < FIXED_FLOAT32_ARRAY_TYPE); 5996 STATIC_ASSERT(FIXED_INT16_ARRAY_TYPE < FIXED_FLOAT32_ARRAY_TYPE); 5997 STATIC_ASSERT(FIXED_INT32_ARRAY_TYPE < FIXED_FLOAT32_ARRAY_TYPE); 5998 STATIC_ASSERT(FIXED_UINT8_ARRAY_TYPE < FIXED_FLOAT32_ARRAY_TYPE); 5999 STATIC_ASSERT(FIXED_UINT16_ARRAY_TYPE < FIXED_FLOAT32_ARRAY_TYPE); 6000 STATIC_ASSERT(FIXED_UINT32_ARRAY_TYPE < FIXED_FLOAT32_ARRAY_TYPE); 6001 a->Branch(a->Int32LessThan(elements_instance_type, 6002 a->Int32Constant(FIXED_FLOAT32_ARRAY_TYPE)), 6003 ¬_float_or_clamped, &is_float_or_clamped); 6004 a->Bind(&is_float_or_clamped); 6005 a->Goto(&invalid); 6006 6007 a->Bind(&invalid); 6008 a->CallRuntime(Runtime::kThrowNotIntegerSharedTypedArrayError, context, 6009 tagged); 6010 a->Return(a->UndefinedConstant()); 6011 6012 a->Bind(¬_float_or_clamped); 6013 *out_instance_type = elements_instance_type; 6014 6015 Node* backing_store = 6016 a->LoadObjectField(array_buffer, JSArrayBuffer::kBackingStoreOffset); 6017 Node* byte_offset = a->ChangeUint32ToWord(a->TruncateTaggedToWord32( 6018 context, 6019 a->LoadObjectField(tagged, JSArrayBufferView::kByteOffsetOffset))); 6020 *out_backing_store = a->IntPtrAdd(backing_store, byte_offset); 6021 } 6022 6023 // https://tc39.github.io/ecmascript_sharedmem/shmem.html#Atomics.ValidateAtomicAccess 6024 compiler::Node* ConvertTaggedAtomicIndexToWord32(CodeStubAssembler* a, 6025 compiler::Node* tagged, 6026 compiler::Node* context) { 6027 using namespace compiler; 6028 CodeStubAssembler::Variable var_result(a, MachineRepresentation::kWord32); 6029 6030 Callable to_number = CodeFactory::ToNumber(a->isolate()); 6031 Node* number_index = a->CallStub(to_number, context, tagged); 6032 CodeStubAssembler::Label done(a, &var_result); 6033 6034 CodeStubAssembler::Label if_numberissmi(a), if_numberisnotsmi(a); 6035 a->Branch(a->WordIsSmi(number_index), &if_numberissmi, &if_numberisnotsmi); 6036 6037 a->Bind(&if_numberissmi); 6038 { 6039 var_result.Bind(a->SmiToWord32(number_index)); 6040 a->Goto(&done); 6041 } 6042 6043 a->Bind(&if_numberisnotsmi); 6044 { 6045 Node* number_index_value = a->LoadHeapNumberValue(number_index); 6046 Node* access_index = a->TruncateFloat64ToWord32(number_index_value); 6047 Node* test_index = a->ChangeInt32ToFloat64(access_index); 6048 6049 CodeStubAssembler::Label if_indexesareequal(a), if_indexesarenotequal(a); 6050 a->Branch(a->Float64Equal(number_index_value, test_index), 6051 &if_indexesareequal, &if_indexesarenotequal); 6052 6053 a->Bind(&if_indexesareequal); 6054 { 6055 var_result.Bind(access_index); 6056 a->Goto(&done); 6057 } 6058 6059 a->Bind(&if_indexesarenotequal); 6060 a->Return( 6061 a->CallRuntime(Runtime::kThrowInvalidAtomicAccessIndexError, context)); 6062 } 6063 6064 a->Bind(&done); 6065 return var_result.value(); 6066 } 6067 6068 void ValidateAtomicIndex(CodeStubAssembler* a, compiler::Node* index_word, 6069 compiler::Node* array_length_word, 6070 compiler::Node* context) { 6071 using namespace compiler; 6072 // Check if the index is in bounds. If not, throw RangeError. 6073 CodeStubAssembler::Label if_inbounds(a), if_notinbounds(a); 6074 a->Branch( 6075 a->WordOr(a->Int32LessThan(index_word, a->Int32Constant(0)), 6076 a->Int32GreaterThanOrEqual(index_word, array_length_word)), 6077 &if_notinbounds, &if_inbounds); 6078 a->Bind(&if_notinbounds); 6079 a->Return( 6080 a->CallRuntime(Runtime::kThrowInvalidAtomicAccessIndexError, context)); 6081 a->Bind(&if_inbounds); 6082 } 6083 6084 } // anonymous namespace 6085 6086 void Builtins::Generate_AtomicsLoad(CodeStubAssembler* a) { 6087 using namespace compiler; 6088 Node* array = a->Parameter(1); 6089 Node* index = a->Parameter(2); 6090 Node* context = a->Parameter(3 + 2); 6091 6092 Node* instance_type; 6093 Node* backing_store; 6094 ValidateSharedTypedArray(a, array, context, &instance_type, &backing_store); 6095 6096 Node* index_word32 = ConvertTaggedAtomicIndexToWord32(a, index, context); 6097 Node* array_length_word32 = a->TruncateTaggedToWord32( 6098 context, a->LoadObjectField(array, JSTypedArray::kLengthOffset)); 6099 ValidateAtomicIndex(a, index_word32, array_length_word32, context); 6100 Node* index_word = a->ChangeUint32ToWord(index_word32); 6101 6102 CodeStubAssembler::Label i8(a), u8(a), i16(a), u16(a), i32(a), u32(a), 6103 other(a); 6104 int32_t case_values[] = { 6105 FIXED_INT8_ARRAY_TYPE, FIXED_UINT8_ARRAY_TYPE, FIXED_INT16_ARRAY_TYPE, 6106 FIXED_UINT16_ARRAY_TYPE, FIXED_INT32_ARRAY_TYPE, FIXED_UINT32_ARRAY_TYPE, 6107 }; 6108 CodeStubAssembler::Label* case_labels[] = { 6109 &i8, &u8, &i16, &u16, &i32, &u32, 6110 }; 6111 a->Switch(instance_type, &other, case_values, case_labels, 6112 arraysize(case_labels)); 6113 6114 a->Bind(&i8); 6115 a->Return( 6116 a->SmiTag(a->AtomicLoad(MachineType::Int8(), backing_store, index_word))); 6117 6118 a->Bind(&u8); 6119 a->Return(a->SmiTag( 6120 a->AtomicLoad(MachineType::Uint8(), backing_store, index_word))); 6121 6122 a->Bind(&i16); 6123 a->Return(a->SmiTag(a->AtomicLoad(MachineType::Int16(), backing_store, 6124 a->WordShl(index_word, 1)))); 6125 6126 a->Bind(&u16); 6127 a->Return(a->SmiTag(a->AtomicLoad(MachineType::Uint16(), backing_store, 6128 a->WordShl(index_word, 1)))); 6129 6130 a->Bind(&i32); 6131 a->Return(a->ChangeInt32ToTagged(a->AtomicLoad( 6132 MachineType::Int32(), backing_store, a->WordShl(index_word, 2)))); 6133 6134 a->Bind(&u32); 6135 a->Return(a->ChangeUint32ToTagged(a->AtomicLoad( 6136 MachineType::Uint32(), backing_store, a->WordShl(index_word, 2)))); 6137 6138 // This shouldn't happen, we've already validated the type. 6139 a->Bind(&other); 6140 a->Return(a->Int32Constant(0)); 6141 } 6142 6143 void Builtins::Generate_AtomicsStore(CodeStubAssembler* a) { 6144 using namespace compiler; 6145 Node* array = a->Parameter(1); 6146 Node* index = a->Parameter(2); 6147 Node* value = a->Parameter(3); 6148 Node* context = a->Parameter(4 + 2); 6149 6150 Node* instance_type; 6151 Node* backing_store; 6152 ValidateSharedTypedArray(a, array, context, &instance_type, &backing_store); 6153 6154 Node* index_word32 = ConvertTaggedAtomicIndexToWord32(a, index, context); 6155 Node* array_length_word32 = a->TruncateTaggedToWord32( 6156 context, a->LoadObjectField(array, JSTypedArray::kLengthOffset)); 6157 ValidateAtomicIndex(a, index_word32, array_length_word32, context); 6158 Node* index_word = a->ChangeUint32ToWord(index_word32); 6159 6160 Callable to_integer = CodeFactory::ToInteger(a->isolate()); 6161 Node* value_integer = a->CallStub(to_integer, context, value); 6162 Node* value_word32 = a->TruncateTaggedToWord32(context, value_integer); 6163 6164 CodeStubAssembler::Label u8(a), u16(a), u32(a), other(a); 6165 int32_t case_values[] = { 6166 FIXED_INT8_ARRAY_TYPE, FIXED_UINT8_ARRAY_TYPE, FIXED_INT16_ARRAY_TYPE, 6167 FIXED_UINT16_ARRAY_TYPE, FIXED_INT32_ARRAY_TYPE, FIXED_UINT32_ARRAY_TYPE, 6168 }; 6169 CodeStubAssembler::Label* case_labels[] = { 6170 &u8, &u8, &u16, &u16, &u32, &u32, 6171 }; 6172 a->Switch(instance_type, &other, case_values, case_labels, 6173 arraysize(case_labels)); 6174 6175 a->Bind(&u8); 6176 a->AtomicStore(MachineRepresentation::kWord8, backing_store, index_word, 6177 value_word32); 6178 a->Return(value_integer); 6179 6180 a->Bind(&u16); 6181 a->SmiTag(a->AtomicStore(MachineRepresentation::kWord16, backing_store, 6182 a->WordShl(index_word, 1), value_word32)); 6183 a->Return(value_integer); 6184 6185 a->Bind(&u32); 6186 a->AtomicStore(MachineRepresentation::kWord32, backing_store, 6187 a->WordShl(index_word, 2), value_word32); 6188 a->Return(value_integer); 6189 6190 // This shouldn't happen, we've already validated the type. 6191 a->Bind(&other); 6192 a->Return(a->Int32Constant(0)); 6193 } 6194 6195 #define DEFINE_BUILTIN_ACCESSOR_C(name) \ 6196 Handle<Code> Builtins::name() { \ 6197 Code** code_address = reinterpret_cast<Code**>(builtin_address(k##name)); \ 6198 return Handle<Code>(code_address); \ 6199 } 6200 #define DEFINE_BUILTIN_ACCESSOR_A(name, kind, extra) \ 6201 Handle<Code> Builtins::name() { \ 6202 Code** code_address = reinterpret_cast<Code**>(builtin_address(k##name)); \ 6203 return Handle<Code>(code_address); \ 6204 } 6205 #define DEFINE_BUILTIN_ACCESSOR_T(name, argc) \ 6206 Handle<Code> Builtins::name() { \ 6207 Code** code_address = reinterpret_cast<Code**>(builtin_address(k##name)); \ 6208 return Handle<Code>(code_address); \ 6209 } 6210 #define DEFINE_BUILTIN_ACCESSOR_S(name, kind, extra, interface_descriptor) \ 6211 Handle<Code> Builtins::name() { \ 6212 Code** code_address = reinterpret_cast<Code**>(builtin_address(k##name)); \ 6213 return Handle<Code>(code_address); \ 6214 } 6215 #define DEFINE_BUILTIN_ACCESSOR_H(name, kind) \ 6216 Handle<Code> Builtins::name() { \ 6217 Code** code_address = \ 6218 reinterpret_cast<Code**>(builtin_address(k##name)); \ 6219 return Handle<Code>(code_address); \ 6220 } 6221 BUILTIN_LIST_C(DEFINE_BUILTIN_ACCESSOR_C) 6222 BUILTIN_LIST_A(DEFINE_BUILTIN_ACCESSOR_A) 6223 BUILTIN_LIST_T(DEFINE_BUILTIN_ACCESSOR_T) 6224 BUILTIN_LIST_S(DEFINE_BUILTIN_ACCESSOR_S) 6225 BUILTIN_LIST_H(DEFINE_BUILTIN_ACCESSOR_H) 6226 BUILTIN_LIST_DEBUG_A(DEFINE_BUILTIN_ACCESSOR_A) 6227 #undef DEFINE_BUILTIN_ACCESSOR_C 6228 #undef DEFINE_BUILTIN_ACCESSOR_A 6229 #undef DEFINE_BUILTIN_ACCESSOR_T 6230 #undef DEFINE_BUILTIN_ACCESSOR_S 6231 #undef DEFINE_BUILTIN_ACCESSOR_H 6232 6233 } // namespace internal 6234 } // namespace v8 6235