From 814048a04f667f4537ad80a3ae63d3699b4afdb2 Mon Sep 17 00:00:00 2001 From: machenbach Date: Mon, 27 Jul 2015 13:32:00 -0700 Subject: [PATCH] Revert of Remove ExternalArray, derived types, and element kinds (patchset #5 id:80001 of https://codereview.chromium.org/1254623002/) Reason for revert: [Sheriff] Breaks several layout tests, e.g.: http://build.chromium.org/p/client.v8.fyi/builders/V8-Blink%20Linux%2032/builds/1067 Several output lines change from PASS to FAIL. If the changes are intended, please land a needsmanualrebaseline change in blink first. Original issue's description: > Remove ExternalArray, derived types, and element kinds > > BUG=v8:3996 > R=jarin@chromium.org, mvstanton@chromium.org, bmeurer@chromium.org > LOG=y > > Committed: https://crrev.com/607ef7c6009a24ebf195b4cab7b0b436c5afd21c > Cr-Commit-Position: refs/heads/master@{#29872} TBR=bmeurer@chromium.org,hpayer@chromium.org,jarin@chromium.org,mvstanton@chromium.org,jochen@chromium.org NOPRESUBMIT=true NOTREECHECKS=true NOTRY=true BUG=v8:3996 Review URL: https://codereview.chromium.org/1257223002 Cr-Commit-Position: refs/heads/master@{#29883} --- include/v8.h | 2 +- src/arm/lithium-arm.cc | 9 +- src/arm/lithium-arm.h | 10 + src/arm/lithium-codegen-arm.cc | 38 ++- src/arm64/lithium-arm64.cc | 9 +- src/arm64/lithium-codegen-arm64.cc | 30 +- src/bootstrapper.cc | 34 ++- src/code-stubs-hydrogen.cc | 61 +++- src/code-stubs.cc | 1 + src/compiler/access-builder.cc | 8 + src/compiler/access-builder.h | 3 + src/compiler/js-typed-lowering.cc | 14 +- src/contexts.h | 10 + src/elements-kind.cc | 45 ++- src/elements-kind.h | 37 ++- src/elements.cc | 35 +++ src/factory.cc | 22 +- src/factory.h | 6 +- src/heap-snapshot-generator.cc | 6 +- src/heap/heap.cc | 98 +++++- src/heap/heap.h | 34 ++- src/heap/objects-visiting.cc | 5 + src/hydrogen-instructions.cc | 24 +- src/hydrogen-instructions.h | 57 +++- src/hydrogen-uint32-analysis.cc | 12 +- src/hydrogen.cc | 58 ++-- src/ia32/lithium-codegen-ia32.cc | 34 ++- src/ia32/lithium-ia32.cc | 12 +- src/ia32/lithium-ia32.h | 18 +- src/ic/handler-compiler.cc | 1 + src/ic/ic-compiler.cc | 3 + src/ic/ic.cc | 7 +- src/lookup.cc | 4 +- src/mips/lithium-codegen-mips.cc | 38 ++- src/mips/lithium-mips.cc | 9 +- src/mips/lithium-mips.h | 10 + src/mips64/lithium-codegen-mips64.cc | 38 ++- src/mips64/lithium-mips64.cc | 9 +- src/mips64/lithium-mips64.h | 10 + src/objects-debug.cc | 20 +- src/objects-inl.h | 259 +++++++++++++++- src/objects-printer.cc | 31 ++ src/objects.cc | 213 +++++++++++-- src/objects.h | 321 +++++++++++++++++++- src/ppc/lithium-codegen-ppc.cc | 38 ++- src/ppc/lithium-ppc.cc | 9 +- src/ppc/lithium-ppc.h | 8 + src/runtime/runtime-array.cc | 54 +++- src/runtime/runtime-test.cc | 13 +- src/runtime/runtime-typedarray.cc | 37 ++- src/runtime/runtime.h | 12 +- src/x64/lithium-codegen-x64.cc | 34 ++- src/x64/lithium-x64.cc | 15 +- src/x64/lithium-x64.h | 18 +- src/x87/lithium-codegen-x87.cc | 34 ++- src/x87/lithium-x87.cc | 12 +- src/x87/lithium-x87.h | 18 +- test/cctest/compiler/test-run-properties.cc | 18 +- test/cctest/test-api.cc | 36 +-- test/mjsunit/elements-kind.js | 55 +++- test/mjsunit/opt-elements-kind.js | 65 ++-- test/mjsunit/osr-elements-kind.js | 65 ++-- 62 files changed, 1890 insertions(+), 356 deletions(-) diff --git a/include/v8.h b/include/v8.h index 50f0f5fd2..084d41a71 100644 --- a/include/v8.h +++ b/include/v8.h @@ -6946,7 +6946,7 @@ class Internals { static const int kNodeIsIndependentShift = 3; static const int kNodeIsPartiallyDependentShift = 4; - static const int kJSObjectType = 0xb6; + static const int kJSObjectType = 0xbf; static const int kFirstNonstringType = 0x80; static const int kOddballType = 0x83; static const int kForeignType = 0x87; diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc index 49747b775..ad34013a2 100644 --- a/src/arm/lithium-arm.cc +++ b/src/arm/lithium-arm.cc @@ -2240,7 +2240,7 @@ LInstruction* LChunkBuilder::DoLoadKeyed(HLoadKeyed* instr) { LOperand* key = UseRegisterOrConstantAtStart(instr->key()); LInstruction* result = NULL; - if (!instr->is_fixed_typed_array()) { + if (!instr->is_typed_elements()) { LOperand* obj = NULL; if (instr->representation().IsDouble()) { obj = UseRegister(instr->elements()); @@ -2260,9 +2260,10 @@ LInstruction* LChunkBuilder::DoLoadKeyed(HLoadKeyed* instr) { } bool needs_environment; - if (instr->is_fixed_typed_array()) { + if (instr->is_external() || instr->is_fixed_typed_array()) { // see LCodeGen::DoLoadKeyedExternalArray - needs_environment = elements_kind == UINT32_ELEMENTS && + needs_environment = (elements_kind == EXTERNAL_UINT32_ELEMENTS || + elements_kind == UINT32_ELEMENTS) && !instr->CheckFlag(HInstruction::kUint32); } else { // see LCodeGen::DoLoadKeyedFixedDoubleArray and @@ -2297,7 +2298,7 @@ LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) { LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) { - if (!instr->is_fixed_typed_array()) { + if (!instr->is_typed_elements()) { DCHECK(instr->elements()->representation().IsTagged()); bool needs_write_barrier = instr->NeedsWriteBarrier(); LOperand* object = NULL; diff --git a/src/arm/lithium-arm.h b/src/arm/lithium-arm.h index 7f2ab11b2..4eeca332e 100644 --- a/src/arm/lithium-arm.h +++ b/src/arm/lithium-arm.h @@ -1647,9 +1647,15 @@ class LLoadKeyed final : public LTemplateInstruction<1, 2, 0> { ElementsKind elements_kind() const { return hydrogen()->elements_kind(); } + bool is_external() const { + return hydrogen()->is_external(); + } bool is_fixed_typed_array() const { return hydrogen()->is_fixed_typed_array(); } + bool is_typed_elements() const { + return is_external() || is_fixed_typed_array(); + } DECLARE_CONCRETE_INSTRUCTION(LoadKeyed, "load-keyed") DECLARE_HYDROGEN_ACCESSOR(LoadKeyed) @@ -2249,9 +2255,13 @@ class LStoreKeyed final : public LTemplateInstruction<0, 3, 0> { inputs_[2] = value; } + bool is_external() const { return hydrogen()->is_external(); } bool is_fixed_typed_array() const { return hydrogen()->is_fixed_typed_array(); } + bool is_typed_elements() const { + return is_external() || is_fixed_typed_array(); + } LOperand* elements() { return inputs_[0]; } LOperand* key() { return inputs_[1]; } LOperand* value() { return inputs_[2]; } diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc index 5fe81d255..97881ba1a 100644 --- a/src/arm/lithium-codegen-arm.cc +++ b/src/arm/lithium-codegen-arm.cc @@ -3190,13 +3190,17 @@ void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) { ? (element_size_shift - kSmiTagSize) : element_size_shift; int base_offset = instr->base_offset(); - if (elements_kind == FLOAT32_ELEMENTS || elements_kind == FLOAT64_ELEMENTS) { + if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS || + elements_kind == FLOAT32_ELEMENTS || + elements_kind == EXTERNAL_FLOAT64_ELEMENTS || + elements_kind == FLOAT64_ELEMENTS) { DwVfpRegister result = ToDoubleRegister(instr->result()); Operand operand = key_is_constant ? Operand(constant_key << element_size_shift) : Operand(key, LSL, shift_size); __ add(scratch0(), external_pointer, operand); - if (elements_kind == FLOAT32_ELEMENTS) { + if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS || + elements_kind == FLOAT32_ELEMENTS) { __ vldr(double_scratch0().low(), scratch0(), base_offset); __ vcvt_f64_f32(result, double_scratch0().low()); } else { // i.e. elements_kind == EXTERNAL_DOUBLE_ELEMENTS @@ -3208,22 +3212,29 @@ void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) { key, external_pointer, key_is_constant, constant_key, element_size_shift, shift_size, base_offset); switch (elements_kind) { + case EXTERNAL_INT8_ELEMENTS: case INT8_ELEMENTS: __ ldrsb(result, mem_operand); break; + case EXTERNAL_UINT8_CLAMPED_ELEMENTS: + case EXTERNAL_UINT8_ELEMENTS: case UINT8_ELEMENTS: case UINT8_CLAMPED_ELEMENTS: __ ldrb(result, mem_operand); break; + case EXTERNAL_INT16_ELEMENTS: case INT16_ELEMENTS: __ ldrsh(result, mem_operand); break; + case EXTERNAL_UINT16_ELEMENTS: case UINT16_ELEMENTS: __ ldrh(result, mem_operand); break; + case EXTERNAL_INT32_ELEMENTS: case INT32_ELEMENTS: __ ldr(result, mem_operand); break; + case EXTERNAL_UINT32_ELEMENTS: case UINT32_ELEMENTS: __ ldr(result, mem_operand); if (!instr->hydrogen()->CheckFlag(HInstruction::kUint32)) { @@ -3233,6 +3244,8 @@ void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) { break; case FLOAT32_ELEMENTS: case FLOAT64_ELEMENTS: + case EXTERNAL_FLOAT32_ELEMENTS: + case EXTERNAL_FLOAT64_ELEMENTS: case FAST_HOLEY_DOUBLE_ELEMENTS: case FAST_HOLEY_ELEMENTS: case FAST_HOLEY_SMI_ELEMENTS: @@ -3342,7 +3355,7 @@ void LCodeGen::DoLoadKeyedFixedArray(LLoadKeyed* instr) { void LCodeGen::DoLoadKeyed(LLoadKeyed* instr) { - if (instr->is_fixed_typed_array()) { + if (instr->is_typed_elements()) { DoLoadKeyedExternalArray(instr); } else if (instr->hydrogen()->representation().IsDouble()) { DoLoadKeyedFixedDoubleArray(instr); @@ -4304,7 +4317,10 @@ void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) { ? (element_size_shift - kSmiTagSize) : element_size_shift; int base_offset = instr->base_offset(); - if (elements_kind == FLOAT32_ELEMENTS || elements_kind == FLOAT64_ELEMENTS) { + if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS || + elements_kind == FLOAT32_ELEMENTS || + elements_kind == EXTERNAL_FLOAT64_ELEMENTS || + elements_kind == FLOAT64_ELEMENTS) { Register address = scratch0(); DwVfpRegister value(ToDoubleRegister(instr->value())); if (key_is_constant) { @@ -4317,7 +4333,8 @@ void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) { } else { __ add(address, external_pointer, Operand(key, LSL, shift_size)); } - if (elements_kind == FLOAT32_ELEMENTS) { + if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS || + elements_kind == FLOAT32_ELEMENTS) { __ vcvt_f32_f64(double_scratch0().low(), value); __ vstr(double_scratch0().low(), address, base_offset); } else { // Storing doubles, not floats. @@ -4330,21 +4347,30 @@ void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) { element_size_shift, shift_size, base_offset); switch (elements_kind) { + case EXTERNAL_UINT8_CLAMPED_ELEMENTS: + case EXTERNAL_INT8_ELEMENTS: + case EXTERNAL_UINT8_ELEMENTS: case UINT8_ELEMENTS: case UINT8_CLAMPED_ELEMENTS: case INT8_ELEMENTS: __ strb(value, mem_operand); break; + case EXTERNAL_INT16_ELEMENTS: + case EXTERNAL_UINT16_ELEMENTS: case INT16_ELEMENTS: case UINT16_ELEMENTS: __ strh(value, mem_operand); break; + case EXTERNAL_INT32_ELEMENTS: + case EXTERNAL_UINT32_ELEMENTS: case INT32_ELEMENTS: case UINT32_ELEMENTS: __ str(value, mem_operand); break; case FLOAT32_ELEMENTS: case FLOAT64_ELEMENTS: + case EXTERNAL_FLOAT32_ELEMENTS: + case EXTERNAL_FLOAT64_ELEMENTS: case FAST_DOUBLE_ELEMENTS: case FAST_ELEMENTS: case FAST_SMI_ELEMENTS: @@ -4450,7 +4476,7 @@ void LCodeGen::DoStoreKeyedFixedArray(LStoreKeyed* instr) { void LCodeGen::DoStoreKeyed(LStoreKeyed* instr) { // By cases: external, fast double - if (instr->is_fixed_typed_array()) { + if (instr->is_typed_elements()) { DoStoreKeyedExternalArray(instr); } else if (instr->hydrogen()->value()->representation().IsDouble()) { DoStoreKeyedFixedDoubleArray(instr); diff --git a/src/arm64/lithium-arm64.cc b/src/arm64/lithium-arm64.cc index 2c12ce0f1..e1119c2c6 100644 --- a/src/arm64/lithium-arm64.cc +++ b/src/arm64/lithium-arm64.cc @@ -1731,7 +1731,7 @@ LInstruction* LChunkBuilder::DoLoadKeyed(HLoadKeyed* instr) { LOperand* elements = UseRegister(instr->elements()); LOperand* key = UseRegisterOrConstant(instr->key()); - if (!instr->is_fixed_typed_array()) { + if (!instr->is_typed_elements()) { if (instr->representation().IsDouble()) { LOperand* temp = (!instr->key()->IsConstant() || instr->RequiresHoleCheck()) @@ -1765,7 +1765,8 @@ LInstruction* LChunkBuilder::DoLoadKeyed(HLoadKeyed* instr) { LOperand* temp = instr->key()->IsConstant() ? NULL : TempRegister(); LInstruction* result = DefineAsRegister( new(zone()) LLoadKeyedExternal(elements, key, temp)); - if (elements_kind == UINT32_ELEMENTS && + if ((elements_kind == EXTERNAL_UINT32_ELEMENTS || + elements_kind == UINT32_ELEMENTS) && !instr->CheckFlag(HInstruction::kUint32)) { result = AssignEnvironment(result); } @@ -2369,7 +2370,7 @@ LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) { LOperand* elements = NULL; LOperand* val = NULL; - if (!instr->is_fixed_typed_array() && + if (!instr->is_typed_elements() && instr->value()->representation().IsTagged() && instr->NeedsWriteBarrier()) { // RecordWrite() will clobber all registers. @@ -2382,7 +2383,7 @@ LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) { temp = instr->key()->IsConstant() ? NULL : TempRegister(); } - if (instr->is_fixed_typed_array()) { + if (instr->is_typed_elements()) { DCHECK((instr->value()->representation().IsInteger32() && !IsDoubleOrFloatElementsKind(instr->elements_kind())) || (instr->value()->representation().IsDouble() && diff --git a/src/arm64/lithium-codegen-arm64.cc b/src/arm64/lithium-codegen-arm64.cc index 5502e7bea..cac7f92ec 100644 --- a/src/arm64/lithium-codegen-arm64.cc +++ b/src/arm64/lithium-codegen-arm64.cc @@ -3458,33 +3458,42 @@ void LCodeGen::DoLoadKeyedExternal(LLoadKeyedExternal* instr) { elements_kind, instr->base_offset()); - if (elements_kind == FLOAT32_ELEMENTS) { + if ((elements_kind == EXTERNAL_FLOAT32_ELEMENTS) || + (elements_kind == FLOAT32_ELEMENTS)) { DoubleRegister result = ToDoubleRegister(instr->result()); __ Ldr(result.S(), mem_op); __ Fcvt(result, result.S()); - } else if (elements_kind == FLOAT64_ELEMENTS) { + } else if ((elements_kind == EXTERNAL_FLOAT64_ELEMENTS) || + (elements_kind == FLOAT64_ELEMENTS)) { DoubleRegister result = ToDoubleRegister(instr->result()); __ Ldr(result, mem_op); } else { Register result = ToRegister(instr->result()); switch (elements_kind) { + case EXTERNAL_INT8_ELEMENTS: case INT8_ELEMENTS: __ Ldrsb(result, mem_op); break; + case EXTERNAL_UINT8_CLAMPED_ELEMENTS: + case EXTERNAL_UINT8_ELEMENTS: case UINT8_ELEMENTS: case UINT8_CLAMPED_ELEMENTS: __ Ldrb(result, mem_op); break; + case EXTERNAL_INT16_ELEMENTS: case INT16_ELEMENTS: __ Ldrsh(result, mem_op); break; + case EXTERNAL_UINT16_ELEMENTS: case UINT16_ELEMENTS: __ Ldrh(result, mem_op); break; + case EXTERNAL_INT32_ELEMENTS: case INT32_ELEMENTS: __ Ldrsw(result, mem_op); break; + case EXTERNAL_UINT32_ELEMENTS: case UINT32_ELEMENTS: __ Ldr(result.W(), mem_op); if (!instr->hydrogen()->CheckFlag(HInstruction::kUint32)) { @@ -3495,6 +3504,8 @@ void LCodeGen::DoLoadKeyedExternal(LLoadKeyedExternal* instr) { break; case FLOAT32_ELEMENTS: case FLOAT64_ELEMENTS: + case EXTERNAL_FLOAT32_ELEMENTS: + case EXTERNAL_FLOAT64_ELEMENTS: case FAST_HOLEY_DOUBLE_ELEMENTS: case FAST_HOLEY_ELEMENTS: case FAST_HOLEY_SMI_ELEMENTS: @@ -5169,33 +5180,44 @@ void LCodeGen::DoStoreKeyedExternal(LStoreKeyedExternal* instr) { elements_kind, instr->base_offset()); - if (elements_kind == FLOAT32_ELEMENTS) { + if ((elements_kind == EXTERNAL_FLOAT32_ELEMENTS) || + (elements_kind == FLOAT32_ELEMENTS)) { DoubleRegister value = ToDoubleRegister(instr->value()); DoubleRegister dbl_scratch = double_scratch(); __ Fcvt(dbl_scratch.S(), value); __ Str(dbl_scratch.S(), dst); - } else if (elements_kind == FLOAT64_ELEMENTS) { + } else if ((elements_kind == EXTERNAL_FLOAT64_ELEMENTS) || + (elements_kind == FLOAT64_ELEMENTS)) { DoubleRegister value = ToDoubleRegister(instr->value()); __ Str(value, dst); } else { Register value = ToRegister(instr->value()); switch (elements_kind) { + case EXTERNAL_UINT8_CLAMPED_ELEMENTS: + case EXTERNAL_INT8_ELEMENTS: + case EXTERNAL_UINT8_ELEMENTS: case UINT8_ELEMENTS: case UINT8_CLAMPED_ELEMENTS: case INT8_ELEMENTS: __ Strb(value, dst); break; + case EXTERNAL_INT16_ELEMENTS: + case EXTERNAL_UINT16_ELEMENTS: case INT16_ELEMENTS: case UINT16_ELEMENTS: __ Strh(value, dst); break; + case EXTERNAL_INT32_ELEMENTS: + case EXTERNAL_UINT32_ELEMENTS: case INT32_ELEMENTS: case UINT32_ELEMENTS: __ Str(value.W(), dst); break; case FLOAT32_ELEMENTS: case FLOAT64_ELEMENTS: + case EXTERNAL_FLOAT32_ELEMENTS: + case EXTERNAL_FLOAT64_ELEMENTS: case FAST_DOUBLE_ELEMENTS: case FAST_ELEMENTS: case FAST_SMI_ELEMENTS: diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc index 561f7e094..71b61e6b5 100644 --- a/src/bootstrapper.cc +++ b/src/bootstrapper.cc @@ -235,8 +235,11 @@ class Genesis BASE_EMBEDDED { ElementsKind elements_kind); bool InstallNatives(ContextType context_type); - void InstallTypedArray(const char* name, ElementsKind elements_kind, - Handle* fun); + void InstallTypedArray( + const char* name, + ElementsKind elements_kind, + Handle* fun, + Handle* external_map); bool InstallExperimentalNatives(); bool InstallExtraNatives(); void InstallBuiltinFunctionIds(); @@ -1281,12 +1284,17 @@ void Genesis::InitializeGlobal(Handle global_object, } { // -- T y p e d A r r a y s -#define INSTALL_TYPED_ARRAY(Type, type, TYPE, ctype, size) \ - { \ - Handle fun; \ - InstallTypedArray(#Type "Array", TYPE##_ELEMENTS, &fun); \ - native_context()->set_##type##_array_fun(*fun); \ - } +#define INSTALL_TYPED_ARRAY(Type, type, TYPE, ctype, size) \ + { \ + Handle fun; \ + Handle external_map; \ + InstallTypedArray(#Type "Array", \ + TYPE##_ELEMENTS, \ + &fun, \ + &external_map); \ + native_context()->set_##type##_array_fun(*fun); \ + native_context()->set_##type##_array_external_map(*external_map); \ + } TYPED_ARRAYS(INSTALL_TYPED_ARRAY) #undef INSTALL_TYPED_ARRAY @@ -1497,8 +1505,11 @@ void Genesis::InitializeGlobal(Handle global_object, } -void Genesis::InstallTypedArray(const char* name, ElementsKind elements_kind, - Handle* fun) { +void Genesis::InstallTypedArray( + const char* name, + ElementsKind elements_kind, + Handle* fun, + Handle* external_map) { Handle global = Handle(native_context()->global_object()); Handle result = InstallFunction( global, name, JS_TYPED_ARRAY_TYPE, JSTypedArray::kSize, @@ -1511,6 +1522,9 @@ void Genesis::InstallTypedArray(const char* name, ElementsKind elements_kind, JSFunction::SetInitialMap(result, initial_map, handle(initial_map->prototype(), isolate())); *fun = result; + + ElementsKind external_kind = GetNextTransitionElementsKind(elements_kind); + *external_map = Map::AsElementsKind(initial_map, external_kind); } diff --git a/src/code-stubs-hydrogen.cc b/src/code-stubs-hydrogen.cc index fb46633f0..d5addc036 100644 --- a/src/code-stubs-hydrogen.cc +++ b/src/code-stubs-hydrogen.cc @@ -1987,6 +1987,13 @@ class CodeStubGraphBuilder HValue* bit_field2, ElementsKind kind); + void BuildExternalElementLoad(HGraphBuilder::IfBuilder* if_builder, + HValue* receiver, + HValue* key, + HValue* instance_type, + HValue* bit_field2, + ElementsKind kind); + KeyedLoadGenericStub* casted_stub() { return static_cast(stub()); } @@ -2008,6 +2015,8 @@ void CodeStubGraphBuilder::BuildElementsKindLimitCheck( void CodeStubGraphBuilder::BuildFastElementLoad( HGraphBuilder::IfBuilder* if_builder, HValue* receiver, HValue* key, HValue* instance_type, HValue* bit_field2, ElementsKind kind) { + DCHECK(!IsExternalArrayElementsKind(kind)); + BuildElementsKindLimitCheck(if_builder, bit_field2, kind); IfBuilder js_array_check(this); @@ -2027,6 +2036,20 @@ void CodeStubGraphBuilder::BuildFastElementLoad( } +void CodeStubGraphBuilder::BuildExternalElementLoad( + HGraphBuilder::IfBuilder* if_builder, HValue* receiver, HValue* key, + HValue* instance_type, HValue* bit_field2, ElementsKind kind) { + DCHECK(IsExternalArrayElementsKind(kind)); + + BuildElementsKindLimitCheck(if_builder, bit_field2, kind); + + Push(BuildUncheckedMonomorphicElementAccess(receiver, key, NULL, + false, kind, + LOAD, NEVER_RETURN_HOLE, + STANDARD_STORE)); +} + + HValue* CodeStubGraphBuilder::BuildCodeStub() { HValue* receiver = GetParameter(LoadDescriptor::kReceiverIndex); HValue* key = GetParameter(LoadDescriptor::kNameIndex); @@ -2088,6 +2111,42 @@ HValue* CodeStubGraphBuilder::BuildCodeStub() { Deoptimizer::EAGER); Push(graph()->GetConstant0()); + kind_if.Else(); + BuildExternalElementLoad(&kind_if, receiver, key, instance_type, bit_field2, + EXTERNAL_INT8_ELEMENTS); + + kind_if.Else(); + BuildExternalElementLoad(&kind_if, receiver, key, instance_type, bit_field2, + EXTERNAL_UINT8_ELEMENTS); + + kind_if.Else(); + BuildExternalElementLoad(&kind_if, receiver, key, instance_type, bit_field2, + EXTERNAL_INT16_ELEMENTS); + + kind_if.Else(); + BuildExternalElementLoad(&kind_if, receiver, key, instance_type, bit_field2, + EXTERNAL_UINT16_ELEMENTS); + + kind_if.Else(); + BuildExternalElementLoad(&kind_if, receiver, key, instance_type, bit_field2, + EXTERNAL_INT32_ELEMENTS); + + kind_if.Else(); + BuildExternalElementLoad(&kind_if, receiver, key, instance_type, bit_field2, + EXTERNAL_UINT32_ELEMENTS); + + kind_if.Else(); + BuildExternalElementLoad(&kind_if, receiver, key, instance_type, bit_field2, + EXTERNAL_FLOAT32_ELEMENTS); + + kind_if.Else(); + BuildExternalElementLoad(&kind_if, receiver, key, instance_type, bit_field2, + EXTERNAL_FLOAT64_ELEMENTS); + + kind_if.Else(); + BuildExternalElementLoad(&kind_if, receiver, key, instance_type, bit_field2, + EXTERNAL_UINT8_CLAMPED_ELEMENTS); + kind_if.ElseDeopt( Deoptimizer::kElementsKindUnhandledInKeyedLoadGenericStub); @@ -2175,7 +2234,7 @@ HValue* CodeStubGraphBuilder::BuildCodeStub() { index->ClearFlag(HValue::kCanOverflow); HValue* property_index = Add(cache_field_offsets, index, nullptr, - INT32_ELEMENTS, NEVER_RETURN_HOLE, 0); + EXTERNAL_INT32_ELEMENTS, NEVER_RETURN_HOLE, 0); Push(property_index); } lookup_if->Else(); diff --git a/src/code-stubs.cc b/src/code-stubs.cc index ee57db741..877da682f 100644 --- a/src/code-stubs.cc +++ b/src/code-stubs.cc @@ -807,6 +807,7 @@ void StoreElementStub::Generate(MacroAssembler* masm) { case FAST_DOUBLE_ELEMENTS: case FAST_HOLEY_DOUBLE_ELEMENTS: #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ + case EXTERNAL_##TYPE##_ELEMENTS: \ case TYPE##_ELEMENTS: TYPED_ARRAYS(TYPED_ARRAY_CASE) diff --git a/src/compiler/access-builder.cc b/src/compiler/access-builder.cc index b54982f4c..247016347 100644 --- a/src/compiler/access-builder.cc +++ b/src/compiler/access-builder.cc @@ -80,6 +80,14 @@ FieldAccess AccessBuilder::ForFixedArrayLength() { } +// static +FieldAccess AccessBuilder::ForExternalArrayPointer() { + FieldAccess access = {kTaggedBase, ExternalArray::kExternalPointerOffset, + MaybeHandle(), Type::UntaggedPointer(), kMachPtr}; + return access; +} + + // static FieldAccess AccessBuilder::ForDescriptorArrayEnumCache() { FieldAccess access = {kTaggedBase, DescriptorArray::kEnumCacheOffset, diff --git a/src/compiler/access-builder.h b/src/compiler/access-builder.h index 95be3e0dd..240ffdcb5 100644 --- a/src/compiler/access-builder.h +++ b/src/compiler/access-builder.h @@ -43,6 +43,9 @@ class AccessBuilder final : public AllStatic { // Provides access to FixedArray::length() field. static FieldAccess ForFixedArrayLength(); + // Provides access to ExternalArray::external_pointer() field. + static FieldAccess ForExternalArrayPointer(); + // Provides access to DescriptorArray::enum_cache() field. static FieldAccess ForDescriptorArrayEnumCache(); diff --git a/src/compiler/js-typed-lowering.cc b/src/compiler/js-typed-lowering.cc index 628e7e07b..ea1b4644f 100644 --- a/src/compiler/js-typed-lowering.cc +++ b/src/compiler/js-typed-lowering.cc @@ -832,10 +832,11 @@ Reduction JSTypedLowering::ReduceJSLoadProperty(Node* node) { size_t const k = ElementSizeLog2Of(access.machine_type()); double const byte_length = array->byte_length()->Number(); CHECK_LT(k, arraysize(shifted_int32_ranges_)); - if (key_type->Is(shifted_int32_ranges_[k]) && byte_length <= kMaxInt) { + if (IsExternalArrayElementsKind(array->map()->elements_kind()) && + key_type->Is(shifted_int32_ranges_[k]) && byte_length <= kMaxInt) { // JSLoadProperty(typed-array, int32) - Handle elements = - Handle::cast(handle(array->elements())); + Handle elements = + Handle::cast(handle(array->elements())); Node* buffer = jsgraph()->PointerConstant(elements->external_pointer()); Node* length = jsgraph()->Constant(byte_length); Node* effect = NodeProperties::GetEffectInput(node); @@ -878,11 +879,12 @@ Reduction JSTypedLowering::ReduceJSStoreProperty(Node* node) { size_t const k = ElementSizeLog2Of(access.machine_type()); double const byte_length = array->byte_length()->Number(); CHECK_LT(k, arraysize(shifted_int32_ranges_)); - if (access.external_array_type() != kExternalUint8ClampedArray && + if (IsExternalArrayElementsKind(array->map()->elements_kind()) && + access.external_array_type() != kExternalUint8ClampedArray && key_type->Is(shifted_int32_ranges_[k]) && byte_length <= kMaxInt) { // JSLoadProperty(typed-array, int32) - Handle elements = - Handle::cast(handle(array->elements())); + Handle elements = + Handle::cast(handle(array->elements())); Node* buffer = jsgraph()->PointerConstant(elements->external_pointer()); Node* length = jsgraph()->Constant(byte_length); Node* context = NodeProperties::GetContextInput(node); diff --git a/src/contexts.h b/src/contexts.h index 37fc31565..fc2983194 100644 --- a/src/contexts.h +++ b/src/contexts.h @@ -115,6 +115,16 @@ enum BindingFlags { V(FLOAT32_ARRAY_FUN_INDEX, JSFunction, float32_array_fun) \ V(FLOAT64_ARRAY_FUN_INDEX, JSFunction, float64_array_fun) \ V(UINT8_CLAMPED_ARRAY_FUN_INDEX, JSFunction, uint8_clamped_array_fun) \ + V(INT8_ARRAY_EXTERNAL_MAP_INDEX, Map, int8_array_external_map) \ + V(UINT8_ARRAY_EXTERNAL_MAP_INDEX, Map, uint8_array_external_map) \ + V(INT16_ARRAY_EXTERNAL_MAP_INDEX, Map, int16_array_external_map) \ + V(UINT16_ARRAY_EXTERNAL_MAP_INDEX, Map, uint16_array_external_map) \ + V(INT32_ARRAY_EXTERNAL_MAP_INDEX, Map, int32_array_external_map) \ + V(UINT32_ARRAY_EXTERNAL_MAP_INDEX, Map, uint32_array_external_map) \ + V(FLOAT32_ARRAY_EXTERNAL_MAP_INDEX, Map, float32_array_external_map) \ + V(FLOAT64_ARRAY_EXTERNAL_MAP_INDEX, Map, float64_array_external_map) \ + V(UINT8_CLAMPED_ARRAY_EXTERNAL_MAP_INDEX, Map, \ + uint8_clamped_array_external_map) \ V(DATA_VIEW_FUN_INDEX, JSFunction, data_view_fun) \ V(SLOPPY_FUNCTION_MAP_INDEX, Map, sloppy_function_map) \ V(SLOPPY_FUNCTION_WITH_READONLY_PROTOTYPE_MAP_INDEX, Map, \ diff --git a/src/elements-kind.cc b/src/elements-kind.cc index 0d29c3047..07d2837bd 100644 --- a/src/elements-kind.cc +++ b/src/elements-kind.cc @@ -15,17 +15,26 @@ namespace internal { int ElementsKindToShiftSize(ElementsKind elements_kind) { switch (elements_kind) { + case EXTERNAL_INT8_ELEMENTS: + case EXTERNAL_UINT8_CLAMPED_ELEMENTS: + case EXTERNAL_UINT8_ELEMENTS: case UINT8_ELEMENTS: case INT8_ELEMENTS: case UINT8_CLAMPED_ELEMENTS: return 0; + case EXTERNAL_INT16_ELEMENTS: + case EXTERNAL_UINT16_ELEMENTS: case UINT16_ELEMENTS: case INT16_ELEMENTS: return 1; + case EXTERNAL_INT32_ELEMENTS: + case EXTERNAL_UINT32_ELEMENTS: + case EXTERNAL_FLOAT32_ELEMENTS: case UINT32_ELEMENTS: case INT32_ELEMENTS: case FLOAT32_ELEMENTS: return 2; + case EXTERNAL_FLOAT64_ELEMENTS: case FAST_DOUBLE_ELEMENTS: case FAST_HOLEY_DOUBLE_ELEMENTS: case FLOAT64_ELEMENTS: @@ -44,10 +53,16 @@ int ElementsKindToShiftSize(ElementsKind elements_kind) { } +static bool IsTypedArrayElementsKind(ElementsKind elements_kind) { + return IsFixedTypedArrayElementsKind(elements_kind) || + IsExternalArrayElementsKind(elements_kind); +} + + int GetDefaultHeaderSizeForElementsKind(ElementsKind elements_kind) { STATIC_ASSERT(FixedArray::kHeaderSize == FixedDoubleArray::kHeaderSize); - if (IsFixedTypedArrayElementsKind(elements_kind)) { + if (IsTypedArrayElementsKind(elements_kind)) { return 0; } else { return FixedArray::kHeaderSize - kHeapObjectTag; @@ -110,8 +125,17 @@ int GetSequenceIndexFromFastElementsKind(ElementsKind elements_kind) { ElementsKind GetNextTransitionElementsKind(ElementsKind kind) { - int index = GetSequenceIndexFromFastElementsKind(kind); - return GetFastElementsKindFromSequenceIndex(index + 1); + switch (kind) { +#define FIXED_TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ + case TYPE##_ELEMENTS: return EXTERNAL_##TYPE##_ELEMENTS; + + TYPED_ARRAYS(FIXED_TYPED_ARRAY_CASE) +#undef FIXED_TYPED_ARRAY_CASE + default: { + int index = GetSequenceIndexFromFastElementsKind(kind); + return GetFastElementsKindFromSequenceIndex(index + 1); + } + } } @@ -122,9 +146,18 @@ static inline bool IsFastTransitionTarget(ElementsKind elements_kind) { bool IsMoreGeneralElementsKindTransition(ElementsKind from_kind, ElementsKind to_kind) { - if (IsFixedTypedArrayElementsKind(from_kind) || - IsFixedTypedArrayElementsKind(to_kind)) { - return false; + if (IsTypedArrayElementsKind(from_kind) || + IsTypedArrayElementsKind(to_kind)) { + switch (from_kind) { +#define FIXED_TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ + case TYPE##_ELEMENTS: \ + return to_kind == EXTERNAL_##TYPE##_ELEMENTS; + + TYPED_ARRAYS(FIXED_TYPED_ARRAY_CASE); +#undef FIXED_TYPED_ARRAY_CASE + default: + return false; + } } if (IsFastElementsKind(from_kind) && IsFastTransitionTarget(to_kind)) { switch (from_kind) { diff --git a/src/elements-kind.h b/src/elements-kind.h index 0254a4fb5..c3184b938 100644 --- a/src/elements-kind.h +++ b/src/elements-kind.h @@ -33,6 +33,17 @@ enum ElementsKind { FAST_SLOPPY_ARGUMENTS_ELEMENTS, SLOW_SLOPPY_ARGUMENTS_ELEMENTS, + // The "fast" kind for external arrays + EXTERNAL_INT8_ELEMENTS, + EXTERNAL_UINT8_ELEMENTS, + EXTERNAL_INT16_ELEMENTS, + EXTERNAL_UINT16_ELEMENTS, + EXTERNAL_INT32_ELEMENTS, + EXTERNAL_UINT32_ELEMENTS, + EXTERNAL_FLOAT32_ELEMENTS, + EXTERNAL_FLOAT64_ELEMENTS, + EXTERNAL_UINT8_CLAMPED_ELEMENTS, + // Fixed typed arrays UINT8_ELEMENTS, INT8_ELEMENTS, @@ -49,6 +60,8 @@ enum ElementsKind { LAST_ELEMENTS_KIND = UINT8_CLAMPED_ELEMENTS, FIRST_FAST_ELEMENTS_KIND = FAST_SMI_ELEMENTS, LAST_FAST_ELEMENTS_KIND = FAST_HOLEY_DOUBLE_ELEMENTS, + FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND = EXTERNAL_INT8_ELEMENTS, + LAST_EXTERNAL_ARRAY_ELEMENTS_KIND = EXTERNAL_UINT8_CLAMPED_ELEMENTS, FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND = UINT8_ELEMENTS, LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND = UINT8_CLAMPED_ELEMENTS, TERMINAL_FAST_ELEMENTS_KIND = FAST_HOLEY_ELEMENTS @@ -84,15 +97,21 @@ inline bool IsSloppyArgumentsElements(ElementsKind kind) { } -inline bool IsFixedTypedArrayElementsKind(ElementsKind kind) { - return kind >= FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND && - kind <= LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND; +inline bool IsExternalArrayElementsKind(ElementsKind kind) { + return kind >= FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND && + kind <= LAST_EXTERNAL_ARRAY_ELEMENTS_KIND; } inline bool IsTerminalElementsKind(ElementsKind kind) { return kind == TERMINAL_FAST_ELEMENTS_KIND || - IsFixedTypedArrayElementsKind(kind); + IsExternalArrayElementsKind(kind); +} + + +inline bool IsFixedTypedArrayElementsKind(ElementsKind kind) { + return kind >= FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND && + kind <= LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND; } @@ -114,13 +133,21 @@ inline bool IsFastDoubleElementsKind(ElementsKind kind) { } +inline bool IsExternalFloatOrDoubleElementsKind(ElementsKind kind) { + return kind == EXTERNAL_FLOAT64_ELEMENTS || + kind == EXTERNAL_FLOAT32_ELEMENTS; +} + + inline bool IsFixedFloatElementsKind(ElementsKind kind) { return kind == FLOAT32_ELEMENTS || kind == FLOAT64_ELEMENTS; } inline bool IsDoubleOrFloatElementsKind(ElementsKind kind) { - return IsFastDoubleElementsKind(kind) || IsFixedFloatElementsKind(kind); + return IsFastDoubleElementsKind(kind) || + IsExternalFloatOrDoubleElementsKind(kind) || + IsFixedFloatElementsKind(kind); } diff --git a/src/elements.cc b/src/elements.cc index 7ef13b30d..d1ddc8dc4 100644 --- a/src/elements.cc +++ b/src/elements.cc @@ -27,6 +27,15 @@ // - FastPackedDoubleElementsAccessor // - FastHoleyDoubleElementsAccessor // - TypedElementsAccessor: template, with instantiations: +// - ExternalInt8ElementsAccessor +// - ExternalUint8ElementsAccessor +// - ExternalInt16ElementsAccessor +// - ExternalUint16ElementsAccessor +// - ExternalInt32ElementsAccessor +// - ExternalUint32ElementsAccessor +// - ExternalFloat32ElementsAccessor +// - ExternalFloat64ElementsAccessor +// - ExternalUint8ClampedElementsAccessor // - FixedUint8ElementsAccessor // - FixedInt8ElementsAccessor // - FixedUint16ElementsAccessor @@ -70,6 +79,23 @@ static const int kPackedSizeNotKnown = -1; FixedArray) \ V(SlowSloppyArgumentsElementsAccessor, SLOW_SLOPPY_ARGUMENTS_ELEMENTS, \ FixedArray) \ + V(ExternalInt8ElementsAccessor, EXTERNAL_INT8_ELEMENTS, ExternalInt8Array) \ + V(ExternalUint8ElementsAccessor, EXTERNAL_UINT8_ELEMENTS, \ + ExternalUint8Array) \ + V(ExternalInt16ElementsAccessor, EXTERNAL_INT16_ELEMENTS, \ + ExternalInt16Array) \ + V(ExternalUint16ElementsAccessor, EXTERNAL_UINT16_ELEMENTS, \ + ExternalUint16Array) \ + V(ExternalInt32ElementsAccessor, EXTERNAL_INT32_ELEMENTS, \ + ExternalInt32Array) \ + V(ExternalUint32ElementsAccessor, EXTERNAL_UINT32_ELEMENTS, \ + ExternalUint32Array) \ + V(ExternalFloat32ElementsAccessor, EXTERNAL_FLOAT32_ELEMENTS, \ + ExternalFloat32Array) \ + V(ExternalFloat64ElementsAccessor, EXTERNAL_FLOAT64_ELEMENTS, \ + ExternalFloat64Array) \ + V(ExternalUint8ClampedElementsAccessor, EXTERNAL_UINT8_CLAMPED_ELEMENTS, \ + ExternalUint8ClampedArray) \ V(FixedUint8ElementsAccessor, UINT8_ELEMENTS, FixedUint8Array) \ V(FixedInt8ElementsAccessor, INT8_ELEMENTS, FixedInt8Array) \ V(FixedUint16ElementsAccessor, UINT16_ELEMENTS, FixedUint16Array) \ @@ -1192,6 +1218,7 @@ class FastSmiOrObjectElementsAccessor case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: UNREACHABLE(); #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ + case EXTERNAL_##TYPE##_ELEMENTS: \ case TYPE##_ELEMENTS: \ UNREACHABLE(); TYPED_ARRAYS(TYPED_ARRAY_CASE) @@ -1288,6 +1315,7 @@ class FastDoubleElementsAccessor UNREACHABLE(); #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ + case EXTERNAL_##TYPE##_ELEMENTS: \ case TYPE##_ELEMENTS: \ UNREACHABLE(); TYPED_ARRAYS(TYPED_ARRAY_CASE) @@ -1378,6 +1406,13 @@ class TypedElementsAccessor +#define EXTERNAL_ELEMENTS_ACCESSOR(Type, type, TYPE, ctype, size) \ + typedef TypedElementsAccessor \ + External##Type##ElementsAccessor; + +TYPED_ARRAYS(EXTERNAL_ELEMENTS_ACCESSOR) +#undef EXTERNAL_ELEMENTS_ACCESSOR + #define FIXED_ELEMENTS_ACCESSOR(Type, type, TYPE, ctype, size) \ typedef TypedElementsAccessor \ Fixed##Type##ElementsAccessor; diff --git a/src/factory.cc b/src/factory.cc index 1d594d3eb..e2a5e0569 100644 --- a/src/factory.cc +++ b/src/factory.cc @@ -883,14 +883,18 @@ Handle Factory::NewBytecodeArray(int length, } -Handle Factory::NewFixedTypedArrayWithExternalPointer( - int length, ExternalArrayType array_type, void* external_pointer, - PretenureFlag pretenure) { +Handle Factory::NewExternalArray(int length, + ExternalArrayType array_type, + void* external_pointer, + PretenureFlag pretenure) { DCHECK(0 <= length && length <= Smi::kMaxValue); CALL_HEAP_FUNCTION( - isolate(), isolate()->heap()->AllocateFixedTypedArrayWithExternalPointer( - length, array_type, external_pointer, pretenure), - FixedTypedArrayBase); + isolate(), + isolate()->heap()->AllocateExternalArray(length, + array_type, + external_pointer, + pretenure), + ExternalArray); } @@ -1761,11 +1765,11 @@ ElementsKind GetExternalArrayElementsKind(ExternalArrayType type) { switch (type) { #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ case kExternal##Type##Array: \ - return TYPE##_ELEMENTS; + return EXTERNAL_##TYPE##_ELEMENTS; TYPED_ARRAYS(TYPED_ARRAY_CASE) } UNREACHABLE(); - return FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND; + return FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND; #undef TYPED_ARRAY_CASE } @@ -1907,7 +1911,7 @@ Handle Factory::NewJSTypedArray(ExternalArrayType type, Handle length_object = NewNumberFromSize(length); obj->set_length(*length_object); - Handle elements = NewFixedTypedArrayWithExternalPointer( + Handle elements = NewExternalArray( static_cast(length), type, static_cast(buffer->backing_store()) + byte_offset); Handle map = JSObject::GetElementsTransitionMap(obj, elements_kind); diff --git a/src/factory.h b/src/factory.h index 9d42130ee..1253779a1 100644 --- a/src/factory.h +++ b/src/factory.h @@ -286,8 +286,10 @@ class Factory final { Handle NewBytecodeArray(int length, const byte* raw_bytecodes, int frame_size); - Handle NewFixedTypedArrayWithExternalPointer( - int length, ExternalArrayType array_type, void* external_pointer, + Handle NewExternalArray( + int length, + ExternalArrayType array_type, + void* external_pointer, PretenureFlag pretenure = NOT_TENURED); Handle NewFixedTypedArray( diff --git a/src/heap-snapshot-generator.cc b/src/heap-snapshot-generator.cc index 34936fb8e..63916a268 100644 --- a/src/heap-snapshot-generator.cc +++ b/src/heap-snapshot-generator.cc @@ -856,8 +856,10 @@ HeapEntry* V8HeapExplorer::AddEntry(HeapObject* object) { return AddEntry(object, HeapEntry::kHidden, "system / NativeContext"); } else if (object->IsContext()) { return AddEntry(object, HeapEntry::kObject, "system / Context"); - } else if (object->IsFixedArray() || object->IsFixedDoubleArray() || - object->IsByteArray()) { + } else if (object->IsFixedArray() || + object->IsFixedDoubleArray() || + object->IsByteArray() || + object->IsExternalArray()) { return AddEntry(object, HeapEntry::kArray, ""); } else if (object->IsHeapNumber()) { return AddEntry(object, HeapEntry::kHeapNumber, "number"); diff --git a/src/heap/heap.cc b/src/heap/heap.cc index b75c6f7bc..80b28d195 100644 --- a/src/heap/heap.cc +++ b/src/heap/heap.cc @@ -2500,8 +2500,7 @@ class ScavengingVisitor : public StaticVisitorBase { DCHECK(map_word.IsForwardingAddress()); FixedTypedArrayBase* target = reinterpret_cast(map_word.ToForwardingAddress()); - if (target->base_pointer() != Smi::FromInt(0)) - target->set_base_pointer(target, SKIP_WRITE_BARRIER); + target->set_base_pointer(target, SKIP_WRITE_BARRIER); } @@ -2514,8 +2513,7 @@ class ScavengingVisitor : public StaticVisitorBase { DCHECK(map_word.IsForwardingAddress()); FixedTypedArrayBase* target = reinterpret_cast(map_word.ToForwardingAddress()); - if (target->base_pointer() != Smi::FromInt(0)) - target->set_base_pointer(target, SKIP_WRITE_BARRIER); + target->set_base_pointer(target, SKIP_WRITE_BARRIER); } @@ -3006,6 +3004,13 @@ bool Heap::CreateInitialMaps() { ALLOCATE_VARSIZE_MAP(BYTECODE_ARRAY_TYPE, bytecode_array) ALLOCATE_VARSIZE_MAP(FREE_SPACE_TYPE, free_space) +#define ALLOCATE_EXTERNAL_ARRAY_MAP(Type, type, TYPE, ctype, size) \ + ALLOCATE_MAP(EXTERNAL_##TYPE##_ARRAY_TYPE, ExternalArray::kSize, \ + external_##type##_array) + + TYPED_ARRAYS(ALLOCATE_EXTERNAL_ARRAY_MAP) +#undef ALLOCATE_EXTERNAL_ARRAY_MAP + #define ALLOCATE_FIXED_TYPED_ARRAY_MAP(Type, type, TYPE, ctype, size) \ ALLOCATE_VARSIZE_MAP(FIXED_##TYPE##_ARRAY_TYPE, fixed_##type##_array) @@ -3071,6 +3076,17 @@ bool Heap::CreateInitialMaps() { set_empty_bytecode_array(bytecode_array); } +#define ALLOCATE_EMPTY_EXTERNAL_ARRAY(Type, type, TYPE, ctype, size) \ + { \ + ExternalArray* obj; \ + if (!AllocateEmptyExternalArray(kExternal##Type##Array).To(&obj)) \ + return false; \ + set_empty_external_##type##_array(obj); \ + } + + TYPED_ARRAYS(ALLOCATE_EMPTY_EXTERNAL_ARRAY) +#undef ALLOCATE_EMPTY_EXTERNAL_ARRAY + #define ALLOCATE_EMPTY_FIXED_TYPED_ARRAY(Type, type, TYPE, ctype, size) \ { \ FixedTypedArrayBase* obj; \ @@ -3686,6 +3702,27 @@ void Heap::AddAllocationSiteToScratchpad(AllocationSite* site, } +Map* Heap::MapForExternalArrayType(ExternalArrayType array_type) { + return Map::cast(roots_[RootIndexForExternalArrayType(array_type)]); +} + + +Heap::RootListIndex Heap::RootIndexForExternalArrayType( + ExternalArrayType array_type) { + switch (array_type) { +#define ARRAY_TYPE_TO_ROOT_INDEX(Type, type, TYPE, ctype, size) \ + case kExternal##Type##Array: \ + return kExternal##Type##ArrayMapRootIndex; + + TYPED_ARRAYS(ARRAY_TYPE_TO_ROOT_INDEX) +#undef ARRAY_TYPE_TO_ROOT_INDEX + + default: + UNREACHABLE(); + return kUndefinedValueRootIndex; + } +} + Map* Heap::MapForFixedTypedArray(ExternalArrayType array_type) { return Map::cast(roots_[RootIndexForFixedTypedArray(array_type)]); @@ -3709,6 +3746,23 @@ Heap::RootListIndex Heap::RootIndexForFixedTypedArray( } +Heap::RootListIndex Heap::RootIndexForEmptyExternalArray( + ElementsKind elementsKind) { + switch (elementsKind) { +#define ELEMENT_KIND_TO_ROOT_INDEX(Type, type, TYPE, ctype, size) \ + case EXTERNAL_##TYPE##_ELEMENTS: \ + return kEmptyExternal##Type##ArrayRootIndex; + + TYPED_ARRAYS(ELEMENT_KIND_TO_ROOT_INDEX) +#undef ELEMENT_KIND_TO_ROOT_INDEX + + default: + UNREACHABLE(); + return kUndefinedValueRootIndex; + } +} + + Heap::RootListIndex Heap::RootIndexForEmptyFixedTypedArray( ElementsKind elementsKind) { switch (elementsKind) { @@ -3725,6 +3779,12 @@ Heap::RootListIndex Heap::RootIndexForEmptyFixedTypedArray( } +ExternalArray* Heap::EmptyExternalArrayForMap(Map* map) { + return ExternalArray::cast( + roots_[RootIndexForEmptyExternalArray(map->elements_kind())]); +} + + FixedTypedArrayBase* Heap::EmptyFixedTypedArrayForMap(Map* map) { return FixedTypedArrayBase::cast( roots_[RootIndexForEmptyFixedTypedArray(map->elements_kind())]); @@ -3945,10 +4005,11 @@ void Heap::RightTrimFixedArray(FixedArrayBase* object, int elements_to_trim) { } -AllocationResult Heap::AllocateFixedTypedArrayWithExternalPointer( - int length, ExternalArrayType array_type, void* external_pointer, - PretenureFlag pretenure) { - int size = FixedTypedArrayBase::kHeaderSize; +AllocationResult Heap::AllocateExternalArray(int length, + ExternalArrayType array_type, + void* external_pointer, + PretenureFlag pretenure) { + int size = ExternalArray::kSize; AllocationSpace space = SelectSpace(size, pretenure); HeapObject* result; { @@ -3956,12 +4017,10 @@ AllocationResult Heap::AllocateFixedTypedArrayWithExternalPointer( if (!allocation.To(&result)) return allocation; } - result->set_map_no_write_barrier(MapForFixedTypedArray(array_type)); - FixedTypedArrayBase* elements = FixedTypedArrayBase::cast(result); - elements->set_base_pointer(Smi::FromInt(0), SKIP_WRITE_BARRIER); - elements->set_external_pointer(external_pointer, SKIP_WRITE_BARRIER); - elements->set_length(length); - return elements; + result->set_map_no_write_barrier(MapForExternalArrayType(array_type)); + ExternalArray::cast(result)->set_length(length); + ExternalArray::cast(result)->set_external_pointer(external_pointer); + return result; } static void ForFixedTypedArray(ExternalArrayType array_type, int* element_size, @@ -4001,7 +4060,7 @@ AllocationResult Heap::AllocateFixedTypedArray(int length, array_type == kExternalFloat64Array ? kDoubleAligned : kWordAligned); if (!allocation.To(&object)) return allocation; - object->set_map_no_write_barrier(MapForFixedTypedArray(array_type)); + object->set_map(MapForFixedTypedArray(array_type)); FixedTypedArrayBase* elements = FixedTypedArrayBase::cast(object); elements->set_base_pointer(elements, SKIP_WRITE_BARRIER); elements->set_external_pointer( @@ -4216,7 +4275,8 @@ AllocationResult Heap::AllocateJSObjectFromMap( // Initialize the JSObject. InitializeJSObjectFromMap(js_obj, properties, map); - DCHECK(js_obj->HasFastElements() || js_obj->HasFixedTypedArrayElements()); + DCHECK(js_obj->HasFastElements() || js_obj->HasExternalArrayElements() || + js_obj->HasFixedTypedArrayElements()); return js_obj; } @@ -4508,6 +4568,12 @@ AllocationResult Heap::AllocateEmptyFixedArray() { } +AllocationResult Heap::AllocateEmptyExternalArray( + ExternalArrayType array_type) { + return AllocateExternalArray(0, array_type, NULL, TENURED); +} + + AllocationResult Heap::CopyAndTenureFixedCOWArray(FixedArray* src) { if (!InNewSpace(src)) { return src; diff --git a/src/heap/heap.h b/src/heap/heap.h index 15577ee02..edc3d2c8d 100644 --- a/src/heap/heap.h +++ b/src/heap/heap.h @@ -105,6 +105,25 @@ namespace internal { V(Map, short_external_one_byte_internalized_string_map, \ ShortExternalOneByteInternalizedStringMap) \ V(Map, short_external_one_byte_string_map, ShortExternalOneByteStringMap) \ + V(Map, external_int8_array_map, ExternalInt8ArrayMap) \ + V(Map, external_uint8_array_map, ExternalUint8ArrayMap) \ + V(Map, external_int16_array_map, ExternalInt16ArrayMap) \ + V(Map, external_uint16_array_map, ExternalUint16ArrayMap) \ + V(Map, external_int32_array_map, ExternalInt32ArrayMap) \ + V(Map, external_uint32_array_map, ExternalUint32ArrayMap) \ + V(Map, external_float32_array_map, ExternalFloat32ArrayMap) \ + V(Map, external_float64_array_map, ExternalFloat64ArrayMap) \ + V(Map, external_uint8_clamped_array_map, ExternalUint8ClampedArrayMap) \ + V(ExternalArray, empty_external_int8_array, EmptyExternalInt8Array) \ + V(ExternalArray, empty_external_uint8_array, EmptyExternalUint8Array) \ + V(ExternalArray, empty_external_int16_array, EmptyExternalInt16Array) \ + V(ExternalArray, empty_external_uint16_array, EmptyExternalUint16Array) \ + V(ExternalArray, empty_external_int32_array, EmptyExternalInt32Array) \ + V(ExternalArray, empty_external_uint32_array, EmptyExternalUint32Array) \ + V(ExternalArray, empty_external_float32_array, EmptyExternalFloat32Array) \ + V(ExternalArray, empty_external_float64_array, EmptyExternalFloat64Array) \ + V(ExternalArray, empty_external_uint8_clamped_array, \ + EmptyExternalUint8ClampedArray) \ V(Map, fixed_uint8_array_map, FixedUint8ArrayMap) \ V(Map, fixed_int8_array_map, FixedInt8ArrayMap) \ V(Map, fixed_uint16_array_map, FixedUint16ArrayMap) \ @@ -1250,7 +1269,12 @@ class Heap { Map* MapForFixedTypedArray(ExternalArrayType array_type); RootListIndex RootIndexForFixedTypedArray(ExternalArrayType array_type); + Map* MapForExternalArrayType(ExternalArrayType array_type); + RootListIndex RootIndexForExternalArrayType(ExternalArrayType array_type); + + RootListIndex RootIndexForEmptyExternalArray(ElementsKind kind); RootListIndex RootIndexForEmptyFixedTypedArray(ElementsKind kind); + ExternalArray* EmptyExternalArrayForMap(Map* map); FixedTypedArrayBase* EmptyFixedTypedArrayForMap(Map* map); void RecordStats(HeapStats* stats, bool take_snapshot = false); @@ -2022,9 +2046,9 @@ class Heap { MUST_USE_RESULT AllocationResult AllocateSymbol(); // Allocates an external array of the specified length and type. - MUST_USE_RESULT AllocationResult AllocateFixedTypedArrayWithExternalPointer( - int length, ExternalArrayType array_type, void* external_pointer, - PretenureFlag pretenure); + MUST_USE_RESULT AllocationResult + AllocateExternalArray(int length, ExternalArrayType array_type, + void* external_pointer, PretenureFlag pretenure); // Allocates a fixed typed array of the specified length and type. MUST_USE_RESULT AllocationResult @@ -2052,6 +2076,10 @@ class Heap { // Allocate empty fixed array. MUST_USE_RESULT AllocationResult AllocateEmptyFixedArray(); + // Allocate empty external array of given type. + MUST_USE_RESULT AllocationResult + AllocateEmptyExternalArray(ExternalArrayType array_type); + // Allocate empty fixed typed array of given type. MUST_USE_RESULT AllocationResult AllocateEmptyFixedTypedArray(ExternalArrayType array_type); diff --git a/src/heap/objects-visiting.cc b/src/heap/objects-visiting.cc index 70f26a504..8de0da962 100644 --- a/src/heap/objects-visiting.cc +++ b/src/heap/objects-visiting.cc @@ -139,8 +139,13 @@ StaticVisitorBase::VisitorId StaticVisitorBase::GetVisitorId( case HEAP_NUMBER_TYPE: case MUTABLE_HEAP_NUMBER_TYPE: case FLOAT32X4_TYPE: +#define EXTERNAL_ARRAY_CASE(Type, type, TYPE, ctype, size) \ + case EXTERNAL_##TYPE##_ARRAY_TYPE: + + TYPED_ARRAYS(EXTERNAL_ARRAY_CASE) return GetVisitorIdForSize(kVisitDataObject, kVisitDataObjectGeneric, instance_size, has_unboxed_fields); +#undef EXTERNAL_ARRAY_CASE case FIXED_UINT8_ARRAY_TYPE: case FIXED_INT8_ARRAY_TYPE: diff --git a/src/hydrogen-instructions.cc b/src/hydrogen-instructions.cc index 10f4bf3f5..24259c8b7 100644 --- a/src/hydrogen-instructions.cc +++ b/src/hydrogen-instructions.cc @@ -3207,13 +3207,18 @@ Range* HLoadNamedField::InferRange(Zone* zone) { Range* HLoadKeyed::InferRange(Zone* zone) { switch (elements_kind()) { + case EXTERNAL_INT8_ELEMENTS: case INT8_ELEMENTS: return new(zone) Range(kMinInt8, kMaxInt8); + case EXTERNAL_UINT8_ELEMENTS: + case EXTERNAL_UINT8_CLAMPED_ELEMENTS: case UINT8_ELEMENTS: case UINT8_CLAMPED_ELEMENTS: return new(zone) Range(kMinUInt8, kMaxUInt8); + case EXTERNAL_INT16_ELEMENTS: case INT16_ELEMENTS: return new(zone) Range(kMinInt16, kMaxInt16); + case EXTERNAL_UINT16_ELEMENTS: case UINT16_ELEMENTS: return new(zone) Range(kMinUInt16, kMaxUInt16); default: @@ -3456,11 +3461,11 @@ std::ostream& HLoadNamedGeneric::PrintDataTo( std::ostream& HLoadKeyed::PrintDataTo(std::ostream& os) const { // NOLINT - if (!is_fixed_typed_array()) { + if (!is_external()) { os << NameOf(elements()); } else { - DCHECK(elements_kind() >= FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND && - elements_kind() <= LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND); + DCHECK(elements_kind() >= FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND && + elements_kind() <= LAST_EXTERNAL_ARRAY_ELEMENTS_KIND); os << NameOf(elements()) << "." << ElementsKindToString(elements_kind()); } @@ -3495,7 +3500,7 @@ bool HLoadKeyed::UsesMustHandleHole() const { return false; } - if (IsFixedTypedArrayElementsKind(elements_kind())) { + if (IsExternalArrayElementsKind(elements_kind())) { return false; } @@ -3535,7 +3540,7 @@ bool HLoadKeyed::RequiresHoleCheck() const { return false; } - if (IsFixedTypedArrayElementsKind(elements_kind())) { + if (IsExternalArrayElementsKind(elements_kind())) { return false; } @@ -3610,11 +3615,11 @@ std::ostream& HStoreNamedField::PrintDataTo(std::ostream& os) const { // NOLINT std::ostream& HStoreKeyed::PrintDataTo(std::ostream& os) const { // NOLINT - if (!is_fixed_typed_array()) { + if (!is_external()) { os << NameOf(elements()); } else { - DCHECK(elements_kind() >= FIRST_FIXED_TYPED_ARRAY_ELEMENTS_KIND && - elements_kind() <= LAST_FIXED_TYPED_ARRAY_ELEMENTS_KIND); + DCHECK(elements_kind() >= FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND && + elements_kind() <= LAST_EXTERNAL_ARRAY_ELEMENTS_KIND); os << NameOf(elements()) << "." << ElementsKindToString(elements_kind()); } @@ -3978,7 +3983,8 @@ bool HStoreKeyed::NeedsCanonicalization() { switch (value()->opcode()) { case kLoadKeyed: { ElementsKind load_kind = HLoadKeyed::cast(value())->elements_kind(); - return IsFixedFloatElementsKind(load_kind); + return IsExternalFloatOrDoubleElementsKind(load_kind) || + IsFixedFloatElementsKind(load_kind); } case kChange: { Representation from = HChange::cast(value())->from(); diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h index 8cf65d5c8..3d3c56cc4 100644 --- a/src/hydrogen-instructions.h +++ b/src/hydrogen-instructions.h @@ -6248,6 +6248,11 @@ class HObjectAccess final { JSArrayBuffer::kBitFieldSlot, Representation::Smi()); } + static HObjectAccess ForExternalArrayExternalPointer() { + return HObjectAccess::ForObservableJSObjectOffset( + ExternalArray::kExternalPointerOffset, Representation::External()); + } + static HObjectAccess ForJSArrayBufferViewBuffer() { return HObjectAccess::ForObservableJSObjectOffset( JSArrayBufferView::kBufferOffset); @@ -6617,9 +6622,15 @@ class HLoadKeyed final : public HTemplateInstruction<3>, DECLARE_INSTRUCTION_FACTORY_P6(HLoadKeyed, HValue*, HValue*, HValue*, ElementsKind, LoadKeyedHoleMode, int); + bool is_external() const { + return IsExternalArrayElementsKind(elements_kind()); + } bool is_fixed_typed_array() const { return IsFixedTypedArrayElementsKind(elements_kind()); } + bool is_typed_elements() const { + return is_external() || is_fixed_typed_array(); + } HValue* elements() const { return OperandAt(0); } HValue* key() const { return OperandAt(1); } HValue* dependency() const { @@ -6650,8 +6661,8 @@ class HLoadKeyed final : public HTemplateInstruction<3>, // kind_fixed_typed_array: external[int32] (none) // kind_external: external[int32] (none) if (index == 0) { - return is_fixed_typed_array() ? Representation::External() - : Representation::Tagged(); + return is_typed_elements() ? Representation::External() + : Representation::Tagged(); } if (index == 1) { return ArrayInstructionInterface::KeyedAccessIndexRequirement( @@ -6700,7 +6711,7 @@ class HLoadKeyed final : public HTemplateInstruction<3>, SetOperandAt(1, key); SetOperandAt(2, dependency != NULL ? dependency : obj); - if (!is_fixed_typed_array()) { + if (!is_typed_elements()) { // I can detect the case between storing double (holey and fast) and // smi/object by looking at elements_kind_. DCHECK(IsFastSmiOrObjectElementsKind(elements_kind) || @@ -6726,15 +6737,18 @@ class HLoadKeyed final : public HTemplateInstruction<3>, SetDependsOnFlag(kDoubleArrayElements); } } else { - if (elements_kind == FLOAT32_ELEMENTS || + if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS || + elements_kind == EXTERNAL_FLOAT64_ELEMENTS || + elements_kind == FLOAT32_ELEMENTS || elements_kind == FLOAT64_ELEMENTS) { set_representation(Representation::Double()); } else { set_representation(Representation::Integer32()); } - if (is_fixed_typed_array()) { + if (is_external()) { SetDependsOnFlag(kExternalMemory); + } else if (is_fixed_typed_array()) { SetDependsOnFlag(kTypedArrayElements); } else { UNREACHABLE(); @@ -7109,8 +7123,8 @@ class HStoreKeyed final : public HTemplateInstruction<3>, // kind_fixed_typed_array: tagged[int32] = (double | int32) // kind_external: external[int32] = (double | int32) if (index == 0) { - return is_fixed_typed_array() ? Representation::External() - : Representation::Tagged(); + return is_typed_elements() ? Representation::External() + : Representation::Tagged(); } else if (index == 1) { return ArrayInstructionInterface::KeyedAccessIndexRequirement( OperandAt(1)->representation()); @@ -7135,16 +7149,24 @@ class HStoreKeyed final : public HTemplateInstruction<3>, return Representation::Smi(); } - if (IsFixedTypedArrayElementsKind(kind)) { - return Representation::Integer32(); - } - return Representation::Tagged(); + return IsExternalArrayElementsKind(kind) || + IsFixedTypedArrayElementsKind(kind) + ? Representation::Integer32() + : Representation::Tagged(); + } + + bool is_external() const { + return IsExternalArrayElementsKind(elements_kind()); } bool is_fixed_typed_array() const { return IsFixedTypedArrayElementsKind(elements_kind()); } + bool is_typed_elements() const { + return is_external() || is_fixed_typed_array(); + } + Representation observed_input_representation(int index) override { if (index < 2) return RequiredInputRepresentation(index); if (IsUninitialized()) { @@ -7234,20 +7256,25 @@ class HStoreKeyed final : public HTemplateInstruction<3>, SetFlag(kTrackSideEffectDominators); SetDependsOnFlag(kNewSpacePromotion); } - if (IsFastDoubleElementsKind(elements_kind)) { + if (is_external()) { + SetChangesFlag(kExternalMemory); + SetFlag(kAllowUndefinedAsNaN); + } else if (IsFastDoubleElementsKind(elements_kind)) { SetChangesFlag(kDoubleArrayElements); } else if (IsFastSmiElementsKind(elements_kind)) { SetChangesFlag(kArrayElements); } else if (is_fixed_typed_array()) { SetChangesFlag(kTypedArrayElements); - SetChangesFlag(kExternalMemory); SetFlag(kAllowUndefinedAsNaN); } else { SetChangesFlag(kArrayElements); } - // {UNSIGNED_,}{BYTE,SHORT,INT}_ELEMENTS are truncating. - if (elements_kind >= UINT8_ELEMENTS && elements_kind <= INT32_ELEMENTS) { + // EXTERNAL_{UNSIGNED_,}{BYTE,SHORT,INT}_ELEMENTS are truncating. + if ((elements_kind >= EXTERNAL_INT8_ELEMENTS && + elements_kind <= EXTERNAL_UINT32_ELEMENTS) || + (elements_kind >= UINT8_ELEMENTS && + elements_kind <= INT32_ELEMENTS)) { SetFlag(kTruncatingToInt32); } } diff --git a/src/hydrogen-uint32-analysis.cc b/src/hydrogen-uint32-analysis.cc index c6cbc9bc3..37f19ebda 100644 --- a/src/hydrogen-uint32-analysis.cc +++ b/src/hydrogen-uint32-analysis.cc @@ -10,6 +10,10 @@ namespace internal { static bool IsUnsignedLoad(HLoadKeyed* instr) { switch (instr->elements_kind()) { + case EXTERNAL_UINT8_ELEMENTS: + case EXTERNAL_UINT16_ELEMENTS: + case EXTERNAL_UINT32_ELEMENTS: + case EXTERNAL_UINT8_CLAMPED_ELEMENTS: case UINT8_ELEMENTS: case UINT16_ELEMENTS: case UINT32_ELEMENTS: @@ -46,14 +50,14 @@ bool HUint32AnalysisPhase::IsSafeUint32Use(HValue* val, HValue* use) { return true; } else if (use->IsStoreKeyed()) { HStoreKeyed* store = HStoreKeyed::cast(use); - if (store->is_fixed_typed_array()) { + if (store->is_external()) { // Storing a value into an external integer array is a bit level // operation. if (store->value() == val) { // Clamping or a conversion to double should have beed inserted. - DCHECK(store->elements_kind() != UINT8_CLAMPED_ELEMENTS); - DCHECK(store->elements_kind() != FLOAT32_ELEMENTS); - DCHECK(store->elements_kind() != FLOAT64_ELEMENTS); + DCHECK(store->elements_kind() != EXTERNAL_UINT8_CLAMPED_ELEMENTS); + DCHECK(store->elements_kind() != EXTERNAL_FLOAT32_ELEMENTS); + DCHECK(store->elements_kind() != EXTERNAL_FLOAT64_ELEMENTS); return true; } } diff --git a/src/hydrogen.cc b/src/hydrogen.cc index abfe9cab2..f4bd41797 100644 --- a/src/hydrogen.cc +++ b/src/hydrogen.cc @@ -2416,7 +2416,9 @@ HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess( KeyedAccessStoreMode store_mode) { DCHECK(top_info()->IsStub() || checked_object->IsCompareMap() || checked_object->IsCheckMaps()); - DCHECK(!IsFixedTypedArrayElementsKind(elements_kind) || !is_js_array); + DCHECK((!IsExternalArrayElementsKind(elements_kind) && + !IsFixedTypedArrayElementsKind(elements_kind)) || + !is_js_array); // No GVNFlag is necessary for ElementsKind if there is an explicit dependency // on a HElementsTransition instruction. The flag can also be removed if the // map to check has FAST_HOLEY_ELEMENTS, since there can be no further @@ -2447,17 +2449,24 @@ HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess( } length->set_type(HType::Smi()); HValue* checked_key = NULL; - if (IsFixedTypedArrayElementsKind(elements_kind)) { + if (IsExternalArrayElementsKind(elements_kind) || + IsFixedTypedArrayElementsKind(elements_kind)) { checked_object = Add(checked_object); - HValue* external_pointer = Add( - elements, nullptr, - HObjectAccess::ForFixedTypedArrayBaseExternalPointer()); - HValue* base_pointer = Add( - elements, nullptr, HObjectAccess::ForFixedTypedArrayBaseBasePointer()); - HValue* backing_store = AddUncasted( - external_pointer, base_pointer, Strength::WEAK, AddOfExternalAndTagged); - + HValue* backing_store; + if (IsExternalArrayElementsKind(elements_kind)) { + backing_store = Add( + elements, nullptr, HObjectAccess::ForExternalArrayExternalPointer()); + } else { + HValue* external_pointer = Add( + elements, nullptr, + HObjectAccess::ForFixedTypedArrayBaseExternalPointer()); + HValue* base_pointer = Add( + elements, nullptr, + HObjectAccess::ForFixedTypedArrayBaseBasePointer()); + backing_store = AddUncasted(external_pointer, base_pointer, + Strength::WEAK, AddOfExternalAndTagged); + } if (store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) { NoObservableSideEffectsScope no_effects(this); IfBuilder length_checker(this); @@ -2689,7 +2698,8 @@ HInstruction* HGraphBuilder::AddElementAccess( LoadKeyedHoleMode load_mode) { if (access_type == STORE) { DCHECK(val != NULL); - if (elements_kind == UINT8_CLAMPED_ELEMENTS) { + if (elements_kind == EXTERNAL_UINT8_CLAMPED_ELEMENTS || + elements_kind == UINT8_CLAMPED_ELEMENTS) { val = Add(val); } return Add(elements, checked_key, val, elements_kind, @@ -2700,7 +2710,8 @@ HInstruction* HGraphBuilder::AddElementAccess( DCHECK(val == NULL); HLoadKeyed* load = Add( elements, checked_key, dependency, elements_kind, load_mode); - if (elements_kind == UINT32_ELEMENTS) { + if (elements_kind == EXTERNAL_UINT32_ELEMENTS || + elements_kind == UINT32_ELEMENTS) { graph()->RecordUint32Instruction(load); } return load; @@ -7402,6 +7413,7 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess( val)); } else { DCHECK(IsFastElementsKind(elements_kind) || + IsExternalArrayElementsKind(elements_kind) || IsFixedTypedArrayElementsKind(elements_kind)); LoadKeyedHoleMode load_mode = BuildKeyedHoleMode(map); // Happily, mapcompare is a checked object. @@ -9936,14 +9948,14 @@ HValue* HOptimizedGraphBuilder::BuildAllocateExternalElements( bool is_zero_byte_offset, HValue* buffer, HValue* byte_offset, HValue* length) { Handle external_array_map( - isolate()->heap()->MapForFixedTypedArray(array_type)); + isolate()->heap()->MapForExternalArrayType(array_type)); // The HForceRepresentation is to prevent possible deopt on int-smi // conversion after allocation but before the new object fields are set. length = AddUncasted(length, Representation::Smi()); - HValue* elements = Add( - Add(FixedTypedArrayBase::kHeaderSize), HType::HeapObject(), - NOT_TENURED, external_array_map->instance_type()); + HValue* elements = + Add(Add(ExternalArray::kSize), HType::HeapObject(), + NOT_TENURED, external_array_map->instance_type()); AddStoreMapConstant(elements, external_array_map); Add(elements, @@ -9965,11 +9977,8 @@ HValue* HOptimizedGraphBuilder::BuildAllocateExternalElements( } Add(elements, - HObjectAccess::ForFixedTypedArrayBaseBasePointer(), - graph()->GetConstant0()); - Add(elements, - HObjectAccess::ForFixedTypedArrayBaseExternalPointer(), - typed_array_start); + HObjectAccess::ForExternalArrayExternalPointer(), + typed_array_start); return elements; } @@ -10116,10 +10125,13 @@ void HOptimizedGraphBuilder::GenerateTypedArrayInitialize( ExternalArrayType array_type = kExternalInt8Array; // Bogus initialization. size_t element_size = 1; // Bogus initialization. + ElementsKind external_elements_kind = // Bogus initialization. + EXTERNAL_INT8_ELEMENTS; ElementsKind fixed_elements_kind = // Bogus initialization. INT8_ELEMENTS; Runtime::ArrayIdToTypeAndSize(array_id, &array_type, + &external_elements_kind, &fixed_elements_kind, &element_size); @@ -10144,8 +10156,8 @@ void HOptimizedGraphBuilder::GenerateTypedArrayInitialize( if (buffer != NULL) { elements = BuildAllocateExternalElements( array_type, is_zero_byte_offset, buffer, byte_offset, length); - Handle obj_map = - TypedArrayMap(isolate(), array_type, fixed_elements_kind); + Handle obj_map = TypedArrayMap( + isolate(), array_type, external_elements_kind); AddStoreMapConstant(obj, obj_map); } else { DCHECK(is_zero_byte_offset); diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc index 892193a3f..db2602c17 100644 --- a/src/ia32/lithium-codegen-ia32.cc +++ b/src/ia32/lithium-codegen-ia32.cc @@ -3070,31 +3070,40 @@ void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) { instr->hydrogen()->key()->representation(), elements_kind, instr->base_offset())); - if (elements_kind == FLOAT32_ELEMENTS) { + if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS || + elements_kind == FLOAT32_ELEMENTS) { XMMRegister result(ToDoubleRegister(instr->result())); __ movss(result, operand); __ cvtss2sd(result, result); - } else if (elements_kind == FLOAT64_ELEMENTS) { + } else if (elements_kind == EXTERNAL_FLOAT64_ELEMENTS || + elements_kind == FLOAT64_ELEMENTS) { __ movsd(ToDoubleRegister(instr->result()), operand); } else { Register result(ToRegister(instr->result())); switch (elements_kind) { + case EXTERNAL_INT8_ELEMENTS: case INT8_ELEMENTS: __ movsx_b(result, operand); break; + case EXTERNAL_UINT8_CLAMPED_ELEMENTS: + case EXTERNAL_UINT8_ELEMENTS: case UINT8_ELEMENTS: case UINT8_CLAMPED_ELEMENTS: __ movzx_b(result, operand); break; + case EXTERNAL_INT16_ELEMENTS: case INT16_ELEMENTS: __ movsx_w(result, operand); break; + case EXTERNAL_UINT16_ELEMENTS: case UINT16_ELEMENTS: __ movzx_w(result, operand); break; + case EXTERNAL_INT32_ELEMENTS: case INT32_ELEMENTS: __ mov(result, operand); break; + case EXTERNAL_UINT32_ELEMENTS: case UINT32_ELEMENTS: __ mov(result, operand); if (!instr->hydrogen()->CheckFlag(HInstruction::kUint32)) { @@ -3102,6 +3111,8 @@ void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) { DeoptimizeIf(negative, instr, Deoptimizer::kNegativeValue); } break; + case EXTERNAL_FLOAT32_ELEMENTS: + case EXTERNAL_FLOAT64_ELEMENTS: case FLOAT32_ELEMENTS: case FLOAT64_ELEMENTS: case FAST_SMI_ELEMENTS: @@ -3181,7 +3192,7 @@ void LCodeGen::DoLoadKeyedFixedArray(LLoadKeyed* instr) { void LCodeGen::DoLoadKeyed(LLoadKeyed* instr) { - if (instr->is_fixed_typed_array()) { + if (instr->is_typed_elements()) { DoLoadKeyedExternalArray(instr); } else if (instr->hydrogen()->representation().IsDouble()) { DoLoadKeyedFixedDoubleArray(instr); @@ -4196,28 +4207,39 @@ void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) { instr->hydrogen()->key()->representation(), elements_kind, instr->base_offset())); - if (elements_kind == FLOAT32_ELEMENTS) { + if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS || + elements_kind == FLOAT32_ELEMENTS) { XMMRegister xmm_scratch = double_scratch0(); __ cvtsd2ss(xmm_scratch, ToDoubleRegister(instr->value())); __ movss(operand, xmm_scratch); - } else if (elements_kind == FLOAT64_ELEMENTS) { + } else if (elements_kind == EXTERNAL_FLOAT64_ELEMENTS || + elements_kind == FLOAT64_ELEMENTS) { __ movsd(operand, ToDoubleRegister(instr->value())); } else { Register value = ToRegister(instr->value()); switch (elements_kind) { + case EXTERNAL_UINT8_CLAMPED_ELEMENTS: + case EXTERNAL_UINT8_ELEMENTS: + case EXTERNAL_INT8_ELEMENTS: case UINT8_ELEMENTS: case INT8_ELEMENTS: case UINT8_CLAMPED_ELEMENTS: __ mov_b(operand, value); break; + case EXTERNAL_INT16_ELEMENTS: + case EXTERNAL_UINT16_ELEMENTS: case UINT16_ELEMENTS: case INT16_ELEMENTS: __ mov_w(operand, value); break; + case EXTERNAL_INT32_ELEMENTS: + case EXTERNAL_UINT32_ELEMENTS: case UINT32_ELEMENTS: case INT32_ELEMENTS: __ mov(operand, value); break; + case EXTERNAL_FLOAT32_ELEMENTS: + case EXTERNAL_FLOAT64_ELEMENTS: case FLOAT32_ELEMENTS: case FLOAT64_ELEMENTS: case FAST_SMI_ELEMENTS: @@ -4303,7 +4325,7 @@ void LCodeGen::DoStoreKeyedFixedArray(LStoreKeyed* instr) { void LCodeGen::DoStoreKeyed(LStoreKeyed* instr) { // By cases...external, fast-double, fast - if (instr->is_fixed_typed_array()) { + if (instr->is_typed_elements()) { DoStoreKeyedExternalArray(instr); } else if (instr->hydrogen()->value()->representation().IsDouble()) { DoStoreKeyedFixedDoubleArray(instr); diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc index e00b43d6f..eeccdd050 100644 --- a/src/ia32/lithium-ia32.cc +++ b/src/ia32/lithium-ia32.cc @@ -2242,7 +2242,7 @@ LInstruction* LChunkBuilder::DoLoadKeyed(HLoadKeyed* instr) { : UseRegisterOrConstantAtStart(instr->key()); LInstruction* result = NULL; - if (!instr->is_fixed_typed_array()) { + if (!instr->is_typed_elements()) { LOperand* obj = UseRegisterAtStart(instr->elements()); result = DefineAsRegister(new(zone()) LLoadKeyed(obj, key)); } else { @@ -2256,9 +2256,10 @@ LInstruction* LChunkBuilder::DoLoadKeyed(HLoadKeyed* instr) { } bool needs_environment; - if (instr->is_fixed_typed_array()) { + if (instr->is_external() || instr->is_fixed_typed_array()) { // see LCodeGen::DoLoadKeyedExternalArray - needs_environment = elements_kind == UINT32_ELEMENTS && + needs_environment = (elements_kind == EXTERNAL_UINT32_ELEMENTS || + elements_kind == UINT32_ELEMENTS) && !instr->CheckFlag(HInstruction::kUint32); } else { // see LCodeGen::DoLoadKeyedFixedDoubleArray and @@ -2295,6 +2296,9 @@ LOperand* LChunkBuilder::GetStoreKeyedValueOperand(HStoreKeyed* instr) { // Determine if we need a byte register in this case for the value. bool val_is_fixed_register = + elements_kind == EXTERNAL_INT8_ELEMENTS || + elements_kind == EXTERNAL_UINT8_ELEMENTS || + elements_kind == EXTERNAL_UINT8_CLAMPED_ELEMENTS || elements_kind == UINT8_ELEMENTS || elements_kind == INT8_ELEMENTS || elements_kind == UINT8_CLAMPED_ELEMENTS; @@ -2307,7 +2311,7 @@ LOperand* LChunkBuilder::GetStoreKeyedValueOperand(HStoreKeyed* instr) { LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) { - if (!instr->is_fixed_typed_array()) { + if (!instr->is_typed_elements()) { DCHECK(instr->elements()->representation().IsTagged()); DCHECK(instr->key()->representation().IsInteger32() || instr->key()->representation().IsSmi()); diff --git a/src/ia32/lithium-ia32.h b/src/ia32/lithium-ia32.h index 7a95ee4cd..ac544a6af 100644 --- a/src/ia32/lithium-ia32.h +++ b/src/ia32/lithium-ia32.h @@ -1641,9 +1641,15 @@ class LLoadKeyed final : public LTemplateInstruction<1, 2, 0> { ElementsKind elements_kind() const { return hydrogen()->elements_kind(); } + bool is_external() const { + return hydrogen()->is_external(); + } bool is_fixed_typed_array() const { return hydrogen()->is_fixed_typed_array(); } + bool is_typed_elements() const { + return is_external() || is_fixed_typed_array(); + } DECLARE_CONCRETE_INSTRUCTION(LoadKeyed, "load-keyed") DECLARE_HYDROGEN_ACCESSOR(LoadKeyed) @@ -1663,8 +1669,12 @@ inline static bool ExternalArrayOpRequiresTemp( // an index cannot fold the scale operation into a load and need an extra // temp register to do the work. return key_representation.IsSmi() && - (elements_kind == UINT8_ELEMENTS || elements_kind == INT8_ELEMENTS || - elements_kind == UINT8_CLAMPED_ELEMENTS); + (elements_kind == EXTERNAL_INT8_ELEMENTS || + elements_kind == EXTERNAL_UINT8_ELEMENTS || + elements_kind == EXTERNAL_UINT8_CLAMPED_ELEMENTS || + elements_kind == UINT8_ELEMENTS || + elements_kind == INT8_ELEMENTS || + elements_kind == UINT8_CLAMPED_ELEMENTS); } @@ -2249,9 +2259,13 @@ class LStoreKeyed final : public LTemplateInstruction<0, 3, 0> { inputs_[2] = val; } + bool is_external() const { return hydrogen()->is_external(); } bool is_fixed_typed_array() const { return hydrogen()->is_fixed_typed_array(); } + bool is_typed_elements() const { + return is_external() || is_fixed_typed_array(); + } LOperand* elements() { return inputs_[0]; } LOperand* key() { return inputs_[1]; } LOperand* value() { return inputs_[2]; } diff --git a/src/ic/handler-compiler.cc b/src/ic/handler-compiler.cc index c7220afe1..379e79fca 100644 --- a/src/ic/handler-compiler.cc +++ b/src/ic/handler-compiler.cc @@ -577,6 +577,7 @@ void ElementHandlerCompiler::CompileElementHandlers( } else if (IsSloppyArgumentsElements(elements_kind)) { cached_stub = KeyedLoadSloppyArgumentsStub(isolate()).GetCode(); } else if (IsFastElementsKind(elements_kind) || + IsExternalArrayElementsKind(elements_kind) || IsFixedTypedArrayElementsKind(elements_kind)) { cached_stub = LoadFastElementStub(isolate(), is_js_array, elements_kind, convert_hole_to_undefined).GetCode(); diff --git a/src/ic/ic-compiler.cc b/src/ic/ic-compiler.cc index 4fe30234e..a5ae6cfff 100644 --- a/src/ic/ic-compiler.cc +++ b/src/ic/ic-compiler.cc @@ -109,6 +109,7 @@ Handle PropertyICCompiler::ComputeKeyedLoadMonomorphicHandler( } else if (receiver_map->has_sloppy_arguments_elements()) { stub = KeyedLoadSloppyArgumentsStub(isolate).GetCode(); } else if (receiver_map->has_fast_elements() || + receiver_map->has_external_array_elements() || receiver_map->has_fixed_typed_array_elements()) { stub = LoadFastElementStub(isolate, is_js_array, elements_kind, convert_hole_to_undefined).GetCode(); @@ -368,6 +369,7 @@ Handle PropertyICCompiler::CompileKeyedStorePolymorphic( if (IsSloppyArgumentsElements(elements_kind)) { cached_stub = KeyedStoreSloppyArgumentsStub(isolate()).GetCode(); } else if (receiver_map->has_fast_elements() || + receiver_map->has_external_array_elements() || receiver_map->has_fixed_typed_array_elements()) { cached_stub = StoreFastElementStub(isolate(), is_js_array, elements_kind, store_mode).GetCode(); @@ -399,6 +401,7 @@ Handle PropertyICCompiler::CompileKeyedStoreMonomorphic( if (receiver_map->has_sloppy_arguments_elements()) { stub = KeyedStoreSloppyArgumentsStub(isolate()).GetCode(); } else if (receiver_map->has_fast_elements() || + receiver_map->has_external_array_elements() || receiver_map->has_fixed_typed_array_elements()) { stub = StoreFastElementStub(isolate(), is_jsarray, elements_kind, store_mode).GetCode(); diff --git a/src/ic/ic.cc b/src/ic/ic.cc index 19f469982..99307f700 100644 --- a/src/ic/ic.cc +++ b/src/ic/ic.cc @@ -1953,7 +1953,8 @@ Handle KeyedStoreIC::StoreElementStub(Handle receiver, if (store_mode != STANDARD_STORE) { int external_arrays = 0; for (int i = 0; i < target_receiver_maps.length(); ++i) { - if (target_receiver_maps[i]->has_fixed_typed_array_elements()) { + if (target_receiver_maps[i]->has_external_array_elements() || + target_receiver_maps[i]->has_fixed_typed_array_elements()) { external_arrays++; } } @@ -1990,7 +1991,7 @@ Handle KeyedStoreIC::ComputeTransitionedMap( case STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_DOUBLE: return Map::TransitionElementsTo(map, FAST_HOLEY_DOUBLE_ELEMENTS); case STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS: - DCHECK(map->has_fixed_typed_array_elements()); + DCHECK(map->has_external_array_elements()); // Fall through case STORE_NO_TRANSITION_HANDLE_COW: case STANDARD_STORE: @@ -2073,7 +2074,7 @@ static KeyedAccessStoreMode GetStoreMode(Handle receiver, } } if (!FLAG_trace_external_array_abuse && - receiver->map()->has_fixed_typed_array_elements() && oob_access) { + receiver->map()->has_external_array_elements() && oob_access) { return STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS; } Heap* heap = receiver->GetHeap(); diff --git a/src/lookup.cc b/src/lookup.cc index 75d460328..7d9f79168 100644 --- a/src/lookup.cc +++ b/src/lookup.cc @@ -117,7 +117,8 @@ void LookupIterator::ReloadPropertyInformation() { void LookupIterator::ReloadHolderMap() { DCHECK_EQ(DATA, state_); DCHECK(IsElement()); - DCHECK(JSObject::cast(*holder_)->HasFixedTypedArrayElements()); + DCHECK(JSObject::cast(*holder_)->HasExternalArrayElements() || + JSObject::cast(*holder_)->HasFixedTypedArrayElements()); if (*holder_map_ != holder_->map()) { holder_map_ = handle(holder_->map(), isolate_); } @@ -160,6 +161,7 @@ void LookupIterator::ReconfigureDataProperty(Handle value, DCHECK(HolderIsReceiverOrHiddenPrototype()); Handle holder = GetHolder(); if (IsElement()) { + DCHECK(!holder->HasExternalArrayElements()); DCHECK(!holder->HasFixedTypedArrayElements()); DCHECK(attributes != NONE || !holder->HasFastElements()); Handle elements(holder->elements()); diff --git a/src/mips/lithium-codegen-mips.cc b/src/mips/lithium-codegen-mips.cc index 43fa8be1c..c5db715d6 100644 --- a/src/mips/lithium-codegen-mips.cc +++ b/src/mips/lithium-codegen-mips.cc @@ -3114,7 +3114,10 @@ void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) { ? (element_size_shift - kSmiTagSize) : element_size_shift; int base_offset = instr->base_offset(); - if (elements_kind == FLOAT32_ELEMENTS || elements_kind == FLOAT64_ELEMENTS) { + if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS || + elements_kind == FLOAT32_ELEMENTS || + elements_kind == EXTERNAL_FLOAT64_ELEMENTS || + elements_kind == FLOAT64_ELEMENTS) { FPURegister result = ToDoubleRegister(instr->result()); if (key_is_constant) { __ Addu(scratch0(), external_pointer, constant_key << element_size_shift); @@ -3122,7 +3125,8 @@ void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) { __ sll(scratch0(), key, shift_size); __ Addu(scratch0(), scratch0(), external_pointer); } - if (elements_kind == FLOAT32_ELEMENTS) { + if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS || + elements_kind == FLOAT32_ELEMENTS) { __ lwc1(result, MemOperand(scratch0(), base_offset)); __ cvt_d_s(result, result); } else { // i.e. elements_kind == EXTERNAL_DOUBLE_ELEMENTS @@ -3134,22 +3138,29 @@ void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) { key, external_pointer, key_is_constant, constant_key, element_size_shift, shift_size, base_offset); switch (elements_kind) { + case EXTERNAL_INT8_ELEMENTS: case INT8_ELEMENTS: __ lb(result, mem_operand); break; + case EXTERNAL_UINT8_CLAMPED_ELEMENTS: + case EXTERNAL_UINT8_ELEMENTS: case UINT8_ELEMENTS: case UINT8_CLAMPED_ELEMENTS: __ lbu(result, mem_operand); break; + case EXTERNAL_INT16_ELEMENTS: case INT16_ELEMENTS: __ lh(result, mem_operand); break; + case EXTERNAL_UINT16_ELEMENTS: case UINT16_ELEMENTS: __ lhu(result, mem_operand); break; + case EXTERNAL_INT32_ELEMENTS: case INT32_ELEMENTS: __ lw(result, mem_operand); break; + case EXTERNAL_UINT32_ELEMENTS: case UINT32_ELEMENTS: __ lw(result, mem_operand); if (!instr->hydrogen()->CheckFlag(HInstruction::kUint32)) { @@ -3159,6 +3170,8 @@ void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) { break; case FLOAT32_ELEMENTS: case FLOAT64_ELEMENTS: + case EXTERNAL_FLOAT32_ELEMENTS: + case EXTERNAL_FLOAT64_ELEMENTS: case FAST_DOUBLE_ELEMENTS: case FAST_ELEMENTS: case FAST_SMI_ELEMENTS: @@ -3270,7 +3283,7 @@ void LCodeGen::DoLoadKeyedFixedArray(LLoadKeyed* instr) { void LCodeGen::DoLoadKeyed(LLoadKeyed* instr) { - if (instr->is_fixed_typed_array()) { + if (instr->is_typed_elements()) { DoLoadKeyedExternalArray(instr); } else if (instr->hydrogen()->representation().IsDouble()) { DoLoadKeyedFixedDoubleArray(instr); @@ -4265,7 +4278,10 @@ void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) { ? (element_size_shift - kSmiTagSize) : element_size_shift; int base_offset = instr->base_offset(); - if (elements_kind == FLOAT32_ELEMENTS || elements_kind == FLOAT64_ELEMENTS) { + if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS || + elements_kind == FLOAT32_ELEMENTS || + elements_kind == EXTERNAL_FLOAT64_ELEMENTS || + elements_kind == FLOAT64_ELEMENTS) { Register address = scratch0(); FPURegister value(ToDoubleRegister(instr->value())); if (key_is_constant) { @@ -4280,7 +4296,8 @@ void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) { __ Addu(address, external_pointer, address); } - if (elements_kind == FLOAT32_ELEMENTS) { + if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS || + elements_kind == FLOAT32_ELEMENTS) { __ cvt_s_d(double_scratch0(), value); __ swc1(double_scratch0(), MemOperand(address, base_offset)); } else { // Storing doubles, not floats. @@ -4293,21 +4310,30 @@ void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) { element_size_shift, shift_size, base_offset); switch (elements_kind) { + case EXTERNAL_UINT8_CLAMPED_ELEMENTS: + case EXTERNAL_INT8_ELEMENTS: + case EXTERNAL_UINT8_ELEMENTS: case UINT8_ELEMENTS: case UINT8_CLAMPED_ELEMENTS: case INT8_ELEMENTS: __ sb(value, mem_operand); break; + case EXTERNAL_INT16_ELEMENTS: + case EXTERNAL_UINT16_ELEMENTS: case INT16_ELEMENTS: case UINT16_ELEMENTS: __ sh(value, mem_operand); break; + case EXTERNAL_INT32_ELEMENTS: + case EXTERNAL_UINT32_ELEMENTS: case INT32_ELEMENTS: case UINT32_ELEMENTS: __ sw(value, mem_operand); break; case FLOAT32_ELEMENTS: case FLOAT64_ELEMENTS: + case EXTERNAL_FLOAT32_ELEMENTS: + case EXTERNAL_FLOAT64_ELEMENTS: case FAST_DOUBLE_ELEMENTS: case FAST_ELEMENTS: case FAST_SMI_ELEMENTS: @@ -4421,7 +4447,7 @@ void LCodeGen::DoStoreKeyedFixedArray(LStoreKeyed* instr) { void LCodeGen::DoStoreKeyed(LStoreKeyed* instr) { // By cases: external, fast double - if (instr->is_fixed_typed_array()) { + if (instr->is_typed_elements()) { DoStoreKeyedExternalArray(instr); } else if (instr->hydrogen()->value()->representation().IsDouble()) { DoStoreKeyedFixedDoubleArray(instr); diff --git a/src/mips/lithium-mips.cc b/src/mips/lithium-mips.cc index 28e77e82c..550610902 100644 --- a/src/mips/lithium-mips.cc +++ b/src/mips/lithium-mips.cc @@ -2187,7 +2187,7 @@ LInstruction* LChunkBuilder::DoLoadKeyed(HLoadKeyed* instr) { LOperand* key = UseRegisterOrConstantAtStart(instr->key()); LInstruction* result = NULL; - if (!instr->is_fixed_typed_array()) { + if (!instr->is_typed_elements()) { LOperand* obj = NULL; if (instr->representation().IsDouble()) { obj = UseRegister(instr->elements()); @@ -2207,9 +2207,10 @@ LInstruction* LChunkBuilder::DoLoadKeyed(HLoadKeyed* instr) { } bool needs_environment; - if (instr->is_fixed_typed_array()) { + if (instr->is_external() || instr->is_fixed_typed_array()) { // see LCodeGen::DoLoadKeyedExternalArray - needs_environment = elements_kind == UINT32_ELEMENTS && + needs_environment = (elements_kind == EXTERNAL_UINT32_ELEMENTS || + elements_kind == UINT32_ELEMENTS) && !instr->CheckFlag(HInstruction::kUint32); } else { // see LCodeGen::DoLoadKeyedFixedDoubleArray and @@ -2244,7 +2245,7 @@ LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) { LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) { - if (!instr->is_fixed_typed_array()) { + if (!instr->is_typed_elements()) { DCHECK(instr->elements()->representation().IsTagged()); bool needs_write_barrier = instr->NeedsWriteBarrier(); LOperand* object = NULL; diff --git a/src/mips/lithium-mips.h b/src/mips/lithium-mips.h index e423b694b..1b8b5e5bf 100644 --- a/src/mips/lithium-mips.h +++ b/src/mips/lithium-mips.h @@ -1610,9 +1610,15 @@ class LLoadKeyed final : public LTemplateInstruction<1, 2, 0> { ElementsKind elements_kind() const { return hydrogen()->elements_kind(); } + bool is_external() const { + return hydrogen()->is_external(); + } bool is_fixed_typed_array() const { return hydrogen()->is_fixed_typed_array(); } + bool is_typed_elements() const { + return is_external() || is_fixed_typed_array(); + } DECLARE_CONCRETE_INSTRUCTION(LoadKeyed, "load-keyed") DECLARE_HYDROGEN_ACCESSOR(LoadKeyed) @@ -2212,9 +2218,13 @@ class LStoreKeyed final : public LTemplateInstruction<0, 3, 0> { inputs_[2] = value; } + bool is_external() const { return hydrogen()->is_external(); } bool is_fixed_typed_array() const { return hydrogen()->is_fixed_typed_array(); } + bool is_typed_elements() const { + return is_external() || is_fixed_typed_array(); + } LOperand* elements() { return inputs_[0]; } LOperand* key() { return inputs_[1]; } LOperand* value() { return inputs_[2]; } diff --git a/src/mips64/lithium-codegen-mips64.cc b/src/mips64/lithium-codegen-mips64.cc index a13937c2f..0313878b2 100644 --- a/src/mips64/lithium-codegen-mips64.cc +++ b/src/mips64/lithium-codegen-mips64.cc @@ -3234,7 +3234,10 @@ void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) { : element_size_shift; int base_offset = instr->base_offset(); - if (elements_kind == FLOAT32_ELEMENTS || elements_kind == FLOAT64_ELEMENTS) { + if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS || + elements_kind == FLOAT32_ELEMENTS || + elements_kind == EXTERNAL_FLOAT64_ELEMENTS || + elements_kind == FLOAT64_ELEMENTS) { FPURegister result = ToDoubleRegister(instr->result()); if (key_is_constant) { __ Daddu(scratch0(), external_pointer, @@ -3251,7 +3254,8 @@ void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) { } __ Daddu(scratch0(), scratch0(), external_pointer); } - if (elements_kind == FLOAT32_ELEMENTS) { + if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS || + elements_kind == FLOAT32_ELEMENTS) { __ lwc1(result, MemOperand(scratch0(), base_offset)); __ cvt_d_s(result, result); } else { // i.e. elements_kind == EXTERNAL_DOUBLE_ELEMENTS @@ -3263,22 +3267,29 @@ void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) { key, external_pointer, key_is_constant, constant_key, element_size_shift, shift_size, base_offset); switch (elements_kind) { + case EXTERNAL_INT8_ELEMENTS: case INT8_ELEMENTS: __ lb(result, mem_operand); break; + case EXTERNAL_UINT8_CLAMPED_ELEMENTS: + case EXTERNAL_UINT8_ELEMENTS: case UINT8_ELEMENTS: case UINT8_CLAMPED_ELEMENTS: __ lbu(result, mem_operand); break; + case EXTERNAL_INT16_ELEMENTS: case INT16_ELEMENTS: __ lh(result, mem_operand); break; + case EXTERNAL_UINT16_ELEMENTS: case UINT16_ELEMENTS: __ lhu(result, mem_operand); break; + case EXTERNAL_INT32_ELEMENTS: case INT32_ELEMENTS: __ lw(result, mem_operand); break; + case EXTERNAL_UINT32_ELEMENTS: case UINT32_ELEMENTS: __ lw(result, mem_operand); if (!instr->hydrogen()->CheckFlag(HInstruction::kUint32)) { @@ -3288,6 +3299,8 @@ void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) { break; case FLOAT32_ELEMENTS: case FLOAT64_ELEMENTS: + case EXTERNAL_FLOAT32_ELEMENTS: + case EXTERNAL_FLOAT64_ELEMENTS: case FAST_DOUBLE_ELEMENTS: case FAST_ELEMENTS: case FAST_SMI_ELEMENTS: @@ -3425,7 +3438,7 @@ void LCodeGen::DoLoadKeyedFixedArray(LLoadKeyed* instr) { void LCodeGen::DoLoadKeyed(LLoadKeyed* instr) { - if (instr->is_fixed_typed_array()) { + if (instr->is_typed_elements()) { DoLoadKeyedExternalArray(instr); } else if (instr->hydrogen()->representation().IsDouble()) { DoLoadKeyedFixedDoubleArray(instr); @@ -4459,7 +4472,10 @@ void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) { : element_size_shift; int base_offset = instr->base_offset(); - if (elements_kind == FLOAT32_ELEMENTS || elements_kind == FLOAT64_ELEMENTS) { + if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS || + elements_kind == FLOAT32_ELEMENTS || + elements_kind == EXTERNAL_FLOAT64_ELEMENTS || + elements_kind == FLOAT64_ELEMENTS) { Register address = scratch0(); FPURegister value(ToDoubleRegister(instr->value())); if (key_is_constant) { @@ -4482,7 +4498,8 @@ void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) { __ Daddu(address, external_pointer, address); } - if (elements_kind == FLOAT32_ELEMENTS) { + if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS || + elements_kind == FLOAT32_ELEMENTS) { __ cvt_s_d(double_scratch0(), value); __ swc1(double_scratch0(), MemOperand(address, base_offset)); } else { // Storing doubles, not floats. @@ -4495,21 +4512,30 @@ void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) { element_size_shift, shift_size, base_offset); switch (elements_kind) { + case EXTERNAL_UINT8_CLAMPED_ELEMENTS: + case EXTERNAL_INT8_ELEMENTS: + case EXTERNAL_UINT8_ELEMENTS: case UINT8_ELEMENTS: case UINT8_CLAMPED_ELEMENTS: case INT8_ELEMENTS: __ sb(value, mem_operand); break; + case EXTERNAL_INT16_ELEMENTS: + case EXTERNAL_UINT16_ELEMENTS: case INT16_ELEMENTS: case UINT16_ELEMENTS: __ sh(value, mem_operand); break; + case EXTERNAL_INT32_ELEMENTS: + case EXTERNAL_UINT32_ELEMENTS: case INT32_ELEMENTS: case UINT32_ELEMENTS: __ sw(value, mem_operand); break; case FLOAT32_ELEMENTS: case FLOAT64_ELEMENTS: + case EXTERNAL_FLOAT32_ELEMENTS: + case EXTERNAL_FLOAT64_ELEMENTS: case FAST_DOUBLE_ELEMENTS: case FAST_ELEMENTS: case FAST_SMI_ELEMENTS: @@ -4636,7 +4662,7 @@ void LCodeGen::DoStoreKeyedFixedArray(LStoreKeyed* instr) { void LCodeGen::DoStoreKeyed(LStoreKeyed* instr) { // By cases: external, fast double - if (instr->is_fixed_typed_array()) { + if (instr->is_typed_elements()) { DoStoreKeyedExternalArray(instr); } else if (instr->hydrogen()->value()->representation().IsDouble()) { DoStoreKeyedFixedDoubleArray(instr); diff --git a/src/mips64/lithium-mips64.cc b/src/mips64/lithium-mips64.cc index 6a30a446d..060582585 100644 --- a/src/mips64/lithium-mips64.cc +++ b/src/mips64/lithium-mips64.cc @@ -2190,7 +2190,7 @@ LInstruction* LChunkBuilder::DoLoadKeyed(HLoadKeyed* instr) { LOperand* key = UseRegisterOrConstantAtStart(instr->key()); LInstruction* result = NULL; - if (!instr->is_fixed_typed_array()) { + if (!instr->is_typed_elements()) { LOperand* obj = NULL; if (instr->representation().IsDouble()) { obj = UseRegister(instr->elements()); @@ -2211,9 +2211,10 @@ LInstruction* LChunkBuilder::DoLoadKeyed(HLoadKeyed* instr) { } bool needs_environment; - if (instr->is_fixed_typed_array()) { + if (instr->is_external() || instr->is_fixed_typed_array()) { // see LCodeGen::DoLoadKeyedExternalArray - needs_environment = elements_kind == UINT32_ELEMENTS && + needs_environment = (elements_kind == EXTERNAL_UINT32_ELEMENTS || + elements_kind == UINT32_ELEMENTS) && !instr->CheckFlag(HInstruction::kUint32); } else { // see LCodeGen::DoLoadKeyedFixedDoubleArray and @@ -2248,7 +2249,7 @@ LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) { LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) { - if (!instr->is_fixed_typed_array()) { + if (!instr->is_typed_elements()) { DCHECK(instr->elements()->representation().IsTagged()); bool needs_write_barrier = instr->NeedsWriteBarrier(); LOperand* object = NULL; diff --git a/src/mips64/lithium-mips64.h b/src/mips64/lithium-mips64.h index 9a8681f06..24088699d 100644 --- a/src/mips64/lithium-mips64.h +++ b/src/mips64/lithium-mips64.h @@ -1672,9 +1672,15 @@ class LLoadKeyed final : public LTemplateInstruction<1, 2, 0> { ElementsKind elements_kind() const { return hydrogen()->elements_kind(); } + bool is_external() const { + return hydrogen()->is_external(); + } bool is_fixed_typed_array() const { return hydrogen()->is_fixed_typed_array(); } + bool is_typed_elements() const { + return is_external() || is_fixed_typed_array(); + } DECLARE_CONCRETE_INSTRUCTION(LoadKeyed, "load-keyed") DECLARE_HYDROGEN_ACCESSOR(LoadKeyed) @@ -2258,9 +2264,13 @@ class LStoreKeyed final : public LTemplateInstruction<0, 3, 0> { inputs_[2] = value; } + bool is_external() const { return hydrogen()->is_external(); } bool is_fixed_typed_array() const { return hydrogen()->is_fixed_typed_array(); } + bool is_typed_elements() const { + return is_external() || is_fixed_typed_array(); + } LOperand* elements() { return inputs_[0]; } LOperand* key() { return inputs_[1]; } LOperand* value() { return inputs_[2]; } diff --git a/src/objects-debug.cc b/src/objects-debug.cc index 5babfdf1a..b68895fbc 100644 --- a/src/objects-debug.cc +++ b/src/objects-debug.cc @@ -78,6 +78,9 @@ void HeapObject::HeapObjectVerify() { break; #define VERIFY_TYPED_ARRAY(Type, type, TYPE, ctype, size) \ + case EXTERNAL_##TYPE##_ARRAY_TYPE: \ + External##Type##Array::cast(this)->External##Type##ArrayVerify(); \ + break; \ case FIXED_##TYPE##_ARRAY_TYPE: \ Fixed##Type##Array::cast(this)->FixedTypedArrayVerify(); \ break; @@ -233,17 +236,21 @@ void FreeSpace::FreeSpaceVerify() { } +#define EXTERNAL_ARRAY_VERIFY(Type, type, TYPE, ctype, size) \ + void External##Type##Array::External##Type##ArrayVerify() { \ + CHECK(IsExternal##Type##Array()); \ + } + +TYPED_ARRAYS(EXTERNAL_ARRAY_VERIFY) +#undef EXTERNAL_ARRAY_VERIFY + + template void FixedTypedArray::FixedTypedArrayVerify() { CHECK(IsHeapObject() && HeapObject::cast(this)->map()->instance_type() == Traits::kInstanceType); - if (base_pointer() == this) { - CHECK(external_pointer() == - ExternalReference::fixed_typed_array_base_data_offset().address()); - } else { - CHECK(base_pointer() == nullptr); - } + CHECK(base_pointer() == this); } @@ -1089,6 +1096,7 @@ void JSObject::IncrementSpillStatistics(SpillInformation* info) { } #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ + case EXTERNAL_##TYPE##_ELEMENTS: \ case TYPE##_ELEMENTS: TYPED_ARRAYS(TYPED_ARRAY_CASE) diff --git a/src/objects-inl.h b/src/objects-inl.h index 4929c0d2d..8e28aacd7 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -141,7 +141,8 @@ int PropertyDetails::field_width_in_words() const { bool Object::IsFixedArrayBase() const { - return IsFixedArray() || IsFixedDoubleArray() || IsFixedTypedArrayBase(); + return IsFixedArray() || IsFixedDoubleArray() || IsFixedTypedArrayBase() || + IsExternalArray(); } @@ -269,7 +270,8 @@ bool Object::IsExternalTwoByteString() const { bool Object::HasValidElements() { // Dictionary is covered under FixedArray. - return IsFixedArray() || IsFixedDoubleArray() || IsFixedTypedArrayBase(); + return IsFixedArray() || IsFixedDoubleArray() || IsExternalArray() || + IsFixedTypedArrayBase(); } @@ -657,8 +659,18 @@ bool Object::IsFiller() const { } +bool Object::IsExternalArray() const { + if (!Object::IsHeapObject()) + return false; + InstanceType instance_type = + HeapObject::cast(this)->map()->instance_type(); + return (instance_type >= FIRST_EXTERNAL_ARRAY_TYPE && + instance_type <= LAST_EXTERNAL_ARRAY_TYPE); +} + #define TYPED_ARRAY_TYPE_CHECKER(Type, type, TYPE, ctype, size) \ + TYPE_CHECKER(External##Type##Array, EXTERNAL_##TYPE##_ARRAY_TYPE) \ TYPE_CHECKER(Fixed##Type##Array, FIXED_##TYPE##_ARRAY_TYPE) TYPED_ARRAYS(TYPED_ARRAY_TYPE_CHECKER) @@ -2631,6 +2643,10 @@ FixedArrayBase* Map::GetInitialElements() { has_fast_double_elements()) { DCHECK(!GetHeap()->InNewSpace(GetHeap()->empty_fixed_array())); return GetHeap()->empty_fixed_array(); + } else if (has_external_array_elements()) { + ExternalArray* empty_array = GetHeap()->EmptyExternalArrayForMap(this); + DCHECK(!GetHeap()->InNewSpace(empty_array)); + return empty_array; } else if (has_fixed_typed_array_elements()) { FixedTypedArrayBase* empty_array = GetHeap()->EmptyFixedTypedArrayForMap(this); @@ -2919,9 +2935,19 @@ CAST_ACCESSOR(DeoptimizationInputData) CAST_ACCESSOR(DeoptimizationOutputData) CAST_ACCESSOR(DependentCode) CAST_ACCESSOR(DescriptorArray) +CAST_ACCESSOR(ExternalArray) CAST_ACCESSOR(ExternalOneByteString) +CAST_ACCESSOR(ExternalFloat32Array) +CAST_ACCESSOR(ExternalFloat64Array) +CAST_ACCESSOR(ExternalInt16Array) +CAST_ACCESSOR(ExternalInt32Array) +CAST_ACCESSOR(ExternalInt8Array) CAST_ACCESSOR(ExternalString) CAST_ACCESSOR(ExternalTwoByteString) +CAST_ACCESSOR(ExternalUint16Array) +CAST_ACCESSOR(ExternalUint32Array) +CAST_ACCESSOR(ExternalUint8Array) +CAST_ACCESSOR(ExternalUint8ClampedArray) CAST_ACCESSOR(FixedArray) CAST_ACCESSOR(FixedArrayBase) CAST_ACCESSOR(FixedDoubleArray) @@ -3631,6 +3657,211 @@ Address BytecodeArray::GetFirstBytecodeAddress() { } +uint8_t* ExternalUint8ClampedArray::external_uint8_clamped_pointer() { + return reinterpret_cast(external_pointer()); +} + + +uint8_t ExternalUint8ClampedArray::get_scalar(int index) { + DCHECK((index >= 0) && (index < this->length())); + uint8_t* ptr = external_uint8_clamped_pointer(); + return ptr[index]; +} + + +Handle ExternalUint8ClampedArray::get( + Handle array, + int index) { + return Handle(Smi::FromInt(array->get_scalar(index)), + array->GetIsolate()); +} + + +void ExternalUint8ClampedArray::set(int index, uint8_t value) { + DCHECK((index >= 0) && (index < this->length())); + uint8_t* ptr = external_uint8_clamped_pointer(); + ptr[index] = value; +} + + +void* ExternalArray::external_pointer() const { + intptr_t ptr = READ_INTPTR_FIELD(this, kExternalPointerOffset); + return reinterpret_cast(ptr); +} + + +void ExternalArray::set_external_pointer(void* value, WriteBarrierMode mode) { + intptr_t ptr = reinterpret_cast(value); + WRITE_INTPTR_FIELD(this, kExternalPointerOffset, ptr); +} + + +int8_t ExternalInt8Array::get_scalar(int index) { + DCHECK((index >= 0) && (index < this->length())); + int8_t* ptr = static_cast(external_pointer()); + return ptr[index]; +} + + +Handle ExternalInt8Array::get(Handle array, + int index) { + return Handle(Smi::FromInt(array->get_scalar(index)), + array->GetIsolate()); +} + + +void ExternalInt8Array::set(int index, int8_t value) { + DCHECK((index >= 0) && (index < this->length())); + int8_t* ptr = static_cast(external_pointer()); + ptr[index] = value; +} + + +uint8_t ExternalUint8Array::get_scalar(int index) { + DCHECK((index >= 0) && (index < this->length())); + uint8_t* ptr = static_cast(external_pointer()); + return ptr[index]; +} + + +Handle ExternalUint8Array::get(Handle array, + int index) { + return Handle(Smi::FromInt(array->get_scalar(index)), + array->GetIsolate()); +} + + +void ExternalUint8Array::set(int index, uint8_t value) { + DCHECK((index >= 0) && (index < this->length())); + uint8_t* ptr = static_cast(external_pointer()); + ptr[index] = value; +} + + +int16_t ExternalInt16Array::get_scalar(int index) { + DCHECK((index >= 0) && (index < this->length())); + int16_t* ptr = static_cast(external_pointer()); + return ptr[index]; +} + + +Handle ExternalInt16Array::get(Handle array, + int index) { + return Handle(Smi::FromInt(array->get_scalar(index)), + array->GetIsolate()); +} + + +void ExternalInt16Array::set(int index, int16_t value) { + DCHECK((index >= 0) && (index < this->length())); + int16_t* ptr = static_cast(external_pointer()); + ptr[index] = value; +} + + +uint16_t ExternalUint16Array::get_scalar(int index) { + DCHECK((index >= 0) && (index < this->length())); + uint16_t* ptr = static_cast(external_pointer()); + return ptr[index]; +} + + +Handle ExternalUint16Array::get(Handle array, + int index) { + return Handle(Smi::FromInt(array->get_scalar(index)), + array->GetIsolate()); +} + + +void ExternalUint16Array::set(int index, uint16_t value) { + DCHECK((index >= 0) && (index < this->length())); + uint16_t* ptr = static_cast(external_pointer()); + ptr[index] = value; +} + + +int32_t ExternalInt32Array::get_scalar(int index) { + DCHECK((index >= 0) && (index < this->length())); + int32_t* ptr = static_cast(external_pointer()); + return ptr[index]; +} + + +Handle ExternalInt32Array::get(Handle array, + int index) { + return array->GetIsolate()->factory()-> + NewNumberFromInt(array->get_scalar(index)); +} + + +void ExternalInt32Array::set(int index, int32_t value) { + DCHECK((index >= 0) && (index < this->length())); + int32_t* ptr = static_cast(external_pointer()); + ptr[index] = value; +} + + +uint32_t ExternalUint32Array::get_scalar(int index) { + DCHECK((index >= 0) && (index < this->length())); + uint32_t* ptr = static_cast(external_pointer()); + return ptr[index]; +} + + +Handle ExternalUint32Array::get(Handle array, + int index) { + return array->GetIsolate()->factory()-> + NewNumberFromUint(array->get_scalar(index)); +} + + +void ExternalUint32Array::set(int index, uint32_t value) { + DCHECK((index >= 0) && (index < this->length())); + uint32_t* ptr = static_cast(external_pointer()); + ptr[index] = value; +} + + +float ExternalFloat32Array::get_scalar(int index) { + DCHECK((index >= 0) && (index < this->length())); + float* ptr = static_cast(external_pointer()); + return ptr[index]; +} + + +Handle ExternalFloat32Array::get(Handle array, + int index) { + return array->GetIsolate()->factory()->NewNumber(array->get_scalar(index)); +} + + +void ExternalFloat32Array::set(int index, float value) { + DCHECK((index >= 0) && (index < this->length())); + float* ptr = static_cast(external_pointer()); + ptr[index] = value; +} + + +double ExternalFloat64Array::get_scalar(int index) { + DCHECK((index >= 0) && (index < this->length())); + double* ptr = static_cast(external_pointer()); + return ptr[index]; +} + + +Handle ExternalFloat64Array::get(Handle array, + int index) { + return array->GetIsolate()->factory()->NewNumber(array->get_scalar(index)); +} + + +void ExternalFloat64Array::set(int index, double value) { + DCHECK((index >= 0) && (index < this->length())); + double* ptr = static_cast(external_pointer()); + ptr[index] = value; +} + + ACCESSORS(FixedTypedArrayBase, base_pointer, Object, kBasePointerOffset) @@ -3673,7 +3904,6 @@ int FixedTypedArrayBase::ElementSize(InstanceType type) { int FixedTypedArrayBase::DataSize(InstanceType type) { - if (base_pointer() == Smi::FromInt(0)) return 0; return length() * ElementSize(type); } @@ -6081,6 +6311,27 @@ bool JSObject::HasSloppyArgumentsElements() { } +bool JSObject::HasExternalArrayElements() { + HeapObject* array = elements(); + DCHECK(array != NULL); + return array->IsExternalArray(); +} + + +#define EXTERNAL_ELEMENTS_CHECK(Type, type, TYPE, ctype, size) \ +bool JSObject::HasExternal##Type##Elements() { \ + HeapObject* array = elements(); \ + DCHECK(array != NULL); \ + if (!array->IsHeapObject()) \ + return false; \ + return array->map()->instance_type() == EXTERNAL_##TYPE##_ARRAY_TYPE; \ +} + +TYPED_ARRAYS(EXTERNAL_ELEMENTS_CHECK) + +#undef EXTERNAL_ELEMENTS_CHECK + + bool JSObject::HasFixedTypedArrayElements() { HeapObject* array = elements(); DCHECK(array != NULL); @@ -6752,7 +7003,7 @@ bool JSArray::SetLengthWouldNormalize(Heap* heap, uint32_t new_length) { bool JSArray::AllowsSetLength() { bool result = elements()->IsFixedArray() || elements()->IsFixedDoubleArray(); - DCHECK(result == !HasFixedTypedArrayElements()); + DCHECK(result == !HasExternalArrayElements()); return result; } diff --git a/src/objects-printer.cc b/src/objects-printer.cc index cb67d6a6e..f45a03545 100644 --- a/src/objects-printer.cc +++ b/src/objects-printer.cc @@ -80,6 +80,14 @@ void HeapObject::HeapObjectPrint(std::ostream& os) { // NOLINT FreeSpace::cast(this)->FreeSpacePrint(os); break; +#define PRINT_EXTERNAL_ARRAY(Type, type, TYPE, ctype, size) \ + case EXTERNAL_##TYPE##_ARRAY_TYPE: \ + External##Type##Array::cast(this)->External##Type##ArrayPrint(os); \ + break; + + TYPED_ARRAYS(PRINT_EXTERNAL_ARRAY) +#undef PRINT_EXTERNAL_ARRAY + #define PRINT_FIXED_TYPED_ARRAY(Type, type, TYPE, ctype, size) \ case Fixed##Type##Array::kInstanceType: \ Fixed##Type##Array::cast(this)->FixedTypedArrayPrint(os); \ @@ -207,6 +215,16 @@ void FreeSpace::FreeSpacePrint(std::ostream& os) { // NOLINT } +#define EXTERNAL_ARRAY_PRINTER(Type, type, TYPE, ctype, size) \ + void External##Type##Array::External##Type##ArrayPrint(std::ostream& os) { \ + os << "external " #type " array"; \ + } + +TYPED_ARRAYS(EXTERNAL_ARRAY_PRINTER) + +#undef EXTERNAL_ARRAY_PRINTER + + template void FixedTypedArray::FixedTypedArrayPrint( std::ostream& os) { // NOLINT @@ -303,6 +321,19 @@ void JSObject::PrintElements(std::ostream& os) { // NOLINT break; \ } + PRINT_ELEMENTS(EXTERNAL_UINT8_CLAMPED_ELEMENTS, ExternalUint8ClampedArray) + PRINT_ELEMENTS(EXTERNAL_INT8_ELEMENTS, ExternalInt8Array) + PRINT_ELEMENTS(EXTERNAL_UINT8_ELEMENTS, + ExternalUint8Array) + PRINT_ELEMENTS(EXTERNAL_INT16_ELEMENTS, ExternalInt16Array) + PRINT_ELEMENTS(EXTERNAL_UINT16_ELEMENTS, + ExternalUint16Array) + PRINT_ELEMENTS(EXTERNAL_INT32_ELEMENTS, ExternalInt32Array) + PRINT_ELEMENTS(EXTERNAL_UINT32_ELEMENTS, + ExternalUint32Array) + PRINT_ELEMENTS(EXTERNAL_FLOAT32_ELEMENTS, ExternalFloat32Array) + PRINT_ELEMENTS(EXTERNAL_FLOAT64_ELEMENTS, ExternalFloat64Array) + PRINT_ELEMENTS(UINT8_ELEMENTS, FixedUint8Array) PRINT_ELEMENTS(UINT8_CLAMPED_ELEMENTS, FixedUint8ClampedArray) PRINT_ELEMENTS(INT8_ELEMENTS, FixedInt8Array) diff --git a/src/objects.cc b/src/objects.cc index c6d613b2c..2e1443ab4 100644 --- a/src/objects.cc +++ b/src/objects.cc @@ -1281,6 +1281,10 @@ void HeapObject::HeapObjectShortPrint(std::ostream& os) { // NOLINT os << "Size() << "]>"; break; #define TYPED_ARRAY_SHORT_PRINT(Type, type, TYPE, ctype, size) \ + case EXTERNAL_##TYPE##_ARRAY_TYPE: \ + os << "length() << "]>"; \ + break; \ case FIXED_##TYPE##_ARRAY_TYPE: \ os << "length() \ << "]>"; \ @@ -1504,6 +1508,9 @@ void HeapObject::IterateBody(InstanceType type, int object_size, break; #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ + case EXTERNAL_##TYPE##_ARRAY_TYPE: \ + break; \ + \ case FIXED_##TYPE##_ARRAY_TYPE: \ reinterpret_cast(this) \ ->FixedTypedArrayBaseIterateBody(v); \ @@ -3311,7 +3318,8 @@ MaybeHandle Object::SetDataProperty(LookupIterator* it, Handle to_assign = value; // Convert the incoming value to a number for storing into typed arrays. - if (it->IsElement() && receiver->HasFixedTypedArrayElements()) { + if (it->IsElement() && (receiver->HasExternalArrayElements() || + receiver->HasFixedTypedArrayElements())) { if (!value->IsNumber() && !value->IsUndefined()) { ASSIGN_RETURN_ON_EXCEPTION(it->isolate(), to_assign, Execution::ToNumber(it->isolate(), value), @@ -3423,11 +3431,13 @@ MaybeHandle Object::AddDataProperty(LookupIterator* it, } if (FLAG_trace_external_array_abuse && - array->HasFixedTypedArrayElements()) { + (array->HasExternalArrayElements() || + array->HasFixedTypedArrayElements())) { CheckArrayAbuse(array, "typed elements write", it->index(), true); } - if (FLAG_trace_js_array_abuse && !array->HasFixedTypedArrayElements()) { + if (FLAG_trace_js_array_abuse && !array->HasExternalArrayElements() && + !array->HasFixedTypedArrayElements()) { CheckArrayAbuse(array, "elements write", it->index(), false); } } @@ -4256,7 +4266,8 @@ MaybeHandle JSObject::DefineOwnPropertyIgnoreAttributes( // Special case: properties of typed arrays cannot be reconfigured to // non-writable nor to non-enumerable. - if (it->IsElement() && object->HasFixedTypedArrayElements()) { + if (it->IsElement() && (object->HasExternalArrayElements() || + object->HasFixedTypedArrayElements())) { return RedefineNonconfigurableProperty(it->isolate(), it->GetName(), value, STRICT); } @@ -4839,7 +4850,8 @@ Handle JSObject::GetNormalizedElementDictionary( Handle JSObject::NormalizeElements( Handle object) { - DCHECK(!object->HasFixedTypedArrayElements()); + DCHECK(!object->HasExternalArrayElements() && + !object->HasFixedTypedArrayElements()); Isolate* isolate = object->GetIsolate(); // Find the backing store. @@ -5344,6 +5356,7 @@ bool JSObject::ReferencesObject(Object* obj) { // Raw pixels and external arrays do not reference other // objects. #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ + case EXTERNAL_##TYPE##_ELEMENTS: \ case TYPE##_ELEMENTS: \ break; @@ -5453,7 +5466,8 @@ MaybeHandle JSObject::PreventExtensions(Handle object) { } // It's not possible to seal objects with external array elements - if (object->HasFixedTypedArrayElements()) { + if (object->HasExternalArrayElements() || + object->HasFixedTypedArrayElements()) { THROW_NEW_ERROR( isolate, NewTypeError(MessageTemplate::kCannotPreventExtExternalArray), Object); @@ -5546,7 +5560,8 @@ MaybeHandle JSObject::PreventExtensionsWithTransition( } // It's not possible to seal or freeze objects with external array elements - if (object->HasFixedTypedArrayElements()) { + if (object->HasExternalArrayElements() || + object->HasFixedTypedArrayElements()) { THROW_NEW_ERROR( isolate, NewTypeError(MessageTemplate::kCannotPreventExtExternalArray), Object); @@ -5815,7 +5830,7 @@ MaybeHandle JSObjectWalkVisitor::StructureWalk( // Deep copy own elements. // Pixel elements cannot be created using an object literal. - DCHECK(!copy->HasFixedTypedArrayElements()); + DCHECK(!copy->HasExternalArrayElements()); switch (kind) { case FAST_SMI_ELEMENTS: case FAST_ELEMENTS: @@ -5877,6 +5892,7 @@ MaybeHandle JSObjectWalkVisitor::StructureWalk( #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ + case EXTERNAL_##TYPE##_ELEMENTS: \ case TYPE##_ELEMENTS: \ TYPED_ARRAYS(TYPED_ARRAY_CASE) @@ -6279,7 +6295,8 @@ MaybeHandle JSObject::DefineAccessor(Handle object, } // Ignore accessors on typed arrays. - if (it.IsElement() && object->HasFixedTypedArrayElements()) { + if (it.IsElement() && (object->HasFixedTypedArrayElements() || + object->HasExternalArrayElements())) { return it.factory()->undefined_value(); } @@ -6342,7 +6359,8 @@ MaybeHandle JSObject::SetAccessor(Handle object, } // Ignore accessors on typed arrays. - if (it.IsElement() && object->HasFixedTypedArrayElements()) { + if (it.IsElement() && (object->HasFixedTypedArrayElements() || + object->HasExternalArrayElements())) { return it.factory()->undefined_value(); } @@ -6759,10 +6777,13 @@ Handle Map::CopyAsElementsKind(Handle map, ElementsKind kind, Map* maybe_elements_transition_map = NULL; if (flag == INSERT_TRANSITION) { maybe_elements_transition_map = map->ElementsTransitionMap(); - DCHECK(maybe_elements_transition_map == NULL || - (maybe_elements_transition_map->elements_kind() == - DICTIONARY_ELEMENTS && - kind == DICTIONARY_ELEMENTS)); + DCHECK( + maybe_elements_transition_map == NULL || + ((maybe_elements_transition_map->elements_kind() == + DICTIONARY_ELEMENTS || + IsExternalArrayElementsKind( + maybe_elements_transition_map->elements_kind())) && + (kind == DICTIONARY_ELEMENTS || IsExternalArrayElementsKind(kind)))); DCHECK(!IsFastElementsKind(kind) || IsMoreGeneralElementsKindTransition(map->elements_kind(), kind)); DCHECK(kind != map->elements_kind()); @@ -12578,6 +12599,7 @@ int JSObject::GetFastElementsUsage() { case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: case DICTIONARY_ELEMENTS: #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ + case EXTERNAL_##TYPE##_ELEMENTS: \ case TYPE##_ELEMENTS: \ TYPED_ARRAYS(TYPED_ARRAY_CASE) @@ -13011,6 +13033,7 @@ int JSObject::GetOwnElementKeys(FixedArray* storage, } #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ + case EXTERNAL_##TYPE##_ELEMENTS: \ case TYPE##_ELEMENTS: \ TYPED_ARRAYS(TYPED_ARRAY_CASE) @@ -13832,7 +13855,8 @@ Handle JSObject::PrepareElementsForSort(Handle object, JSObject::ValidateElements(object); JSObject::SetMapAndElements(object, new_map, fast_elements); - } else if (object->HasFixedTypedArrayElements()) { + } else if (object->HasExternalArrayElements() || + object->HasFixedTypedArrayElements()) { // Typed arrays cannot have holes or undefined elements. return handle(Smi::FromInt( FixedArrayBase::cast(object->elements())->length()), isolate); @@ -13935,6 +13959,7 @@ Handle JSObject::PrepareElementsForSort(Handle object, ExternalArrayType JSTypedArray::type() { switch (elements()->map()->instance_type()) { #define INSTANCE_TYPE_TO_ARRAY_TYPE(Type, type, TYPE, ctype, size) \ + case EXTERNAL_##TYPE##_ARRAY_TYPE: \ case FIXED_##TYPE##_ARRAY_TYPE: \ return kExternal##Type##Array; @@ -13950,9 +13975,9 @@ ExternalArrayType JSTypedArray::type() { size_t JSTypedArray::element_size() { switch (elements()->map()->instance_type()) { -#define INSTANCE_TYPE_TO_ELEMENT_SIZE(Type, type, TYPE, ctype, size) \ - case FIXED_##TYPE##_ARRAY_TYPE: \ - return size; +#define INSTANCE_TYPE_TO_ELEMENT_SIZE(Type, type, TYPE, ctype, size) \ + case EXTERNAL_##TYPE##_ARRAY_TYPE: \ + return size; TYPED_ARRAYS(INSTANCE_TYPE_TO_ELEMENT_SIZE) #undef INSTANCE_TYPE_TO_ELEMENT_SIZE @@ -13970,6 +13995,131 @@ void FixedArray::SetValue(uint32_t index, Object* value) { set(index, value); } void FixedDoubleArray::SetValue(uint32_t index, Object* value) { set(index, value->Number()); } + + +void ExternalUint8ClampedArray::SetValue(uint32_t index, Object* value) { + uint8_t clamped_value = 0; + if (value->IsSmi()) { + int int_value = Smi::cast(value)->value(); + if (int_value < 0) { + clamped_value = 0; + } else if (int_value > 255) { + clamped_value = 255; + } else { + clamped_value = static_cast(int_value); + } + } else if (value->IsHeapNumber()) { + double double_value = HeapNumber::cast(value)->value(); + if (!(double_value > 0)) { + // NaN and less than zero clamp to zero. + clamped_value = 0; + } else if (double_value > 255) { + // Greater than 255 clamp to 255. + clamped_value = 255; + } else { + // Other doubles are rounded to the nearest integer. + clamped_value = static_cast(lrint(double_value)); + } + } else { + // Clamp undefined to zero (default). All other types have been + // converted to a number type further up in the call chain. + DCHECK(value->IsUndefined()); + } + set(index, clamped_value); +} + + +template +static void ExternalArrayIntSetter(ExternalArrayClass* receiver, uint32_t index, + Object* value) { + ValueType cast_value = 0; + if (value->IsSmi()) { + int int_value = Smi::cast(value)->value(); + cast_value = static_cast(int_value); + } else if (value->IsHeapNumber()) { + double double_value = HeapNumber::cast(value)->value(); + cast_value = static_cast(DoubleToInt32(double_value)); + } else { + // Clamp undefined to zero (default). All other types have been + // converted to a number type further up in the call chain. + DCHECK(value->IsUndefined()); + } + receiver->set(index, cast_value); +} + + +void ExternalInt8Array::SetValue(uint32_t index, Object* value) { + ExternalArrayIntSetter(this, index, value); +} + + +void ExternalUint8Array::SetValue(uint32_t index, Object* value) { + ExternalArrayIntSetter(this, index, value); +} + + +void ExternalInt16Array::SetValue(uint32_t index, Object* value) { + ExternalArrayIntSetter(this, index, value); +} + + +void ExternalUint16Array::SetValue(uint32_t index, Object* value) { + ExternalArrayIntSetter(this, index, value); +} + + +void ExternalInt32Array::SetValue(uint32_t index, Object* value) { + ExternalArrayIntSetter(this, index, value); +} + + +void ExternalUint32Array::SetValue(uint32_t index, Object* value) { + uint32_t cast_value = 0; + if (value->IsSmi()) { + int int_value = Smi::cast(value)->value(); + cast_value = static_cast(int_value); + } else if (value->IsHeapNumber()) { + double double_value = HeapNumber::cast(value)->value(); + cast_value = static_cast(DoubleToUint32(double_value)); + } else { + // Clamp undefined to zero (default). All other types have been + // converted to a number type further up in the call chain. + DCHECK(value->IsUndefined()); + } + set(index, cast_value); +} + + +void ExternalFloat32Array::SetValue(uint32_t index, Object* value) { + float cast_value = std::numeric_limits::quiet_NaN(); + if (value->IsSmi()) { + int int_value = Smi::cast(value)->value(); + cast_value = static_cast(int_value); + } else if (value->IsHeapNumber()) { + double double_value = HeapNumber::cast(value)->value(); + cast_value = static_cast(double_value); + } else { + // Clamp undefined to NaN (default). All other types have been + // converted to a number type further up in the call chain. + DCHECK(value->IsUndefined()); + } + set(index, cast_value); +} + + +void ExternalFloat64Array::SetValue(uint32_t index, Object* value) { + double double_value = std::numeric_limits::quiet_NaN(); + if (value->IsNumber()) { + double_value = value->Number(); + } else { + // Clamp undefined to NaN (default). All other types have been + // converted to a number type further up in the call chain. + DCHECK(value->IsUndefined()); + } + set(index, double_value); +} + + void GlobalObject::InvalidatePropertyCell(Handle global, Handle name) { DCHECK(!global->HasFastProperties()); @@ -15581,6 +15731,21 @@ void JSArrayBuffer::Neuter() { } +static ElementsKind FixedToExternalElementsKind(ElementsKind elements_kind) { + switch (elements_kind) { +#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ + case TYPE##_ELEMENTS: return EXTERNAL_##TYPE##_ELEMENTS; + + TYPED_ARRAYS(TYPED_ARRAY_CASE) +#undef TYPED_ARRAY_CASE + + default: + UNREACHABLE(); + return FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND; + } +} + + Handle JSTypedArray::MaterializeArrayBuffer( Handle typed_array) { @@ -15589,6 +15754,10 @@ Handle JSTypedArray::MaterializeArrayBuffer( DCHECK(IsFixedTypedArrayElementsKind(map->elements_kind())); + Handle new_map = Map::TransitionElementsTo( + map, + FixedToExternalElementsKind(map->elements_kind())); + Handle fixed_typed_array( FixedTypedArrayBase::cast(typed_array->elements())); @@ -15605,19 +15774,19 @@ Handle JSTypedArray::MaterializeArrayBuffer( memcpy(buffer->backing_store(), fixed_typed_array->DataPtr(), fixed_typed_array->DataSize()); - Handle new_elements = - isolate->factory()->NewFixedTypedArrayWithExternalPointer( + Handle new_elements = + isolate->factory()->NewExternalArray( fixed_typed_array->length(), typed_array->type(), static_cast(buffer->backing_store())); - typed_array->set_elements(*new_elements); + JSObject::SetMapAndElements(typed_array, new_map, new_elements); return buffer; } Handle JSTypedArray::GetBuffer() { - if (JSArrayBuffer::cast(buffer())->backing_store() != nullptr) { + if (IsExternalArrayElementsKind(map()->elements_kind())) { Handle result(buffer(), GetIsolate()); return Handle::cast(result); } diff --git a/src/objects.h b/src/objects.h index 7c5b982ae..342a00e1e 100644 --- a/src/objects.h +++ b/src/objects.h @@ -93,6 +93,15 @@ // - ScriptContextTable // - WeakFixedArray // - FixedDoubleArray +// - ExternalArray +// - ExternalUint8ClampedArray +// - ExternalInt8Array +// - ExternalUint8Array +// - ExternalInt16Array +// - ExternalUint16Array +// - ExternalInt32Array +// - ExternalUint32Array +// - ExternalFloat32Array // - Name // - String // - SeqString @@ -383,6 +392,18 @@ const int kStubMinorKeyBits = kSmiValueSize - kStubMajorKeyBits - 1; V(BYTE_ARRAY_TYPE) \ V(BYTECODE_ARRAY_TYPE) \ V(FREE_SPACE_TYPE) \ + /* Note: the order of these external array */ \ + /* types is relied upon in */ \ + /* Object::IsExternalArray(). */ \ + V(EXTERNAL_INT8_ARRAY_TYPE) \ + V(EXTERNAL_UINT8_ARRAY_TYPE) \ + V(EXTERNAL_INT16_ARRAY_TYPE) \ + V(EXTERNAL_UINT16_ARRAY_TYPE) \ + V(EXTERNAL_INT32_ARRAY_TYPE) \ + V(EXTERNAL_UINT32_ARRAY_TYPE) \ + V(EXTERNAL_FLOAT32_ARRAY_TYPE) \ + V(EXTERNAL_FLOAT64_ARRAY_TYPE) \ + V(EXTERNAL_UINT8_CLAMPED_ARRAY_TYPE) \ \ V(FIXED_INT8_ARRAY_TYPE) \ V(FIXED_UINT8_ARRAY_TYPE) \ @@ -668,6 +689,15 @@ enum InstanceType { BYTE_ARRAY_TYPE, BYTECODE_ARRAY_TYPE, FREE_SPACE_TYPE, + EXTERNAL_INT8_ARRAY_TYPE, // FIRST_EXTERNAL_ARRAY_TYPE + EXTERNAL_UINT8_ARRAY_TYPE, + EXTERNAL_INT16_ARRAY_TYPE, + EXTERNAL_UINT16_ARRAY_TYPE, + EXTERNAL_INT32_ARRAY_TYPE, + EXTERNAL_UINT32_ARRAY_TYPE, + EXTERNAL_FLOAT32_ARRAY_TYPE, + EXTERNAL_FLOAT64_ARRAY_TYPE, + EXTERNAL_UINT8_CLAMPED_ARRAY_TYPE, // LAST_EXTERNAL_ARRAY_TYPE FIXED_INT8_ARRAY_TYPE, // FIRST_FIXED_TYPED_ARRAY_TYPE FIXED_UINT8_ARRAY_TYPE, FIXED_INT16_ARRAY_TYPE, @@ -750,6 +780,9 @@ enum InstanceType { // Boundaries for testing for a SIMD type. FIRST_SIMD_TYPE = FLOAT32X4_TYPE, LAST_SIMD_TYPE = FLOAT32X4_TYPE, + // Boundaries for testing for an external array. + FIRST_EXTERNAL_ARRAY_TYPE = EXTERNAL_INT8_ARRAY_TYPE, + LAST_EXTERNAL_ARRAY_TYPE = EXTERNAL_UINT8_CLAMPED_ARRAY_TYPE, // Boundaries for testing for a fixed typed array. FIRST_FIXED_TYPED_ARRAY_TYPE = FIXED_INT8_ARRAY_TYPE, LAST_FIXED_TYPED_ARRAY_TYPE = FIXED_UINT8_CLAMPED_ARRAY_TYPE, @@ -779,6 +812,9 @@ enum InstanceType { NUM_OF_CALLABLE_SPEC_OBJECT_TYPES = 2 }; +const int kExternalArrayTypeCount = + LAST_EXTERNAL_ARRAY_TYPE - FIRST_EXTERNAL_ARRAY_TYPE + 1; + STATIC_ASSERT(JS_OBJECT_TYPE == Internals::kJSObjectType); STATIC_ASSERT(FIRST_NONSTRING_TYPE == Internals::kFirstNonstringType); STATIC_ASSERT(ODDBALL_TYPE == Internals::kOddballType); @@ -897,6 +933,16 @@ template inline bool Is(Object* obj); V(InternalizedString) \ V(Symbol) \ \ + V(ExternalArray) \ + V(ExternalInt8Array) \ + V(ExternalUint8Array) \ + V(ExternalInt16Array) \ + V(ExternalUint16Array) \ + V(ExternalInt32Array) \ + V(ExternalUint32Array) \ + V(ExternalFloat32Array) \ + V(ExternalFloat64Array) \ + V(ExternalUint8ClampedArray) \ V(FixedTypedArrayBase) \ V(FixedUint8Array) \ V(FixedInt8Array) \ @@ -1726,8 +1772,9 @@ class JSObject: public JSReceiver { // writing to any element the array must be copied. Use // EnsureWritableFastElements in this case. // - // In the slow mode the elements is either a NumberDictionary, a - // FixedArray parameter map for a (sloppy) arguments object. + // In the slow mode the elements is either a NumberDictionary, an + // ExternalArray, or a FixedArray parameter map for a (sloppy) + // arguments object. DECL_ACCESSORS(elements, FixedArrayBase) inline void initialize_elements(); static void ResetElements(Handle object); @@ -1754,6 +1801,17 @@ class JSObject: public JSReceiver { inline bool HasSloppyArgumentsElements(); inline bool HasDictionaryElements(); + inline bool HasExternalUint8ClampedElements(); + inline bool HasExternalArrayElements(); + inline bool HasExternalInt8Elements(); + inline bool HasExternalUint8Elements(); + inline bool HasExternalInt16Elements(); + inline bool HasExternalUint16Elements(); + inline bool HasExternalInt32Elements(); + inline bool HasExternalUint32Elements(); + inline bool HasExternalFloat32Elements(); + inline bool HasExternalFloat64Elements(); + inline bool HasFixedTypedArrayElements(); inline bool HasFixedUint8ClampedElements(); @@ -4273,14 +4331,261 @@ class FreeSpace: public HeapObject { V(Uint8Clamped, uint8_clamped, UINT8_CLAMPED, uint8_t, 1) + +// An ExternalArray represents a fixed-size array of primitive values +// which live outside the JavaScript heap. Its subclasses are used to +// implement the CanvasArray types being defined in the WebGL +// specification. As of this writing the first public draft is not yet +// available, but Khronos members can access the draft at: +// https://cvs.khronos.org/svn/repos/3dweb/trunk/doc/spec/WebGL-spec.html +// +// The semantics of these arrays differ from CanvasPixelArray. +// Out-of-range values passed to the setter are converted via a C +// cast, not clamping. Out-of-range indices cause exceptions to be +// raised rather than being silently ignored. +class ExternalArray: public FixedArrayBase { + public: + inline bool is_the_hole(int index) { return false; } + + // [external_pointer]: The pointer to the external memory area backing this + // external array. + DECL_ACCESSORS(external_pointer, void) // Pointer to the data store. + + DECLARE_CAST(ExternalArray) + + // Maximal acceptable length for an external array. + static const int kMaxLength = 0x3fffffff; + + // ExternalArray headers are not quadword aligned. + static const int kExternalPointerOffset = + POINTER_SIZE_ALIGN(FixedArrayBase::kLengthOffset + kPointerSize); + static const int kSize = kExternalPointerOffset + kPointerSize; + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalArray); +}; + + +// A ExternalUint8ClampedArray represents a fixed-size byte array with special +// semantics used for implementing the CanvasPixelArray object. Please see the +// specification at: + +// http://www.whatwg.org/specs/web-apps/current-work/ +// multipage/the-canvas-element.html#canvaspixelarray +// In particular, write access clamps the value written to 0 or 255 if the +// value written is outside this range. +class ExternalUint8ClampedArray: public ExternalArray { + public: + inline uint8_t* external_uint8_clamped_pointer(); + + // Setter and getter. + inline uint8_t get_scalar(int index); + static inline Handle get(Handle array, + int index); + inline void set(int index, uint8_t value); + + // This accessor applies the correct conversion from Smi, HeapNumber + // and undefined and clamps the converted value between 0 and 255. + void SetValue(uint32_t index, Object* value); + + DECLARE_CAST(ExternalUint8ClampedArray) + + // Dispatched behavior. + DECLARE_PRINTER(ExternalUint8ClampedArray) + DECLARE_VERIFIER(ExternalUint8ClampedArray) + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalUint8ClampedArray); +}; + + +class ExternalInt8Array: public ExternalArray { + public: + // Setter and getter. + inline int8_t get_scalar(int index); + static inline Handle get(Handle array, int index); + inline void set(int index, int8_t value); + + // This accessor applies the correct conversion from Smi, HeapNumber + // and undefined. + void SetValue(uint32_t index, Object* value); + + DECLARE_CAST(ExternalInt8Array) + + // Dispatched behavior. + DECLARE_PRINTER(ExternalInt8Array) + DECLARE_VERIFIER(ExternalInt8Array) + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalInt8Array); +}; + + +class ExternalUint8Array: public ExternalArray { + public: + // Setter and getter. + inline uint8_t get_scalar(int index); + static inline Handle get(Handle array, int index); + inline void set(int index, uint8_t value); + + // This accessor applies the correct conversion from Smi, HeapNumber + // and undefined. + void SetValue(uint32_t index, Object* value); + + DECLARE_CAST(ExternalUint8Array) + + // Dispatched behavior. + DECLARE_PRINTER(ExternalUint8Array) + DECLARE_VERIFIER(ExternalUint8Array) + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalUint8Array); +}; + + +class ExternalInt16Array: public ExternalArray { + public: + // Setter and getter. + inline int16_t get_scalar(int index); + static inline Handle get(Handle array, int index); + inline void set(int index, int16_t value); + + // This accessor applies the correct conversion from Smi, HeapNumber + // and undefined. + void SetValue(uint32_t index, Object* value); + + DECLARE_CAST(ExternalInt16Array) + + // Dispatched behavior. + DECLARE_PRINTER(ExternalInt16Array) + DECLARE_VERIFIER(ExternalInt16Array) + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalInt16Array); +}; + + +class ExternalUint16Array: public ExternalArray { + public: + // Setter and getter. + inline uint16_t get_scalar(int index); + static inline Handle get(Handle array, + int index); + inline void set(int index, uint16_t value); + + // This accessor applies the correct conversion from Smi, HeapNumber + // and undefined. + void SetValue(uint32_t index, Object* value); + + DECLARE_CAST(ExternalUint16Array) + + // Dispatched behavior. + DECLARE_PRINTER(ExternalUint16Array) + DECLARE_VERIFIER(ExternalUint16Array) + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalUint16Array); +}; + + +class ExternalInt32Array: public ExternalArray { + public: + // Setter and getter. + inline int32_t get_scalar(int index); + static inline Handle get(Handle array, int index); + inline void set(int index, int32_t value); + + // This accessor applies the correct conversion from Smi, HeapNumber + // and undefined. + void SetValue(uint32_t index, Object* value); + + DECLARE_CAST(ExternalInt32Array) + + // Dispatched behavior. + DECLARE_PRINTER(ExternalInt32Array) + DECLARE_VERIFIER(ExternalInt32Array) + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalInt32Array); +}; + + +class ExternalUint32Array: public ExternalArray { + public: + // Setter and getter. + inline uint32_t get_scalar(int index); + static inline Handle get(Handle array, + int index); + inline void set(int index, uint32_t value); + + // This accessor applies the correct conversion from Smi, HeapNumber + // and undefined. + void SetValue(uint32_t index, Object* value); + + DECLARE_CAST(ExternalUint32Array) + + // Dispatched behavior. + DECLARE_PRINTER(ExternalUint32Array) + DECLARE_VERIFIER(ExternalUint32Array) + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalUint32Array); +}; + + +class ExternalFloat32Array: public ExternalArray { + public: + // Setter and getter. + inline float get_scalar(int index); + static inline Handle get(Handle array, + int index); + inline void set(int index, float value); + + // This accessor applies the correct conversion from Smi, HeapNumber + // and undefined. + void SetValue(uint32_t index, Object* value); + + DECLARE_CAST(ExternalFloat32Array) + + // Dispatched behavior. + DECLARE_PRINTER(ExternalFloat32Array) + DECLARE_VERIFIER(ExternalFloat32Array) + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalFloat32Array); +}; + + +class ExternalFloat64Array: public ExternalArray { + public: + // Setter and getter. + inline double get_scalar(int index); + static inline Handle get(Handle array, + int index); + inline void set(int index, double value); + + // This accessor applies the correct conversion from Smi, HeapNumber + // and undefined. + void SetValue(uint32_t index, Object* value); + + DECLARE_CAST(ExternalFloat64Array) + + // Dispatched behavior. + DECLARE_PRINTER(ExternalFloat64Array) + DECLARE_VERIFIER(ExternalFloat64Array) + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(ExternalFloat64Array); +}; + + class FixedTypedArrayBase: public FixedArrayBase { public: - // [base_pointer]: Either points to the FixedTypedArrayBase itself or nullptr. + // [base_pointer]: For now, points to the FixedTypedArrayBase itself. DECL_ACCESSORS(base_pointer, Object) - // [external_pointer]: Contains the offset between base_pointer and the start - // of the data. If the base_pointer is a nullptr, the external_pointer - // therefore points to the actual backing store. + // [external_pointer]: For now, contains the offset between base_pointer and + // the start of the data. DECL_ACCESSORS(external_pointer, void) // Dispatched behavior. @@ -5431,6 +5736,10 @@ class Map: public HeapObject { return IsSloppyArgumentsElements(elements_kind()); } + inline bool has_external_array_elements() { + return IsExternalArrayElementsKind(elements_kind()); + } + inline bool has_fixed_typed_array_elements() { return IsFixedTypedArrayElementsKind(elements_kind()); } diff --git a/src/ppc/lithium-codegen-ppc.cc b/src/ppc/lithium-codegen-ppc.cc index dc9790b98..bb7287c62 100644 --- a/src/ppc/lithium-codegen-ppc.cc +++ b/src/ppc/lithium-codegen-ppc.cc @@ -3297,7 +3297,10 @@ void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) { bool key_is_smi = instr->hydrogen()->key()->representation().IsSmi(); int base_offset = instr->base_offset(); - if (elements_kind == FLOAT32_ELEMENTS || elements_kind == FLOAT64_ELEMENTS) { + if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS || + elements_kind == FLOAT32_ELEMENTS || + elements_kind == EXTERNAL_FLOAT64_ELEMENTS || + elements_kind == FLOAT64_ELEMENTS) { DoubleRegister result = ToDoubleRegister(instr->result()); if (key_is_constant) { __ Add(scratch0(), external_pointer, constant_key << element_size_shift, @@ -3306,7 +3309,8 @@ void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) { __ IndexToArrayOffset(r0, key, element_size_shift, key_is_smi); __ add(scratch0(), external_pointer, r0); } - if (elements_kind == FLOAT32_ELEMENTS) { + if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS || + elements_kind == FLOAT32_ELEMENTS) { __ lfs(result, MemOperand(scratch0(), base_offset)); } else { // i.e. elements_kind == EXTERNAL_DOUBLE_ELEMENTS __ lfd(result, MemOperand(scratch0(), base_offset)); @@ -3317,6 +3321,7 @@ void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) { PrepareKeyedOperand(key, external_pointer, key_is_constant, key_is_smi, constant_key, element_size_shift, base_offset); switch (elements_kind) { + case EXTERNAL_INT8_ELEMENTS: case INT8_ELEMENTS: if (key_is_constant) { __ LoadByte(result, mem_operand, r0); @@ -3325,6 +3330,8 @@ void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) { } __ extsb(result, result); break; + case EXTERNAL_UINT8_CLAMPED_ELEMENTS: + case EXTERNAL_UINT8_ELEMENTS: case UINT8_ELEMENTS: case UINT8_CLAMPED_ELEMENTS: if (key_is_constant) { @@ -3333,6 +3340,7 @@ void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) { __ lbzx(result, mem_operand); } break; + case EXTERNAL_INT16_ELEMENTS: case INT16_ELEMENTS: if (key_is_constant) { __ LoadHalfWordArith(result, mem_operand, r0); @@ -3340,6 +3348,7 @@ void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) { __ lhax(result, mem_operand); } break; + case EXTERNAL_UINT16_ELEMENTS: case UINT16_ELEMENTS: if (key_is_constant) { __ LoadHalfWord(result, mem_operand, r0); @@ -3347,6 +3356,7 @@ void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) { __ lhzx(result, mem_operand); } break; + case EXTERNAL_INT32_ELEMENTS: case INT32_ELEMENTS: if (key_is_constant) { __ LoadWordArith(result, mem_operand, r0); @@ -3354,6 +3364,7 @@ void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) { __ lwax(result, mem_operand); } break; + case EXTERNAL_UINT32_ELEMENTS: case UINT32_ELEMENTS: if (key_is_constant) { __ LoadWord(result, mem_operand, r0); @@ -3368,6 +3379,8 @@ void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) { break; case FLOAT32_ELEMENTS: case FLOAT64_ELEMENTS: + case EXTERNAL_FLOAT32_ELEMENTS: + case EXTERNAL_FLOAT64_ELEMENTS: case FAST_HOLEY_DOUBLE_ELEMENTS: case FAST_HOLEY_ELEMENTS: case FAST_HOLEY_SMI_ELEMENTS: @@ -3504,7 +3517,7 @@ void LCodeGen::DoLoadKeyedFixedArray(LLoadKeyed* instr) { void LCodeGen::DoLoadKeyed(LLoadKeyed* instr) { - if (instr->is_fixed_typed_array()) { + if (instr->is_typed_elements()) { DoLoadKeyedExternalArray(instr); } else if (instr->hydrogen()->representation().IsDouble()) { DoLoadKeyedFixedDoubleArray(instr); @@ -4558,7 +4571,10 @@ void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) { bool key_is_smi = instr->hydrogen()->key()->representation().IsSmi(); int base_offset = instr->base_offset(); - if (elements_kind == FLOAT32_ELEMENTS || elements_kind == FLOAT64_ELEMENTS) { + if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS || + elements_kind == FLOAT32_ELEMENTS || + elements_kind == EXTERNAL_FLOAT64_ELEMENTS || + elements_kind == FLOAT64_ELEMENTS) { Register address = scratch0(); DoubleRegister value(ToDoubleRegister(instr->value())); if (key_is_constant) { @@ -4572,7 +4588,8 @@ void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) { __ IndexToArrayOffset(r0, key, element_size_shift, key_is_smi); __ add(address, external_pointer, r0); } - if (elements_kind == FLOAT32_ELEMENTS) { + if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS || + elements_kind == FLOAT32_ELEMENTS) { __ frsp(double_scratch0(), value); __ stfs(double_scratch0(), MemOperand(address, base_offset)); } else { // Storing doubles, not floats. @@ -4584,6 +4601,9 @@ void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) { PrepareKeyedOperand(key, external_pointer, key_is_constant, key_is_smi, constant_key, element_size_shift, base_offset); switch (elements_kind) { + case EXTERNAL_UINT8_CLAMPED_ELEMENTS: + case EXTERNAL_INT8_ELEMENTS: + case EXTERNAL_UINT8_ELEMENTS: case UINT8_ELEMENTS: case UINT8_CLAMPED_ELEMENTS: case INT8_ELEMENTS: @@ -4593,6 +4613,8 @@ void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) { __ stbx(value, mem_operand); } break; + case EXTERNAL_INT16_ELEMENTS: + case EXTERNAL_UINT16_ELEMENTS: case INT16_ELEMENTS: case UINT16_ELEMENTS: if (key_is_constant) { @@ -4601,6 +4623,8 @@ void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) { __ sthx(value, mem_operand); } break; + case EXTERNAL_INT32_ELEMENTS: + case EXTERNAL_UINT32_ELEMENTS: case INT32_ELEMENTS: case UINT32_ELEMENTS: if (key_is_constant) { @@ -4611,6 +4635,8 @@ void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) { break; case FLOAT32_ELEMENTS: case FLOAT64_ELEMENTS: + case EXTERNAL_FLOAT32_ELEMENTS: + case EXTERNAL_FLOAT64_ELEMENTS: case FAST_DOUBLE_ELEMENTS: case FAST_ELEMENTS: case FAST_SMI_ELEMENTS: @@ -4728,7 +4754,7 @@ void LCodeGen::DoStoreKeyedFixedArray(LStoreKeyed* instr) { void LCodeGen::DoStoreKeyed(LStoreKeyed* instr) { // By cases: external, fast double - if (instr->is_fixed_typed_array()) { + if (instr->is_typed_elements()) { DoStoreKeyedExternalArray(instr); } else if (instr->hydrogen()->value()->representation().IsDouble()) { DoStoreKeyedFixedDoubleArray(instr); diff --git a/src/ppc/lithium-ppc.cc b/src/ppc/lithium-ppc.cc index 19ea818a3..92dc76b22 100644 --- a/src/ppc/lithium-ppc.cc +++ b/src/ppc/lithium-ppc.cc @@ -2198,7 +2198,7 @@ LInstruction* LChunkBuilder::DoLoadKeyed(HLoadKeyed* instr) { LOperand* key = UseRegisterOrConstantAtStart(instr->key()); LInstruction* result = NULL; - if (!instr->is_fixed_typed_array()) { + if (!instr->is_typed_elements()) { LOperand* obj = NULL; if (instr->representation().IsDouble()) { obj = UseRegister(instr->elements()); @@ -2216,9 +2216,10 @@ LInstruction* LChunkBuilder::DoLoadKeyed(HLoadKeyed* instr) { } bool needs_environment; - if (instr->is_fixed_typed_array()) { + if (instr->is_external() || instr->is_fixed_typed_array()) { // see LCodeGen::DoLoadKeyedExternalArray - needs_environment = elements_kind == UINT32_ELEMENTS && + needs_environment = (elements_kind == EXTERNAL_UINT32_ELEMENTS || + elements_kind == UINT32_ELEMENTS) && !instr->CheckFlag(HInstruction::kUint32); } else { // see LCodeGen::DoLoadKeyedFixedDoubleArray and @@ -2252,7 +2253,7 @@ LInstruction* LChunkBuilder::DoLoadKeyedGeneric(HLoadKeyedGeneric* instr) { LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) { - if (!instr->is_fixed_typed_array()) { + if (!instr->is_typed_elements()) { DCHECK(instr->elements()->representation().IsTagged()); bool needs_write_barrier = instr->NeedsWriteBarrier(); LOperand* object = NULL; diff --git a/src/ppc/lithium-ppc.h b/src/ppc/lithium-ppc.h index dbf980321..f2426d0d5 100644 --- a/src/ppc/lithium-ppc.h +++ b/src/ppc/lithium-ppc.h @@ -1587,9 +1587,13 @@ class LLoadKeyed final : public LTemplateInstruction<1, 2, 0> { LOperand* elements() { return inputs_[0]; } LOperand* key() { return inputs_[1]; } ElementsKind elements_kind() const { return hydrogen()->elements_kind(); } + bool is_external() const { return hydrogen()->is_external(); } bool is_fixed_typed_array() const { return hydrogen()->is_fixed_typed_array(); } + bool is_typed_elements() const { + return is_external() || is_fixed_typed_array(); + } DECLARE_CONCRETE_INSTRUCTION(LoadKeyed, "load-keyed") DECLARE_HYDROGEN_ACCESSOR(LoadKeyed) @@ -2164,9 +2168,13 @@ class LStoreKeyed final : public LTemplateInstruction<0, 3, 0> { inputs_[2] = value; } + bool is_external() const { return hydrogen()->is_external(); } bool is_fixed_typed_array() const { return hydrogen()->is_fixed_typed_array(); } + bool is_typed_elements() const { + return is_external() || is_fixed_typed_array(); + } LOperand* elements() { return inputs_[0]; } LOperand* key() { return inputs_[1]; } LOperand* value() { return inputs_[2]; } diff --git a/src/runtime/runtime-array.cc b/src/runtime/runtime-array.cc index b5655db61..af2d4c548 100644 --- a/src/runtime/runtime-array.cc +++ b/src/runtime/runtime-array.cc @@ -298,6 +298,7 @@ static uint32_t EstimateElementCount(Handle array) { case FAST_SLOPPY_ARGUMENTS_ELEMENTS: case SLOW_SLOPPY_ARGUMENTS_ELEMENTS: #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ + case EXTERNAL_##TYPE##_ELEMENTS: \ case TYPE##_ELEMENTS: TYPED_ARRAYS(TYPED_ARRAY_CASE) @@ -417,6 +418,7 @@ static void CollectElementIndices(Handle object, uint32_t range, } #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ case TYPE##_ELEMENTS: \ + case EXTERNAL_##TYPE##_ELEMENTS: TYPED_ARRAYS(TYPED_ARRAY_CASE) #undef TYPED_ARRAY_CASE @@ -608,6 +610,15 @@ static bool IterateElements(Isolate* isolate, Handle receiver, } break; } + case EXTERNAL_UINT8_CLAMPED_ELEMENTS: { + Handle pixels( + ExternalUint8ClampedArray::cast(receiver->elements())); + for (uint32_t j = 0; j < length; j++) { + Handle e(Smi::FromInt(pixels->get_scalar(j)), isolate); + visitor->visit(j, e); + } + break; + } case UINT8_CLAMPED_ELEMENTS: { Handle pixels( FixedUint8ClampedArray::cast(receiver->elements())); @@ -617,41 +628,81 @@ static bool IterateElements(Isolate* isolate, Handle receiver, } break; } + case EXTERNAL_INT8_ELEMENTS: { + IterateTypedArrayElements( + isolate, receiver, true, true, visitor); + break; + } case INT8_ELEMENTS: { IterateTypedArrayElements( isolate, receiver, true, true, visitor); break; } + case EXTERNAL_UINT8_ELEMENTS: { + IterateTypedArrayElements( + isolate, receiver, true, true, visitor); + break; + } case UINT8_ELEMENTS: { IterateTypedArrayElements( isolate, receiver, true, true, visitor); break; } + case EXTERNAL_INT16_ELEMENTS: { + IterateTypedArrayElements( + isolate, receiver, true, true, visitor); + break; + } case INT16_ELEMENTS: { IterateTypedArrayElements( isolate, receiver, true, true, visitor); break; } + case EXTERNAL_UINT16_ELEMENTS: { + IterateTypedArrayElements( + isolate, receiver, true, true, visitor); + break; + } case UINT16_ELEMENTS: { IterateTypedArrayElements( isolate, receiver, true, true, visitor); break; } + case EXTERNAL_INT32_ELEMENTS: { + IterateTypedArrayElements( + isolate, receiver, true, false, visitor); + break; + } case INT32_ELEMENTS: { IterateTypedArrayElements( isolate, receiver, true, false, visitor); break; } + case EXTERNAL_UINT32_ELEMENTS: { + IterateTypedArrayElements( + isolate, receiver, true, false, visitor); + break; + } case UINT32_ELEMENTS: { IterateTypedArrayElements( isolate, receiver, true, false, visitor); break; } + case EXTERNAL_FLOAT32_ELEMENTS: { + IterateTypedArrayElements( + isolate, receiver, false, false, visitor); + break; + } case FLOAT32_ELEMENTS: { IterateTypedArrayElements( isolate, receiver, false, false, visitor); break; } + case EXTERNAL_FLOAT64_ELEMENTS: { + IterateTypedArrayElements( + isolate, receiver, false, false, visitor); + break; + } case FLOAT64_ELEMENTS: { IterateTypedArrayElements( isolate, receiver, false, false, visitor); @@ -1182,7 +1233,8 @@ RUNTIME_FUNCTION(Runtime_NormalizeElements) { HandleScope scope(isolate); DCHECK(args.length() == 1); CONVERT_ARG_HANDLE_CHECKED(JSObject, array, 0); - RUNTIME_ASSERT(!array->HasFixedTypedArrayElements() && + RUNTIME_ASSERT(!array->HasExternalArrayElements() && + !array->HasFixedTypedArrayElements() && !array->IsJSGlobalProxy()); JSObject::NormalizeElements(array); return *array; diff --git a/src/runtime/runtime-test.cc b/src/runtime/runtime-test.cc index 7ae885e2f..6422efdaa 100644 --- a/src/runtime/runtime-test.cc +++ b/src/runtime/runtime-test.cc @@ -480,13 +480,24 @@ ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements) ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastHoleyElements) ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements) ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(SloppyArgumentsElements) -ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FixedTypedArrayElements) +ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements) // Properties test sitting with elements tests - not fooling anyone. ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastProperties) #undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION +#define TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION(Type, type, TYPE, ctype, size) \ + RUNTIME_FUNCTION(Runtime_HasExternal##Type##Elements) { \ + CONVERT_ARG_CHECKED(JSObject, obj, 0); \ + return isolate->heap()->ToBoolean(obj->HasExternal##Type##Elements()); \ + } + +TYPED_ARRAYS(TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION) + +#undef TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION + + #define FIXED_TYPED_ARRAYS_CHECK_RUNTIME_FUNCTION(Type, type, TYPE, ctype, s) \ RUNTIME_FUNCTION(Runtime_HasFixed##Type##Elements) { \ CONVERT_ARG_CHECKED(JSObject, obj, 0); \ diff --git a/src/runtime/runtime-typedarray.cc b/src/runtime/runtime-typedarray.cc index bfb810e76..4d3552470 100644 --- a/src/runtime/runtime-typedarray.cc +++ b/src/runtime/runtime-typedarray.cc @@ -159,12 +159,14 @@ RUNTIME_FUNCTION(Runtime_ArrayBufferNeuter) { void Runtime::ArrayIdToTypeAndSize(int arrayId, ExternalArrayType* array_type, + ElementsKind* external_elements_kind, ElementsKind* fixed_elements_kind, size_t* element_size) { switch (arrayId) { #define ARRAY_ID_CASE(Type, type, TYPE, ctype, size) \ case ARRAY_ID_##TYPE: \ *array_type = kExternal##Type##Array; \ + *external_elements_kind = EXTERNAL_##TYPE##_ELEMENTS; \ *fixed_elements_kind = TYPE##_ELEMENTS; \ *element_size = size; \ break; @@ -193,9 +195,11 @@ RUNTIME_FUNCTION(Runtime_TypedArrayInitialize) { ExternalArrayType array_type = kExternalInt8Array; // Bogus initialization. size_t element_size = 1; // Bogus initialization. + ElementsKind external_elements_kind = + EXTERNAL_INT8_ELEMENTS; // Bogus initialization. ElementsKind fixed_elements_kind = INT8_ELEMENTS; // Bogus initialization. - Runtime::ArrayIdToTypeAndSize(arrayId, &array_type, &fixed_elements_kind, - &element_size); + Runtime::ArrayIdToTypeAndSize(arrayId, &array_type, &external_elements_kind, + &fixed_elements_kind, &element_size); RUNTIME_ASSERT(holder->map()->elements_kind() == fixed_elements_kind); size_t byte_offset = 0; @@ -237,11 +241,13 @@ RUNTIME_FUNCTION(Runtime_TypedArrayInitialize) { Handle buffer = Handle::cast(maybe_buffer); holder->set_buffer(*buffer); - Handle elements = - isolate->factory()->NewFixedTypedArrayWithExternalPointer( - static_cast(length), array_type, - static_cast(buffer->backing_store()) + byte_offset); - holder->set_elements(*elements); + Handle elements = isolate->factory()->NewExternalArray( + static_cast(length), array_type, + static_cast(buffer->backing_store()) + byte_offset); + Handle map = + JSObject::GetElementsTransitionMap(holder, external_elements_kind); + JSObject::SetMapAndElements(holder, map, elements); + DCHECK(IsExternalArrayElementsKind(holder->map()->elements_kind())); } else { Handle buffer = isolate->factory()->NewJSArrayBuffer(); Runtime::SetupArrayBuffer(isolate, buffer, true, NULL, byte_length, @@ -274,9 +280,11 @@ RUNTIME_FUNCTION(Runtime_TypedArrayInitializeFromArrayLike) { ExternalArrayType array_type = kExternalInt8Array; // Bogus initialization. size_t element_size = 1; // Bogus initialization. + ElementsKind external_elements_kind = + EXTERNAL_INT8_ELEMENTS; // Bogus intialization. ElementsKind fixed_elements_kind = INT8_ELEMENTS; // Bogus initialization. - Runtime::ArrayIdToTypeAndSize(arrayId, &array_type, &fixed_elements_kind, - &element_size); + Runtime::ArrayIdToTypeAndSize(arrayId, &array_type, &external_elements_kind, + &fixed_elements_kind, &element_size); RUNTIME_ASSERT(holder->map()->elements_kind() == fixed_elements_kind); @@ -332,11 +340,12 @@ RUNTIME_FUNCTION(Runtime_TypedArrayInitializeFromArrayLike) { holder->set_byte_length(*byte_length_obj); holder->set_length(*length_obj); - Handle elements = - isolate->factory()->NewFixedTypedArrayWithExternalPointer( - static_cast(length), array_type, - static_cast(buffer->backing_store())); - holder->set_elements(*elements); + Handle elements = isolate->factory()->NewExternalArray( + static_cast(length), array_type, + static_cast(buffer->backing_store())); + Handle map = + JSObject::GetElementsTransitionMap(holder, external_elements_kind); + JSObject::SetMapAndElements(holder, map, elements); if (source->IsJSTypedArray()) { Handle typed_array(JSTypedArray::cast(*source)); diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h index dcd0e4ce6..1e2471cf9 100644 --- a/src/runtime/runtime.h +++ b/src/runtime/runtime.h @@ -658,8 +658,17 @@ namespace internal { F(HasFastHoleyElements, 1, 1) \ F(HasDictionaryElements, 1, 1) \ F(HasSloppyArgumentsElements, 1, 1) \ - F(HasFixedTypedArrayElements, 1, 1) \ + F(HasExternalArrayElements, 1, 1) \ F(HasFastProperties, 1, 1) \ + F(HasExternalUint8Elements, 1, 1) \ + F(HasExternalInt8Elements, 1, 1) \ + F(HasExternalUint16Elements, 1, 1) \ + F(HasExternalInt16Elements, 1, 1) \ + F(HasExternalUint32Elements, 1, 1) \ + F(HasExternalInt32Elements, 1, 1) \ + F(HasExternalFloat32Elements, 1, 1) \ + F(HasExternalFloat64Elements, 1, 1) \ + F(HasExternalUint8ClampedElements, 1, 1) \ F(HasFixedUint8Elements, 1, 1) \ F(HasFixedInt8Elements, 1, 1) \ F(HasFixedUint16Elements, 1, 1) \ @@ -918,6 +927,7 @@ class Runtime : public AllStatic { }; static void ArrayIdToTypeAndSize(int array_id, ExternalArrayType* type, + ElementsKind* external_elements_kind, ElementsKind* fixed_elements_kind, size_t* element_size); diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc index 387949b2d..a4c36b893 100644 --- a/src/x64/lithium-codegen-x64.cc +++ b/src/x64/lithium-codegen-x64.cc @@ -3116,31 +3116,40 @@ void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) { elements_kind, instr->base_offset())); - if (elements_kind == FLOAT32_ELEMENTS) { + if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS || + elements_kind == FLOAT32_ELEMENTS) { XMMRegister result(ToDoubleRegister(instr->result())); __ movss(result, operand); __ cvtss2sd(result, result); - } else if (elements_kind == FLOAT64_ELEMENTS) { + } else if (elements_kind == EXTERNAL_FLOAT64_ELEMENTS || + elements_kind == FLOAT64_ELEMENTS) { __ movsd(ToDoubleRegister(instr->result()), operand); } else { Register result(ToRegister(instr->result())); switch (elements_kind) { + case EXTERNAL_INT8_ELEMENTS: case INT8_ELEMENTS: __ movsxbl(result, operand); break; + case EXTERNAL_UINT8_ELEMENTS: + case EXTERNAL_UINT8_CLAMPED_ELEMENTS: case UINT8_ELEMENTS: case UINT8_CLAMPED_ELEMENTS: __ movzxbl(result, operand); break; + case EXTERNAL_INT16_ELEMENTS: case INT16_ELEMENTS: __ movsxwl(result, operand); break; + case EXTERNAL_UINT16_ELEMENTS: case UINT16_ELEMENTS: __ movzxwl(result, operand); break; + case EXTERNAL_INT32_ELEMENTS: case INT32_ELEMENTS: __ movl(result, operand); break; + case EXTERNAL_UINT32_ELEMENTS: case UINT32_ELEMENTS: __ movl(result, operand); if (!instr->hydrogen()->CheckFlag(HInstruction::kUint32)) { @@ -3148,6 +3157,8 @@ void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) { DeoptimizeIf(negative, instr, Deoptimizer::kNegativeValue); } break; + case EXTERNAL_FLOAT32_ELEMENTS: + case EXTERNAL_FLOAT64_ELEMENTS: case FLOAT32_ELEMENTS: case FLOAT64_ELEMENTS: case FAST_ELEMENTS: @@ -3266,7 +3277,7 @@ void LCodeGen::DoLoadKeyedFixedArray(LLoadKeyed* instr) { void LCodeGen::DoLoadKeyed(LLoadKeyed* instr) { - if (instr->is_fixed_typed_array()) { + if (instr->is_typed_elements()) { DoLoadKeyedExternalArray(instr); } else if (instr->hydrogen()->representation().IsDouble()) { DoLoadKeyedFixedDoubleArray(instr); @@ -4368,28 +4379,39 @@ void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) { elements_kind, instr->base_offset())); - if (elements_kind == FLOAT32_ELEMENTS) { + if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS || + elements_kind == FLOAT32_ELEMENTS) { XMMRegister value(ToDoubleRegister(instr->value())); __ cvtsd2ss(value, value); __ movss(operand, value); - } else if (elements_kind == FLOAT64_ELEMENTS) { + } else if (elements_kind == EXTERNAL_FLOAT64_ELEMENTS || + elements_kind == FLOAT64_ELEMENTS) { __ movsd(operand, ToDoubleRegister(instr->value())); } else { Register value(ToRegister(instr->value())); switch (elements_kind) { + case EXTERNAL_UINT8_CLAMPED_ELEMENTS: + case EXTERNAL_INT8_ELEMENTS: + case EXTERNAL_UINT8_ELEMENTS: case INT8_ELEMENTS: case UINT8_ELEMENTS: case UINT8_CLAMPED_ELEMENTS: __ movb(operand, value); break; + case EXTERNAL_INT16_ELEMENTS: + case EXTERNAL_UINT16_ELEMENTS: case INT16_ELEMENTS: case UINT16_ELEMENTS: __ movw(operand, value); break; + case EXTERNAL_INT32_ELEMENTS: + case EXTERNAL_UINT32_ELEMENTS: case INT32_ELEMENTS: case UINT32_ELEMENTS: __ movl(operand, value); break; + case EXTERNAL_FLOAT32_ELEMENTS: + case EXTERNAL_FLOAT64_ELEMENTS: case FLOAT32_ELEMENTS: case FLOAT64_ELEMENTS: case FAST_ELEMENTS: @@ -4513,7 +4535,7 @@ void LCodeGen::DoStoreKeyedFixedArray(LStoreKeyed* instr) { void LCodeGen::DoStoreKeyed(LStoreKeyed* instr) { - if (instr->is_fixed_typed_array()) { + if (instr->is_typed_elements()) { DoStoreKeyedExternalArray(instr); } else if (instr->hydrogen()->value()->representation().IsDouble()) { DoStoreKeyedFixedDoubleArray(instr); diff --git a/src/x64/lithium-x64.cc b/src/x64/lithium-x64.cc index 27e798460..46bb35ae8 100644 --- a/src/x64/lithium-x64.cc +++ b/src/x64/lithium-x64.cc @@ -2241,7 +2241,7 @@ LInstruction* LChunkBuilder::DoLoadKeyed(HLoadKeyed* instr) { FindDehoistedKeyDefinitions(instr->key()); } - if (!instr->is_fixed_typed_array()) { + if (!instr->is_typed_elements()) { LOperand* obj = UseRegisterAtStart(instr->elements()); result = DefineAsRegister(new(zone()) LLoadKeyed(obj, key)); } else { @@ -2255,9 +2255,10 @@ LInstruction* LChunkBuilder::DoLoadKeyed(HLoadKeyed* instr) { } bool needs_environment; - if (instr->is_fixed_typed_array()) { + if (instr->is_external() || instr->is_fixed_typed_array()) { // see LCodeGen::DoLoadKeyedExternalArray - needs_environment = elements_kind == UINT32_ELEMENTS && + needs_environment = (elements_kind == EXTERNAL_UINT32_ELEMENTS || + elements_kind == UINT32_ELEMENTS) && !instr->CheckFlag(HInstruction::kUint32); } else { // see LCodeGen::DoLoadKeyedFixedDoubleArray and @@ -2297,7 +2298,7 @@ LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) { FindDehoistedKeyDefinitions(instr->key()); } - if (!instr->is_fixed_typed_array()) { + if (!instr->is_typed_elements()) { DCHECK(instr->elements()->representation().IsTagged()); bool needs_write_barrier = instr->NeedsWriteBarrier(); LOperand* object = NULL; @@ -2332,8 +2333,10 @@ LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) { (instr->value()->representation().IsDouble() && IsDoubleOrFloatElementsKind(elements_kind))); DCHECK(instr->elements()->representation().IsExternal()); - bool val_is_temp_register = elements_kind == UINT8_CLAMPED_ELEMENTS || - elements_kind == FLOAT32_ELEMENTS; + bool val_is_temp_register = + elements_kind == EXTERNAL_UINT8_CLAMPED_ELEMENTS || + elements_kind == EXTERNAL_FLOAT32_ELEMENTS || + elements_kind == FLOAT32_ELEMENTS; LOperand* val = val_is_temp_register ? UseTempRegister(instr->value()) : UseRegister(instr->value()); LOperand* key = NULL; diff --git a/src/x64/lithium-x64.h b/src/x64/lithium-x64.h index 06158d479..95d56beb2 100644 --- a/src/x64/lithium-x64.h +++ b/src/x64/lithium-x64.h @@ -1617,8 +1617,12 @@ inline static bool ExternalArrayOpRequiresTemp( // an index cannot fold the scale operation into a load and need an extra // temp register to do the work. return SmiValuesAre31Bits() && key_representation.IsSmi() && - (elements_kind == UINT8_ELEMENTS || elements_kind == INT8_ELEMENTS || - elements_kind == UINT8_CLAMPED_ELEMENTS); + (elements_kind == EXTERNAL_INT8_ELEMENTS || + elements_kind == EXTERNAL_UINT8_ELEMENTS || + elements_kind == EXTERNAL_UINT8_CLAMPED_ELEMENTS || + elements_kind == UINT8_ELEMENTS || + elements_kind == INT8_ELEMENTS || + elements_kind == UINT8_CLAMPED_ELEMENTS); } @@ -1632,9 +1636,15 @@ class LLoadKeyed final : public LTemplateInstruction<1, 2, 0> { DECLARE_CONCRETE_INSTRUCTION(LoadKeyed, "load-keyed") DECLARE_HYDROGEN_ACCESSOR(LoadKeyed) + bool is_external() const { + return hydrogen()->is_external(); + } bool is_fixed_typed_array() const { return hydrogen()->is_fixed_typed_array(); } + bool is_typed_elements() const { + return is_external() || is_fixed_typed_array(); + } LOperand* elements() { return inputs_[0]; } LOperand* key() { return inputs_[1]; } void PrintDataTo(StringStream* stream) override; @@ -2225,9 +2235,13 @@ class LStoreKeyed final : public LTemplateInstruction<0, 3, 0> { inputs_[2] = value; } + bool is_external() const { return hydrogen()->is_external(); } bool is_fixed_typed_array() const { return hydrogen()->is_fixed_typed_array(); } + bool is_typed_elements() const { + return is_external() || is_fixed_typed_array(); + } LOperand* elements() { return inputs_[0]; } LOperand* key() { return inputs_[1]; } LOperand* value() { return inputs_[2]; } diff --git a/src/x87/lithium-codegen-x87.cc b/src/x87/lithium-codegen-x87.cc index 6e74b4510..ee96cf698 100644 --- a/src/x87/lithium-codegen-x87.cc +++ b/src/x87/lithium-codegen-x87.cc @@ -3344,29 +3344,38 @@ void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) { instr->hydrogen()->key()->representation(), elements_kind, instr->base_offset())); - if (elements_kind == FLOAT32_ELEMENTS) { + if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS || + elements_kind == FLOAT32_ELEMENTS) { X87Mov(ToX87Register(instr->result()), operand, kX87FloatOperand); - } else if (elements_kind == FLOAT64_ELEMENTS) { + } else if (elements_kind == EXTERNAL_FLOAT64_ELEMENTS || + elements_kind == FLOAT64_ELEMENTS) { X87Mov(ToX87Register(instr->result()), operand); } else { Register result(ToRegister(instr->result())); switch (elements_kind) { + case EXTERNAL_INT8_ELEMENTS: case INT8_ELEMENTS: __ movsx_b(result, operand); break; + case EXTERNAL_UINT8_CLAMPED_ELEMENTS: + case EXTERNAL_UINT8_ELEMENTS: case UINT8_ELEMENTS: case UINT8_CLAMPED_ELEMENTS: __ movzx_b(result, operand); break; + case EXTERNAL_INT16_ELEMENTS: case INT16_ELEMENTS: __ movsx_w(result, operand); break; + case EXTERNAL_UINT16_ELEMENTS: case UINT16_ELEMENTS: __ movzx_w(result, operand); break; + case EXTERNAL_INT32_ELEMENTS: case INT32_ELEMENTS: __ mov(result, operand); break; + case EXTERNAL_UINT32_ELEMENTS: case UINT32_ELEMENTS: __ mov(result, operand); if (!instr->hydrogen()->CheckFlag(HInstruction::kUint32)) { @@ -3374,6 +3383,8 @@ void LCodeGen::DoLoadKeyedExternalArray(LLoadKeyed* instr) { DeoptimizeIf(negative, instr, Deoptimizer::kNegativeValue); } break; + case EXTERNAL_FLOAT32_ELEMENTS: + case EXTERNAL_FLOAT64_ELEMENTS: case FLOAT32_ELEMENTS: case FLOAT64_ELEMENTS: case FAST_SMI_ELEMENTS: @@ -3452,7 +3463,7 @@ void LCodeGen::DoLoadKeyedFixedArray(LLoadKeyed* instr) { void LCodeGen::DoLoadKeyed(LLoadKeyed* instr) { - if (instr->is_fixed_typed_array()) { + if (instr->is_typed_elements()) { DoLoadKeyedExternalArray(instr); } else if (instr->hydrogen()->representation().IsDouble()) { DoLoadKeyedFixedDoubleArray(instr); @@ -4599,9 +4610,11 @@ void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) { instr->hydrogen()->key()->representation(), elements_kind, instr->base_offset())); - if (elements_kind == FLOAT32_ELEMENTS) { + if (elements_kind == EXTERNAL_FLOAT32_ELEMENTS || + elements_kind == FLOAT32_ELEMENTS) { X87Mov(operand, ToX87Register(instr->value()), kX87FloatOperand); - } else if (elements_kind == FLOAT64_ELEMENTS) { + } else if (elements_kind == EXTERNAL_FLOAT64_ELEMENTS || + elements_kind == FLOAT64_ELEMENTS) { uint64_t int_val = kHoleNanInt64; int32_t lower = static_cast(int_val); int32_t upper = static_cast(int_val >> (kBitsPerInt)); @@ -4631,19 +4644,28 @@ void LCodeGen::DoStoreKeyedExternalArray(LStoreKeyed* instr) { } else { Register value = ToRegister(instr->value()); switch (elements_kind) { + case EXTERNAL_UINT8_CLAMPED_ELEMENTS: + case EXTERNAL_UINT8_ELEMENTS: + case EXTERNAL_INT8_ELEMENTS: case UINT8_ELEMENTS: case INT8_ELEMENTS: case UINT8_CLAMPED_ELEMENTS: __ mov_b(operand, value); break; + case EXTERNAL_INT16_ELEMENTS: + case EXTERNAL_UINT16_ELEMENTS: case UINT16_ELEMENTS: case INT16_ELEMENTS: __ mov_w(operand, value); break; + case EXTERNAL_INT32_ELEMENTS: + case EXTERNAL_UINT32_ELEMENTS: case UINT32_ELEMENTS: case INT32_ELEMENTS: __ mov(operand, value); break; + case EXTERNAL_FLOAT32_ELEMENTS: + case EXTERNAL_FLOAT64_ELEMENTS: case FLOAT32_ELEMENTS: case FLOAT64_ELEMENTS: case FAST_SMI_ELEMENTS: @@ -4759,7 +4781,7 @@ void LCodeGen::DoStoreKeyedFixedArray(LStoreKeyed* instr) { void LCodeGen::DoStoreKeyed(LStoreKeyed* instr) { // By cases...external, fast-double, fast - if (instr->is_fixed_typed_array()) { + if (instr->is_typed_elements()) { DoStoreKeyedExternalArray(instr); } else if (instr->hydrogen()->value()->representation().IsDouble()) { DoStoreKeyedFixedDoubleArray(instr); diff --git a/src/x87/lithium-x87.cc b/src/x87/lithium-x87.cc index 9e310b2a3..2f5f15f28 100644 --- a/src/x87/lithium-x87.cc +++ b/src/x87/lithium-x87.cc @@ -2240,7 +2240,7 @@ LInstruction* LChunkBuilder::DoLoadKeyed(HLoadKeyed* instr) { : UseRegisterOrConstantAtStart(instr->key()); LInstruction* result = NULL; - if (!instr->is_fixed_typed_array()) { + if (!instr->is_typed_elements()) { LOperand* obj = UseRegisterAtStart(instr->elements()); result = DefineAsRegister(new(zone()) LLoadKeyed(obj, key)); } else { @@ -2254,9 +2254,10 @@ LInstruction* LChunkBuilder::DoLoadKeyed(HLoadKeyed* instr) { } bool needs_environment; - if (instr->is_fixed_typed_array()) { + if (instr->is_external() || instr->is_fixed_typed_array()) { // see LCodeGen::DoLoadKeyedExternalArray - needs_environment = elements_kind == UINT32_ELEMENTS && + needs_environment = (elements_kind == EXTERNAL_UINT32_ELEMENTS || + elements_kind == UINT32_ELEMENTS) && !instr->CheckFlag(HInstruction::kUint32); } else { // see LCodeGen::DoLoadKeyedFixedDoubleArray and @@ -2293,6 +2294,9 @@ LOperand* LChunkBuilder::GetStoreKeyedValueOperand(HStoreKeyed* instr) { // Determine if we need a byte register in this case for the value. bool val_is_fixed_register = + elements_kind == EXTERNAL_INT8_ELEMENTS || + elements_kind == EXTERNAL_UINT8_ELEMENTS || + elements_kind == EXTERNAL_UINT8_CLAMPED_ELEMENTS || elements_kind == UINT8_ELEMENTS || elements_kind == INT8_ELEMENTS || elements_kind == UINT8_CLAMPED_ELEMENTS; @@ -2309,7 +2313,7 @@ LOperand* LChunkBuilder::GetStoreKeyedValueOperand(HStoreKeyed* instr) { LInstruction* LChunkBuilder::DoStoreKeyed(HStoreKeyed* instr) { - if (!instr->is_fixed_typed_array()) { + if (!instr->is_typed_elements()) { DCHECK(instr->elements()->representation().IsTagged()); DCHECK(instr->key()->representation().IsInteger32() || instr->key()->representation().IsSmi()); diff --git a/src/x87/lithium-x87.h b/src/x87/lithium-x87.h index cf6c1e181..b8f881dda 100644 --- a/src/x87/lithium-x87.h +++ b/src/x87/lithium-x87.h @@ -1649,9 +1649,15 @@ class LLoadKeyed final : public LTemplateInstruction<1, 2, 0> { ElementsKind elements_kind() const { return hydrogen()->elements_kind(); } + bool is_external() const { + return hydrogen()->is_external(); + } bool is_fixed_typed_array() const { return hydrogen()->is_fixed_typed_array(); } + bool is_typed_elements() const { + return is_external() || is_fixed_typed_array(); + } DECLARE_CONCRETE_INSTRUCTION(LoadKeyed, "load-keyed") DECLARE_HYDROGEN_ACCESSOR(LoadKeyed) @@ -1671,8 +1677,12 @@ inline static bool ExternalArrayOpRequiresTemp( // an index cannot fold the scale operation into a load and need an extra // temp register to do the work. return key_representation.IsSmi() && - (elements_kind == UINT8_ELEMENTS || elements_kind == INT8_ELEMENTS || - elements_kind == UINT8_CLAMPED_ELEMENTS); + (elements_kind == EXTERNAL_INT8_ELEMENTS || + elements_kind == EXTERNAL_UINT8_ELEMENTS || + elements_kind == EXTERNAL_UINT8_CLAMPED_ELEMENTS || + elements_kind == UINT8_ELEMENTS || + elements_kind == INT8_ELEMENTS || + elements_kind == UINT8_CLAMPED_ELEMENTS); } @@ -2253,9 +2263,13 @@ class LStoreKeyed final : public LTemplateInstruction<0, 3, 0> { inputs_[2] = val; } + bool is_external() const { return hydrogen()->is_external(); } bool is_fixed_typed_array() const { return hydrogen()->is_fixed_typed_array(); } + bool is_typed_elements() const { + return is_external() || is_fixed_typed_array(); + } LOperand* elements() { return inputs_[0]; } LOperand* key() { return inputs_[1]; } LOperand* value() { return inputs_[2]; } diff --git a/test/cctest/compiler/test-run-properties.cc b/test/cctest/compiler/test-run-properties.cc index b7677f7fd..d4442f7a8 100644 --- a/test/cctest/compiler/test-run-properties.cc +++ b/test/cctest/compiler/test-run-properties.cc @@ -21,15 +21,16 @@ static void TypedArrayLoadHelper(const char* array_type) { values_builder.AddFormatted("a[%d] = 0x%08x;", i, kValues[i]); } - // Note that below source creates two different typed arrays with the same - // elements kind to get coverage for both (on heap / with external backing - // store) access patterns. + // Note that below source creates two different typed arrays with distinct + // elements kind to get coverage for both access patterns: + // - IsFixedTypedArrayElementsKind(x) + // - IsExternalArrayElementsKind(y) const char* source = "(function(a) {" " var x = (a = new %sArray(%d)); %s;" " var y = (a = new %sArray(%d)); %s; %%TypedArrayGetBuffer(y);" " if (!%%HasFixed%sElements(x)) %%AbortJS('x');" - " if (!%%HasFixed%sElements(y)) %%AbortJS('y');" + " if (!%%HasExternal%sElements(y)) %%AbortJS('y');" " function f(a,b) {" " a = a | 0; b = b | 0;" " return x[a] + y[b];" @@ -83,15 +84,16 @@ static void TypedArrayStoreHelper(const char* array_type) { values_builder.AddFormatted("a[%d] = 0x%08x;", i, kValues[i]); } - // Note that below source creates two different typed arrays with the same - // elements kind to get coverage for both (on heap/with external backing - // store) access patterns. + // Note that below source creates two different typed arrays with distinct + // elements kind to get coverage for both access patterns: + // - IsFixedTypedArrayElementsKind(x) + // - IsExternalArrayElementsKind(y) const char* source = "(function(a) {" " var x = (a = new %sArray(%d)); %s;" " var y = (a = new %sArray(%d)); %s; %%TypedArrayGetBuffer(y);" " if (!%%HasFixed%sElements(x)) %%AbortJS('x');" - " if (!%%HasFixed%sElements(y)) %%AbortJS('y');" + " if (!%%HasExternal%sElements(y)) %%AbortJS('y');" " function f(a,b) {" " a = a | 0; b = b | 0;" " var t = x[a];" diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc index f4d346330..df32722e6 100644 --- a/test/cctest/test-api.cc +++ b/test/cctest/test-api.cc @@ -14149,58 +14149,58 @@ void TypedArrayTestHelper(i::ExternalArrayType array_type, int64_t low, THREADED_TEST(Uint8Array) { - TypedArrayTestHelper(i::kExternalUint8Array, 0, 0xFF); } THREADED_TEST(Int8Array) { - TypedArrayTestHelper(i::kExternalInt8Array, -0x80, 0x7F); } THREADED_TEST(Uint16Array) { - TypedArrayTestHelper(i::kExternalUint16Array, 0, 0xFFFF); } THREADED_TEST(Int16Array) { - TypedArrayTestHelper(i::kExternalInt16Array, -0x8000, 0x7FFF); } THREADED_TEST(Uint32Array) { - TypedArrayTestHelper(i::kExternalUint32Array, 0, UINT_MAX); } THREADED_TEST(Int32Array) { - TypedArrayTestHelper(i::kExternalInt32Array, INT_MIN, INT_MAX); } THREADED_TEST(Float32Array) { - TypedArrayTestHelper(i::kExternalFloat32Array, -500, 500); } THREADED_TEST(Float64Array) { - TypedArrayTestHelper(i::kExternalFloat64Array, -500, 500); } THREADED_TEST(Uint8ClampedArray) { TypedArrayTestHelper( + i::ExternalUint8ClampedArray, v8::ArrayBuffer>( i::kExternalUint8ClampedArray, 0, 0xFF); } @@ -14226,14 +14226,14 @@ THREADED_TEST(DataView) { THREADED_TEST(SharedUint8Array) { i::FLAG_harmony_sharedarraybuffer = true; - TypedArrayTestHelper(i::kExternalUint8Array, 0, 0xFF); } THREADED_TEST(SharedInt8Array) { i::FLAG_harmony_sharedarraybuffer = true; - TypedArrayTestHelper(i::kExternalInt8Array, -0x80, 0x7F); } @@ -14241,7 +14241,7 @@ THREADED_TEST(SharedInt8Array) { THREADED_TEST(SharedUint16Array) { i::FLAG_harmony_sharedarraybuffer = true; - TypedArrayTestHelper(i::kExternalUint16Array, 0, 0xFFFF); } @@ -14249,7 +14249,7 @@ THREADED_TEST(SharedUint16Array) { THREADED_TEST(SharedInt16Array) { i::FLAG_harmony_sharedarraybuffer = true; - TypedArrayTestHelper(i::kExternalInt16Array, -0x8000, 0x7FFF); } @@ -14257,7 +14257,7 @@ THREADED_TEST(SharedInt16Array) { THREADED_TEST(SharedUint32Array) { i::FLAG_harmony_sharedarraybuffer = true; - TypedArrayTestHelper(i::kExternalUint32Array, 0, UINT_MAX); } @@ -14265,7 +14265,7 @@ THREADED_TEST(SharedUint32Array) { THREADED_TEST(SharedInt32Array) { i::FLAG_harmony_sharedarraybuffer = true; - TypedArrayTestHelper(i::kExternalInt32Array, INT_MIN, INT_MAX); } @@ -14273,7 +14273,7 @@ THREADED_TEST(SharedInt32Array) { THREADED_TEST(SharedFloat32Array) { i::FLAG_harmony_sharedarraybuffer = true; - TypedArrayTestHelper(i::kExternalFloat32Array, -500, 500); } @@ -14281,7 +14281,7 @@ THREADED_TEST(SharedFloat32Array) { THREADED_TEST(SharedFloat64Array) { i::FLAG_harmony_sharedarraybuffer = true; - TypedArrayTestHelper(i::kExternalFloat64Array, -500, 500); } @@ -14290,7 +14290,7 @@ THREADED_TEST(SharedFloat64Array) { THREADED_TEST(SharedUint8ClampedArray) { i::FLAG_harmony_sharedarraybuffer = true; TypedArrayTestHelper( + i::ExternalUint8ClampedArray, v8::SharedArrayBuffer>( i::kExternalUint8ClampedArray, 0, 0xFF); } diff --git a/test/mjsunit/elements-kind.js b/test/mjsunit/elements-kind.js index 4da8a9dc6..cb2d178a7 100644 --- a/test/mjsunit/elements-kind.js +++ b/test/mjsunit/elements-kind.js @@ -32,6 +32,15 @@ var elements_kind = { fast : 'fast elements', fast_double : 'fast double elements', dictionary : 'dictionary elements', + external_int32 : 'external int8 elements', + external_uint8 : 'external uint8 elements', + external_int16 : 'external int16 elements', + external_uint16 : 'external uint16 elements', + external_int32 : 'external int32 elements', + external_uint32 : 'external uint32 elements', + external_float32 : 'external float32 elements', + external_float64 : 'external float64 elements', + external_uint8_clamped : 'external uint8_clamped elements', fixed_int32 : 'fixed int8 elements', fixed_uint8 : 'fixed uint8 elements', fixed_int16 : 'fixed int16 elements', @@ -49,6 +58,34 @@ function getKind(obj) { if (%HasFastDoubleElements(obj)) return elements_kind.fast_double; if (%HasDictionaryElements(obj)) return elements_kind.dictionary; + // Every external kind is also an external array. + if (%HasExternalInt8Elements(obj)) { + return elements_kind.external_int8; + } + if (%HasExternalUint8Elements(obj)) { + return elements_kind.external_uint8; + } + if (%HasExternalInt16Elements(obj)) { + return elements_kind.external_int16; + } + if (%HasExternalUint16Elements(obj)) { + return elements_kind.external_uint16; + } + if (%HasExternalInt32Elements(obj)) { + return elements_kind.external_int32; + } + if (%HasExternalUint32Elements(obj)) { + return elements_kind.external_uint32; + } + if (%HasExternalFloat32Elements(obj)) { + return elements_kind.external_float32; + } + if (%HasExternalFloat64Elements(obj)) { + return elements_kind.external_float64; + } + if (%HasExternalUint8ClampedElements(obj)) { + return elements_kind.external_uint8_clamped; + } if (%HasFixedInt8Elements(obj)) { return elements_kind.fixed_int8; } @@ -127,15 +164,15 @@ function test_wrapper() { assertKind(elements_kind.fixed_uint8_clamped, new Uint8ClampedArray(512)); var ab = new ArrayBuffer(128); - assertKind(elements_kind.fixed_int8, new Int8Array(ab)); - assertKind(elements_kind.fixed_uint8, new Uint8Array(ab)); - assertKind(elements_kind.fixed_int16, new Int16Array(ab)); - assertKind(elements_kind.fixed_uint16, new Uint16Array(ab)); - assertKind(elements_kind.fixed_int32, new Int32Array(ab)); - assertKind(elements_kind.fixed_uint32, new Uint32Array(ab)); - assertKind(elements_kind.fixed_float32, new Float32Array(ab)); - assertKind(elements_kind.fixed_float64, new Float64Array(ab)); - assertKind(elements_kind.fixed_uint8_clamped, new Uint8ClampedArray(ab)); + assertKind(elements_kind.external_int8, new Int8Array(ab)); + assertKind(elements_kind.external_uint8, new Uint8Array(ab)); + assertKind(elements_kind.external_int16, new Int16Array(ab)); + assertKind(elements_kind.external_uint16, new Uint16Array(ab)); + assertKind(elements_kind.external_int32, new Int32Array(ab)); + assertKind(elements_kind.external_uint32, new Uint32Array(ab)); + assertKind(elements_kind.external_float32, new Float32Array(ab)); + assertKind(elements_kind.external_float64, new Float64Array(ab)); + assertKind(elements_kind.external_uint8_clamped, new Uint8ClampedArray(ab)); // Crankshaft support for smi-only array elements. function monomorphic(array) { diff --git a/test/mjsunit/opt-elements-kind.js b/test/mjsunit/opt-elements-kind.js index 515305a92..5f4f43729 100644 --- a/test/mjsunit/opt-elements-kind.js +++ b/test/mjsunit/opt-elements-kind.js @@ -33,19 +33,19 @@ // Flags: --stress-runs=2 var elements_kind = { - fast_smi_only : 'fast smi only elements', - fast : 'fast elements', - fast_double : 'fast double elements', - dictionary : 'dictionary elements', - fixed_int32 : 'fixed int8 elements', - fixed_uint8 : 'fixed uint8 elements', - fixed_int16 : 'fixed int16 elements', - fixed_uint16 : 'fixed uint16 elements', - fixed_int32 : 'fixed int32 elements', - fixed_uint32 : 'fixed uint32 elements', - fixed_float32 : 'fixed float32 elements', - fixed_float64 : 'fixed float64 elements', - fixed_uint8_clamped : 'fixed uint8_clamped elements' + fast_smi_only : 'fast smi only elements', + fast : 'fast elements', + fast_double : 'fast double elements', + dictionary : 'dictionary elements', + external_byte : 'external byte elements', + external_unsigned_byte : 'external unsigned byte elements', + external_short : 'external short elements', + external_unsigned_short : 'external unsigned short elements', + external_int : 'external int elements', + external_unsigned_int : 'external unsigned int elements', + external_float : 'external float elements', + external_double : 'external double elements', + external_pixel : 'external pixel elements' } function getKind(obj) { @@ -53,33 +53,34 @@ function getKind(obj) { if (%HasFastObjectElements(obj)) return elements_kind.fast; if (%HasFastDoubleElements(obj)) return elements_kind.fast_double; if (%HasDictionaryElements(obj)) return elements_kind.dictionary; - - if (%HasFixedInt8Elements(obj)) { - return elements_kind.fixed_int8; + // Every external kind is also an external array. + assertTrue(%HasExternalArrayElements(obj)); + if (%HasExternalByteElements(obj)) { + return elements_kind.external_byte; } - if (%HasFixedUint8Elements(obj)) { - return elements_kind.fixed_uint8; + if (%HasExternalUnsignedByteElements(obj)) { + return elements_kind.external_unsigned_byte; } - if (%HasFixedInt16Elements(obj)) { - return elements_kind.fixed_int16; + if (%HasExternalShortElements(obj)) { + return elements_kind.external_short; } - if (%HasFixedUint16Elements(obj)) { - return elements_kind.fixed_uint16; + if (%HasExternalUnsignedShortElements(obj)) { + return elements_kind.external_unsigned_short; } - if (%HasFixedInt32Elements(obj)) { - return elements_kind.fixed_int32; + if (%HasExternalIntElements(obj)) { + return elements_kind.external_int; } - if (%HasFixedUint32Elements(obj)) { - return elements_kind.fixed_uint32; + if (%HasExternalUnsignedIntElements(obj)) { + return elements_kind.external_unsigned_int; } - if (%HasFixedFloat32Elements(obj)) { - return elements_kind.fixed_float32; + if (%HasExternalFloatElements(obj)) { + return elements_kind.external_float; } - if (%HasFixedFloat64Elements(obj)) { - return elements_kind.fixed_float64; + if (%HasExternalDoubleElements(obj)) { + return elements_kind.external_double; } - if (%HasFixedUint8ClampedElements(obj)) { - return elements_kind.fixed_uint8_clamped; + if (%HasExternalPixelElements(obj)) { + return elements_kind.external_pixel; } } diff --git a/test/mjsunit/osr-elements-kind.js b/test/mjsunit/osr-elements-kind.js index bd15ef37e..389b6dac6 100644 --- a/test/mjsunit/osr-elements-kind.js +++ b/test/mjsunit/osr-elements-kind.js @@ -33,19 +33,19 @@ // Flags: --stress-runs=2 var elements_kind = { - fast_smi_only : 'fast smi only elements', - fast : 'fast elements', - fast_double : 'fast double elements', - dictionary : 'dictionary elements', - fixed_int32 : 'fixed int8 elements', - fixed_uint8 : 'fixed uint8 elements', - fixed_int16 : 'fixed int16 elements', - fixed_uint16 : 'fixed uint16 elements', - fixed_int32 : 'fixed int32 elements', - fixed_uint32 : 'fixed uint32 elements', - fixed_float32 : 'fixed float32 elements', - fixed_float64 : 'fixed float64 elements', - fixed_uint8_clamped : 'fixed uint8_clamped elements' + fast_smi_only : 'fast smi only elements', + fast : 'fast elements', + fast_double : 'fast double elements', + dictionary : 'dictionary elements', + external_byte : 'external byte elements', + external_unsigned_byte : 'external unsigned byte elements', + external_short : 'external short elements', + external_unsigned_short : 'external unsigned short elements', + external_int : 'external int elements', + external_unsigned_int : 'external unsigned int elements', + external_float : 'external float elements', + external_double : 'external double elements', + external_pixel : 'external pixel elements' } function getKind(obj) { @@ -53,33 +53,34 @@ function getKind(obj) { if (%HasFastObjectElements(obj)) return elements_kind.fast; if (%HasFastDoubleElements(obj)) return elements_kind.fast_double; if (%HasDictionaryElements(obj)) return elements_kind.dictionary; - - if (%HasFixedInt8Elements(obj)) { - return elements_kind.fixed_int8; + // Every external kind is also an external array. + assertTrue(%HasExternalArrayElements(obj)); + if (%HasExternalByteElements(obj)) { + return elements_kind.external_byte; } - if (%HasFixedUint8Elements(obj)) { - return elements_kind.fixed_uint8; + if (%HasExternalUnsignedByteElements(obj)) { + return elements_kind.external_unsigned_byte; } - if (%HasFixedInt16Elements(obj)) { - return elements_kind.fixed_int16; + if (%HasExternalShortElements(obj)) { + return elements_kind.external_short; } - if (%HasFixedUint16Elements(obj)) { - return elements_kind.fixed_uint16; + if (%HasExternalUnsignedShortElements(obj)) { + return elements_kind.external_unsigned_short; } - if (%HasFixedInt32Elements(obj)) { - return elements_kind.fixed_int32; + if (%HasExternalIntElements(obj)) { + return elements_kind.external_int; } - if (%HasFixedUint32Elements(obj)) { - return elements_kind.fixed_uint32; + if (%HasExternalUnsignedIntElements(obj)) { + return elements_kind.external_unsigned_int; } - if (%HasFixedFloat32Elements(obj)) { - return elements_kind.fixed_float32; + if (%HasExternalFloatElements(obj)) { + return elements_kind.external_float; } - if (%HasFixedFloat64Elements(obj)) { - return elements_kind.fixed_float64; + if (%HasExternalDoubleElements(obj)) { + return elements_kind.external_double; } - if (%HasFixedUint8ClampedElements(obj)) { - return elements_kind.fixed_uint8_clamped; + if (%HasExternalPixelElements(obj)) { + return elements_kind.external_pixel; } } -- 2.34.1