mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Handle extended indexes around JSOP_*BLOCKCHAIN (610026, r=billm).
This commit is contained in:
parent
44a3f3c372
commit
fdf9d2fd7c
@ -1529,8 +1529,7 @@ EmitKnownBlockChain(JSContext *cx, JSCodeGenerator *cg, JSObjectBox *box)
|
||||
{
|
||||
if (box)
|
||||
return EmitIndexOp(cx, JSOP_BLOCKCHAIN, box->index, cg);
|
||||
else
|
||||
return js_Emit1(cx, cg, JSOP_NULLBLOCKCHAIN) >= 0;
|
||||
return js_Emit1(cx, cg, JSOP_NULLBLOCKCHAIN) >= 0;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
|
@ -202,36 +202,37 @@ js::GetBlockChain(JSContext *cx, JSStackFrame *fp)
|
||||
if (!fp->isScriptFrame())
|
||||
return NULL;
|
||||
|
||||
/* Assume that imacros don't affect blockChain */
|
||||
jsbytecode *target = fp->hasImacropc() ? fp->imacropc() : fp->pc(cx);
|
||||
|
||||
JSScript *script = fp->script();
|
||||
jsbytecode *start = script->code;
|
||||
/* Assume that imacros don't affect blockChain */
|
||||
jsbytecode *pc = fp->hasImacropc() ? fp->imacropc() : fp->pc(cx);
|
||||
|
||||
JS_ASSERT(pc >= start && pc < script->code + script->length);
|
||||
JS_ASSERT(target >= start && target < start + script->length);
|
||||
|
||||
JSObject *blockChain = NULL;
|
||||
if (*pc == JSOP_BLOCKCHAIN) {
|
||||
blockChain = script->getObject(GET_INDEX(pc));
|
||||
} else if (*pc == JSOP_NULLBLOCKCHAIN) {
|
||||
blockChain = NULL;
|
||||
} else {
|
||||
ptrdiff_t oplen;
|
||||
for (jsbytecode *p = start; p < pc; p += oplen) {
|
||||
JSOp op = js_GetOpcode(cx, script, p);
|
||||
const JSCodeSpec *cs = &js_CodeSpec[op];
|
||||
oplen = cs->length;
|
||||
if (oplen < 0)
|
||||
oplen = js_GetVariableBytecodeLength(p);
|
||||
uintN indexBase = 0;
|
||||
ptrdiff_t oplen;
|
||||
for (jsbytecode *pc = start; pc < target; pc += oplen) {
|
||||
JSOp op = js_GetOpcode(cx, script, pc);
|
||||
const JSCodeSpec *cs = &js_CodeSpec[op];
|
||||
oplen = cs->length;
|
||||
if (oplen < 0)
|
||||
oplen = js_GetVariableBytecodeLength(pc);
|
||||
|
||||
if (op == JSOP_ENTERBLOCK)
|
||||
blockChain = script->getObject(GET_INDEX(p));
|
||||
else if (op == JSOP_LEAVEBLOCK || op == JSOP_LEAVEBLOCKEXPR)
|
||||
blockChain = blockChain->getParent();
|
||||
else if (op == JSOP_BLOCKCHAIN)
|
||||
blockChain = script->getObject(GET_INDEX(p));
|
||||
else if (op == JSOP_NULLBLOCKCHAIN)
|
||||
blockChain = NULL;
|
||||
}
|
||||
if (op == JSOP_INDEXBASE)
|
||||
indexBase = GET_INDEXBASE(pc);
|
||||
else if (op == JSOP_INDEXBASE1 || op == JSOP_INDEXBASE2 || op == JSOP_INDEXBASE3)
|
||||
indexBase = (op - JSOP_INDEXBASE1 + 1) << 16;
|
||||
else if (op == JSOP_RESETBASE || op == JSOP_RESETBASE0)
|
||||
indexBase = 0;
|
||||
else if (op == JSOP_ENTERBLOCK)
|
||||
blockChain = script->getObject(indexBase + GET_INDEX(pc));
|
||||
else if (op == JSOP_LEAVEBLOCK || op == JSOP_LEAVEBLOCKEXPR)
|
||||
blockChain = blockChain->getParent();
|
||||
else if (op == JSOP_BLOCKCHAIN)
|
||||
blockChain = script->getObject(indexBase + GET_INDEX(pc));
|
||||
else if (op == JSOP_NULLBLOCKCHAIN)
|
||||
blockChain = NULL;
|
||||
}
|
||||
|
||||
return blockChain;
|
||||
@ -249,29 +250,19 @@ js::GetBlockChainFast(JSContext *cx, JSStackFrame *fp, JSOp op, size_t oplen)
|
||||
{
|
||||
/* Assume that we're in a script frame. */
|
||||
jsbytecode *pc = fp->pc(cx);
|
||||
JS_ASSERT(js_GetOpcode(cx, fp->script(), pc) == op);
|
||||
|
||||
/* The fast path. */
|
||||
if (pc[oplen] == JSOP_NULLBLOCKCHAIN) {
|
||||
JS_ASSERT(js_GetOpcode(cx, fp->script(), pc) == op);
|
||||
pc += oplen;
|
||||
op = JSOp(*pc);
|
||||
JS_ASSERT(js_GetOpcode(cx, fp->script(), pc) == op);
|
||||
|
||||
/* The fast paths assume no JSOP_RESETBASE/INDEXBASE noise. */
|
||||
if (op == JSOP_NULLBLOCKCHAIN)
|
||||
return NULL;
|
||||
}
|
||||
if (op == JSOP_BLOCKCHAIN)
|
||||
return fp->script()->getObject(GET_INDEX(pc));
|
||||
|
||||
JSScript *script = fp->script();
|
||||
|
||||
JS_ASSERT(js_GetOpcode(cx, script, pc) == op);
|
||||
|
||||
JSObject *blockChain;
|
||||
JSOp opNext = js_GetOpcode(cx, script, pc + oplen);
|
||||
if (opNext == JSOP_BLOCKCHAIN) {
|
||||
blockChain = script->getObject(GET_INDEX(pc + oplen));
|
||||
} else if (opNext == JSOP_NULLBLOCKCHAIN) {
|
||||
blockChain = NULL;
|
||||
} else {
|
||||
blockChain = NULL; /* appease gcc */
|
||||
JS_NOT_REACHED("invalid opcode for fast block chain access");
|
||||
}
|
||||
|
||||
return blockChain;
|
||||
return GetBlockChain(cx, fp);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -5639,7 +5630,7 @@ BEGIN_CASE(JSOP_LAMBDA)
|
||||
parent = ®s.fp->scopeChain();
|
||||
|
||||
if (obj->getParent() == parent) {
|
||||
jsbytecode *pc2 = js_AdvanceOverBlockchain(regs.pc + JSOP_LAMBDA_LENGTH);
|
||||
jsbytecode *pc2 = AdvanceOverBlockchainOp(regs.pc + JSOP_LAMBDA_LENGTH);
|
||||
JSOp op2 = JSOp(*pc2);
|
||||
|
||||
/*
|
||||
|
@ -4109,10 +4109,9 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
|
||||
pc += len;
|
||||
if (*pc == JSOP_BLOCKCHAIN) {
|
||||
pc += JSOP_BLOCKCHAIN_LENGTH;
|
||||
} else if (*pc == JSOP_NULLBLOCKCHAIN) {
|
||||
pc += JSOP_NULLBLOCKCHAIN_LENGTH;
|
||||
} else {
|
||||
JS_NOT_REACHED("should see block chain operation");
|
||||
LOCAL_ASSERT(*pc == JSOP_NULLBLOCKCHAIN);
|
||||
pc += JSOP_NULLBLOCKCHAIN_LENGTH;
|
||||
}
|
||||
LOCAL_ASSERT(*pc == JSOP_PUSH);
|
||||
pc += JSOP_PUSH_LENGTH;
|
||||
|
@ -455,7 +455,7 @@ OPDEF(JSOP_UINT24, 188,"uint24", NULL, 4, 0, 1, 16, JOF_UINT24
|
||||
* JSOP_INDEXBASE and JSOP_RESETBASE to provide the upper bits of the index.
|
||||
* See jsemit.c, EmitIndexOp.
|
||||
*/
|
||||
OPDEF(JSOP_INDEXBASE, 189,"atombase", NULL, 2, 0, 0, 0, JOF_UINT8|JOF_INDEXBASE)
|
||||
OPDEF(JSOP_INDEXBASE, 189,"indexbase", NULL, 2, 0, 0, 0, JOF_UINT8|JOF_INDEXBASE)
|
||||
OPDEF(JSOP_RESETBASE, 190,"resetbase", NULL, 1, 0, 0, 0, JOF_BYTE)
|
||||
OPDEF(JSOP_RESETBASE0, 191,"resetbase0", NULL, 1, 0, 0, 0, JOF_BYTE)
|
||||
|
||||
@ -532,9 +532,9 @@ OPDEF(JSOP_GETLOCALPROP, 211,"getlocalprop", NULL, 5, 0, 1, 18, JOF_SLOTAT
|
||||
* Optimize atom segments 1-3. These must be followed by JSOP_RESETBASE0 after
|
||||
* the opcode that they prefix.
|
||||
*/
|
||||
OPDEF(JSOP_INDEXBASE1, 212,"atombase1", NULL, 1, 0, 0, 0, JOF_BYTE |JOF_INDEXBASE)
|
||||
OPDEF(JSOP_INDEXBASE2, 213,"atombase2", NULL, 1, 0, 0, 0, JOF_BYTE |JOF_INDEXBASE)
|
||||
OPDEF(JSOP_INDEXBASE3, 214,"atombase3", NULL, 1, 0, 0, 0, JOF_BYTE |JOF_INDEXBASE)
|
||||
OPDEF(JSOP_INDEXBASE1, 212,"indexbase1", NULL, 1, 0, 0, 0, JOF_BYTE |JOF_INDEXBASE)
|
||||
OPDEF(JSOP_INDEXBASE2, 213,"indexbase2", NULL, 1, 0, 0, 0, JOF_BYTE |JOF_INDEXBASE)
|
||||
OPDEF(JSOP_INDEXBASE3, 214,"indexbase3", NULL, 1, 0, 0, 0, JOF_BYTE |JOF_INDEXBASE)
|
||||
|
||||
OPDEF(JSOP_CALLGNAME, 215, "callgname", NULL, 3, 0, 2, 19, JOF_ATOM|JOF_NAME|JOF_CALLOP|JOF_GNAME)
|
||||
OPDEF(JSOP_CALLLOCAL, 216, "calllocal", NULL, 3, 0, 2, 19, JOF_LOCAL|JOF_NAME|JOF_CALLOP)
|
||||
|
@ -13,12 +13,11 @@
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla Communicator client code, released
|
||||
* March 31, 1998.
|
||||
* The Original Code is the Mozilla SpiderMonkey JaegerMonkey implementation
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1998
|
||||
* Mozilla Foundation
|
||||
* Portions created by the Initial Developer are Copyright (C) 2002-2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
@ -39,13 +38,20 @@
|
||||
|
||||
#include "jsautooplen.h"
|
||||
|
||||
namespace js {
|
||||
|
||||
/*
|
||||
* Warning: this does not skip JSOP_RESETBASE* or JSOP_INDEXBASE* ops, so it is
|
||||
* useful only when checking for optimization opportunities.
|
||||
*/
|
||||
JS_ALWAYS_INLINE jsbytecode *
|
||||
js_AdvanceOverBlockchain(jsbytecode *pc)
|
||||
AdvanceOverBlockchainOp(jsbytecode *pc)
|
||||
{
|
||||
if (*pc == JSOP_NULLBLOCKCHAIN)
|
||||
return pc + JSOP_NULLBLOCKCHAIN_LENGTH;
|
||||
else if (*pc == JSOP_BLOCKCHAIN)
|
||||
if (*pc == JSOP_BLOCKCHAIN)
|
||||
return pc + JSOP_BLOCKCHAIN_LENGTH;
|
||||
else
|
||||
return pc;
|
||||
return pc;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -14847,7 +14847,7 @@ TraceRecorder::record_JSOP_LAMBDA()
|
||||
if (FUN_OBJECT(fun)->getParent() != globalObj)
|
||||
RETURN_STOP_A("Null closure function object parent must be global object");
|
||||
|
||||
jsbytecode *pc2 = js_AdvanceOverBlockchain(cx->regs->pc + JSOP_LAMBDA_LENGTH);
|
||||
jsbytecode *pc2 = AdvanceOverBlockchainOp(cx->regs->pc + JSOP_LAMBDA_LENGTH);
|
||||
JSOp op2 = JSOp(*pc2);
|
||||
|
||||
if (op2 == JSOP_INITMETHOD) {
|
||||
|
@ -1719,7 +1719,7 @@ mjit::Compiler::generateMethod()
|
||||
JSObjStubFun stub = stubs::Lambda;
|
||||
uint32 uses = 0;
|
||||
|
||||
jsbytecode *pc2 = js_AdvanceOverBlockchain(PC + JSOP_LAMBDA_LENGTH);
|
||||
jsbytecode *pc2 = AdvanceOverBlockchainOp(PC + JSOP_LAMBDA_LENGTH);
|
||||
JSOp next = JSOp(*pc2);
|
||||
|
||||
if (next == JSOP_INITMETHOD) {
|
||||
|
@ -50,4 +50,5 @@ script regress-600137.js
|
||||
script regress-601399.js
|
||||
script regress-602621.js
|
||||
fails-if(!xulRuntime.shell) script regress-607863.js
|
||||
script regress-610026.js
|
||||
script regress-609617.js
|
||||
|
65
js/src/tests/js1_8_5/regress/regress-610026.js
Normal file
65
js/src/tests/js1_8_5/regress/regress-610026.js
Normal file
@ -0,0 +1,65 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/*
|
||||
* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/licenses/publicdomain/
|
||||
*/
|
||||
|
||||
var expect = "pass";
|
||||
var actual;
|
||||
|
||||
/*
|
||||
* We hardcode here that GenerateBlockId limits a program to 2^20 blocks. Start
|
||||
* with 2^19 blocks, then test 2^20 - 1 blocks, finally test the limit.
|
||||
*/
|
||||
var s = "{}";
|
||||
for (var i = 0; i < 19; i++)
|
||||
s += s;
|
||||
|
||||
try {
|
||||
eval(s);
|
||||
actual = "pass";
|
||||
} catch (e) {
|
||||
actual = "fail: " + e;
|
||||
}
|
||||
|
||||
assertEq(actual, expect);
|
||||
|
||||
s += s.slice(0, -2);
|
||||
|
||||
try {
|
||||
eval(s);
|
||||
actual = "pass";
|
||||
} catch (e) {
|
||||
actual = "fail: " + e;
|
||||
}
|
||||
|
||||
assertEq(actual, expect);
|
||||
|
||||
s += "{}";
|
||||
|
||||
try {
|
||||
eval(s);
|
||||
actual = "fail: expected InternalError: program too large";
|
||||
} catch (e) {
|
||||
actual = (e.message == "program too large") ? "pass" : "fail: " + e;
|
||||
}
|
||||
|
||||
assertEq(actual, expect);
|
||||
|
||||
/* Make 64K blocks in a row, each with two vars, the second one named x. */
|
||||
s = "{let y, x;}";
|
||||
for (i = 0; i < 16; i++)
|
||||
s += s;
|
||||
|
||||
/* Now append code to alias block 0 and botch a JS_NOT_REACHED or get the wrong x. */
|
||||
s += "var g; { let x = 42; g = function() { return x; }; x = x; }";
|
||||
|
||||
try {
|
||||
eval(s);
|
||||
actual = g();
|
||||
} catch (e) {
|
||||
actual = e;
|
||||
}
|
||||
assertEq(actual, 42);
|
||||
|
||||
reportCompare(0, 0, "ok");
|
Loading…
Reference in New Issue
Block a user