2017-03-16 11:32:01 +00:00
|
|
|
// Copyright 2017 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-gen.h"
|
|
|
|
#include "src/builtins/builtins.h"
|
|
|
|
#include "src/code-stub-assembler.h"
|
|
|
|
#include "src/macro-assembler.h"
|
|
|
|
#include "src/runtime/runtime.h"
|
|
|
|
|
|
|
|
namespace v8 {
|
|
|
|
namespace internal {
|
|
|
|
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
// 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.
|
|
|
|
|
|
|
|
TF_BUILTIN(CopyFastSmiOrObjectElements, CodeStubAssembler) {
|
|
|
|
Node* object = Parameter(Descriptor::kObject);
|
|
|
|
|
|
|
|
// Load the {object}s elements.
|
|
|
|
Node* source = LoadObjectField(object, JSObject::kElementsOffset);
|
|
|
|
|
|
|
|
ParameterMode mode = OptimalParameterMode();
|
|
|
|
Node* length = TaggedToParameter(LoadFixedArrayBaseLength(source), mode);
|
|
|
|
|
|
|
|
// Check if we can allocate in new space.
|
2017-06-30 11:26:14 +00:00
|
|
|
ElementsKind kind = PACKED_ELEMENTS;
|
2017-03-16 11:32:01 +00:00
|
|
|
int max_elements = FixedArrayBase::GetMaxLengthForNewSpaceAllocation(kind);
|
|
|
|
Label if_newspace(this), if_oldspace(this);
|
|
|
|
Branch(UintPtrOrSmiLessThan(length, IntPtrOrSmiConstant(max_elements, mode),
|
|
|
|
mode),
|
|
|
|
&if_newspace, &if_oldspace);
|
|
|
|
|
2017-04-06 10:46:06 +00:00
|
|
|
BIND(&if_newspace);
|
2017-03-16 11:32:01 +00:00
|
|
|
{
|
|
|
|
Node* target = AllocateFixedArray(kind, length, mode);
|
|
|
|
CopyFixedArrayElements(kind, source, target, length, SKIP_WRITE_BARRIER,
|
|
|
|
mode);
|
|
|
|
StoreObjectField(object, JSObject::kElementsOffset, target);
|
|
|
|
Return(target);
|
|
|
|
}
|
|
|
|
|
2017-04-06 10:46:06 +00:00
|
|
|
BIND(&if_oldspace);
|
2017-03-16 11:32:01 +00:00
|
|
|
{
|
|
|
|
Node* target = AllocateFixedArray(kind, length, mode, kPretenured);
|
|
|
|
CopyFixedArrayElements(kind, source, target, length, UPDATE_WRITE_BARRIER,
|
|
|
|
mode);
|
|
|
|
StoreObjectField(object, JSObject::kElementsOffset, target);
|
|
|
|
Return(target);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TF_BUILTIN(GrowFastDoubleElements, CodeStubAssembler) {
|
|
|
|
Node* object = Parameter(Descriptor::kObject);
|
|
|
|
Node* key = Parameter(Descriptor::kKey);
|
|
|
|
Node* context = Parameter(Descriptor::kContext);
|
|
|
|
|
|
|
|
Label runtime(this, Label::kDeferred);
|
|
|
|
Node* elements = LoadElements(object);
|
2017-06-30 11:26:14 +00:00
|
|
|
elements = TryGrowElementsCapacity(object, elements, PACKED_DOUBLE_ELEMENTS,
|
2017-03-16 11:32:01 +00:00
|
|
|
key, &runtime);
|
|
|
|
Return(elements);
|
|
|
|
|
2017-04-06 10:46:06 +00:00
|
|
|
BIND(&runtime);
|
2017-03-16 11:32:01 +00:00
|
|
|
TailCallRuntime(Runtime::kGrowArrayElements, context, object, key);
|
|
|
|
}
|
|
|
|
|
|
|
|
TF_BUILTIN(GrowFastSmiOrObjectElements, CodeStubAssembler) {
|
|
|
|
Node* object = Parameter(Descriptor::kObject);
|
|
|
|
Node* key = Parameter(Descriptor::kKey);
|
|
|
|
Node* context = Parameter(Descriptor::kContext);
|
|
|
|
|
|
|
|
Label runtime(this, Label::kDeferred);
|
|
|
|
Node* elements = LoadElements(object);
|
|
|
|
elements =
|
2017-06-30 11:26:14 +00:00
|
|
|
TryGrowElementsCapacity(object, elements, PACKED_ELEMENTS, key, &runtime);
|
2017-03-16 11:32:01 +00:00
|
|
|
Return(elements);
|
|
|
|
|
2017-04-06 10:46:06 +00:00
|
|
|
BIND(&runtime);
|
2017-03-16 11:32:01 +00:00
|
|
|
TailCallRuntime(Runtime::kGrowArrayElements, context, object, key);
|
|
|
|
}
|
|
|
|
|
|
|
|
TF_BUILTIN(NewUnmappedArgumentsElements, CodeStubAssembler) {
|
|
|
|
Node* frame = Parameter(Descriptor::kFrame);
|
|
|
|
Node* length = SmiToWord(Parameter(Descriptor::kLength));
|
|
|
|
|
|
|
|
// Check if we can allocate in new space.
|
2017-06-30 11:26:14 +00:00
|
|
|
ElementsKind kind = PACKED_ELEMENTS;
|
2017-03-16 11:32:01 +00:00
|
|
|
int max_elements = FixedArray::GetMaxLengthForNewSpaceAllocation(kind);
|
|
|
|
Label if_newspace(this), if_oldspace(this, Label::kDeferred);
|
|
|
|
Branch(IntPtrLessThan(length, IntPtrConstant(max_elements)), &if_newspace,
|
|
|
|
&if_oldspace);
|
|
|
|
|
2017-04-06 10:46:06 +00:00
|
|
|
BIND(&if_newspace);
|
2017-03-16 11:32:01 +00:00
|
|
|
{
|
|
|
|
// Prefer EmptyFixedArray in case of non-positive {length} (the {length}
|
|
|
|
// can be negative here for rest parameters).
|
|
|
|
Label if_empty(this), if_notempty(this);
|
|
|
|
Branch(IntPtrLessThanOrEqual(length, IntPtrConstant(0)), &if_empty,
|
|
|
|
&if_notempty);
|
|
|
|
|
2017-04-06 10:46:06 +00:00
|
|
|
BIND(&if_empty);
|
2017-03-16 11:32:01 +00:00
|
|
|
Return(EmptyFixedArrayConstant());
|
|
|
|
|
2017-04-06 10:46:06 +00:00
|
|
|
BIND(&if_notempty);
|
2017-03-16 11:32:01 +00:00
|
|
|
{
|
|
|
|
// Allocate a FixedArray in new space.
|
|
|
|
Node* result = AllocateFixedArray(kind, length);
|
|
|
|
|
|
|
|
// Compute the effective {offset} into the {frame}.
|
|
|
|
Node* offset = IntPtrAdd(length, IntPtrConstant(1));
|
|
|
|
|
|
|
|
// Copy the parameters from {frame} (starting at {offset}) to {result}.
|
2017-04-07 08:20:35 +00:00
|
|
|
VARIABLE(var_index, MachineType::PointerRepresentation());
|
2017-03-16 11:32:01 +00:00
|
|
|
Label loop(this, &var_index), done_loop(this);
|
|
|
|
var_index.Bind(IntPtrConstant(0));
|
|
|
|
Goto(&loop);
|
2017-04-06 10:46:06 +00:00
|
|
|
BIND(&loop);
|
2017-03-16 11:32:01 +00:00
|
|
|
{
|
|
|
|
// Load the current {index}.
|
|
|
|
Node* index = var_index.value();
|
|
|
|
|
|
|
|
// Check if we are done.
|
|
|
|
GotoIf(WordEqual(index, length), &done_loop);
|
|
|
|
|
|
|
|
// Load the parameter at the given {index}.
|
|
|
|
Node* value = Load(MachineType::AnyTagged(), frame,
|
2017-05-19 13:17:02 +00:00
|
|
|
TimesPointerSize(IntPtrSub(offset, index)));
|
2017-03-16 11:32:01 +00:00
|
|
|
|
|
|
|
// Store the {value} into the {result}.
|
|
|
|
StoreFixedArrayElement(result, index, value, SKIP_WRITE_BARRIER);
|
|
|
|
|
|
|
|
// Continue with next {index}.
|
|
|
|
var_index.Bind(IntPtrAdd(index, IntPtrConstant(1)));
|
|
|
|
Goto(&loop);
|
|
|
|
}
|
|
|
|
|
2017-04-06 10:46:06 +00:00
|
|
|
BIND(&done_loop);
|
2017-03-16 11:32:01 +00:00
|
|
|
Return(result);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-06 10:46:06 +00:00
|
|
|
BIND(&if_oldspace);
|
2017-03-16 11:32:01 +00:00
|
|
|
{
|
|
|
|
// Allocate in old space (or large object space).
|
|
|
|
TailCallRuntime(Runtime::kNewArgumentsElements, NoContextConstant(),
|
|
|
|
BitcastWordToTagged(frame), SmiFromWord(length));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-20 10:55:37 +00:00
|
|
|
TF_BUILTIN(ReturnReceiver, CodeStubAssembler) {
|
|
|
|
Return(Parameter(Descriptor::kReceiver));
|
|
|
|
}
|
2017-03-16 11:32:01 +00:00
|
|
|
|
2017-04-20 12:11:05 +00:00
|
|
|
class DeletePropertyBaseAssembler : public CodeStubAssembler {
|
|
|
|
public:
|
|
|
|
explicit DeletePropertyBaseAssembler(compiler::CodeAssemblerState* state)
|
|
|
|
: CodeStubAssembler(state) {}
|
|
|
|
|
|
|
|
void DeleteDictionaryProperty(Node* receiver, Node* properties, Node* name,
|
|
|
|
Node* context, Label* dont_delete,
|
|
|
|
Label* notfound) {
|
|
|
|
VARIABLE(var_name_index, MachineType::PointerRepresentation());
|
|
|
|
Label dictionary_found(this, &var_name_index);
|
|
|
|
NameDictionaryLookup<NameDictionary>(properties, name, &dictionary_found,
|
|
|
|
&var_name_index, notfound);
|
|
|
|
|
|
|
|
BIND(&dictionary_found);
|
|
|
|
Node* key_index = var_name_index.value();
|
|
|
|
Node* details =
|
|
|
|
LoadDetailsByKeyIndex<NameDictionary>(properties, key_index);
|
|
|
|
GotoIf(IsSetWord32(details, PropertyDetails::kAttributesDontDeleteMask),
|
|
|
|
dont_delete);
|
|
|
|
// Overwrite the entry itself (see NameDictionary::SetEntry).
|
|
|
|
Node* filler = TheHoleConstant();
|
|
|
|
DCHECK(Heap::RootIsImmortalImmovable(Heap::kTheHoleValueRootIndex));
|
|
|
|
StoreFixedArrayElement(properties, key_index, filler, SKIP_WRITE_BARRIER);
|
|
|
|
StoreValueByKeyIndex<NameDictionary>(properties, key_index, filler,
|
|
|
|
SKIP_WRITE_BARRIER);
|
|
|
|
StoreDetailsByKeyIndex<NameDictionary>(properties, key_index,
|
|
|
|
SmiConstant(Smi::kZero));
|
|
|
|
|
|
|
|
// Update bookkeeping information (see NameDictionary::ElementRemoved).
|
|
|
|
Node* nof = GetNumberOfElements<NameDictionary>(properties);
|
|
|
|
Node* new_nof = SmiSub(nof, SmiConstant(1));
|
|
|
|
SetNumberOfElements<NameDictionary>(properties, new_nof);
|
|
|
|
Node* num_deleted = GetNumberOfDeletedElements<NameDictionary>(properties);
|
|
|
|
Node* new_deleted = SmiAdd(num_deleted, SmiConstant(1));
|
|
|
|
SetNumberOfDeletedElements<NameDictionary>(properties, new_deleted);
|
|
|
|
|
|
|
|
// Shrink the dictionary if necessary (see NameDictionary::Shrink).
|
|
|
|
Label shrinking_done(this);
|
|
|
|
Node* capacity = GetCapacity<NameDictionary>(properties);
|
|
|
|
GotoIf(SmiGreaterThan(new_nof, SmiShr(capacity, 2)), &shrinking_done);
|
|
|
|
GotoIf(SmiLessThan(new_nof, SmiConstant(16)), &shrinking_done);
|
2017-06-12 14:03:47 +00:00
|
|
|
CallRuntime(Runtime::kShrinkPropertyDictionary, context, receiver);
|
2017-04-20 12:11:05 +00:00
|
|
|
Goto(&shrinking_done);
|
|
|
|
BIND(&shrinking_done);
|
|
|
|
|
|
|
|
Return(TrueConstant());
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
TF_BUILTIN(DeleteProperty, DeletePropertyBaseAssembler) {
|
|
|
|
Node* receiver = Parameter(Descriptor::kObject);
|
|
|
|
Node* key = Parameter(Descriptor::kKey);
|
|
|
|
Node* language_mode = Parameter(Descriptor::kLanguageMode);
|
|
|
|
Node* context = Parameter(Descriptor::kContext);
|
|
|
|
|
|
|
|
VARIABLE(var_index, MachineType::PointerRepresentation());
|
|
|
|
VARIABLE(var_unique, MachineRepresentation::kTagged, key);
|
|
|
|
Label if_index(this), if_unique_name(this), if_notunique(this),
|
|
|
|
if_notfound(this), slow(this);
|
|
|
|
|
|
|
|
GotoIf(TaggedIsSmi(receiver), &slow);
|
|
|
|
Node* receiver_map = LoadMap(receiver);
|
|
|
|
Node* instance_type = LoadMapInstanceType(receiver_map);
|
|
|
|
GotoIf(Int32LessThanOrEqual(instance_type,
|
|
|
|
Int32Constant(LAST_CUSTOM_ELEMENTS_RECEIVER)),
|
|
|
|
&slow);
|
|
|
|
TryToName(key, &if_index, &var_index, &if_unique_name, &var_unique, &slow,
|
|
|
|
&if_notunique);
|
|
|
|
|
|
|
|
BIND(&if_index);
|
|
|
|
{
|
|
|
|
Comment("integer index");
|
|
|
|
Goto(&slow); // TODO(jkummerow): Implement more smarts here.
|
|
|
|
}
|
|
|
|
|
|
|
|
BIND(&if_unique_name);
|
|
|
|
{
|
|
|
|
Comment("key is unique name");
|
|
|
|
Node* unique = var_unique.value();
|
|
|
|
CheckForAssociatedProtector(unique, &slow);
|
|
|
|
|
|
|
|
Label dictionary(this), dont_delete(this);
|
|
|
|
Node* properties = LoadProperties(receiver);
|
|
|
|
Node* properties_map = LoadMap(properties);
|
|
|
|
GotoIf(WordEqual(properties_map, LoadRoot(Heap::kHashTableMapRootIndex)),
|
|
|
|
&dictionary);
|
2017-05-03 15:50:50 +00:00
|
|
|
// Fast properties need to clear recorded slots, which can only be done
|
|
|
|
// in C++.
|
|
|
|
Goto(&slow);
|
2017-04-20 12:11:05 +00:00
|
|
|
|
|
|
|
BIND(&dictionary);
|
|
|
|
{
|
|
|
|
DeleteDictionaryProperty(receiver, properties, unique, context,
|
|
|
|
&dont_delete, &if_notfound);
|
|
|
|
}
|
|
|
|
|
|
|
|
BIND(&dont_delete);
|
|
|
|
{
|
|
|
|
STATIC_ASSERT(LANGUAGE_END == 2);
|
|
|
|
GotoIf(SmiNotEqual(language_mode, SmiConstant(SLOPPY)), &slow);
|
|
|
|
Return(FalseConstant());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
BIND(&if_notunique);
|
|
|
|
{
|
|
|
|
// If the string was not found in the string table, then no object can
|
|
|
|
// have a property with that name.
|
|
|
|
TryInternalizeString(key, &if_index, &var_index, &if_unique_name,
|
|
|
|
&var_unique, &if_notfound, &slow);
|
|
|
|
}
|
|
|
|
|
|
|
|
BIND(&if_notfound);
|
|
|
|
Return(TrueConstant());
|
|
|
|
|
|
|
|
BIND(&slow);
|
|
|
|
{
|
|
|
|
TailCallRuntime(Runtime::kDeleteProperty, context, receiver, key,
|
|
|
|
language_mode);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-16 11:32:01 +00:00
|
|
|
} // namespace internal
|
|
|
|
} // namespace v8
|