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