Commit d3d12541 authored by clemensh's avatar clemensh Committed by Commit bot

Revert of [wasm] Fix location for error in asm.js ToNumber conversion...

Revert of [wasm] Fix location for error in asm.js ToNumber conversion (patchset #5 id:80001 of https://codereview.chromium.org/2555243002/ )

Reason for revert:
gc-stress failures

Original issue's description:
> [wasm] Fix location for error in asm.js ToNumber conversion
>
> In the asm.js code translated to wasm, we call imported functions via a
> WASM_TO_JS stub, which first calls the function and then calls ToNumber
> on the return value. Exceptions can happen in both calls.
> We were only ever reporting the location of the function call, whereas
> asm.js code executed via turbofan reported the location of the type
> coercion operator ("+" on "+foo()" or "|" on "foo()|0").
>
> This CL implements the same behaviour for asm.js code translated to
> wasm. The following is changed:
> - the AsmWasmBuilder records the parent node when descending on a binary
>   operator (also "+foo()" is represented by a binary operation).
> - it stores not one location per call in the source position side
>   table, but two (one for the call, one for the parent which does the
>   type coercion).
> - the wasm compiler annotates the source positions "0" and "1" to the
>   two calls in the WASM_TO_JS wrapper (only if the module origin is
>   asm.js).
> - during stack trace generation (in the StackTraceIterator), when we
>   move from the WASM_TO_JS frame to the WASM frame, we remember at which
>   call inside the WASM_TO_JS wrapper we are, and encode this information
>   in the generated caller state, used for the WASM frame.
> - the same information is also stored in the FrameArray which is used
>   to reconstruct the stack trace later.
>
> R=titzer@chromium.org, bradnelson@chromium.org
> CC=jgruber@chromium.org
> BUG=v8:4203,v8:5724
>
> Committed: https://crrev.com/94cd46b55e24fa2bb7b06b3da4d5ba7f029bc262
> Cr-Commit-Position: refs/heads/master@{#41599}

TBR=bradnelson@chromium.org,mstarzinger@chromium.org,titzer@chromium.org
# Skipping CQ checks because original CL landed less than 1 days ago.
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=v8:4203,v8:5724

Review-Url: https://codereview.chromium.org/2563613003
Cr-Commit-Position: refs/heads/master@{#41601}
parent 6595e740
......@@ -71,8 +71,7 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
foreign_init_function_(nullptr),
function_tables_(ZoneHashMap::kDefaultHashMapCapacity,
ZoneAllocationPolicy(zone)),
imported_function_table_(this),
parent_binop_(nullptr) {
imported_function_table_(this) {
InitializeAstVisitor(isolate);
}
......@@ -1399,10 +1398,6 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
bool VisitCallExpression(Call* expr) {
Call::CallType call_type = expr->GetCallType();
bool returns_value = true;
// Save the parent now, it might be overwritten in VisitCallArgs.
BinaryOperation* parent_binop = parent_binop_;
switch (call_type) {
case Call::OTHER_CALL: {
VariableProxy* proxy = expr->expression()->AsVariableProxy();
......@@ -1433,20 +1428,13 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
uint32_t index = imported_function_table_.LookupOrInsertImportUse(
vp->var(), sig.Build());
VisitCallArgs(expr);
// For non-void functions, we must know the parent node.
DCHECK_IMPLIES(returns_value, parent_binop != nullptr);
DCHECK_IMPLIES(returns_value, parent_binop->left() == expr ||
parent_binop->right() == expr);
int pos = expr->position();
int parent_pos = returns_value ? parent_binop->position() : pos;
current_function_builder_->AddAsmWasmOffset(pos, parent_pos);
current_function_builder_->AddAsmWasmOffset(expr->position());
current_function_builder_->Emit(kExprCallFunction);
current_function_builder_->EmitVarInt(index);
} else {
WasmFunctionBuilder* function = LookupOrInsertFunction(vp->var());
VisitCallArgs(expr);
current_function_builder_->AddAsmWasmOffset(expr->position(),
expr->position());
current_function_builder_->AddAsmWasmOffset(expr->position());
current_function_builder_->Emit(kExprCallFunction);
current_function_builder_->EmitDirectCallIndex(
function->func_index());
......@@ -1472,8 +1460,7 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
VisitCallArgs(expr);
current_function_builder_->EmitGetLocal(tmp.index());
current_function_builder_->AddAsmWasmOffset(expr->position(),
expr->position());
current_function_builder_->AddAsmWasmOffset(expr->position());
current_function_builder_->Emit(kExprCallIndirect);
current_function_builder_->EmitVarInt(indices->signature_index);
current_function_builder_->EmitVarInt(0); // table index
......@@ -1645,7 +1632,6 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
void VisitBinaryOperation(BinaryOperation* expr) {
ConvertOperation convertOperation = MatchBinaryOperation(expr);
static const bool kDontIgnoreSign = false;
parent_binop_ = expr;
if (convertOperation == kToDouble) {
RECURSE(Visit(expr->left()));
TypeIndex type = TypeIndexOf(expr->left(), kDontIgnoreSign);
......@@ -1949,9 +1935,6 @@ class AsmWasmBuilderImpl final : public AstVisitor<AsmWasmBuilderImpl> {
uint32_t next_table_index_;
ZoneHashMap function_tables_;
ImportedFunctionTable imported_function_table_;
// Remember the parent node for reporting the correct location for ToNumber
// conversions after calls.
BinaryOperation* parent_binop_;
DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
......
......@@ -137,14 +137,14 @@ class PipelineData {
// For machine graph testing entry point.
PipelineData(ZoneStats* zone_stats, CompilationInfo* info, Graph* graph,
Schedule* schedule, SourcePositionTable* source_positions)
Schedule* schedule)
: isolate_(info->isolate()),
info_(info),
debug_name_(info_->GetDebugName()),
zone_stats_(zone_stats),
graph_zone_scope_(zone_stats_, ZONE_NAME),
graph_(graph),
source_positions_(source_positions),
source_positions_(new (info->zone()) SourcePositionTable(graph_)),
schedule_(schedule),
instruction_zone_scope_(zone_stats_, ZONE_NAME),
instruction_zone_(instruction_zone_scope_.zone()),
......@@ -1641,8 +1641,7 @@ Handle<Code> Pipeline::GenerateCodeForCodeStub(Isolate* isolate,
// Construct a pipeline for scheduling and code generation.
ZoneStats zone_stats(isolate->allocator());
SourcePositionTable source_positions(graph);
PipelineData data(&zone_stats, &info, graph, schedule, &source_positions);
PipelineData data(&zone_stats, &info, graph, schedule);
std::unique_ptr<PipelineStatistics> pipeline_statistics;
if (FLAG_turbo_stats || FLAG_turbo_stats_nvp) {
pipeline_statistics.reset(new PipelineStatistics(&info, &zone_stats));
......@@ -1696,16 +1695,13 @@ Handle<Code> Pipeline::GenerateCodeForTesting(CompilationInfo* info,
}
// static
Handle<Code> Pipeline::GenerateCodeForTesting(
CompilationInfo* info, CallDescriptor* call_descriptor, Graph* graph,
Schedule* schedule, SourcePositionTable* source_positions) {
Handle<Code> Pipeline::GenerateCodeForTesting(CompilationInfo* info,
CallDescriptor* call_descriptor,
Graph* graph,
Schedule* schedule) {
// Construct a pipeline for scheduling and code generation.
ZoneStats zone_stats(info->isolate()->allocator());
// TODO(wasm): Refactor code generation to check for non-existing source
// table, then remove this conditional allocation.
if (!source_positions)
source_positions = new (info->zone()) SourcePositionTable(graph);
PipelineData data(&zone_stats, info, graph, schedule, source_positions);
PipelineData data(&zone_stats, info, graph, schedule);
std::unique_ptr<PipelineStatistics> pipeline_statistics;
if (FLAG_turbo_stats || FLAG_turbo_stats_nvp) {
pipeline_statistics.reset(new PipelineStatistics(info, &zone_stats));
......
......@@ -68,10 +68,10 @@ class Pipeline : public AllStatic {
// Run the pipeline on a machine graph and generate code. If {schedule} is
// {nullptr}, then compute a new schedule for code generation.
static Handle<Code> GenerateCodeForTesting(
CompilationInfo* info, CallDescriptor* call_descriptor, Graph* graph,
Schedule* schedule = nullptr,
SourcePositionTable* source_positions = nullptr);
static Handle<Code> GenerateCodeForTesting(CompilationInfo* info,
CallDescriptor* call_descriptor,
Graph* graph,
Schedule* schedule = nullptr);
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(Pipeline);
......
......@@ -2451,8 +2451,6 @@ Node* WasmGraphBuilder::BuildJavaScriptToNumber(Node* node, Node* context) {
Node* result = graph()->NewNode(jsgraph()->common()->Call(desc), stub_code,
node, context, *effect_, *control_);
SetSourcePosition(result, 1);
*effect_ = result;
return result;
......@@ -2852,7 +2850,6 @@ void WasmGraphBuilder::BuildWasmToJSWrapper(Handle<JSReceiver> target,
}
*effect_ = call;
SetSourcePosition(call, 0);
// Convert the return value back.
Node* i32_zero = jsgraph()->Int32Constant(0);
......@@ -3327,8 +3324,7 @@ Handle<Code> CompileJSToWasmWrapper(Isolate* isolate,
Handle<Code> CompileWasmToJSWrapper(Isolate* isolate, Handle<JSReceiver> target,
wasm::FunctionSig* sig, uint32_t index,
Handle<String> module_name,
MaybeHandle<String> import_name,
wasm::ModuleOrigin origin) {
MaybeHandle<String> import_name) {
//----------------------------------------------------------------------------
// Create the Graph
//----------------------------------------------------------------------------
......@@ -3341,11 +3337,7 @@ Handle<Code> CompileWasmToJSWrapper(Isolate* isolate, Handle<JSReceiver> target,
Node* control = nullptr;
Node* effect = nullptr;
SourcePositionTable* source_position_table =
origin == wasm::kAsmJsOrigin ? new (&zone) SourcePositionTable(&graph)
: nullptr;
WasmGraphBuilder builder(&zone, &jsgraph, sig, source_position_table);
WasmGraphBuilder builder(&zone, &jsgraph, sig);
builder.set_control_ptr(&control);
builder.set_effect_ptr(&effect);
builder.BuildWasmToJSWrapper(target, sig);
......@@ -3381,8 +3373,7 @@ Handle<Code> CompileWasmToJSWrapper(Isolate* isolate, Handle<JSReceiver> target,
}
CompilationInfo info(func_name, isolate, &zone, flags);
code = Pipeline::GenerateCodeForTesting(&info, incoming, &graph, nullptr,
source_position_table);
code = Pipeline::GenerateCodeForTesting(&info, incoming, &graph, nullptr);
#ifdef ENABLE_DISASSEMBLER
if (FLAG_print_opt_code && !code.is_null()) {
OFStream os(stdout);
......
......@@ -94,8 +94,7 @@ class WasmCompilationUnit final {
Handle<Code> CompileWasmToJSWrapper(Isolate* isolate, Handle<JSReceiver> target,
wasm::FunctionSig* sig, uint32_t index,
Handle<String> module_name,
MaybeHandle<String> import_name,
wasm::ModuleOrigin origin);
MaybeHandle<String> import_name);
// Wraps a given wasm code object, producing a code object.
Handle<Code> CompileJSToWasmWrapper(Isolate* isolate,
......
......@@ -1580,20 +1580,11 @@ int WasmFrame::position() const {
isolate());
DCHECK_LE(0, position);
position = WasmCompiledModule::GetAsmJsSourcePosition(
compiled_module, function_index(), static_cast<uint32_t>(position),
at_to_number_conversion());
compiled_module, function_index(), static_cast<uint32_t>(position));
}
return position;
}
bool WasmFrame::at_to_number_conversion() const {
// WasmToJsFrame::ComputeCallerState encoded this for us in the constant pool
// address. If there was no WasmToJsFrame above us, we just return false here,
// but this information is not relevant in this case anyway.
intptr_t addr_int = reinterpret_cast<intptr_t>(constant_pool_address());
return addr_int == 1;
}
int WasmFrame::LookupExceptionHandlerInTable(int* stack_slots) {
DCHECK_NOT_NULL(stack_slots);
Code* code = LookupCode();
......@@ -1603,20 +1594,6 @@ int WasmFrame::LookupExceptionHandlerInTable(int* stack_slots) {
return table->LookupReturn(pc_offset);
}
void WasmToJsFrame::ComputeCallerState(State* state) const {
// Remember at which of the two calls inside it we are, and transfer this
// information to the subsequent WASM frame.
Code* code = unchecked_code();
AbstractCode* abstract_code = AbstractCode::cast(code);
int offset = static_cast<int>(pc() - code->instruction_start());
int at_to_number_call = abstract_code->SourcePosition(offset);
DCHECK(at_to_number_call == 0 || at_to_number_call == 1);
StubFrame::ComputeCallerState(state);
// Use a little hack here: The constant pool address is not used for wasm
// frames, so use it to encode whether we are at the to_number call.
state->constant_pool_address = reinterpret_cast<Address*>(at_to_number_call);
}
namespace {
......
......@@ -1111,7 +1111,6 @@ class WasmFrame : public StandardFrame {
uint32_t function_index() const;
Script* script() const override;
int position() const override;
bool at_to_number_conversion() const;
static WasmFrame* cast(StackFrame* frame) {
DCHECK(frame->is_wasm());
......@@ -1135,8 +1134,6 @@ class WasmToJsFrame : public StubFrame {
inline explicit WasmToJsFrame(StackFrameIteratorBase* iterator);
private:
void ComputeCallerState(State* state) const override;
friend class StackFrameIteratorBase;
};
......
......@@ -523,15 +523,9 @@ Handle<Object> Isolate::CaptureSimpleStackTrace(Handle<JSReceiver> error_object,
// be a wasm object.
DCHECK(wasm::IsWasmInstance(*instance) || instance->IsUndefined(this));
int flags = 0;
if (wasm::WasmIsAsmJs(*instance, this)) {
flags |= FrameArray::kIsAsmJsWasmFrame;
if (wasm_frame->at_to_number_conversion()) {
flags |= FrameArray::kAsmJsAtNumberConversion;
}
} else {
flags |= FrameArray::kIsWasmFrame;
}
int flags = wasm::WasmIsAsmJs(*instance, this)
? FrameArray::kIsAsmJsWasmFrame
: FrameArray::kIsWasmFrame;
elements =
FrameArray::AppendWasmFrame(elements, instance, wasm_function_index,
......@@ -1563,10 +1557,8 @@ bool Isolate::ComputeLocationFromStackTrace(MessageLocation* target,
int func_index = elements->WasmFunctionIndex(i)->value();
int code_offset = elements->Offset(i)->value();
int byte_pos = elements->Code(i)->SourcePosition(code_offset);
bool at_to_number_conversion =
elements->Flags(i)->value() & FrameArray::kAsmJsAtNumberConversion;
int source_pos = WasmCompiledModule::GetAsmJsSourcePosition(
compiled_module, func_index, byte_pos, at_to_number_conversion);
compiled_module, func_index, byte_pos);
Handle<Script> script = compiled_module->script();
*target = MessageLocation(script, source_pos, source_pos + 1);
......
......@@ -680,15 +680,6 @@ Handle<Object> WasmStackFrame::Null() const {
return isolate_->factory()->null_value();
}
void AsmJsWasmStackFrame::FromFrameArray(Isolate* isolate,
Handle<FrameArray> array,
int frame_ix) {
DCHECK(array->IsAsmJsWasmFrame(frame_ix));
WasmStackFrame::FromFrameArray(isolate, array, frame_ix);
is_at_number_conversion_ =
array->Flags(frame_ix)->value() & FrameArray::kAsmJsAtNumberConversion;
}
Handle<Object> AsmJsWasmStackFrame::GetReceiver() const {
return isolate_->global_proxy();
}
......@@ -720,8 +711,7 @@ int AsmJsWasmStackFrame::GetPosition() const {
isolate_);
DCHECK_LE(0, byte_offset);
return WasmCompiledModule::GetAsmJsSourcePosition(
compiled_module, wasm_func_index_, static_cast<uint32_t>(byte_offset),
is_at_number_conversion_);
compiled_module, wasm_func_index_, static_cast<uint32_t>(byte_offset));
}
int AsmJsWasmStackFrame::GetLineNumber() {
......
......@@ -163,7 +163,6 @@ class WasmStackFrame : public StackFrameBase {
void FromFrameArray(Isolate* isolate, Handle<FrameArray> array, int frame_ix);
friend class FrameArrayIterator;
friend class AsmJsWasmStackFrame;
};
class AsmJsWasmStackFrame : public WasmStackFrame {
......@@ -181,12 +180,6 @@ class AsmJsWasmStackFrame : public WasmStackFrame {
int GetColumnNumber() override;
MaybeHandle<String> ToString() override;
private:
friend class FrameArrayIterator;
void FromFrameArray(Isolate* isolate, Handle<FrameArray> array, int frame_ix);
bool is_at_number_conversion_;
};
class FrameArrayIterator {
......
......@@ -3132,7 +3132,6 @@ class FrameArray : public FixedArray {
static const int kIsAsmJsWasmFrame = 1 << 1;
static const int kIsStrict = 1 << 2;
static const int kForceConstructor = 1 << 3;
static const int kAsmJsAtNumberConversion = 1 << 4;
static Handle<FrameArray> AppendJSFrame(Handle<FrameArray> in,
Handle<Object> receiver,
......
......@@ -1204,7 +1204,7 @@ AsmJsOffsetsResult DecodeAsmJsOffsets(const byte* tables_start,
for (uint32_t i = 0; i < functions_count && decoder.ok(); ++i) {
uint32_t size = decoder.consume_u32v("table size");
if (size == 0) {
table.push_back(std::vector<AsmJsOffsetEntry>());
table.push_back(std::vector<std::pair<int, int>>());
continue;
}
if (!decoder.checkAvailable(size)) {
......@@ -1214,17 +1214,12 @@ AsmJsOffsetsResult DecodeAsmJsOffsets(const byte* tables_start,
uint32_t locals_size = decoder.consume_u32("locals size");
int last_byte_offset = locals_size;
int last_asm_position = 0;
std::vector<AsmJsOffsetEntry> func_asm_offsets;
std::vector<std::pair<int, int>> func_asm_offsets;
func_asm_offsets.reserve(size / 4); // conservative estimation
while (decoder.ok() && decoder.pc() < table_end) {
last_byte_offset += decoder.consume_u32v("byte offset delta");
int call_position =
last_asm_position + decoder.consume_i32v("call position delta");
int to_number_position =
call_position + decoder.consume_i32v("to_number position delta");
last_asm_position = to_number_position;
func_asm_offsets.push_back(
{last_byte_offset, call_position, to_number_position});
last_asm_position += decoder.consume_i32v("asm position delta");
func_asm_offsets.push_back({last_byte_offset, last_asm_position});
}
if (decoder.pc() != table_end) {
decoder.error("broken asm offset table");
......
......@@ -18,12 +18,7 @@ typedef Result<const WasmModule*> ModuleResult;
typedef Result<WasmFunction*> FunctionResult;
typedef std::vector<std::pair<int, int>> FunctionOffsets;
typedef Result<FunctionOffsets> FunctionOffsetsResult;
struct AsmJsOffsetEntry {
int byte_offset;
int source_position_call;
int source_position_number_conversion;
};
typedef std::vector<std::vector<AsmJsOffsetEntry>> AsmJsOffsets;
typedef std::vector<std::vector<std::pair<int, int>>> AsmJsOffsets;
typedef Result<AsmJsOffsets> AsmJsOffsetsResult;
// Decodes the bytes of a WASM module between {module_start} and {module_end}.
......
......@@ -150,8 +150,7 @@ void WasmFunctionBuilder::SetName(Vector<const char> name) {
memcpy(name_.data(), name.start(), name.length());
}
void WasmFunctionBuilder::AddAsmWasmOffset(int call_position,
int to_number_position) {
void WasmFunctionBuilder::AddAsmWasmOffset(int asm_position) {
// We only want to emit one mapping per byte offset:
DCHECK(asm_offsets_.size() == 0 || body_.size() > last_asm_byte_offset_);
......@@ -160,12 +159,9 @@ void WasmFunctionBuilder::AddAsmWasmOffset(int call_position,
asm_offsets_.write_u32v(byte_offset - last_asm_byte_offset_);
last_asm_byte_offset_ = byte_offset;
DCHECK_GE(call_position, 0);
asm_offsets_.write_i32v(call_position - last_asm_source_position_);
DCHECK_GE(to_number_position, 0);
asm_offsets_.write_i32v(to_number_position - call_position);
last_asm_source_position_ = to_number_position;
DCHECK_GE(asm_position, 0);
asm_offsets_.write_i32v(asm_position - last_asm_source_position_);
last_asm_source_position_ = asm_position;
}
void WasmFunctionBuilder::WriteSignature(ZoneBuffer& buffer) const {
......
......@@ -134,7 +134,7 @@ class V8_EXPORT_PRIVATE WasmFunctionBuilder : public ZoneObject {
void EmitDirectCallIndex(uint32_t index);
void ExportAs(Vector<const char> name);
void SetName(Vector<const char> name);
void AddAsmWasmOffset(int call_position, int to_number_position);
void AddAsmWasmOffset(int asm_position);
void WriteSignature(ZoneBuffer& buffer) const;
void WriteExports(ZoneBuffer& buffer) const;
......
......@@ -977,8 +977,7 @@ static Handle<Code> CompileImportWrapper(Isolate* isolate, int index,
FunctionSig* sig,
Handle<JSReceiver> target,
Handle<String> module_name,
MaybeHandle<String> import_name,
ModuleOrigin origin) {
MaybeHandle<String> import_name) {
Handle<Code> code;
WasmFunction* other_func = GetWasmFunctionForImportWrapper(isolate, target);
if (other_func) {
......@@ -992,7 +991,7 @@ static Handle<Code> CompileImportWrapper(Isolate* isolate, int index,
} else {
// Signature mismatch. Compile a new wrapper for the new signature.
return compiler::CompileWasmToJSWrapper(isolate, target, sig, index,
module_name, import_name, origin);
module_name, import_name);
}
}
......@@ -1549,8 +1548,7 @@ class WasmInstanceBuilder {
Handle<Code> import_wrapper = CompileImportWrapper(
isolate_, index, module_->functions[import.index].sig,
Handle<JSReceiver>::cast(function), module_name, function_name,
module_->origin);
Handle<JSReceiver>::cast(function), module_name, function_name);
if (import_wrapper.is_null()) {
ReportFFIError("imported function does not match the expected type",
index, module_name, function_name);
......
......@@ -461,14 +461,6 @@ bool WasmCompiledModule::GetPositionInfo(uint32_t position,
}
namespace {
enum AsmJsOffsetTableEntryLayout {
kOTEByteOffset,
kOTECallPosition,
kOTENumberConvPosition,
kOTESize
};
Handle<ByteArray> GetDecodedAsmJsOffsetTable(
Handle<WasmCompiledModule> compiled_module, Isolate* isolate) {
DCHECK(compiled_module->has_asm_js_offset_table());
......@@ -496,16 +488,13 @@ Handle<ByteArray> GetDecodedAsmJsOffsetTable(
static_cast<int>(compiled_module->module()->num_imported_functions);
DCHECK_EQ(compiled_module->module()->functions.size(),
static_cast<size_t>(num_functions) + num_imported_functions);
int num_entries = 0;
// One byte to encode that this is a decoded table.
int total_size = 1;
for (int func = 0; func < num_functions; ++func) {
size_t new_size = asm_offsets.val[func].size();
DCHECK_LE(new_size, static_cast<size_t>(kMaxInt) - num_entries);
num_entries += static_cast<int>(new_size);
size_t new_size = asm_offsets.val[func].size() * 2 * kIntSize;
DCHECK_LE(new_size, static_cast<size_t>(kMaxInt) - total_size);
total_size += static_cast<int>(new_size);
}
// One byte to encode that this is a decoded table.
DCHECK_GE(kMaxInt,
1 + static_cast<uint64_t>(num_entries) * kOTESize * kIntSize);
int total_size = 1 + num_entries * kOTESize * kIntSize;
Handle<ByteArray> decoded_table =
isolate->factory()->NewByteArray(total_size, TENURED);
decoded_table->set(total_size - 1, AsmJsTableType::Decoded);
......@@ -514,19 +503,16 @@ Handle<ByteArray> GetDecodedAsmJsOffsetTable(
int idx = 0;
std::vector<WasmFunction>& wasm_funs = compiled_module->module()->functions;
for (int func = 0; func < num_functions; ++func) {
std::vector<AsmJsOffsetEntry>& func_asm_offsets = asm_offsets.val[func];
std::vector<std::pair<int, int>>& func_asm_offsets = asm_offsets.val[func];
if (func_asm_offsets.empty()) continue;
int func_offset =
wasm_funs[num_imported_functions + func].code_start_offset;
for (AsmJsOffsetEntry& e : func_asm_offsets) {
for (std::pair<int, int> p : func_asm_offsets) {
// Byte offsets must be strictly monotonously increasing:
DCHECK_IMPLIES(idx > 0, func_offset + e.byte_offset >
decoded_table->get_int(idx - kOTESize));
decoded_table->set_int(idx + kOTEByteOffset, func_offset + e.byte_offset);
decoded_table->set_int(idx + kOTECallPosition, e.source_position_call);
decoded_table->set_int(idx + kOTENumberConvPosition,
e.source_position_number_conversion);
idx += kOTESize;
DCHECK(idx == 0 ||
func_offset + p.first > decoded_table->get_int(idx - 2));
decoded_table->set_int(idx++, func_offset + p.first);
decoded_table->set_int(idx++, p.second);
}
}
DCHECK_EQ(total_size, idx * kIntSize + 1);
......@@ -536,7 +522,7 @@ Handle<ByteArray> GetDecodedAsmJsOffsetTable(
int WasmCompiledModule::GetAsmJsSourcePosition(
Handle<WasmCompiledModule> compiled_module, uint32_t func_index,
uint32_t byte_offset, bool is_at_number_conversion) {
uint32_t byte_offset) {
Isolate* isolate = compiled_module->GetIsolate();
Handle<ByteArray> offset_table =
GetDecodedAsmJsOffsetTable(compiled_module, isolate);
......@@ -547,12 +533,12 @@ int WasmCompiledModule::GetAsmJsSourcePosition(
uint32_t total_offset = func_code_offset + byte_offset;
// Binary search for the total byte offset.
int left = 0; // inclusive
int right = offset_table->length() / kIntSize / kOTESize; // exclusive
int left = 0; // inclusive
int right = offset_table->length() / kIntSize / 2; // exclusive
DCHECK_LT(left, right);
while (right - left > 1) {
int mid = left + (right - left) / 2;
int mid_entry = offset_table->get_int(kOTESize * mid);
int mid_entry = offset_table->get_int(2 * mid);
DCHECK_GE(kMaxInt, mid_entry);
if (static_cast<uint32_t>(mid_entry) <= total_offset) {
left = mid;
......@@ -562,9 +548,9 @@ int WasmCompiledModule::GetAsmJsSourcePosition(
}
// There should be an entry for each position that could show up on the stack
// trace:
DCHECK_EQ(total_offset, offset_table->get_int(kOTESize * left));
int idx = is_at_number_conversion ? kOTENumberConvPosition : kOTECallPosition;
return offset_table->get_int(kOTESize * left + idx);
DCHECK_EQ(total_offset,
static_cast<uint32_t>(offset_table->get_int(2 * left)));
return offset_table->get_int(2 * left + 1);
}
v8::debug::WasmDisassembly WasmCompiledModule::DisassembleFunction(
......
......@@ -296,8 +296,7 @@ class WasmCompiledModule : public FixedArray {
// Get the asm.js source position from a byte offset.
// Must only be called if the associated wasm object was created from asm.js.
static int GetAsmJsSourcePosition(Handle<WasmCompiledModule> debug_info,
uint32_t func_index, uint32_t byte_offset,
bool is_at_number_conversion);
uint32_t func_index, uint32_t byte_offset);
// Compute the disassembly of a wasm function.
// Returns the disassembly string and a list of <byte_offset, line, column>
......
......@@ -199,9 +199,9 @@ class TestingModule : public ModuleEnv {
Handle<JSFunction> jsfunc = Handle<JSFunction>::cast(v8::Utils::OpenHandle(
*v8::Local<v8::Function>::Cast(CompileRun(source))));
uint32_t index = AddFunction(sig, Handle<Code>::null());
Handle<Code> code = CompileWasmToJSWrapper(
isolate_, jsfunc, sig, index, Handle<String>::null(),
Handle<String>::null(), module->origin);
Handle<Code> code =
CompileWasmToJSWrapper(isolate_, jsfunc, sig, index,
Handle<String>::null(), Handle<String>::null());
instance->function_code[index] = code;
return index;
}
......
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --validate-asm
var filename = '(?:[^ ]+/)?test/mjsunit/wasm/asm-wasm-exception-in-tonumber.js';
filename = filename.replace(/\//g, '[/\\\\]');
function verifyStack(frames, expected) {
assertTrue(frames.length >= expected.length, 'too few frames');
print('frames on detailed stack (' + frames.length + '):');
frames.forEach((fr, i) => print('[' + i + '] ' + fr));
expected.forEach(function(exp, i) {
assertEquals(
exp[0], frames[i].getFunctionName(), '[' + i + '].getFunctionName()');
assertEquals(
exp[1], frames[i].getColumnNumber(), '[' + i + '].getColumnNumber()');
});
}
function verifyPreformattedStack(e, expected_lines) {
print('preformatted stack: ' + e.stack);
var lines = e.stack.split('\n');
assertTrue(lines.length >= expected_lines.length, 'too few lines');
for (var i = 0; i < expected_lines.length; ++i) {
assertMatches(expected_lines[i], lines[i], 'line ' + i);
}
}
function sym(return_sym) {
if (return_sym) return Symbol();
throw Error("user-thrown");
}
function generateAsmJs(stdlib, foreign) {
'use asm';
var sym = foreign.sym;
function callSym(i) {
i=i|0;
return sym(i|0) | 0;
}
return callSym;
}
function testHelper(use_asm_js, check_detailed, expected, input) {
if (check_detailed) {
Error.prepareStackTrace = (error, frames) => frames;
} else {
delete Error.prepareStackTrace;
}
var fn_code = '(' + generateAsmJs.toString() + ')({}, {sym: sym})';
if (!use_asm_js) fn_code = fn_code.replace('use asm', '');
//print('executing:\n' + fn_code);
var asm_js_fn = eval(fn_code);
try {
asm_js_fn(input);
} catch (e) {
if (check_detailed) {
verifyStack(e.stack, expected);
} else {
verifyPreformattedStack(e, expected);
}
}
}
function testAll(expected_stack, expected_frames, input) {
for (use_asm_js = 0; use_asm_js <= 1; ++use_asm_js) {
for (test_detailed = 0; test_detailed <= 1; ++test_detailed) {
print('\nConfig: asm ' + use_asm_js + '; detailed ' + test_detailed);
testHelper(
use_asm_js, test_detailed,
test_detailed ? expected_frames : expected_stack, input);
}
}
}
(function testStackForThrowAtCall() {
var expected_stack = [
'^Error: user-thrown$',
'^ *at sym \\(' + filename + ':\\d+:9\\)$',
'^ *at callSym \\(.*<anonymous>:\\d+:12\\)$',
];
var expected_frames = [
// function pos
[ "sym", 9],
[ "callSym", 12],
];
testAll(expected_stack, expected_frames, 0);
})();
(function testStackForThrowAtConversion() {
var expected_stack = [
'^TypeError: Cannot convert a Symbol value to a number$',
'^ *at callSym \\(.*<anonymous>:\\d+:21\\)$',
];
var expected_frames = [
// function pos
[ "callSym", 21],
];
testAll(expected_stack, expected_frames, 1);
})();
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