Chromium Code Reviews| Index: src/builtins.cc |
| diff --git a/src/builtins.cc b/src/builtins.cc |
| index fa3921a3544b9119d9fa81e3c06854e44b6b4370..238c498ec32f35c8e6764dcfaf1e040692823828 100644 |
| --- a/src/builtins.cc |
| +++ b/src/builtins.cc |
| @@ -9,6 +9,7 @@ |
| #include "src/arguments.h" |
| #include "src/base/once.h" |
| #include "src/bootstrapper.h" |
| +#include "src/compiler/code-stub-assembler.h" |
| #include "src/dateparser-inl.h" |
| #include "src/elements.h" |
| #include "src/frames-inl.h" |
| @@ -4358,6 +4359,220 @@ void Builtins::Generate_StackCheck(MacroAssembler* masm) { |
| } |
| +namespace { |
| + |
| +void ValidateSharedTypedArray(compiler::CodeStubAssembler* a, |
| + compiler::Node* tagged) { |
| + using namespace compiler; |
| + CodeStubAssembler::Label is_smi(a), not_smi(a), is_typed_array(a), |
| + not_typed_array(a), is_shared(a), not_shared(a), is_float(a), |
| + not_float(a), invalid(a); |
| + Node* context = a->Context(); |
| + |
| + // Check if it is a heap object. |
| + a->Branch(a->WordIsSmi(tagged), &is_smi, ¬_smi); |
| + a->Bind(&is_smi); |
| + a->Goto(&invalid); |
|
binji
2016/02/12 01:46:56
This Bind/Goto dance I end up having to do a lot o
|
| + |
| + // Check if the array's instance type is JSTypedArray. |
| + a->Bind(¬_smi); |
| + a->Branch(a->WordEqual(a->InstanceType(tagged), |
| + a->Int32Constant(JS_TYPED_ARRAY_TYPE)), |
| + &is_typed_array, ¬_typed_array); |
| + a->Bind(¬_typed_array); |
| + a->Goto(&invalid); |
| + |
| + // Check if the array's JSArrayBuffer is shared. |
| + a->Bind(&is_typed_array); |
| + Node* is_buffer_shared = |
| + a->BitFieldValue<JSArrayBuffer::IsShared>(a->LoadObjectField( |
| + a->LoadObjectField(tagged, JSTypedArray::kBufferOffset), |
| + JSArrayBuffer::kBitFieldOffset)); |
| + a->Branch(is_buffer_shared, &is_shared, ¬_shared); |
| + a->Bind(¬_shared); |
| + a->Goto(&invalid); |
| + |
| + // Check if the array's element type is float32 or float64. |
| + // TODO(binji): should fail on clamped as well. |
| + a->Bind(&is_shared); |
| + Node* elements_instance_type = |
| + a->InstanceType(a->LoadObjectField(tagged, JSObject::kElementsOffset)); |
| + a->Branch(a->WordOr(a->WordEqual(elements_instance_type, |
| + a->Int32Constant(FIXED_FLOAT32_ARRAY_TYPE)), |
| + a->WordEqual(elements_instance_type, |
| + a->Int32Constant(FIXED_FLOAT64_ARRAY_TYPE))), |
| + &is_float, ¬_float); |
| + a->Bind(&is_float); |
| + a->Goto(&invalid); |
| + |
| + a->Bind(&invalid); |
| + a->TailCallRuntime(Runtime::kThrowNotIntegerSharedTypedArrayError, context, |
| + tagged); |
| + |
| + a->Bind(¬_float); |
| +} |
| + |
| + |
| +compiler::Node* TaggedNumberAsWord32(compiler::CodeStubAssembler* a, |
| + compiler::Node* tagged) { |
| + using namespace compiler; |
| + CodeStubAssembler::Label is_smi(a), is_not_smi(a), is_word(a); |
| + CodeStubAssembler::Variable result(a, MachineRepresentation::kWord32); |
| + |
| + a->Branch(a->WordIsSmi(tagged), &is_smi, &is_not_smi); |
| + |
| + a->Bind(&is_smi); |
| + result.Bind(a->SmiUntag(tagged)); |
| + a->Goto(&is_word); |
| + |
| + a->Bind(&is_not_smi); |
| + result.Bind(a->ChangeFloat64ToUint32(a->LoadHeapNumber(tagged))); |
| + a->Goto(&is_word); |
| + |
| + a->Bind(&is_word); |
| + return result.value(); |
| +} |
| + |
| + |
| +compiler::Node* ConvertTaggedAtomicIndexToWord32(compiler::CodeStubAssembler* a, |
| + compiler::Node* tagged) { |
| + using namespace compiler; |
| + CodeStubAssembler::Label is_smi(a), is_not_smi(a), is_string(a), |
| + is_not_string(a), strings_equal(a), strings_not_equal(a), |
| + string_number_is_smi(a), string_number_is_not_smi(a), is_number(a), |
| + convert_number(a), is_unknown(a), is_integer(a), is_not_integer(a), |
| + is_word(a), invalid(a); |
| + CodeStubAssembler::Variable number(a, MachineRepresentation::kTagged); |
| + CodeStubAssembler::Variable word(a, MachineRepresentation::kWord32); |
| + Node* context = a->Context(); |
| + |
| + // Check if the index's type is a Smi. |
| + a->Branch(a->WordIsSmi(tagged), &is_smi, &is_not_smi); |
| + |
| + // Check if the index's type is a String. |
| + a->Bind(&is_not_smi); |
| + Node* instance_type = a->InstanceType(tagged); |
| + a->Branch(a->WordEqual( |
| + a->WordAnd(instance_type, a->Int32Constant(kIsNotStringMask)), |
| + a->Int32Constant(0)), |
| + &is_string, &is_not_string); |
| + |
| + // Check that converting the string to a number and back is equal to itself. |
| + a->Bind(&is_string); |
| + Node* string_as_number = |
| + a->CallRuntime(Runtime::kStringToNumber, context, tagged); |
| + a->Branch( |
| + a->WordEqual(a->CallRuntime(Runtime::kStringEquals, context, |
| + a->CallRuntime(Runtime::kNumberToString, |
| + context, string_as_number), |
| + tagged), |
| + a->Int32Constant(EQUAL)), |
| + &strings_equal, &strings_not_equal); |
| + |
| + a->Bind(&strings_not_equal); |
| + a->Goto(&invalid); |
| + |
| + // Check if the string converted to a number is a Smi. |
| + a->Bind(&strings_equal); |
| + a->Branch(a->WordIsSmi(string_as_number), &string_number_is_smi, |
| + &string_number_is_not_smi); |
| + |
| + // If the string-number is a Smi, untag it. |
| + a->Bind(&string_number_is_smi); |
| + word.Bind(a->SmiUntag(string_as_number)); |
| + a->Goto(&is_word); |
| + |
| + // If the string-number is a HeapNumber, convert it to a word32. |
| + a->Bind(&string_number_is_not_smi); |
| + number.Bind(string_as_number); |
| + a->Goto(&convert_number); |
| + |
| + // Check if the index's type is a HeapNumber. |
| + a->Bind(&is_not_string); |
| + a->Branch(a->WordEqual(instance_type, a->Int32Constant(HEAP_NUMBER_TYPE)), |
| + &is_number, &is_unknown); |
| + |
| + // Index is an invalid type, throw. |
| + a->Bind(&is_unknown); |
| + a->Goto(&invalid); |
| + |
| + a->Bind(&is_number); |
| + number.Bind(tagged); |
| + a->Goto(&convert_number); |
| + |
| + // Convert index from a HeapNumber to a word32. |
| + a->Bind(&convert_number); |
| + Node* number_value = a->LoadHeapNumber(number.value()); |
| + word.Bind(a->ChangeFloat64ToUint32(number_value)); |
| + |
| + // Check that the index is an integer. |
| + a->Branch( |
| + a->Float64Equal(a->ChangeUint32ToFloat64(word.value()), number_value), |
| + &is_integer, &is_not_integer); |
| + |
| + a->Bind(&is_not_integer); |
| + a->Goto(&invalid); |
| + |
| + a->Bind(&is_integer); |
| + a->Goto(&is_word); |
| + |
| + // Index is a Smi, untag. |
| + a->Bind(&is_smi); |
| + word.Bind(a->SmiUntag(tagged)); |
| + a->Goto(&is_word); |
| + |
| + a->Bind(&invalid); |
| + a->TailCallRuntime(Runtime::kThrowInvalidAtomicAccessIndexError, context); |
| + |
| + a->Bind(&is_word); |
| + return word.value(); |
| +} |
| + |
| + |
| +void ValidateAtomicIndex(compiler::CodeStubAssembler* a, |
| + compiler::Node* index_word, |
| + compiler::Node* array_length_word) { |
| + using namespace compiler; |
| + // Check if the index is in bounds. If not, throw RangeError. |
| + CodeStubAssembler::Label in_bounds(a), not_in_bounds(a); |
| + a->Branch( |
| + a->WordOr(a->Int32LessThan(index_word, a->Int32Constant(0)), |
| + a->Int32GreaterThanOrEqual(index_word, array_length_word)), |
| + ¬_in_bounds, &in_bounds); |
| + a->Bind(¬_in_bounds); |
| + a->TailCallRuntime(Runtime::kThrowInvalidAtomicAccessIndexError, |
| + a->Context()); |
| + a->Bind(&in_bounds); |
| +} |
| + |
| +} // anonymous namespace |
| + |
| + |
| +void Builtins::Generate_AtomicsLoadCheck(MacroAssembler* masm) { |
| + using namespace compiler; |
| + Isolate* isolate = masm->isolate(); |
| + Zone zone; |
| + CodeStubAssembler a(isolate, &zone, 2, Code::ComputeFlags(Code::STUB), |
| + "AtomicsLoadCheck"); |
| + |
| + Node* array = a.Parameter(0); |
| + Node* index = a.Parameter(1); |
| + ValidateSharedTypedArray(&a, array); |
| + Node* index_word = ConvertTaggedAtomicIndexToWord32(&a, index); |
| + Node* array_length_word = TaggedNumberAsWord32( |
| + &a, a.LoadObjectField(array, JSTypedArray::kLengthOffset)); |
| + ValidateAtomicIndex(&a, index_word, array_length_word); |
| + |
| + AtomicsLoadStub stub(isolate); |
| + // TODO(binji): can't just re-tag index, because it might be out of range. |
| + // Can we just pass the untagged index value to the code stub? |
| + Node* stub_args[] = {array, a.SmiTag(index_word), a.Context()}; |
| + a.TailCallStub(stub, stub_args); |
| + |
| + masm->Jump(a.GenerateCode(), RelocInfo::CODE_TARGET); |
|
binji
2016/02/12 01:46:56
Is this right? I've seen some errors when I run ce
|
| +} |
| + |
| + |
| #define DEFINE_BUILTIN_ACCESSOR_C(name, ignore) \ |
| Handle<Code> Builtins::name() { \ |
| Code** code_address = \ |