Commit c84ca9c4 authored by Daniel Clifford's avatar Daniel Clifford Committed by Commit Bot

Port some SloppyArgumentsElements CSA code to Torque

Specifically, all the EmitKeyedSloppyArgumentsXXX methods.

Change-Id: I5d98c0f031b858e1e5342020f5ad68526c57c42a
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2235694
Commit-Queue: Daniel Clifford <danno@chromium.org>
Reviewed-by: 's avatarTobias Tebbi <tebbi@chromium.org>
Reviewed-by: 's avatarToon Verwaest <verwaest@chromium.org>
Cr-Commit-Position: refs/heads/master@{#69886}
parent 71728016
......@@ -1038,6 +1038,12 @@ const kOneByteStringMap: Map = OneByteStringMapConstant();
// The map of a non-internalized internal SeqTwoByteString.
const kStringMap: Map = StringMapConstant();
macro OutOfBounds<T: type, X: type>(index: T, length: X): bool {
return UintPtrGreaterThanOrEqual(
Convert<uintptr>(Convert<intptr>(index)),
Convert<uintptr>(Convert<intptr>(length)));
}
extern macro IsPrototypeInitialArrayPrototype(implicit context: Context)(Map):
bool;
extern macro IsNoElementsProtectorCellInvalid(): bool;
......
......@@ -40,123 +40,8 @@ class HandlerBuiltinsAssembler : public CodeStubAssembler {
void Generate_ElementsTransitionAndStore(KeyedAccessStoreMode store_mode);
void Generate_StoreFastElementIC(KeyedAccessStoreMode store_mode);
enum class ArgumentsAccessMode { kLoad, kStore, kHas };
// Emits keyed sloppy arguments has. Returns whether the key is in the
// arguments.
TNode<Object> HasKeyedSloppyArguments(TNode<JSObject> receiver,
TNode<Object> key, Label* bailout) {
return EmitKeyedSloppyArguments(receiver, key, base::nullopt, bailout,
ArgumentsAccessMode::kHas);
}
// Emits keyed sloppy arguments load. Returns either the loaded value.
TNode<Object> LoadKeyedSloppyArguments(TNode<JSObject> receiver,
TNode<Object> key, Label* bailout) {
return EmitKeyedSloppyArguments(receiver, key, base::nullopt, bailout,
ArgumentsAccessMode::kLoad);
}
// Emits keyed sloppy arguments store.
void StoreKeyedSloppyArguments(TNode<JSObject> receiver, TNode<Object> key,
TNode<Object> value, Label* bailout) {
EmitKeyedSloppyArguments(receiver, key, value, bailout,
ArgumentsAccessMode::kStore);
}
private:
// Emits keyed sloppy arguments load if the |value| is nullopt or store
// otherwise. Returns either the loaded value or |value|.
TNode<Object> EmitKeyedSloppyArguments(TNode<JSObject> receiver,
TNode<Object> key,
base::Optional<TNode<Object>> value,
Label* bailout,
ArgumentsAccessMode access_mode);
};
TNode<Object> HandlerBuiltinsAssembler::EmitKeyedSloppyArguments(
TNode<JSObject> receiver, TNode<Object> tagged_key,
base::Optional<TNode<Object>> value, Label* bailout,
ArgumentsAccessMode access_mode) {
GotoIfNot(TaggedIsSmi(tagged_key), bailout);
TNode<IntPtrT> key = SmiUntag(CAST(tagged_key));
GotoIf(IntPtrLessThan(key, IntPtrConstant(0)), bailout);
TNode<SloppyArgumentsElements> elements = CAST(LoadElements(receiver));
TNode<IntPtrT> elements_length = LoadAndUntagFixedArrayBaseLength(elements);
TVARIABLE(Object, var_result);
if (access_mode == ArgumentsAccessMode::kStore) {
var_result = *value;
} else {
DCHECK(access_mode == ArgumentsAccessMode::kLoad ||
access_mode == ArgumentsAccessMode::kHas);
}
Label if_mapped(this), if_unmapped(this), end(this, &var_result);
GotoIf(UintPtrGreaterThanOrEqual(key, elements_length), &if_unmapped);
TNode<Object> mapped_index =
LoadSloppyArgumentsElementsMappedEntries(elements, key);
Branch(TaggedEqual(mapped_index, TheHoleConstant()), &if_unmapped,
&if_mapped);
BIND(&if_mapped);
{
TNode<IntPtrT> mapped_index_intptr = SmiUntag(CAST(mapped_index));
TNode<Context> the_context = LoadSloppyArgumentsElementsContext(elements);
if (access_mode == ArgumentsAccessMode::kLoad) {
TNode<Object> result =
LoadContextElement(the_context, mapped_index_intptr);
CSA_ASSERT(this, TaggedNotEqual(result, TheHoleConstant()));
var_result = result;
} else if (access_mode == ArgumentsAccessMode::kHas) {
CSA_ASSERT(this, Word32BinaryNot(IsTheHole(LoadContextElement(
the_context, mapped_index_intptr))));
var_result = TrueConstant();
} else {
StoreContextElement(the_context, mapped_index_intptr, *value);
}
Goto(&end);
}
BIND(&if_unmapped);
{
TNode<HeapObject> backing_store_ho =
LoadSloppyArgumentsElementsArguments(elements);
GotoIf(TaggedNotEqual(LoadMap(backing_store_ho), FixedArrayMapConstant()),
bailout);
TNode<FixedArray> backing_store = CAST(backing_store_ho);
TNode<IntPtrT> backing_store_length =
LoadAndUntagFixedArrayBaseLength(backing_store);
// Out-of-bounds access may involve prototype chain walk and is handled
// in runtime.
GotoIf(UintPtrGreaterThanOrEqual(key, backing_store_length), bailout);
// The key falls into unmapped range.
if (access_mode == ArgumentsAccessMode::kStore) {
StoreFixedArrayElement(backing_store, key, *value);
} else {
TNode<Object> value = LoadFixedArrayElement(backing_store, key);
GotoIf(TaggedEqual(value, TheHoleConstant()), bailout);
if (access_mode == ArgumentsAccessMode::kHas) {
var_result = TrueConstant();
} else {
DCHECK_EQ(access_mode, ArgumentsAccessMode::kLoad);
var_result = value;
}
}
Goto(&end);
}
BIND(&end);
return var_result.value();
}
TF_BUILTIN(LoadIC_StringLength, CodeStubAssembler) {
TNode<String> string = CAST(Parameter(Descriptor::kReceiver));
Return(LoadStringLengthAsSmi(string));
......@@ -463,7 +348,7 @@ TF_BUILTIN(KeyedLoadIC_SloppyArguments, HandlerBuiltinsAssembler) {
Label miss(this);
TNode<Object> result = LoadKeyedSloppyArguments(receiver, key, &miss);
TNode<Object> result = SloppyArgumentsLoad(receiver, key, &miss);
Return(result);
BIND(&miss);
......@@ -485,7 +370,7 @@ void HandlerBuiltinsAssembler::Generate_KeyedStoreIC_SloppyArguments() {
Label miss(this);
StoreKeyedSloppyArguments(receiver, key, value, &miss);
SloppyArgumentsStore(receiver, key, value, &miss);
Return(value);
BIND(&miss);
......@@ -538,7 +423,7 @@ TF_BUILTIN(KeyedHasIC_SloppyArguments, HandlerBuiltinsAssembler) {
Label miss(this);
TNode<Object> result = HasKeyedSloppyArguments(receiver, key, &miss);
TNode<Object> result = SloppyArgumentsHas(receiver, key, &miss);
Return(result);
BIND(&miss);
......
......@@ -53,7 +53,7 @@ extern shape JSStrictArgumentsObject extends JSArgumentsObject {
// entry has been deleted fron the arguments object, and value is looked up in
// the unmapped arguments array, as described above. Otherwise, t is a Smi
// index into the context array specified at elements.context, and the return
// value is elements.context.
// value is elements.context[t].
//
// A graphic representation of a SloppyArgumentsElements object and a
// corresponding unmapped arguments FixedArray:
......@@ -79,7 +79,7 @@ extern shape JSStrictArgumentsObject extends JSArgumentsObject {
@export
class SloppyArgumentsElements extends FixedArrayBase {
context: Context;
arguments: FixedArray;
arguments: FixedArray|NumberDictionary;
mapped_entries[length]: Smi|TheHole;
}
......@@ -316,3 +316,58 @@ builtin NewRestArgumentsElements(
return arguments::NewRestArgumentsElements(
frame, formalParameterCount, Convert<intptr>(argumentCount));
}
macro
AccessSloppyArgumentsCommon(
receiver: JSObject, keyObject: Object): &Object labels Bailout {
const key = Cast<Smi>(keyObject) otherwise Bailout;
const elements =
Cast<SloppyArgumentsElements>(receiver.elements) otherwise Bailout;
try {
if (OutOfBounds(key, elements.length)) goto Unmapped;
const mappedIndex = elements.mapped_entries[key];
typeswitch (mappedIndex) {
case (contextIndex: Smi): {
return &(elements.context.elements[contextIndex]);
}
case (TheHole): {
goto Unmapped;
}
}
} label Unmapped {
typeswitch (elements.arguments) {
case (NumberDictionary): {
goto Bailout;
}
case (arguments: FixedArray): {
if (OutOfBounds(key, arguments.length)) goto Bailout;
if (arguments.objects[key] == TheHole) goto Bailout;
return &(arguments.objects[key]);
}
}
}
}
@export
macro SloppyArgumentsLoad(receiver: JSObject, keyObject: Object):
JSAny labels Bailout {
return UnsafeCast<JSAny>(
*AccessSloppyArgumentsCommon(receiver, keyObject) otherwise Bailout);
}
@export
macro SloppyArgumentsHas(receiver: JSObject, keyObject: Object):
JSAny labels Bailout {
AccessSloppyArgumentsCommon(receiver, keyObject) otherwise Bailout;
return True;
}
@export
macro SloppyArgumentsStore(receiver: JSObject, keyObject: Object, value: JSAny):
JSAny labels Bailout {
let destination =
AccessSloppyArgumentsCommon(receiver, keyObject) otherwise Bailout;
*destination = value;
return value;
}
// Copyright 2020 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.
// Flags: --allow-natives-syntax
function sloppyArgumentsGenerator(a,b) {
arguments[7] = 88;
return arguments;
}
function testLoad() {
let a = sloppyArgumentsGenerator(66,55,45,77);
for (let i=0;i<2;++i) {
assertEquals(a[0], 66);
}
for (let i=0;i<2;++i) {
assertEquals(a[2], 45);
}
for (let i=0;i<2;++i) {
assertEquals(a[10], undefined);
}
for (let i=0;i<2;++i) {
assertEquals(a[6], undefined);
}
for (let i=0;i<2;++i) {
assertEquals(a[7], 88);
}
delete a[0];
for (let i=0;i<2;++i) {
assertEquals(a[0], undefined);
}
}
function testHas() {
let a = sloppyArgumentsGenerator(66,55,45,77);
for (let i=0;i<2;++i) {
assertTrue(0 in a);
}
for (let i=0;i<2;++i) {
assertTrue(2 in a);
}
for (let i=0;i<2;++i) {
assertFalse(10 in a);
}
for (let i=0;i<2;++i) {
assertFalse(6 in a);
}
for (let i=0;i<2;++i) {
assertTrue(7 in a);
}
delete a[0];
for (let i=0;i<2;++i) {
assertFalse(0 in a);
}
}
// Test once without type feedback vector
testLoad();
testHas();
%EnsureFeedbackVectorForFunction(testLoad);
%EnsureFeedbackVectorForFunction(testHas);
// Test again with type feedback vector
testLoad();
testHas();
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment