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 = \ |