// Copyright 2016 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "src/builtins/builtins-utils.h" #include "src/builtins/builtins.h" #include "src/code-stub-assembler.h" #include "src/counters.h" #include "src/interface-descriptors.h" #include "src/macro-assembler.h" #include "src/objects-inl.h" namespace v8 { namespace internal { BUILTIN(Illegal) { UNREACHABLE(); return isolate->heap()->undefined_value(); // Make compiler happy. } BUILTIN(EmptyFunction) { return isolate->heap()->undefined_value(); } BUILTIN(UnsupportedThrower) { HandleScope scope(isolate); THROW_NEW_ERROR_RETURN_FAILURE(isolate, NewError(MessageTemplate::kUnsupported)); } // ----------------------------------------------------------------------------- // Throwers for restricted function properties and strict arguments object // properties BUILTIN(RestrictedFunctionPropertiesThrower) { HandleScope scope(isolate); THROW_NEW_ERROR_RETURN_FAILURE( isolate, NewTypeError(MessageTemplate::kRestrictedFunctionProperties)); } BUILTIN(RestrictedStrictArgumentsPropertiesThrower) { HandleScope scope(isolate); THROW_NEW_ERROR_RETURN_FAILURE( isolate, NewTypeError(MessageTemplate::kStrictPoisonPill)); } // ----------------------------------------------------------------------------- // Interrupt and stack checks. void Builtins::Generate_InterruptCheck(MacroAssembler* masm) { masm->TailCallRuntime(Runtime::kInterrupt); } void Builtins::Generate_StackCheck(MacroAssembler* masm) { masm->TailCallRuntime(Runtime::kStackGuard); } // ----------------------------------------------------------------------------- // TurboFan support builtins. void Builtins::Generate_CopyFastSmiOrObjectElements( compiler::CodeAssemblerState* state) { typedef CodeStubAssembler::Label Label; typedef compiler::Node Node; typedef CopyFastSmiOrObjectElementsDescriptor Descriptor; CodeStubAssembler assembler(state); Node* object = assembler.Parameter(Descriptor::kObject); // Load the {object}s elements. Node* source = assembler.LoadObjectField(object, JSObject::kElementsOffset); CodeStubAssembler::ParameterMode mode = assembler.OptimalParameterMode(); Node* length = assembler.TaggedToParameter( assembler.LoadFixedArrayBaseLength(source), mode); // Check if we can allocate in new space. ElementsKind kind = FAST_ELEMENTS; int max_elements = FixedArrayBase::GetMaxLengthForNewSpaceAllocation(kind); Label if_newspace(&assembler), if_oldspace(&assembler); assembler.Branch( assembler.UintPtrOrSmiLessThan( length, assembler.IntPtrOrSmiConstant(max_elements, mode), mode), &if_newspace, &if_oldspace); assembler.Bind(&if_newspace); { Node* target = assembler.AllocateFixedArray(kind, length, mode); assembler.CopyFixedArrayElements(kind, source, target, length, SKIP_WRITE_BARRIER, mode); assembler.StoreObjectField(object, JSObject::kElementsOffset, target); assembler.Return(target); } assembler.Bind(&if_oldspace); { Node* target = assembler.AllocateFixedArray(kind, length, mode, CodeStubAssembler::kPretenured); assembler.CopyFixedArrayElements(kind, source, target, length, UPDATE_WRITE_BARRIER, mode); assembler.StoreObjectField(object, JSObject::kElementsOffset, target); assembler.Return(target); } } void Builtins::Generate_GrowFastDoubleElements( compiler::CodeAssemblerState* state) { typedef CodeStubAssembler::Label Label; typedef compiler::Node Node; typedef GrowArrayElementsDescriptor Descriptor; CodeStubAssembler assembler(state); Node* object = assembler.Parameter(Descriptor::kObject); Node* key = assembler.Parameter(Descriptor::kKey); Node* context = assembler.Parameter(Descriptor::kContext); Label runtime(&assembler, CodeStubAssembler::Label::kDeferred); Node* elements = assembler.LoadElements(object); elements = assembler.TryGrowElementsCapacity( object, elements, FAST_DOUBLE_ELEMENTS, key, &runtime); assembler.Return(elements); assembler.Bind(&runtime); assembler.TailCallRuntime(Runtime::kGrowArrayElements, context, object, key); } void Builtins::Generate_GrowFastSmiOrObjectElements( compiler::CodeAssemblerState* state) { typedef CodeStubAssembler::Label Label; typedef compiler::Node Node; typedef GrowArrayElementsDescriptor Descriptor; CodeStubAssembler assembler(state); Node* object = assembler.Parameter(Descriptor::kObject); Node* key = assembler.Parameter(Descriptor::kKey); Node* context = assembler.Parameter(Descriptor::kContext); Label runtime(&assembler, CodeStubAssembler::Label::kDeferred); Node* elements = assembler.LoadElements(object); elements = assembler.TryGrowElementsCapacity(object, elements, FAST_ELEMENTS, key, &runtime); assembler.Return(elements); assembler.Bind(&runtime); assembler.TailCallRuntime(Runtime::kGrowArrayElements, context, object, key); } namespace { void Generate_NewArgumentsElements(CodeStubAssembler* assembler, compiler::Node* frame, compiler::Node* length) { typedef CodeStubAssembler::Label Label; typedef CodeStubAssembler::Variable Variable; typedef compiler::Node Node; // Check if we can allocate in new space. ElementsKind kind = FAST_ELEMENTS; int max_elements = FixedArray::GetMaxLengthForNewSpaceAllocation(kind); Label if_newspace(assembler), if_oldspace(assembler, Label::kDeferred); assembler->Branch(assembler->IntPtrLessThan( length, assembler->IntPtrConstant(max_elements)), &if_newspace, &if_oldspace); assembler->Bind(&if_newspace); { // Prefer EmptyFixedArray in case of non-positive {length} (the {length} // can be negative here for rest parameters). Label if_empty(assembler), if_notempty(assembler); assembler->Branch( assembler->IntPtrLessThanOrEqual(length, assembler->IntPtrConstant(0)), &if_empty, &if_notempty); assembler->Bind(&if_empty); assembler->Return(assembler->EmptyFixedArrayConstant()); assembler->Bind(&if_notempty); { // Allocate a FixedArray in new space. Node* result = assembler->AllocateFixedArray(kind, length); // Compute the effective {offset} into the {frame}. Node* offset = assembler->IntPtrAdd(length, assembler->IntPtrConstant(1)); // Copy the parameters from {frame} (starting at {offset}) to {result}. Variable var_index(assembler, MachineType::PointerRepresentation()); Label loop(assembler, &var_index), done_loop(assembler); var_index.Bind(assembler->IntPtrConstant(0)); assembler->Goto(&loop); assembler->Bind(&loop); { // Load the current {index}. Node* index = var_index.value(); // Check if we are done. assembler->GotoIf(assembler->WordEqual(index, length), &done_loop); // Load the parameter at the given {index}. Node* value = assembler->Load( MachineType::AnyTagged(), frame, assembler->WordShl(assembler->IntPtrSub(offset, index), assembler->IntPtrConstant(kPointerSizeLog2))); // Store the {value} into the {result}. assembler->StoreFixedArrayElement(result, index, value, SKIP_WRITE_BARRIER); // Continue with next {index}. var_index.Bind( assembler->IntPtrAdd(index, assembler->IntPtrConstant(1))); assembler->Goto(&loop); } assembler->Bind(&done_loop); assembler->Return(result); } } assembler->Bind(&if_oldspace); { // Allocate in old space (or large object space). assembler->TailCallRuntime( Runtime::kNewArgumentsElements, assembler->NoContextConstant(), assembler->BitcastWordToTagged(frame), assembler->SmiFromWord(length)); } } } // namespace void Builtins::Generate_NewUnmappedArgumentsElements( compiler::CodeAssemblerState* state) { typedef CodeStubAssembler::Label Label; typedef CodeStubAssembler::Variable Variable; typedef compiler::Node Node; typedef NewArgumentsElementsDescriptor Descriptor; CodeStubAssembler assembler(state); Node* formal_parameter_count = assembler.Parameter(Descriptor::kFormalParameterCount); // Determine the frame that holds the parameters. Label done(&assembler); Variable var_frame(&assembler, MachineType::PointerRepresentation()), var_length(&assembler, MachineType::PointerRepresentation()); var_frame.Bind(assembler.LoadParentFramePointer()); var_length.Bind(formal_parameter_count); Node* parent_frame = assembler.Load( MachineType::Pointer(), var_frame.value(), assembler.IntPtrConstant(StandardFrameConstants::kCallerFPOffset)); Node* parent_frame_type = assembler.Load(MachineType::AnyTagged(), parent_frame, assembler.IntPtrConstant( CommonFrameConstants::kContextOrFrameTypeOffset)); assembler.GotoIfNot(assembler.MarkerIsFrameType( parent_frame_type, StackFrame::ARGUMENTS_ADAPTOR), &done); { // Determine the length from the ArgumentsAdaptorFrame. Node* length = assembler.LoadAndUntagSmi( parent_frame, ArgumentsAdaptorFrameConstants::kLengthOffset); // Take the arguments from the ArgumentsAdaptorFrame. var_frame.Bind(parent_frame); var_length.Bind(length); } assembler.Goto(&done); // Allocate the actual FixedArray for the elements. assembler.Bind(&done); Generate_NewArgumentsElements(&assembler, var_frame.value(), var_length.value()); } void Builtins::Generate_NewRestParameterElements( compiler::CodeAssemblerState* state) { typedef CodeStubAssembler::Label Label; typedef compiler::Node Node; typedef NewArgumentsElementsDescriptor Descriptor; CodeStubAssembler assembler(state); Node* formal_parameter_count = assembler.Parameter(Descriptor::kFormalParameterCount); // Check if we have an ArgumentsAdaptorFrame, as we will only have rest // parameters in that case. Label if_empty(&assembler); Node* frame = assembler.Load( MachineType::Pointer(), assembler.LoadParentFramePointer(), assembler.IntPtrConstant(StandardFrameConstants::kCallerFPOffset)); Node* frame_type = assembler.Load(MachineType::AnyTagged(), frame, assembler.IntPtrConstant( CommonFrameConstants::kContextOrFrameTypeOffset)); assembler.GotoIfNot( assembler.MarkerIsFrameType(frame_type, StackFrame::ARGUMENTS_ADAPTOR), &if_empty); // Determine the length from the ArgumentsAdaptorFrame. Node* frame_length = assembler.LoadAndUntagSmi( frame, ArgumentsAdaptorFrameConstants::kLengthOffset); // Compute the actual rest parameter length (may be negative). Node* length = assembler.IntPtrSub(frame_length, formal_parameter_count); // Allocate the actual FixedArray for the elements. Generate_NewArgumentsElements(&assembler, frame, length); // No rest parameters, return an empty FixedArray. assembler.Bind(&if_empty); assembler.Return(assembler.EmptyFixedArrayConstant()); } void Builtins::Generate_ReturnReceiver(compiler::CodeAssemblerState* state) { CodeStubAssembler assembler(state); assembler.Return(assembler.Parameter(0)); } } // namespace internal } // namespace v8