OLD | NEW |
1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/builtins/builtins-utils.h" | 5 #include "src/builtins/builtins-utils.h" |
6 #include "src/builtins/builtins.h" | 6 #include "src/builtins/builtins.h" |
7 #include "src/code-factory.h" | 7 #include "src/code-factory.h" |
8 #include "src/code-stub-assembler.h" | |
9 #include "src/compiler.h" | 8 #include "src/compiler.h" |
10 #include "src/conversions.h" | 9 #include "src/conversions.h" |
11 #include "src/counters.h" | 10 #include "src/counters.h" |
12 #include "src/lookup.h" | 11 #include "src/lookup.h" |
13 #include "src/objects-inl.h" | 12 #include "src/objects-inl.h" |
14 #include "src/string-builder.h" | 13 #include "src/string-builder.h" |
15 | 14 |
16 namespace v8 { | 15 namespace v8 { |
17 namespace internal { | 16 namespace internal { |
18 | 17 |
(...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
265 &it, name, it.property_attributes())); | 264 &it, name, it.property_attributes())); |
266 } | 265 } |
267 return *function; | 266 return *function; |
268 } | 267 } |
269 | 268 |
270 } // namespace | 269 } // namespace |
271 | 270 |
272 // ES6 section 19.2.3.2 Function.prototype.bind ( thisArg, ...args ) | 271 // ES6 section 19.2.3.2 Function.prototype.bind ( thisArg, ...args ) |
273 BUILTIN(FunctionPrototypeBind) { return DoFunctionBind(isolate, args); } | 272 BUILTIN(FunctionPrototypeBind) { return DoFunctionBind(isolate, args); } |
274 | 273 |
275 TF_BUILTIN(FastFunctionPrototypeBind, CodeStubAssembler) { | |
276 Label slow(this); | |
277 | |
278 Node* argc = Parameter(BuiltinDescriptor::kArgumentsCount); | |
279 Node* context = Parameter(BuiltinDescriptor::kContext); | |
280 Node* new_target = Parameter(BuiltinDescriptor::kNewTarget); | |
281 | |
282 CodeStubArguments args(this, ChangeInt32ToIntPtr(argc)); | |
283 | |
284 // Check that receiver has instance type of JS_FUNCTION_TYPE | |
285 Node* receiver = args.GetReceiver(); | |
286 GotoIf(TaggedIsSmi(receiver), &slow); | |
287 | |
288 Node* receiver_map = LoadMap(receiver); | |
289 Node* instance_type = LoadMapInstanceType(receiver_map); | |
290 GotoIf(Word32NotEqual(instance_type, Int32Constant(JS_FUNCTION_TYPE)), &slow); | |
291 | |
292 // Disallow binding of slow-mode functions. We need to figure out whether the | |
293 // length and name property are in the original state. | |
294 Comment("Disallow binding of slow-mode functions"); | |
295 GotoIf(IsDictionaryMap(receiver_map), &slow); | |
296 | |
297 // Check whether the length and name properties are still present as | |
298 // AccessorInfo objects. In that case, their value can be recomputed even if | |
299 // the actual value on the object changes. | |
300 Comment("Check descriptor array length"); | |
301 Node* descriptors = LoadMapDescriptors(receiver_map); | |
302 Node* descriptors_length = LoadFixedArrayBaseLength(descriptors); | |
303 GotoIf(SmiLessThanOrEqual(descriptors_length, SmiConstant(1)), &slow); | |
304 | |
305 // Check whether the length and name properties are still present as | |
306 // AccessorInfo objects. In that case, their value can be recomputed even if | |
307 // the actual value on the object changes. | |
308 Comment("Check name and length properties"); | |
309 const int length_index = JSFunction::kLengthDescriptorIndex; | |
310 Node* maybe_length = LoadFixedArrayElement( | |
311 descriptors, DescriptorArray::ToKeyIndex(length_index)); | |
312 GotoIf(WordNotEqual(maybe_length, LoadRoot(Heap::klength_stringRootIndex)), | |
313 &slow); | |
314 | |
315 Node* maybe_length_accessor = LoadFixedArrayElement( | |
316 descriptors, DescriptorArray::ToValueIndex(length_index)); | |
317 GotoIf(TaggedIsSmi(maybe_length_accessor), &slow); | |
318 Node* length_value_map = LoadMap(maybe_length_accessor); | |
319 GotoIfNot(IsAccessorInfoMap(length_value_map), &slow); | |
320 | |
321 const int name_index = JSFunction::kNameDescriptorIndex; | |
322 Node* maybe_name = LoadFixedArrayElement( | |
323 descriptors, DescriptorArray::ToKeyIndex(name_index)); | |
324 GotoIf(WordNotEqual(maybe_name, LoadRoot(Heap::kname_stringRootIndex)), | |
325 &slow); | |
326 | |
327 Node* maybe_name_accessor = LoadFixedArrayElement( | |
328 descriptors, DescriptorArray::ToValueIndex(name_index)); | |
329 GotoIf(TaggedIsSmi(maybe_name_accessor), &slow); | |
330 Node* name_value_map = LoadMap(maybe_name_accessor); | |
331 GotoIfNot(IsAccessorInfoMap(name_value_map), &slow); | |
332 | |
333 // Choose the right bound function map based on whether the target is | |
334 // constructable. | |
335 Comment("Choose the right bound function map"); | |
336 Variable bound_function_map(this, MachineRepresentation::kTagged); | |
337 Label with_constructor(this); | |
338 VariableList vars({&bound_function_map}, zone()); | |
339 Node* native_context = LoadNativeContext(context); | |
340 | |
341 Label map_done(this, vars); | |
342 Node* bit_field = LoadMapBitField(receiver_map); | |
343 int mask = static_cast<int>(1 << Map::kIsConstructor); | |
344 GotoIf(IsSetWord32(bit_field, mask), &with_constructor); | |
345 | |
346 bound_function_map.Bind(LoadContextElement( | |
347 native_context, Context::BOUND_FUNCTION_WITHOUT_CONSTRUCTOR_MAP_INDEX)); | |
348 Goto(&map_done); | |
349 | |
350 Bind(&with_constructor); | |
351 bound_function_map.Bind(LoadContextElement( | |
352 native_context, Context::BOUND_FUNCTION_WITH_CONSTRUCTOR_MAP_INDEX)); | |
353 Goto(&map_done); | |
354 | |
355 Bind(&map_done); | |
356 | |
357 // Verify that __proto__ matches that of a the target bound function. | |
358 Comment("Verify that __proto__ matches target bound function"); | |
359 Node* prototype = LoadMapPrototype(receiver_map); | |
360 Node* expected_prototype = LoadMapPrototype(bound_function_map.value()); | |
361 GotoIf(WordNotEqual(prototype, expected_prototype), &slow); | |
362 | |
363 // Allocate the arguments array. | |
364 Comment("Allocate the arguments array"); | |
365 Variable argument_array(this, MachineRepresentation::kTagged); | |
366 Label empty_arguments(this); | |
367 Label arguments_done(this, &argument_array); | |
368 GotoIf(Uint32LessThanOrEqual(argc, Int32Constant(1)), &empty_arguments); | |
369 Node* elements_length = ChangeUint32ToWord(Int32Sub(argc, Int32Constant(1))); | |
370 Node* elements = AllocateFixedArray(FAST_ELEMENTS, elements_length); | |
371 Variable index(this, MachineType::PointerRepresentation()); | |
372 index.Bind(IntPtrConstant(0)); | |
373 VariableList foreach_vars({&index}, zone()); | |
374 args.ForEach(foreach_vars, | |
375 [this, elements, &index](Node* arg) { | |
376 StoreFixedArrayElement(elements, index.value(), arg); | |
377 Increment(index); | |
378 }, | |
379 IntPtrConstant(1)); | |
380 argument_array.Bind(elements); | |
381 Goto(&arguments_done); | |
382 | |
383 Bind(&empty_arguments); | |
384 argument_array.Bind(EmptyFixedArrayConstant()); | |
385 Goto(&arguments_done); | |
386 | |
387 Bind(&arguments_done); | |
388 | |
389 // Determine bound receiver. | |
390 Comment("Determine bound receiver"); | |
391 Variable bound_receiver(this, MachineRepresentation::kTagged); | |
392 Label has_receiver(this); | |
393 Label receiver_done(this, &bound_receiver); | |
394 GotoIf(Word32NotEqual(argc, Int32Constant(0)), &has_receiver); | |
395 bound_receiver.Bind(UndefinedConstant()); | |
396 Goto(&receiver_done); | |
397 | |
398 Bind(&has_receiver); | |
399 bound_receiver.Bind(args.AtIndex(0)); | |
400 Goto(&receiver_done); | |
401 | |
402 Bind(&receiver_done); | |
403 | |
404 // Allocate the resulting bound function. | |
405 Comment("Allocate the resulting bound function"); | |
406 Node* bound_function = Allocate(JSBoundFunction::kSize); | |
407 StoreMapNoWriteBarrier(bound_function, bound_function_map.value()); | |
408 StoreObjectFieldNoWriteBarrier( | |
409 bound_function, JSBoundFunction::kBoundTargetFunctionOffset, receiver); | |
410 StoreObjectFieldNoWriteBarrier(bound_function, | |
411 JSBoundFunction::kBoundThisOffset, | |
412 bound_receiver.value()); | |
413 StoreObjectFieldNoWriteBarrier(bound_function, | |
414 JSBoundFunction::kBoundArgumentsOffset, | |
415 argument_array.value()); | |
416 Node* empty_fixed_array = EmptyFixedArrayConstant(); | |
417 StoreObjectFieldNoWriteBarrier(bound_function, JSObject::kPropertiesOffset, | |
418 empty_fixed_array); | |
419 StoreObjectFieldNoWriteBarrier(bound_function, JSObject::kElementsOffset, | |
420 empty_fixed_array); | |
421 | |
422 args.PopAndReturn(bound_function); | |
423 Bind(&slow); | |
424 | |
425 Node* target = LoadFromFrame(StandardFrameConstants::kFunctionOffset, | |
426 MachineType::TaggedPointer()); | |
427 TailCallStub(CodeFactory::FunctionPrototypeBind(isolate()), context, target, | |
428 new_target, argc); | |
429 } | |
430 | |
431 // TODO(verwaest): This is a temporary helper until the FastFunctionBind stub | 274 // TODO(verwaest): This is a temporary helper until the FastFunctionBind stub |
432 // can tailcall to the builtin directly. | 275 // can tailcall to the builtin directly. |
433 RUNTIME_FUNCTION(Runtime_FunctionBind) { | 276 RUNTIME_FUNCTION(Runtime_FunctionBind) { |
434 DCHECK_EQ(2, args.length()); | 277 DCHECK_EQ(2, args.length()); |
435 Arguments* incoming = reinterpret_cast<Arguments*>(args[0]); | 278 Arguments* incoming = reinterpret_cast<Arguments*>(args[0]); |
436 // Rewrap the arguments as builtins arguments. | 279 // Rewrap the arguments as builtins arguments. |
437 int argc = incoming->length() + BuiltinArguments::kNumExtraArgsWithReceiver; | 280 int argc = incoming->length() + BuiltinArguments::kNumExtraArgsWithReceiver; |
438 BuiltinArguments caller_args(argc, incoming->arguments() + 1); | 281 BuiltinArguments caller_args(argc, incoming->arguments() + 1); |
439 return DoFunctionBind(isolate, caller_args); | 282 return DoFunctionBind(isolate, caller_args); |
440 } | 283 } |
441 | 284 |
442 // ES6 section 19.2.3.5 Function.prototype.toString ( ) | 285 // ES6 section 19.2.3.5 Function.prototype.toString ( ) |
443 BUILTIN(FunctionPrototypeToString) { | 286 BUILTIN(FunctionPrototypeToString) { |
444 HandleScope scope(isolate); | 287 HandleScope scope(isolate); |
445 Handle<Object> receiver = args.receiver(); | 288 Handle<Object> receiver = args.receiver(); |
446 if (receiver->IsJSBoundFunction()) { | 289 if (receiver->IsJSBoundFunction()) { |
447 return *JSBoundFunction::ToString(Handle<JSBoundFunction>::cast(receiver)); | 290 return *JSBoundFunction::ToString(Handle<JSBoundFunction>::cast(receiver)); |
448 } else if (receiver->IsJSFunction()) { | 291 } else if (receiver->IsJSFunction()) { |
449 return *JSFunction::ToString(Handle<JSFunction>::cast(receiver)); | 292 return *JSFunction::ToString(Handle<JSFunction>::cast(receiver)); |
450 } | 293 } |
451 THROW_NEW_ERROR_RETURN_FAILURE( | 294 THROW_NEW_ERROR_RETURN_FAILURE( |
452 isolate, NewTypeError(MessageTemplate::kNotGeneric, | 295 isolate, NewTypeError(MessageTemplate::kNotGeneric, |
453 isolate->factory()->NewStringFromAsciiChecked( | 296 isolate->factory()->NewStringFromAsciiChecked( |
454 "Function.prototype.toString"))); | 297 "Function.prototype.toString"))); |
455 } | 298 } |
456 | 299 |
457 // ES6 section 19.2.3.6 Function.prototype [ @@hasInstance ] ( V ) | |
458 TF_BUILTIN(FunctionPrototypeHasInstance, CodeStubAssembler) { | |
459 Node* f = Parameter(0); | |
460 Node* v = Parameter(1); | |
461 Node* context = Parameter(4); | |
462 Node* result = OrdinaryHasInstance(context, f, v); | |
463 Return(result); | |
464 } | |
465 | |
466 } // namespace internal | 300 } // namespace internal |
467 } // namespace v8 | 301 } // namespace v8 |
OLD | NEW |