// r0 -- number of arguments
// r1 -- function
// r2 -- type info cell with elements kind
- static Register registers[] = { r1, r2 };
- descriptor->register_param_count_ = 2;
- if (constant_stack_parameter_count != 0) {
+ static Register registers_variable_args[] = { r1, r2, r0 };
+ static Register registers_no_args[] = { r1, r2 };
+
+ if (constant_stack_parameter_count == 0) {
+ descriptor->register_param_count_ = 2;
+ descriptor->register_params_ = registers_no_args;
+ } else {
// stack param count needs (constructor pointer, and single argument)
+ descriptor->handler_arguments_mode_ = PASS_ARGUMENTS;
descriptor->stack_parameter_count_ = r0;
+ descriptor->register_param_count_ = 3;
+ descriptor->register_params_ = registers_variable_args;
}
+
descriptor->hint_stack_parameter_count_ = constant_stack_parameter_count;
- descriptor->register_params_ = registers;
descriptor->function_mode_ = JS_FUNCTION_STUB_MODE;
descriptor->deoptimization_handler_ =
Runtime::FunctionForId(Runtime::kArrayConstructor)->entry;
// register state
// r0 -- number of arguments
// r1 -- constructor function
- static Register registers[] = { r1 };
- descriptor->register_param_count_ = 1;
+ static Register registers_variable_args[] = { r1, r0 };
+ static Register registers_no_args[] = { r1 };
- if (constant_stack_parameter_count != 0) {
+ if (constant_stack_parameter_count == 0) {
+ descriptor->register_param_count_ = 1;
+ descriptor->register_params_ = registers_no_args;
+ } else {
// stack param count needs (constructor pointer, and single argument)
+ descriptor->handler_arguments_mode_ = PASS_ARGUMENTS;
descriptor->stack_parameter_count_ = r0;
+ descriptor->register_param_count_ = 2;
+ descriptor->register_params_ = registers_variable_args;
}
+
descriptor->hint_stack_parameter_count_ = constant_stack_parameter_count;
- descriptor->register_params_ = registers;
descriptor->function_mode_ = JS_FUNCTION_STUB_MODE;
descriptor->deoptimization_handler_ =
Runtime::FunctionForId(Runtime::kInternalArrayConstructor)->entry;
ApiFunction function(descriptor->deoptimization_handler_);
ExternalReference xref(&function, ExternalReference::BUILTIN_CALL, isolate_);
intptr_t handler = reinterpret_cast<intptr_t>(xref.address());
- int params = descriptor->environment_length();
+ int params = descriptor->GetHandlerParameterCount();
output_frame->SetRegister(r0.code(), params);
output_frame->SetRegister(r1.code(), handler);
}
CodeStubInterfaceDescriptor* descriptor =
info()->code_stub()->GetInterfaceDescriptor(info()->isolate());
int index = static_cast<int>(instr->index());
- Register reg = DESCRIPTOR_GET_PARAMETER_REGISTER(descriptor, index);
+ Register reg = descriptor->GetParameterRegister(index);
return DefineFixed(result, reg);
}
}
next_block->SetJoinId(BailoutId::StubEntry());
set_current_block(next_block);
+ bool runtime_stack_params = descriptor_->stack_parameter_count_.is_valid();
+ HInstruction* stack_parameter_count = NULL;
for (int i = 0; i < param_count; ++i) {
- HParameter* param =
- Add<HParameter>(i, HParameter::REGISTER_PARAMETER);
+ Representation r = descriptor_->IsParameterCountRegister(i)
+ ? Representation::Integer32()
+ : Representation::Tagged();
+ HParameter* param = Add<HParameter>(i, HParameter::REGISTER_PARAMETER, r);
start_environment->Bind(i, param);
parameters_[i] = param;
+ if (descriptor_->IsParameterCountRegister(i)) {
+ param->set_type(HType::Smi());
+ stack_parameter_count = param;
+ arguments_length_ = stack_parameter_count;
+ }
}
- HInstruction* stack_parameter_count;
- if (descriptor_->stack_parameter_count_.is_valid()) {
- ASSERT(descriptor_->environment_length() == (param_count + 1));
- stack_parameter_count = New<HParameter>(param_count,
- HParameter::REGISTER_PARAMETER,
- Representation::Integer32());
- stack_parameter_count->set_type(HType::Smi());
- // It's essential to bind this value to the environment in case of deopt.
- AddInstruction(stack_parameter_count);
- start_environment->Bind(param_count, stack_parameter_count);
- arguments_length_ = stack_parameter_count;
- } else {
- ASSERT(descriptor_->environment_length() == param_count);
+ ASSERT(!runtime_stack_params || arguments_length_ != NULL);
+ if (!runtime_stack_params) {
stack_parameter_count = graph()->GetConstantMinus1();
arguments_length_ = graph()->GetConstant0();
}
if (descriptor_->function_mode_ == JS_FUNCTION_STUB_MODE) {
if (!stack_parameter_count->IsConstant() &&
descriptor_->hint_stack_parameter_count_ < 0) {
- HInstruction* amount = graph()->GetConstant1();
- stack_pop_count = Add<HAdd>(stack_parameter_count, amount);
- stack_pop_count->ChangeRepresentation(Representation::Integer32());
+ HInstruction* constant_one = graph()->GetConstant1();
+ stack_pop_count = Add<HAdd>(stack_parameter_count, constant_one);
stack_pop_count->ClearFlag(HValue::kCanOverflow);
+ // TODO(mvstanton): verify that stack_parameter_count+1 really fits in a
+ // smi.
} else {
int count = descriptor_->hint_stack_parameter_count_;
stack_pop_count = Add<HConstant>(count);
function_mode_(NOT_JS_FUNCTION_STUB_MODE),
register_params_(NULL),
deoptimization_handler_(NULL),
+ handler_arguments_mode_(DONT_PASS_ARGUMENTS),
miss_handler_(),
has_miss_handler_(false) { }
enum StubFunctionMode { NOT_JS_FUNCTION_STUB_MODE, JS_FUNCTION_STUB_MODE };
-
+enum HandlerArgumentsMode { DONT_PASS_ARGUMENTS, PASS_ARGUMENTS };
struct CodeStubInterfaceDescriptor {
CodeStubInterfaceDescriptor();
int register_param_count_;
+
Register stack_parameter_count_;
// if hint_stack_parameter_count_ > 0, the code stub can optimize the
// return sequence. Default value is -1, which means it is ignored.
int hint_stack_parameter_count_;
StubFunctionMode function_mode_;
Register* register_params_;
+
Address deoptimization_handler_;
+ HandlerArgumentsMode handler_arguments_mode_;
int environment_length() const {
- if (stack_parameter_count_.is_valid()) {
- return register_param_count_ + 1;
- }
return register_param_count_;
}
void SetMissHandler(ExternalReference handler) {
miss_handler_ = handler;
has_miss_handler_ = true;
+ // Our miss handler infrastructure doesn't currently support
+ // variable stack parameter counts.
+ ASSERT(!stack_parameter_count_.is_valid());
}
ExternalReference miss_handler() {
return has_miss_handler_;
}
+ Register GetParameterRegister(int index) {
+ return register_params_[index];
+ }
+
+ bool IsParameterCountRegister(int index) {
+ return GetParameterRegister(index).is(stack_parameter_count_);
+ }
+
+ int GetHandlerParameterCount() {
+ int params = environment_length();
+ if (handler_arguments_mode_ == PASS_ARGUMENTS) {
+ params += 1;
+ }
+ return params;
+ }
+
private:
ExternalReference miss_handler_;
bool has_miss_handler_;
};
-// A helper to make up for the fact that type Register is not fully
-// defined outside of the platform directories
-#define DESCRIPTOR_GET_PARAMETER_REGISTER(descriptor, index) \
- ((index) == (descriptor)->register_param_count_) \
- ? (descriptor)->stack_parameter_count_ \
- : (descriptor)->register_params_[(index)]
-
class HydrogenCodeStub : public CodeStub {
public:
}
// Copy the register parameters to the failure frame.
+ int arguments_length_offset = -1;
for (int i = 0; i < descriptor->register_param_count_; ++i) {
output_frame_offset -= kPointerSize;
DoTranslateCommand(iterator, 0, output_frame_offset);
+
+ if (!arg_count_known && descriptor->IsParameterCountRegister(i)) {
+ arguments_length_offset = output_frame_offset;
+ }
}
+ ASSERT(0 == output_frame_offset);
+
if (!arg_count_known) {
- DoTranslateCommand(iterator, 0, length_frame_offset,
- TRANSLATED_VALUE_IS_NATIVE);
- caller_arg_count = output_frame->GetFrameSlot(length_frame_offset);
+ ASSERT(arguments_length_offset >= 0);
+ // We know it's a smi because 1) the code stub guarantees the stack
+ // parameter count is in smi range, and 2) the DoTranslateCommand in the
+ // parameter loop above translated that to a tagged value.
+ Smi* smi_caller_arg_count = reinterpret_cast<Smi*>(
+ output_frame->GetFrameSlot(arguments_length_offset));
+ caller_arg_count = smi_caller_arg_count->value();
+ output_frame->SetFrameSlot(length_frame_offset, caller_arg_count);
+ if (trace_scope_ != NULL) {
+ PrintF(trace_scope_->file(),
+ " 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
+ V8PRIxPTR " ; args.length\n",
+ top_address + length_frame_offset, length_frame_offset,
+ caller_arg_count);
+ }
value = frame_ptr + StandardFrameConstants::kCallerSPOffset +
(caller_arg_count - 1) * kPointerSize;
output_frame->SetFrameSlot(args_arguments_offset, value);
PrintF(trace_scope_->file(),
" 0x%08" V8PRIxPTR ": [top + %d] <- 0x%08"
V8PRIxPTR " ; args.arguments\n",
- top_address + args_arguments_offset, args_arguments_offset, value);
+ top_address + args_arguments_offset, args_arguments_offset,
+ value);
}
}
- ASSERT(0 == output_frame_offset);
-
// Copy the double registers from the input into the output frame.
CopyDoubleRegisters(output_frame);
#endif
-static const char* TraceValueType(bool is_smi, bool is_native = false) {
- if (is_native) {
- return "native";
- } else if (is_smi) {
+static const char* TraceValueType(bool is_smi) {
+ if (is_smi) {
return "smi";
}
void Deoptimizer::DoTranslateCommand(TranslationIterator* iterator,
- int frame_index,
- unsigned output_offset,
- DeoptimizerTranslatedValueType value_type) {
+ int frame_index,
+ unsigned output_offset) {
disasm::NameConverter converter;
// A GC-safe temporary placeholder that we can put in the output frame.
const intptr_t kPlaceholder = reinterpret_cast<intptr_t>(Smi::FromInt(0));
- bool is_native = value_type == TRANSLATED_VALUE_IS_NATIVE;
Translation::Opcode opcode =
static_cast<Translation::Opcode>(iterator->Next());
case Translation::INT32_REGISTER: {
int input_reg = iterator->Next();
intptr_t value = input_->GetRegister(input_reg);
- bool is_smi = (value_type == TRANSLATED_VALUE_IS_TAGGED) &&
- Smi::IsValid(value);
+ bool is_smi = Smi::IsValid(value);
if (trace_scope_ != NULL) {
PrintF(
trace_scope_->file(),
output_offset,
value,
converter.NameOfCPURegister(input_reg),
- TraceValueType(is_smi, is_native));
+ TraceValueType(is_smi));
}
if (is_smi) {
intptr_t tagged_value =
reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
output_[frame_index]->SetFrameSlot(output_offset, tagged_value);
- } else if (value_type == TRANSLATED_VALUE_IS_NATIVE) {
- output_[frame_index]->SetFrameSlot(output_offset, value);
} else {
// We save the untagged value on the side and store a GC-safe
// temporary placeholder in the frame.
- ASSERT(value_type == TRANSLATED_VALUE_IS_TAGGED);
AddDoubleValue(output_[frame_index]->GetTop() + output_offset,
static_cast<double>(static_cast<int32_t>(value)));
output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
case Translation::UINT32_REGISTER: {
int input_reg = iterator->Next();
uintptr_t value = static_cast<uintptr_t>(input_->GetRegister(input_reg));
- bool is_smi = (value_type == TRANSLATED_VALUE_IS_TAGGED) &&
- (value <= static_cast<uintptr_t>(Smi::kMaxValue));
+ bool is_smi = value <= static_cast<uintptr_t>(Smi::kMaxValue);
if (trace_scope_ != NULL) {
PrintF(
trace_scope_->file(),
output_offset,
value,
converter.NameOfCPURegister(input_reg),
- TraceValueType(is_smi, is_native));
+ TraceValueType(is_smi));
}
if (is_smi) {
intptr_t tagged_value =
reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
output_[frame_index]->SetFrameSlot(output_offset, tagged_value);
- } else if (value_type == TRANSLATED_VALUE_IS_NATIVE) {
- output_[frame_index]->SetFrameSlot(output_offset, value);
} else {
// We save the untagged value on the side and store a GC-safe
// temporary placeholder in the frame.
- ASSERT(value_type == TRANSLATED_VALUE_IS_TAGGED);
AddDoubleValue(output_[frame_index]->GetTop() + output_offset,
static_cast<double>(static_cast<uint32_t>(value)));
output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
int input_slot_index = iterator->Next();
unsigned input_offset = input_->GetOffsetFromSlotIndex(input_slot_index);
intptr_t value = input_->GetFrameSlot(input_offset);
- bool is_smi = (value_type == TRANSLATED_VALUE_IS_TAGGED) &&
- Smi::IsValid(value);
+ bool is_smi = Smi::IsValid(value);
if (trace_scope_ != NULL) {
PrintF(trace_scope_->file(),
" 0x%08" V8PRIxPTR ": ",
output_offset,
value,
input_offset,
- TraceValueType(is_smi, is_native));
+ TraceValueType(is_smi));
}
if (is_smi) {
intptr_t tagged_value =
reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
output_[frame_index]->SetFrameSlot(output_offset, tagged_value);
- } else if (value_type == TRANSLATED_VALUE_IS_NATIVE) {
- output_[frame_index]->SetFrameSlot(output_offset, value);
} else {
// We save the untagged value on the side and store a GC-safe
// temporary placeholder in the frame.
- ASSERT(value_type == TRANSLATED_VALUE_IS_TAGGED);
AddDoubleValue(output_[frame_index]->GetTop() + output_offset,
static_cast<double>(static_cast<int32_t>(value)));
output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
unsigned input_offset = input_->GetOffsetFromSlotIndex(input_slot_index);
uintptr_t value =
static_cast<uintptr_t>(input_->GetFrameSlot(input_offset));
- bool is_smi = (value_type == TRANSLATED_VALUE_IS_TAGGED) &&
- (value <= static_cast<uintptr_t>(Smi::kMaxValue));
+ bool is_smi = value <= static_cast<uintptr_t>(Smi::kMaxValue);
if (trace_scope_ != NULL) {
PrintF(trace_scope_->file(),
" 0x%08" V8PRIxPTR ": ",
output_offset,
value,
input_offset,
- TraceValueType(is_smi, is_native));
+ TraceValueType(is_smi));
}
if (is_smi) {
intptr_t tagged_value =
reinterpret_cast<intptr_t>(Smi::FromInt(static_cast<int>(value)));
output_[frame_index]->SetFrameSlot(output_offset, tagged_value);
- } else if (value_type == TRANSLATED_VALUE_IS_NATIVE) {
- output_[frame_index]->SetFrameSlot(output_offset, value);
} else {
// We save the untagged value on the side and store a GC-safe
// temporary placeholder in the frame.
- ASSERT(value_type == TRANSLATED_VALUE_IS_TAGGED);
AddDoubleValue(output_[frame_index]->GetTop() + output_offset,
static_cast<double>(static_cast<uint32_t>(value)));
output_[frame_index]->SetFrameSlot(output_offset, kPlaceholder);
int object_index,
int field_index);
- enum DeoptimizerTranslatedValueType {
- TRANSLATED_VALUE_IS_NATIVE,
- TRANSLATED_VALUE_IS_TAGGED
- };
-
void DoTranslateCommand(TranslationIterator* iterator,
- int frame_index,
- unsigned output_offset,
- DeoptimizerTranslatedValueType value_type = TRANSLATED_VALUE_IS_TAGGED);
+ int frame_index,
+ unsigned output_offset);
unsigned ComputeInputFrameSize() const;
unsigned ComputeFixedSize(JSFunction* function) const;
// eax -- number of arguments
// edi -- function
// ebx -- type info cell with elements kind
- static Register registers[] = { edi, ebx };
- descriptor->register_param_count_ = 2;
+ static Register registers_variable_args[] = { edi, ebx, eax };
+ static Register registers_no_args[] = { edi, ebx };
- if (constant_stack_parameter_count != 0) {
+ if (constant_stack_parameter_count == 0) {
+ descriptor->register_param_count_ = 2;
+ descriptor->register_params_ = registers_no_args;
+ } else {
// stack param count needs (constructor pointer, and single argument)
+ descriptor->handler_arguments_mode_ = PASS_ARGUMENTS;
descriptor->stack_parameter_count_ = eax;
+ descriptor->register_param_count_ = 3;
+ descriptor->register_params_ = registers_variable_args;
}
+
descriptor->hint_stack_parameter_count_ = constant_stack_parameter_count;
- descriptor->register_params_ = registers;
descriptor->function_mode_ = JS_FUNCTION_STUB_MODE;
descriptor->deoptimization_handler_ =
Runtime::FunctionForId(Runtime::kArrayConstructor)->entry;
// register state
// eax -- number of arguments
// edi -- constructor function
- static Register registers[] = { edi };
- descriptor->register_param_count_ = 1;
+ static Register registers_variable_args[] = { edi, eax };
+ static Register registers_no_args[] = { edi };
- if (constant_stack_parameter_count != 0) {
+ if (constant_stack_parameter_count == 0) {
+ descriptor->register_param_count_ = 1;
+ descriptor->register_params_ = registers_no_args;
+ } else {
// stack param count needs (constructor pointer, and single argument)
+ descriptor->handler_arguments_mode_ = PASS_ARGUMENTS;
descriptor->stack_parameter_count_ = eax;
+ descriptor->register_param_count_ = 2;
+ descriptor->register_params_ = registers_variable_args;
}
+
descriptor->hint_stack_parameter_count_ = constant_stack_parameter_count;
- descriptor->register_params_ = registers;
descriptor->function_mode_ = JS_FUNCTION_STUB_MODE;
descriptor->deoptimization_handler_ =
Runtime::FunctionForId(Runtime::kInternalArrayConstructor)->entry;
FrameDescription* output_frame, CodeStubInterfaceDescriptor* descriptor) {
intptr_t handler =
reinterpret_cast<intptr_t>(descriptor->deoptimization_handler_);
- int params = descriptor->environment_length();
+ int params = descriptor->GetHandlerParameterCount();
output_frame->SetRegister(eax.code(), params);
output_frame->SetRegister(ebx.code(), handler);
}
CodeStubInterfaceDescriptor* descriptor =
info()->code_stub()->GetInterfaceDescriptor(info()->isolate());
int index = static_cast<int>(instr->index());
- Register reg = DESCRIPTOR_GET_PARAMETER_REGISTER(descriptor, index);
+ Register reg = descriptor->GetParameterRegister(index);
return DefineFixed(result, reg);
}
}
RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConstructor) {
HandleScope scope(isolate);
// If we get 2 arguments then they are the stub parameters (constructor, type
- // info). If we get 3, then the first one is a pointer to the arguments
- // passed by the caller.
+ // info). If we get 4, then the first one is a pointer to the arguments
+ // passed by the caller, and the last one is the length of the arguments
+ // passed to the caller (redundant, but useful to check on the deoptimizer
+ // with an assert).
Arguments empty_args(0, NULL);
bool no_caller_args = args.length() == 2;
- ASSERT(no_caller_args || args.length() == 3);
+ ASSERT(no_caller_args || args.length() == 4);
int parameters_start = no_caller_args ? 0 : 1;
Arguments* caller_args = no_caller_args
? &empty_args
: reinterpret_cast<Arguments*>(args[0]);
CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, parameters_start);
CONVERT_ARG_HANDLE_CHECKED(Object, type_info, parameters_start + 1);
-
+#ifdef DEBUG
+ if (!no_caller_args) {
+ CONVERT_SMI_ARG_CHECKED(arg_count, parameters_start + 2);
+ ASSERT(arg_count == caller_args->length());
+ }
+#endif
return ArrayConstructorCommon(isolate,
constructor,
type_info,
HandleScope scope(isolate);
Arguments empty_args(0, NULL);
bool no_caller_args = args.length() == 1;
- ASSERT(no_caller_args || args.length() == 2);
+ ASSERT(no_caller_args || args.length() == 3);
int parameters_start = no_caller_args ? 0 : 1;
Arguments* caller_args = no_caller_args
? &empty_args
: reinterpret_cast<Arguments*>(args[0]);
CONVERT_ARG_HANDLE_CHECKED(JSFunction, constructor, parameters_start);
-
+#ifdef DEBUG
+ if (!no_caller_args) {
+ CONVERT_SMI_ARG_CHECKED(arg_count, parameters_start + 1);
+ ASSERT(arg_count == caller_args->length());
+ }
+#endif
return ArrayConstructorCommon(isolate,
constructor,
Handle<Object>::null(),
// rax -- number of arguments
// rdi -- function
// rbx -- type info cell with elements kind
- static Register registers[] = { rdi, rbx };
- descriptor->register_param_count_ = 2;
- if (constant_stack_parameter_count != 0) {
+ static Register registers_variable_args[] = { rdi, rbx, rax };
+ static Register registers_no_args[] = { rdi, rbx };
+
+ if (constant_stack_parameter_count == 0) {
+ descriptor->register_param_count_ = 2;
+ descriptor->register_params_ = registers_no_args;
+ } else {
// stack param count needs (constructor pointer, and single argument)
+ descriptor->handler_arguments_mode_ = PASS_ARGUMENTS;
descriptor->stack_parameter_count_ = rax;
+ descriptor->register_param_count_ = 3;
+ descriptor->register_params_ = registers_variable_args;
}
+
descriptor->hint_stack_parameter_count_ = constant_stack_parameter_count;
- descriptor->register_params_ = registers;
descriptor->function_mode_ = JS_FUNCTION_STUB_MODE;
descriptor->deoptimization_handler_ =
Runtime::FunctionForId(Runtime::kArrayConstructor)->entry;
// register state
// rax -- number of arguments
// rdi -- constructor function
- static Register registers[] = { rdi };
- descriptor->register_param_count_ = 1;
+ static Register registers_variable_args[] = { rdi, rax };
+ static Register registers_no_args[] = { rdi };
- if (constant_stack_parameter_count != 0) {
+ if (constant_stack_parameter_count == 0) {
+ descriptor->register_param_count_ = 1;
+ descriptor->register_params_ = registers_no_args;
+ } else {
// stack param count needs (constructor pointer, and single argument)
+ descriptor->handler_arguments_mode_ = PASS_ARGUMENTS;
descriptor->stack_parameter_count_ = rax;
+ descriptor->register_param_count_ = 2;
+ descriptor->register_params_ = registers_variable_args;
}
+
descriptor->hint_stack_parameter_count_ = constant_stack_parameter_count;
- descriptor->register_params_ = registers;
descriptor->function_mode_ = JS_FUNCTION_STUB_MODE;
descriptor->deoptimization_handler_ =
Runtime::FunctionForId(Runtime::kInternalArrayConstructor)->entry;
FrameDescription* output_frame, CodeStubInterfaceDescriptor* descriptor) {
intptr_t handler =
reinterpret_cast<intptr_t>(descriptor->deoptimization_handler_);
- int params = descriptor->environment_length();
+ int params = descriptor->GetHandlerParameterCount();
output_frame->SetRegister(rax.code(), params);
output_frame->SetRegister(rbx.code(), handler);
}
CodeStubInterfaceDescriptor* descriptor =
info()->code_stub()->GetInterfaceDescriptor(info()->isolate());
int index = static_cast<int>(instr->index());
- Register reg = DESCRIPTOR_GET_PARAMETER_REGISTER(descriptor, index);
+ Register reg = descriptor->GetParameterRegister(index);
return DefineFixed(result, reg);
}
}