Commit abc35080 authored by danno's avatar danno Committed by Commit bot

Add a MathFloor stub generated with TurboFan

This stub will be used as the basis of a Math.floor-specific CallIC to
detect and track calls to floor that return -0.

Along the way:
- Create a TurboFanCodeStub super class from which the StringLength and
MathRound TF stubs derive.
- Fix the ugly hack that passes the first stub parameter as the "this"
pointer in the the TF-compiled JS function.
- Fix bugs in the ia32/x64 disassembler.

Review URL: https://codereview.chromium.org/1137703002

Cr-Commit-Position: refs/heads/master@{#28339}
parent f750cc09
...@@ -393,6 +393,21 @@ void ApiAccessorDescriptor::Initialize(CallInterfaceDescriptorData* data) { ...@@ -393,6 +393,21 @@ void ApiAccessorDescriptor::Initialize(CallInterfaceDescriptorData* data) {
data->Initialize(arraysize(registers), registers, representations, data->Initialize(arraysize(registers), registers, representations,
&default_descriptor); &default_descriptor);
} }
void MathRoundVariantDescriptor::Initialize(CallInterfaceDescriptorData* data) {
Register registers[] = {
cp, // context
r1, // math rounding function
r3, // vector slot id
};
Representation representations[] = {
Representation::Tagged(), //
Representation::Tagged(), //
Representation::Tagged(), //
};
data->Initialize(arraysize(registers), registers, representations);
}
} }
} // namespace v8::internal } // namespace v8::internal
......
...@@ -444,6 +444,21 @@ void ApiAccessorDescriptor::Initialize(CallInterfaceDescriptorData* data) { ...@@ -444,6 +444,21 @@ void ApiAccessorDescriptor::Initialize(CallInterfaceDescriptorData* data) {
data->Initialize(arraysize(registers), registers, representations, data->Initialize(arraysize(registers), registers, representations,
&default_descriptor); &default_descriptor);
} }
void MathRoundVariantDescriptor::Initialize(CallInterfaceDescriptorData* data) {
Register registers[] = {
cp, // context
x1, // math rounding function
x3, // vector slot id
};
Representation representations[] = {
Representation::Tagged(), //
Representation::Tagged(), //
Representation::Tagged(), //
};
data->Initialize(arraysize(registers), registers, representations);
}
} }
} // namespace v8::internal } // namespace v8::internal
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "src/ic/handler-compiler.h" #include "src/ic/handler-compiler.h"
#include "src/ic/ic.h" #include "src/ic/ic.h"
#include "src/macro-assembler.h" #include "src/macro-assembler.h"
#include "src/parser.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
...@@ -453,6 +454,35 @@ void CompareNilICStub::UpdateStatus(Handle<Object> object) { ...@@ -453,6 +454,35 @@ void CompareNilICStub::UpdateStatus(Handle<Object> object) {
} }
namespace {
Handle<JSFunction> GetFunction(Isolate* isolate, const char* name) {
v8::ExtensionConfiguration no_extensions;
Handle<Context> ctx = isolate->bootstrapper()->CreateEnvironment(
MaybeHandle<JSGlobalProxy>(), v8::Handle<v8::ObjectTemplate>(),
&no_extensions);
Handle<JSBuiltinsObject> builtins = handle(ctx->builtins());
MaybeHandle<Object> fun = Object::GetProperty(isolate, builtins, name);
Handle<JSFunction> function = Handle<JSFunction>::cast(fun.ToHandleChecked());
DCHECK(!function->IsUndefined() &&
"JavaScript implementation of stub not found");
// Just to make sure nobody calls this...
function->set_code(isolate->builtins()->builtin(Builtins::kIllegal));
return function;
}
} // namespace
Handle<Code> TurboFanCodeStub::GenerateCode() {
Zone zone;
// Build a "hybrid" CompilationInfo for a JSFunction/CodeStub pair.
ParseInfo parse_info(&zone, GetFunction(isolate(), GetFunctionName()));
CompilationInfo info(&parse_info);
info.SetStub(this);
return info.GenerateCodeStub();
}
template<class StateType> template<class StateType>
void HydrogenCodeStub::TraceTransition(StateType from, StateType to) { void HydrogenCodeStub::TraceTransition(StateType from, StateType to) {
// Note: Although a no-op transition is semantically OK, it is hinting at a // Note: Although a no-op transition is semantically OK, it is hinting at a
......
...@@ -89,6 +89,9 @@ namespace internal { ...@@ -89,6 +89,9 @@ namespace internal {
V(TransitionElementsKind) \ V(TransitionElementsKind) \
V(VectorRawKeyedLoad) \ V(VectorRawKeyedLoad) \
V(VectorRawLoad) \ V(VectorRawLoad) \
/* TurboFanCodeStubs */ \
V(StringLengthTF) \
V(MathFloor) \
/* IC Handler stubs */ \ /* IC Handler stubs */ \
V(ArrayBufferViewLoadField) \ V(ArrayBufferViewLoadField) \
V(LoadConstant) \ V(LoadConstant) \
...@@ -152,6 +155,8 @@ namespace internal { ...@@ -152,6 +155,8 @@ namespace internal {
CODE_STUB_LIST_PPC(V) \ CODE_STUB_LIST_PPC(V) \
CODE_STUB_LIST_MIPS(V) CODE_STUB_LIST_MIPS(V)
static const int kHasReturnedMinusZeroSentinel = 1;
// Stub is base classes of all stubs. // Stub is base classes of all stubs.
class CodeStub BASE_EMBEDDED { class CodeStub BASE_EMBEDDED {
public: public:
...@@ -206,6 +211,8 @@ class CodeStub BASE_EMBEDDED { ...@@ -206,6 +211,8 @@ class CodeStub BASE_EMBEDDED {
virtual CallInterfaceDescriptor GetCallInterfaceDescriptor() = 0; virtual CallInterfaceDescriptor GetCallInterfaceDescriptor() = 0;
virtual int GetStackParameterCount() const { return 0; }
virtual void InitializeDescriptor(CodeStubDescriptor* descriptor) {} virtual void InitializeDescriptor(CodeStubDescriptor* descriptor) {}
static void InitializeDescriptor(Isolate* isolate, uint32_t key, static void InitializeDescriptor(Isolate* isolate, uint32_t key,
...@@ -348,6 +355,19 @@ struct FakeStubForTesting : public CodeStub { ...@@ -348,6 +355,19 @@ struct FakeStubForTesting : public CodeStub {
Handle<Code> GenerateCode() override; \ Handle<Code> GenerateCode() override; \
DEFINE_CODE_STUB(NAME, SUPER) DEFINE_CODE_STUB(NAME, SUPER)
#define DEFINE_TURBOFAN_CODE_STUB(NAME, SUPER, DESC, STACK_PARAMS) \
public: \
NAME##Stub(Isolate* isolate) : SUPER(isolate) {} \
CallInterfaceDescriptor GetCallInterfaceDescriptor() override { \
return DESC(isolate()); \
}; \
virtual const char* GetFunctionName() const override { \
return #NAME "_STUB"; \
} \
int GetStackParameterCount() const override { return STACK_PARAMS; } \
Code::StubType GetStubType() const override { return Code::FAST; } \
DEFINE_CODE_STUB(NAME, SUPER)
#define DEFINE_HANDLER_CODE_STUB(NAME, SUPER) \ #define DEFINE_HANDLER_CODE_STUB(NAME, SUPER) \
public: \ public: \
Handle<Code> GenerateCode() override; \ Handle<Code> GenerateCode() override; \
...@@ -518,6 +538,23 @@ class HydrogenCodeStub : public CodeStub { ...@@ -518,6 +538,23 @@ class HydrogenCodeStub : public CodeStub {
}; };
class TurboFanCodeStub : public CodeStub {
public:
Code::Kind GetCodeKind() const override { return Code::STUB; }
// Retrieve the code for the stub. Generate the code if needed.
Handle<Code> GenerateCode() override;
virtual const char* GetFunctionName() const = 0;
protected:
explicit TurboFanCodeStub(Isolate* isolate) : CodeStub(isolate) {}
private:
DEFINE_CODE_STUB_BASE(TurboFanCodeStub, CodeStub);
};
// Helper interface to prepare to/restore after making runtime calls. // Helper interface to prepare to/restore after making runtime calls.
class RuntimeCallHelper { class RuntimeCallHelper {
public: public:
...@@ -584,6 +621,23 @@ class NopRuntimeCallHelper : public RuntimeCallHelper { ...@@ -584,6 +621,23 @@ class NopRuntimeCallHelper : public RuntimeCallHelper {
}; };
class MathFloorStub : public TurboFanCodeStub {
DEFINE_TURBOFAN_CODE_STUB(MathFloor, TurboFanCodeStub,
MathRoundVariantDescriptor, 1);
};
class StringLengthTFStub : public TurboFanCodeStub {
DEFINE_TURBOFAN_CODE_STUB(StringLengthTF, TurboFanCodeStub, LoadDescriptor,
0);
public:
Code::Kind GetCodeKind() const override { return Code::HANDLER; }
InlineCacheState GetICState() const override { return MONOMORPHIC; }
ExtraICState GetExtraICState() const override { return Code::LOAD_IC; }
};
class NumberToStringStub final : public HydrogenCodeStub { class NumberToStringStub final : public HydrogenCodeStub {
public: public:
explicit NumberToStringStub(Isolate* isolate) : HydrogenCodeStub(isolate) {} explicit NumberToStringStub(Isolate* isolate) : HydrogenCodeStub(isolate) {}
......
...@@ -175,6 +175,14 @@ int CompilationInfo::num_parameters() const { ...@@ -175,6 +175,14 @@ int CompilationInfo::num_parameters() const {
} }
int CompilationInfo::num_parameters_including_this() const {
return num_parameters() + (is_this_defined() ? 1 : 0);
}
bool CompilationInfo::is_this_defined() const { return !IsStub(); }
int CompilationInfo::num_heap_slots() const { int CompilationInfo::num_heap_slots() const {
return has_scope() ? scope()->num_heap_slots() : 0; return has_scope() ? scope()->num_heap_slots() : 0;
} }
...@@ -273,6 +281,14 @@ void CompilationInfo::LogDeoptCallPosition(int pc_offset, int inlining_id) { ...@@ -273,6 +281,14 @@ void CompilationInfo::LogDeoptCallPosition(int pc_offset, int inlining_id) {
} }
Handle<Code> CompilationInfo::GenerateCodeStub() {
// Run a "mini pipeline", extracted from compiler.cc.
CHECK(Parser::ParseStatic(parse_info()));
CHECK(Compiler::Analyze(parse_info()));
return compiler::Pipeline(this).GenerateCode();
}
class HOptimizedGraphBuilderWithPositions: public HOptimizedGraphBuilder { class HOptimizedGraphBuilderWithPositions: public HOptimizedGraphBuilder {
public: public:
explicit HOptimizedGraphBuilderWithPositions(CompilationInfo* info) explicit HOptimizedGraphBuilderWithPositions(CompilationInfo* info)
......
...@@ -165,6 +165,8 @@ class CompilationInfo { ...@@ -165,6 +165,8 @@ class CompilationInfo {
Handle<Code> unoptimized_code() const { return unoptimized_code_; } Handle<Code> unoptimized_code() const { return unoptimized_code_; }
int opt_count() const { return opt_count_; } int opt_count() const { return opt_count_; }
int num_parameters() const; int num_parameters() const;
int num_parameters_including_this() const;
bool is_this_defined() const;
int num_heap_slots() const; int num_heap_slots() const;
Code::Flags flags() const; Code::Flags flags() const;
bool has_scope() const { return scope() != nullptr; } bool has_scope() const { return scope() != nullptr; }
...@@ -387,6 +389,8 @@ class CompilationInfo { ...@@ -387,6 +389,8 @@ class CompilationInfo {
bool is_simple_parameter_list(); bool is_simple_parameter_list();
Handle<Code> GenerateCodeStub();
protected: protected:
ParseInfo* parse_info_; ParseInfo* parse_info_;
......
...@@ -150,6 +150,20 @@ ElementAccess AccessBuilder::ForSeqStringChar(String::Encoding encoding) { ...@@ -150,6 +150,20 @@ ElementAccess AccessBuilder::ForSeqStringChar(String::Encoding encoding) {
return {kUntaggedBase, 0, Type::None(), kMachNone}; return {kUntaggedBase, 0, Type::None(), kMachNone};
} }
// static
FieldAccess AccessBuilder::ForJSFunctionSharedFunctionInfo() {
return {kTaggedBase, JSFunction::kSharedFunctionInfoOffset, Handle<Name>(),
Type::Any(), kMachAnyTagged};
}
// static
FieldAccess AccessBuilder::ForSharedFunctionInfoTypeFeedbackVector() {
return {kTaggedBase, SharedFunctionInfo::kFeedbackVectorOffset,
Handle<Name>(), Type::Any(), kMachAnyTagged};
}
} // namespace compiler } // namespace compiler
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
...@@ -65,6 +65,12 @@ class AccessBuilder final : public AllStatic { ...@@ -65,6 +65,12 @@ class AccessBuilder final : public AllStatic {
// Provides access to the charaters of sequential strings. // Provides access to the charaters of sequential strings.
static ElementAccess ForSeqStringChar(String::Encoding encoding); static ElementAccess ForSeqStringChar(String::Encoding encoding);
// Provides access to the SharedFunctionInfo in a JSFunction.
static FieldAccess ForJSFunctionSharedFunctionInfo();
// Provides access to the TypeFeedbackVector in SharedFunctionInfo.
static FieldAccess ForSharedFunctionInfoTypeFeedbackVector();
private: private:
DISALLOW_IMPLICIT_CONSTRUCTORS(AccessBuilder); DISALLOW_IMPLICIT_CONSTRUCTORS(AccessBuilder);
}; };
......
...@@ -429,7 +429,7 @@ void AstGraphBuilder::CreateFunctionContext(bool constant_context) { ...@@ -429,7 +429,7 @@ void AstGraphBuilder::CreateFunctionContext(bool constant_context) {
Node* AstGraphBuilder::NewOuterContextParam() { Node* AstGraphBuilder::NewOuterContextParam() {
// Parameter (arity + 1) is special for the outer context of the function // Parameter (arity + 1) is special for the outer context of the function
const Operator* op = const Operator* op =
common()->Parameter(info()->num_parameters() + 1, "%context"); common()->Parameter(info()->num_parameters_including_this(), "%context");
return NewNode(op, graph()->start()); return NewNode(op, graph()->start());
} }
...@@ -437,8 +437,8 @@ Node* AstGraphBuilder::NewOuterContextParam() { ...@@ -437,8 +437,8 @@ Node* AstGraphBuilder::NewOuterContextParam() {
Node* AstGraphBuilder::NewCurrentContextOsrValue() { Node* AstGraphBuilder::NewCurrentContextOsrValue() {
// TODO(titzer): use a real OSR value here; a parameter works by accident. // TODO(titzer): use a real OSR value here; a parameter works by accident.
// Parameter (arity + 1) is special for the outer context of the function // Parameter (arity + 1) is special for the outer context of the function
const Operator* op = const Operator* op = common()->Parameter(
common()->Parameter(info()->num_parameters() + 1, "%osr-context"); info()->num_parameters_including_this(), "%osr-context");
return NewNode(op, graph()->start()); return NewNode(op, graph()->start());
} }
...@@ -615,16 +615,22 @@ AstGraphBuilder::Environment::Environment(AstGraphBuilder* builder, ...@@ -615,16 +615,22 @@ AstGraphBuilder::Environment::Environment(AstGraphBuilder* builder,
DCHECK_EQ(scope->num_parameters() + 1, parameters_count()); DCHECK_EQ(scope->num_parameters() + 1, parameters_count());
// Bind the receiver variable. // Bind the receiver variable.
Node* receiver = builder->graph()->NewNode(common()->Parameter(0, "%this"), int param_num = 0;
builder->graph()->start()); if (builder->info()->is_this_defined()) {
values()->push_back(receiver); Node* receiver = builder->graph()->NewNode(
common()->Parameter(param_num++, "%this"), builder->graph()->start());
values()->push_back(receiver);
} else {
values()->push_back(builder->jsgraph()->UndefinedConstant());
}
// Bind all parameter variables. The parameter indices are shifted by 1 // Bind all parameter variables. The parameter indices are shifted by 1
// (receiver is parameter index -1 but environment index 0). // (receiver is parameter index -1 but environment index 0).
for (int i = 0; i < scope->num_parameters(); ++i) { for (int i = 0; i < scope->num_parameters(); ++i) {
const char* debug_name = GetDebugParameterName(graph()->zone(), scope, i); const char* debug_name = GetDebugParameterName(graph()->zone(), scope, i);
Node* parameter = builder->graph()->NewNode( Node* parameter =
common()->Parameter(i + 1, debug_name), builder->graph()->start()); builder->graph()->NewNode(common()->Parameter(param_num++, debug_name),
builder->graph()->start());
values()->push_back(parameter); values()->push_back(parameter);
} }
......
...@@ -74,6 +74,12 @@ Reduction JSIntrinsicLowering::Reduce(Node* node) { ...@@ -74,6 +74,12 @@ Reduction JSIntrinsicLowering::Reduce(Node* node) {
return ReduceUnLikely(node, BranchHint::kFalse); return ReduceUnLikely(node, BranchHint::kFalse);
case Runtime::kInlineValueOf: case Runtime::kInlineValueOf:
return ReduceValueOf(node); return ReduceValueOf(node);
case Runtime::kInlineIsMinusZero:
return ReduceIsMinusZero(node);
case Runtime::kInlineFixedArraySet:
return ReduceFixedArraySet(node);
case Runtime::kInlineGetTypeFeedbackVector:
return ReduceGetTypeFeedbackVector(node);
default: default:
break; break;
} }
...@@ -398,6 +404,67 @@ Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op) { ...@@ -398,6 +404,67 @@ Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op) {
} }
Reduction JSIntrinsicLowering::ReduceIsMinusZero(Node* node) {
Node* value = NodeProperties::GetValueInput(node, 0);
Node* effect = NodeProperties::GetEffectInput(node);
Node* double_lo =
graph()->NewNode(machine()->Float64ExtractLowWord32(), value);
Node* check1 = graph()->NewNode(machine()->Word32Equal(), double_lo,
jsgraph()->ZeroConstant());
Node* double_hi =
graph()->NewNode(machine()->Float64ExtractHighWord32(), value);
Node* check2 = graph()->NewNode(
machine()->Word32Equal(), double_hi,
jsgraph()->Int32Constant(static_cast<int32_t>(0x80000000)));
NodeProperties::ReplaceWithValue(node, node, effect);
Node* and_result = graph()->NewNode(machine()->Word32And(), check1, check2);
return Change(node, machine()->Word32Equal(), and_result,
jsgraph()->Int32Constant(1));
}
Reduction JSIntrinsicLowering::ReduceFixedArraySet(Node* node) {
Node* base = node->InputAt(0);
Node* index = node->InputAt(1);
Node* value = node->InputAt(2);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
Node* store = (graph()->NewNode(
simplified()->StoreElement(AccessBuilder::ForFixedArrayElement()), base,
index, value, effect, control));
NodeProperties::ReplaceWithValue(node, value, store);
return Changed(store);
}
Reduction JSIntrinsicLowering::ReduceGetTypeFeedbackVector(Node* node) {
Node* func = node->InputAt(0);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
FieldAccess access = AccessBuilder::ForJSFunctionSharedFunctionInfo();
Node* load =
graph()->NewNode(simplified()->LoadField(access), func, effect, control);
access = AccessBuilder::ForSharedFunctionInfoTypeFeedbackVector();
return Change(node, simplified()->LoadField(access), load, load, control);
}
Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op, Node* a,
Node* b) {
node->set_op(op);
node->ReplaceInput(0, a);
node->ReplaceInput(1, b);
node->TrimInputCount(2);
NodeProperties::ReplaceWithValue(node, node, node);
return Changed(node);
}
Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op, Node* a, Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op, Node* a,
Node* b, Node* c) { Node* b, Node* c) {
node->set_op(op); node->set_op(op);
......
...@@ -34,6 +34,7 @@ class JSIntrinsicLowering final : public Reducer { ...@@ -34,6 +34,7 @@ class JSIntrinsicLowering final : public Reducer {
Reduction ReduceDoubleLo(Node* node); Reduction ReduceDoubleLo(Node* node);
Reduction ReduceHeapObjectGetMap(Node* node); Reduction ReduceHeapObjectGetMap(Node* node);
Reduction ReduceIncrementStatsCounter(Node* node); Reduction ReduceIncrementStatsCounter(Node* node);
Reduction ReduceIsMinusZero(Node* node);
Reduction ReduceIsInstanceType(Node* node, InstanceType instance_type); Reduction ReduceIsInstanceType(Node* node, InstanceType instance_type);
Reduction ReduceIsNonNegativeSmi(Node* node); Reduction ReduceIsNonNegativeSmi(Node* node);
Reduction ReduceIsSmi(Node* node); Reduction ReduceIsSmi(Node* node);
...@@ -47,8 +48,11 @@ class JSIntrinsicLowering final : public Reducer { ...@@ -47,8 +48,11 @@ class JSIntrinsicLowering final : public Reducer {
Reduction ReduceStringGetLength(Node* node); Reduction ReduceStringGetLength(Node* node);
Reduction ReduceUnLikely(Node* node, BranchHint hint); Reduction ReduceUnLikely(Node* node, BranchHint hint);
Reduction ReduceValueOf(Node* node); Reduction ReduceValueOf(Node* node);
Reduction ReduceFixedArraySet(Node* node);
Reduction ReduceGetTypeFeedbackVector(Node* node);
Reduction Change(Node* node, const Operator* op); Reduction Change(Node* node, const Operator* op);
Reduction Change(Node* node, const Operator* op, Node* a, Node* b);
Reduction Change(Node* node, const Operator* op, Node* a, Node* b, Node* c); Reduction Change(Node* node, const Operator* op, Node* a, Node* b, Node* c);
Reduction ChangeToUndefined(Node* node, Node* effect = nullptr); Reduction ChangeToUndefined(Node* node, Node* effect = nullptr);
......
...@@ -51,11 +51,11 @@ bool CallDescriptor::HasSameReturnLocationsAs( ...@@ -51,11 +51,11 @@ bool CallDescriptor::HasSameReturnLocationsAs(
CallDescriptor* Linkage::ComputeIncoming(Zone* zone, CompilationInfo* info) { CallDescriptor* Linkage::ComputeIncoming(Zone* zone, CompilationInfo* info) {
if (info->code_stub() != NULL) { if (info->code_stub() != NULL) {
// Use the code stub interface descriptor. // Use the code stub interface descriptor.
CallInterfaceDescriptor descriptor = CodeStub* stub = info->code_stub();
info->code_stub()->GetCallInterfaceDescriptor(); CallInterfaceDescriptor descriptor = stub->GetCallInterfaceDescriptor();
return GetStubCallDescriptor(info->isolate(), zone, descriptor, 0, return GetStubCallDescriptor(
CallDescriptor::kNoFlags, info->isolate(), zone, descriptor, stub->GetStackParameterCount(),
Operator::kNoProperties); CallDescriptor::kNoFlags, Operator::kNoProperties);
} }
if (info->function() != NULL) { if (info->function() != NULL) {
// If we already have the function literal, use the number of parameters // If we already have the function literal, use the number of parameters
......
...@@ -1576,6 +1576,7 @@ Bounds Typer::Visitor::TypeJSCallRuntime(Node* node) { ...@@ -1576,6 +1576,7 @@ Bounds Typer::Visitor::TypeJSCallRuntime(Node* node) {
case Runtime::kInlineIsSmi: case Runtime::kInlineIsSmi:
case Runtime::kInlineIsNonNegativeSmi: case Runtime::kInlineIsNonNegativeSmi:
case Runtime::kInlineIsArray: case Runtime::kInlineIsArray:
case Runtime::kInlineIsMinusZero:
case Runtime::kInlineIsFunction: case Runtime::kInlineIsFunction:
case Runtime::kInlineIsRegExp: case Runtime::kInlineIsRegExp:
return Bounds(Type::None(zone()), Type::Boolean(zone())); return Bounds(Type::None(zone()), Type::Boolean(zone()));
......
...@@ -1641,7 +1641,7 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer, ...@@ -1641,7 +1641,7 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
} else if (*data == 0x16) { } else if (*data == 0x16) {
data++; data++;
int mod, regop, rm; int mod, regop, rm;
get_modrm(*data, &mod, &regop, &rm); get_modrm(*data, &mod, &rm, &regop);
int8_t imm8 = static_cast<int8_t>(data[1]); int8_t imm8 = static_cast<int8_t>(data[1]);
AppendToBuffer("pextrd %s,%s,%d", AppendToBuffer("pextrd %s,%s,%d",
NameOfCPURegister(regop), NameOfCPURegister(regop),
......
...@@ -370,6 +370,21 @@ void ApiAccessorDescriptor::Initialize(CallInterfaceDescriptorData* data) { ...@@ -370,6 +370,21 @@ void ApiAccessorDescriptor::Initialize(CallInterfaceDescriptorData* data) {
}; };
data->Initialize(arraysize(registers), registers, representations); data->Initialize(arraysize(registers), registers, representations);
} }
void MathRoundVariantDescriptor::Initialize(CallInterfaceDescriptorData* data) {
Register registers[] = {
esi, // context
edi, // math rounding function
edx, // vector slot id
};
Representation representations[] = {
Representation::Tagged(), //
Representation::Tagged(), //
Representation::Tagged(), //
};
data->Initialize(arraysize(registers), registers, representations);
}
} }
} // namespace v8::internal } // namespace v8::internal
......
...@@ -58,6 +58,7 @@ class PlatformInterfaceDescriptor; ...@@ -58,6 +58,7 @@ class PlatformInterfaceDescriptor;
V(StoreArrayLiteralElement) \ V(StoreArrayLiteralElement) \
V(MathPowTagged) \ V(MathPowTagged) \
V(MathPowInteger) \ V(MathPowInteger) \
V(MathRoundVariant) \
V(ContextOnly) \ V(ContextOnly) \
V(GrowArrayElements) V(GrowArrayElements)
...@@ -528,6 +529,12 @@ class MathPowIntegerDescriptor : public CallInterfaceDescriptor { ...@@ -528,6 +529,12 @@ class MathPowIntegerDescriptor : public CallInterfaceDescriptor {
}; };
class MathRoundVariantDescriptor : public CallInterfaceDescriptor {
public:
DECLARE_DESCRIPTOR(MathRoundVariantDescriptor, CallInterfaceDescriptor)
};
class ContextOnlyDescriptor : public CallInterfaceDescriptor { class ContextOnlyDescriptor : public CallInterfaceDescriptor {
public: public:
DECLARE_DESCRIPTOR(ContextOnlyDescriptor, CallInterfaceDescriptor) DECLARE_DESCRIPTOR(ContextOnlyDescriptor, CallInterfaceDescriptor)
......
...@@ -369,6 +369,21 @@ void ApiAccessorDescriptor::Initialize(CallInterfaceDescriptorData* data) { ...@@ -369,6 +369,21 @@ void ApiAccessorDescriptor::Initialize(CallInterfaceDescriptorData* data) {
}; };
data->Initialize(arraysize(registers), registers, representations); data->Initialize(arraysize(registers), registers, representations);
} }
void MathRoundVariantDescriptor::Initialize(CallInterfaceDescriptorData* data) {
Register registers[] = {
a1, // context
a2, // math rounding function
a3, // vector slot id
};
Representation representations[] = {
Representation::Tagged(), //
Representation::Tagged(), //
Representation::Tagged(), //
};
data->Initialize(arraysize(registers), registers, representations);
}
} }
} // namespace v8::internal } // namespace v8::internal
......
...@@ -369,6 +369,21 @@ void ApiAccessorDescriptor::Initialize(CallInterfaceDescriptorData* data) { ...@@ -369,6 +369,21 @@ void ApiAccessorDescriptor::Initialize(CallInterfaceDescriptorData* data) {
}; };
data->Initialize(arraysize(registers), registers, representations); data->Initialize(arraysize(registers), registers, representations);
} }
void MathRoundVariantDescriptor::Initialize(CallInterfaceDescriptorData* data) {
Register registers[] = {
a1, // context
a2, // math rounding function
a3, // vector slot id
};
Representation representations[] = {
Representation::Tagged(), //
Representation::Tagged(), //
Representation::Tagged(), //
};
data->Initialize(arraysize(registers), registers, representations);
}
} }
} // namespace v8::internal } // namespace v8::internal
......
...@@ -62,7 +62,8 @@ var TO_NUMBER; ...@@ -62,7 +62,8 @@ var TO_NUMBER;
var TO_STRING; var TO_STRING;
var TO_NAME; var TO_NAME;
var STRING_LENGTH_STUB; var StringLengthTF_STUB;
var MathFloor_STUB;
var $defaultNumber; var $defaultNumber;
var $defaultString; var $defaultString;
...@@ -750,11 +751,31 @@ TO_NAME = function TO_NAME() { ...@@ -750,11 +751,31 @@ TO_NAME = function TO_NAME() {
----------------------------------------------- -----------------------------------------------
*/ */
STRING_LENGTH_STUB = function STRING_LENGTH_STUB(name) { StringLengthTF_STUB = function StringLengthTF_STUB(receiver, name) {
var receiver = this; // implicit first parameter
return %_StringGetLength(%_JSValueGetValue(receiver)); return %_StringGetLength(%_JSValueGetValue(receiver));
} }
MathFloor_STUB = function MathFloor_STUB(f, i, v) {
// |f| is calling function's JSFunction
// |i| is TypeFeedbackVector slot # of callee's CallIC for Math.floor call
// |v| is the value to floor
var r = %_MathFloor(+v);
if (%_IsMinusZero(r)) {
// Collect type feedback when the result of the floor is -0. This is
// accomplished by storing a sentinel in the second, "extra"
// TypeFeedbackVector slot corresponding to the Math.floor CallIC call in
// the caller's TypeVector.
%_FixedArraySet(%_GetTypeFeedbackVector(f), ((i|0)+1)|0, 1);
return -0;
}
// Return integers in smi range as smis.
var trunc = r|0;
if (trunc === r) {
return trunc;
}
return r;
}
/* ------------------------------------- /* -------------------------------------
- - - C o n v e r s i o n s - - - - - - C o n v e r s i o n s - - -
......
...@@ -54,6 +54,26 @@ RUNTIME_FUNCTION(Runtime_SpecialArrayFunctions) { ...@@ -54,6 +54,26 @@ RUNTIME_FUNCTION(Runtime_SpecialArrayFunctions) {
} }
RUNTIME_FUNCTION(Runtime_FixedArrayGet) {
SealHandleScope shs(isolate);
DCHECK(args.length() == 2);
CONVERT_ARG_CHECKED(FixedArray, object, 0);
CONVERT_SMI_ARG_CHECKED(index, 1);
return object->get(index);
}
RUNTIME_FUNCTION(Runtime_FixedArraySet) {
SealHandleScope shs(isolate);
DCHECK(args.length() == 3);
CONVERT_ARG_CHECKED(FixedArray, object, 0);
CONVERT_SMI_ARG_CHECKED(index, 1);
CONVERT_ARG_CHECKED(Object, value, 2);
object->set(index, value);
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_TransitionElementsKind) { RUNTIME_FUNCTION(Runtime_TransitionElementsKind) {
HandleScope scope(isolate); HandleScope scope(isolate);
RUNTIME_ASSERT(args.length() == 2); RUNTIME_ASSERT(args.length() == 2);
......
...@@ -27,26 +27,6 @@ RUNTIME_FUNCTION(Runtime_TheHole) { ...@@ -27,26 +27,6 @@ RUNTIME_FUNCTION(Runtime_TheHole) {
} }
RUNTIME_FUNCTION(Runtime_FixedArrayGet) {
SealHandleScope shs(isolate);
DCHECK(args.length() == 2);
CONVERT_ARG_CHECKED(FixedArray, object, 0);
CONVERT_SMI_ARG_CHECKED(index, 1);
return object->get(index);
}
RUNTIME_FUNCTION(Runtime_FixedArraySet) {
SealHandleScope shs(isolate);
DCHECK(args.length() == 3);
CONVERT_ARG_CHECKED(FixedArray, object, 0);
CONVERT_SMI_ARG_CHECKED(index, 1);
CONVERT_ARG_CHECKED(Object, value, 2);
object->set(index, value);
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_JSCollectionGetTable) { RUNTIME_FUNCTION(Runtime_JSCollectionGetTable) {
SealHandleScope shs(isolate); SealHandleScope shs(isolate);
DCHECK(args.length() == 1); DCHECK(args.length() == 1);
......
...@@ -408,5 +408,13 @@ RUNTIME_FUNCTION(Runtime_HarmonyToString) { ...@@ -408,5 +408,13 @@ RUNTIME_FUNCTION(Runtime_HarmonyToString) {
// TODO(caitp): Delete this runtime method when removing --harmony-tostring // TODO(caitp): Delete this runtime method when removing --harmony-tostring
return isolate->heap()->ToBoolean(FLAG_harmony_tostring); return isolate->heap()->ToBoolean(FLAG_harmony_tostring);
} }
RUNTIME_FUNCTION(Runtime_GetTypeFeedbackVector) {
SealHandleScope shs(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_CHECKED(JSFunction, function, 0);
return function->shared()->feedback_vector();
}
} }
} // namespace v8::internal } // namespace v8::internal
...@@ -49,6 +49,8 @@ namespace internal { ...@@ -49,6 +49,8 @@ namespace internal {
F(IsArray, 1, 1) \ F(IsArray, 1, 1) \
F(HasCachedArrayIndex, 1, 1) \ F(HasCachedArrayIndex, 1, 1) \
F(GetCachedArrayIndex, 1, 1) \ F(GetCachedArrayIndex, 1, 1) \
F(FixedArrayGet, 2, 1) \
F(FixedArraySet, 3, 1) \
F(FastOneByteArrayJoin, 2, 1) F(FastOneByteArrayJoin, 2, 1)
...@@ -78,8 +80,6 @@ namespace internal { ...@@ -78,8 +80,6 @@ namespace internal {
#define FOR_EACH_INTRINSIC_COLLECTIONS(F) \ #define FOR_EACH_INTRINSIC_COLLECTIONS(F) \
F(StringGetRawHashField, 1, 1) \ F(StringGetRawHashField, 1, 1) \
F(TheHole, 0, 1) \ F(TheHole, 0, 1) \
F(FixedArrayGet, 2, 1) \
F(FixedArraySet, 3, 1) \
F(JSCollectionGetTable, 1, 1) \ F(JSCollectionGetTable, 1, 1) \
F(GenericHash, 1, 1) \ F(GenericHash, 1, 1) \
F(SetInitialize, 1, 1) \ F(SetInitialize, 1, 1) \
...@@ -302,7 +302,8 @@ namespace internal { ...@@ -302,7 +302,8 @@ namespace internal {
F(IncrementStatsCounter, 1, 1) \ F(IncrementStatsCounter, 1, 1) \
F(Likely, 1, 1) \ F(Likely, 1, 1) \
F(Unlikely, 1, 1) \ F(Unlikely, 1, 1) \
F(HarmonyToString, 0, 1) F(HarmonyToString, 0, 1) \
F(GetTypeFeedbackVector, 1, 1)
#define FOR_EACH_INTRINSIC_JSON(F) \ #define FOR_EACH_INTRINSIC_JSON(F) \
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include "src/v8.h" #include "src/v8.h"
#include "src/code-stubs.h"
#include "src/ic/ic.h" #include "src/ic/ic.h"
#include "src/ic/ic-state.h" #include "src/ic/ic-state.h"
#include "src/objects.h" #include "src/objects.h"
...@@ -312,7 +313,8 @@ InlineCacheState CallICNexus::StateFromFeedback() const { ...@@ -312,7 +313,8 @@ InlineCacheState CallICNexus::StateFromFeedback() const {
Isolate* isolate = GetIsolate(); Isolate* isolate = GetIsolate();
Object* feedback = GetFeedback(); Object* feedback = GetFeedback();
DCHECK(!FLAG_vector_ics || DCHECK(!FLAG_vector_ics ||
GetFeedbackExtra() == *vector()->UninitializedSentinel(isolate)); GetFeedbackExtra() == *vector()->UninitializedSentinel(isolate) ||
GetFeedbackExtra() == Smi::FromInt(kHasReturnedMinusZeroSentinel));
if (feedback == *vector()->MegamorphicSentinel(isolate)) { if (feedback == *vector()->MegamorphicSentinel(isolate)) {
return GENERIC; return GENERIC;
......
...@@ -1390,7 +1390,7 @@ int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) { ...@@ -1390,7 +1390,7 @@ int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) {
AppendToBuffer(",%d", (*current) & 3); AppendToBuffer(",%d", (*current) & 3);
current += 1; current += 1;
} else if (third_byte == 0x16) { } else if (third_byte == 0x16) {
get_modrm(*current, &mod, &regop, &rm); get_modrm(*current, &mod, &rm, &regop);
AppendToBuffer("pextrd "); // reg/m32, xmm, imm8 AppendToBuffer("pextrd "); // reg/m32, xmm, imm8
current += PrintRightOperand(current); current += PrintRightOperand(current);
AppendToBuffer(",%s,%d", NameOfXMMRegister(regop), (*current) & 3); AppendToBuffer(",%s,%d", NameOfXMMRegister(regop), (*current) & 3);
......
...@@ -371,6 +371,21 @@ void ApiAccessorDescriptor::Initialize(CallInterfaceDescriptorData* data) { ...@@ -371,6 +371,21 @@ void ApiAccessorDescriptor::Initialize(CallInterfaceDescriptorData* data) {
}; };
data->Initialize(arraysize(registers), registers, representations); data->Initialize(arraysize(registers), registers, representations);
} }
void MathRoundVariantDescriptor::Initialize(CallInterfaceDescriptorData* data) {
Register registers[] = {
rsi, // context
rdi, // math rounding function
rdx, // vector slot id
};
Representation representations[] = {
Representation::Tagged(), //
Representation::Tagged(), //
Representation::Tagged(), //
};
data->Initialize(arraysize(registers), registers, representations);
}
} }
} // namespace v8::internal } // namespace v8::internal
......
...@@ -6,7 +6,10 @@ ...@@ -6,7 +6,10 @@
#include "src/code-stubs.h" #include "src/code-stubs.h"
#include "src/compiler/common-operator.h" #include "src/compiler/common-operator.h"
#include "src/compiler/graph.h" #include "src/compiler/graph.h"
#include "src/compiler/js-graph.h"
#include "src/compiler/js-operator.h"
#include "src/compiler/linkage.h" #include "src/compiler/linkage.h"
#include "src/compiler/machine-operator.h"
#include "src/compiler/pipeline.h" #include "src/compiler/pipeline.h"
#include "src/parser.h" #include "src/parser.h"
#include "test/cctest/compiler/function-tester.h" #include "test/cctest/compiler/function-tester.h"
...@@ -17,60 +20,54 @@ using namespace v8::internal; ...@@ -17,60 +20,54 @@ using namespace v8::internal;
using namespace v8::internal::compiler; using namespace v8::internal::compiler;
static Handle<JSFunction> GetFunction(Isolate* isolate, const char* name) { TEST(RunMathFloorStub) {
v8::ExtensionConfiguration no_extensions; HandleAndZoneScope scope;
Handle<Context> ctx = isolate->bootstrapper()->CreateEnvironment( Isolate* isolate = scope.main_isolate();
MaybeHandle<JSGlobalProxy>(), v8::Handle<v8::ObjectTemplate>(),
&no_extensions);
Handle<JSBuiltinsObject> builtins = handle(ctx->builtins());
MaybeHandle<Object> fun = Object::GetProperty(isolate, builtins, name);
Handle<JSFunction> function = Handle<JSFunction>::cast(fun.ToHandleChecked());
// Just to make sure nobody calls this...
function->set_code(isolate->builtins()->builtin(Builtins::kIllegal));
return function;
}
class StringLengthStubTF : public CodeStub {
public:
explicit StringLengthStubTF(Isolate* isolate) : CodeStub(isolate) {}
StringLengthStubTF(uint32_t key, Isolate* isolate) : CodeStub(key, isolate) {} // Create code and an accompanying descriptor.
MathFloorStub stub(isolate);
Handle<Code> code = stub.GenerateCode();
Zone* zone = scope.main_zone();
CallInterfaceDescriptor GetCallInterfaceDescriptor() override { CompilationInfo info(&stub, isolate, zone);
return LoadDescriptor(isolate()); CallDescriptor* descriptor = Linkage::ComputeIncoming(zone, &info);
};
Handle<Code> GenerateCode() override { // Create a function to call the code using the descriptor.
Zone zone; Graph graph(zone);
// Build a "hybrid" CompilationInfo for a JSFunction/CodeStub pair. CommonOperatorBuilder common(zone);
ParseInfo parse_info(&zone, GetFunction(isolate(), "STRING_LENGTH_STUB")); JSOperatorBuilder javascript(zone);
CompilationInfo info(&parse_info); MachineOperatorBuilder machine(zone);
info.SetStub(this); JSGraph js(isolate, &graph, &common, &javascript, &machine);
// Run a "mini pipeline", extracted from compiler.cc.
CHECK(Parser::ParseStatic(info.parse_info()));
CHECK(Compiler::Analyze(info.parse_info()));
return Pipeline(&info).GenerateCode();
}
Major MajorKey() const override { return StringLength; }; // FunctionTester (ab)uses a 2-argument function
Code::Kind GetCodeKind() const override { return Code::HANDLER; } Node* start = graph.NewNode(common.Start(2));
InlineCacheState GetICState() const override { return MONOMORPHIC; } // Parameter 0 is the number to round
ExtraICState GetExtraICState() const override { return Code::LOAD_IC; } Node* numberParam = graph.NewNode(common.Parameter(1), start);
Code::StubType GetStubType() const override { return Code::FAST; } Unique<HeapObject> u = Unique<HeapObject>::CreateImmovable(code);
Node* theCode = graph.NewNode(common.HeapConstant(u));
Node* dummyContext = graph.NewNode(common.NumberConstant(0.0));
Node* call = graph.NewNode(common.Call(descriptor), theCode,
js.UndefinedConstant(), js.UndefinedConstant(),
numberParam, dummyContext, start, start);
Node* ret = graph.NewNode(common.Return(), call, call, start);
Node* end = graph.NewNode(common.End(), ret);
graph.SetStart(start);
graph.SetEnd(end);
FunctionTester ft(&graph);
private: Handle<Object> value = ft.Val(1.5);
DISALLOW_COPY_AND_ASSIGN(StringLengthStubTF); Handle<Object> result = ft.Call(value, value).ToHandleChecked();
}; CHECK_EQ(1, Smi::cast(*result)->value());
}
TEST(RunStringLengthStubTF) { TEST(RunStringLengthTFStub) {
HandleAndZoneScope scope; HandleAndZoneScope scope;
Isolate* isolate = scope.main_isolate(); Isolate* isolate = scope.main_isolate();
Zone* zone = scope.main_zone(); Zone* zone = scope.main_zone();
// Create code and an accompanying descriptor. // Create code and an accompanying descriptor.
StringLengthStubTF stub(isolate); StringLengthTFStub stub(isolate);
Handle<Code> code = stub.GenerateCode(); Handle<Code> code = stub.GenerateCode();
CompilationInfo info(&stub, isolate, zone); CompilationInfo info(&stub, isolate, zone);
CallDescriptor* descriptor = Linkage::ComputeIncoming(zone, &info); CallDescriptor* descriptor = Linkage::ComputeIncoming(zone, &info);
......
// Copyright 2015 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Flags: --allow-natives-syntax --expose-natives-as=builtins --noalways-opt
const kExtraTypeFeedbackMinusZeroSentinel = 1;
const kFirstSlotExtraTypeFeedbackIndex = 5;
(function(){
var floorFunc = function() {
Math.floor(NaN);
}
// Execute the function once to make sure it has a type feedback vector.
floorFunc(5);
assertTrue(kExtraTypeFeedbackMinusZeroSentinel !==
%FixedArrayGet(%GetTypeFeedbackVector(floorFunc),
kFirstSlotExtraTypeFeedbackIndex));
assertEquals(5.0, builtins.MathFloor_STUB(floorFunc, 4, 5.5));
assertTrue(kExtraTypeFeedbackMinusZeroSentinel !==
%FixedArrayGet(%GetTypeFeedbackVector(floorFunc),
kFirstSlotExtraTypeFeedbackIndex));
// Executing floor such that it returns -0 should set the proper sentinel in
// the feedback vector.
assertEquals(-Infinity, 1/builtins.MathFloor_STUB(floorFunc, 4, -0));
assertEquals(kExtraTypeFeedbackMinusZeroSentinel,
%FixedArrayGet(%GetTypeFeedbackVector(floorFunc),
kFirstSlotExtraTypeFeedbackIndex));
%ClearFunctionTypeFeedback(floorFunc);
})();
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment