blob: 117e5ab36f6f7b7743ea43ef2e666220ee090e23 [file] [log] [blame]
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00001// Copyright 2011 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include <stdlib.h>
29
30#include "v8.h"
31
32#include "accessors.h"
33#include "api.h"
34#include "arguments.h"
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000035#include "codegen.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000036#include "compilation-cache.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000037#include "compiler.h"
38#include "cpu.h"
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000039#include "dateparser-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000040#include "debug.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000041#include "deoptimizer.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000042#include "execution.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000043#include "global-handles.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000044#include "jsregexp.h"
danno@chromium.org40cb8782011-05-25 07:58:50 +000045#include "json-parser.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000046#include "liveedit.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000047#include "liveobjectlist-inl.h"
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000048#include "misc-intrinsics.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000049#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000050#include "platform.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000051#include "runtime-profiler.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000052#include "runtime.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000053#include "scopeinfo.h"
ager@chromium.org7c537e22008-10-16 08:43:32 +000054#include "smart-pointer.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000055#include "string-search.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000056#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000057#include "v8threads.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000058#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000059
kasperl@chromium.org71affb52009-05-26 05:44:31 +000060namespace v8 {
61namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000062
63
ager@chromium.org3e875802009-06-29 08:26:34 +000064#define RUNTIME_ASSERT(value) \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000065 if (!(value)) return isolate->ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000066
67// Cast the given object to a value of the specified type and store
68// it in a variable with the given name. If the object is not of the
69// expected type call IllegalOperation and return.
70#define CONVERT_CHECKED(Type, name, obj) \
71 RUNTIME_ASSERT(obj->Is##Type()); \
72 Type* name = Type::cast(obj);
73
74#define CONVERT_ARG_CHECKED(Type, name, index) \
75 RUNTIME_ASSERT(args[index]->Is##Type()); \
76 Handle<Type> name = args.at<Type>(index);
77
kasper.lundbd3ec4e2008-07-09 11:06:54 +000078// Cast the given object to a boolean and store it in a variable with
79// the given name. If the object is not a boolean call IllegalOperation
80// and return.
81#define CONVERT_BOOLEAN_CHECKED(name, obj) \
82 RUNTIME_ASSERT(obj->IsBoolean()); \
83 bool name = (obj)->IsTrue();
84
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000085// Cast the given argument to a Smi and store its value in an int variable
86// with the given name. If the argument is not a Smi call IllegalOperation
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000087// and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000088#define CONVERT_SMI_ARG_CHECKED(name, index) \
89 RUNTIME_ASSERT(args[index]->IsSmi()); \
90 int name = args.smi_at(index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000091
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000092// Cast the given argument to a double and store it in a variable with
93// the given name. If the argument is not a number (as opposed to
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000094// the number not-a-number) call IllegalOperation and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000095#define CONVERT_DOUBLE_ARG_CHECKED(name, index) \
96 RUNTIME_ASSERT(args[index]->IsNumber()); \
97 double name = args.number_at(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000098
99// Call the specified converter on the object *comand store the result in
100// a variable of the specified type with the given name. If the
101// object is not a Number call IllegalOperation and return.
102#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
103 RUNTIME_ASSERT(obj->IsNumber()); \
104 type name = NumberTo##Type(obj);
105
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000106
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000107MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
108 JSObject* boilerplate) {
109 StackLimitCheck check(isolate);
110 if (check.HasOverflowed()) return isolate->StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000111
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000112 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000113 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000114 { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000115 if (!maybe_result->ToObject(&result)) return maybe_result;
116 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000117 JSObject* copy = JSObject::cast(result);
118
119 // Deep copy local properties.
120 if (copy->HasFastProperties()) {
121 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000122 for (int i = 0; i < properties->length(); i++) {
123 Object* value = properties->get(i);
124 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000125 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000126 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000127 if (!maybe_result->ToObject(&result)) return maybe_result;
128 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000129 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000130 }
131 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000132 int nof = copy->map()->inobject_properties();
133 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000134 Object* value = copy->InObjectPropertyAt(i);
135 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000136 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000137 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000138 if (!maybe_result->ToObject(&result)) return maybe_result;
139 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000140 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000141 }
142 }
143 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000144 { MaybeObject* maybe_result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000145 heap->AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
lrn@chromium.org303ada72010-10-27 09:33:13 +0000146 if (!maybe_result->ToObject(&result)) return maybe_result;
147 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000148 FixedArray* names = FixedArray::cast(result);
149 copy->GetLocalPropertyNames(names, 0);
150 for (int i = 0; i < names->length(); i++) {
151 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000152 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000153 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000154 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000155 // Only deep copy fields from the object literal expression.
156 // In particular, don't try to copy the length attribute of
157 // an array.
158 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000159 Object* value =
160 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000161 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000162 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000163 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000164 if (!maybe_result->ToObject(&result)) return maybe_result;
165 }
166 { MaybeObject* maybe_result =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000167 // Creating object copy for literals. No strict mode needed.
168 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000169 if (!maybe_result->ToObject(&result)) return maybe_result;
170 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000171 }
172 }
173 }
174
175 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000176 // Pixel elements cannot be created using an object literal.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000177 ASSERT(!copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000178 switch (copy->GetElementsKind()) {
179 case JSObject::FAST_ELEMENTS: {
180 FixedArray* elements = FixedArray::cast(copy->elements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000181 if (elements->map() == heap->fixed_cow_array_map()) {
182 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000183#ifdef DEBUG
184 for (int i = 0; i < elements->length(); i++) {
185 ASSERT(!elements->get(i)->IsJSObject());
186 }
187#endif
188 } else {
189 for (int i = 0; i < elements->length(); i++) {
190 Object* value = elements->get(i);
191 if (value->IsJSObject()) {
192 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000193 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
194 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000195 if (!maybe_result->ToObject(&result)) return maybe_result;
196 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000197 elements->set(i, result);
198 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000199 }
200 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000201 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000202 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000203 case JSObject::DICTIONARY_ELEMENTS: {
204 NumberDictionary* element_dictionary = copy->element_dictionary();
205 int capacity = element_dictionary->Capacity();
206 for (int i = 0; i < capacity; i++) {
207 Object* k = element_dictionary->KeyAt(i);
208 if (element_dictionary->IsKey(k)) {
209 Object* value = element_dictionary->ValueAt(i);
210 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000211 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000212 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
213 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000214 if (!maybe_result->ToObject(&result)) return maybe_result;
215 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000216 element_dictionary->ValueAtPut(i, result);
217 }
218 }
219 }
220 break;
221 }
222 default:
223 UNREACHABLE();
224 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000225 }
226 return copy;
227}
228
229
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000230RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneLiteralBoilerplate) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000231 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000232 return DeepCopyBoilerplate(isolate, boilerplate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000233}
234
235
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000236RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneShallowLiteralBoilerplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000237 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000238 return isolate->heap()->CopyJSObject(boilerplate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000239}
240
241
ager@chromium.org236ad962008-09-25 09:45:57 +0000242static Handle<Map> ComputeObjectLiteralMap(
243 Handle<Context> context,
244 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000245 bool* is_result_from_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000246 Isolate* isolate = context->GetIsolate();
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000247 int properties_length = constant_properties->length();
248 int number_of_properties = properties_length / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000249 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000250 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000251 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000252 for (int p = 0; p != properties_length; p += 2) {
253 Object* key = constant_properties->get(p);
254 uint32_t element_index = 0;
255 if (key->IsSymbol()) {
256 number_of_symbol_keys++;
257 } else if (key->ToArrayIndex(&element_index)) {
258 // An index key does not require space in the property backing store.
259 number_of_properties--;
260 } else {
261 // Bail out as a non-symbol non-index key makes caching impossible.
262 // ASSERT to make sure that the if condition after the loop is false.
263 ASSERT(number_of_symbol_keys != number_of_properties);
264 break;
265 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000266 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000267 // If we only have symbols and array indices among keys then we can
268 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000269 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000270 if ((number_of_symbol_keys == number_of_properties) &&
271 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000272 // Create the fixed array with the key.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000273 Handle<FixedArray> keys =
274 isolate->factory()->NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000275 if (number_of_symbol_keys > 0) {
276 int index = 0;
277 for (int p = 0; p < properties_length; p += 2) {
278 Object* key = constant_properties->get(p);
279 if (key->IsSymbol()) {
280 keys->set(index++, key);
281 }
282 }
283 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000284 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000285 *is_result_from_cache = true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000286 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000287 }
288 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000289 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000290 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000291 Handle<Map>(context->object_function()->initial_map()),
292 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000293}
294
295
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000296static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000297 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000298 Handle<FixedArray> literals,
299 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000300
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000301
302static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000303 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000304 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000305 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000306 bool should_have_fast_elements,
307 bool has_function_literal) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000308 // Get the global context from the literals array. This is the
309 // context in which the function was created and we use the object
310 // function from this context to create the object literal. We do
311 // not use the object function from the current global context
312 // because this might be the object function from another context
313 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000314 Handle<Context> context =
315 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
316
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000317 // In case we have function literals, we want the object to be in
318 // slow properties mode for now. We don't go in the map cache because
319 // maps with constant functions can't be shared if the functions are
320 // not the same (which is the common case).
321 bool is_result_from_cache = false;
322 Handle<Map> map = has_function_literal
323 ? Handle<Map>(context->object_function()->initial_map())
324 : ComputeObjectLiteralMap(context,
325 constant_properties,
326 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000327
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000328 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000329
330 // Normalize the elements of the boilerplate to save space if needed.
331 if (!should_have_fast_elements) NormalizeElements(boilerplate);
332
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000333 // Add the constant properties to the boilerplate.
334 int length = constant_properties->length();
335 bool should_transform =
336 !is_result_from_cache && boilerplate->HasFastProperties();
337 if (should_transform || has_function_literal) {
338 // Normalize the properties of object to avoid n^2 behavior
339 // when extending the object multiple properties. Indicate the number of
340 // properties to be added.
341 NormalizeProperties(boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
342 }
343
344 for (int index = 0; index < length; index +=2) {
345 Handle<Object> key(constant_properties->get(index+0), isolate);
346 Handle<Object> value(constant_properties->get(index+1), isolate);
347 if (value->IsFixedArray()) {
348 // The value contains the constant_properties of a
349 // simple object or array literal.
350 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
351 value = CreateLiteralBoilerplate(isolate, literals, array);
352 if (value.is_null()) return value;
353 }
354 Handle<Object> result;
355 uint32_t element_index = 0;
356 if (key->IsSymbol()) {
357 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
358 // Array index as string (uint32).
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000359 result = SetOwnElement(boilerplate,
360 element_index,
361 value,
362 kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000363 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000364 Handle<String> name(String::cast(*key));
365 ASSERT(!name->AsArrayIndex(&element_index));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000366 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
367 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000368 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000369 } else if (key->ToArrayIndex(&element_index)) {
370 // Array index (uint32).
371 result = SetOwnElement(boilerplate,
372 element_index,
373 value,
374 kNonStrictMode);
375 } else {
376 // Non-uint32 number.
377 ASSERT(key->IsNumber());
378 double num = key->Number();
379 char arr[100];
380 Vector<char> buffer(arr, ARRAY_SIZE(arr));
381 const char* str = DoubleToCString(num, buffer);
382 Handle<String> name =
383 isolate->factory()->NewStringFromAscii(CStrVector(str));
384 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
385 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000386 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000387 // If setting the property on the boilerplate throws an
388 // exception, the exception is converted to an empty handle in
389 // the handle based operations. In that case, we need to
390 // convert back to an exception.
391 if (result.is_null()) return result;
392 }
393
394 // Transform to fast properties if necessary. For object literals with
395 // containing function literals we defer this operation until after all
396 // computed properties have been assigned so that we can generate
397 // constant function properties.
398 if (should_transform && !has_function_literal) {
399 TransformToFastProperties(boilerplate,
400 boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000401 }
402
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000403 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000404}
405
406
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000407static Handle<Object> CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000408 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000409 Handle<FixedArray> literals,
410 Handle<FixedArray> elements) {
411 // Create the JSArray.
412 Handle<JSFunction> constructor(
413 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000414 Handle<Object> object = isolate->factory()->NewJSObject(constructor);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000415
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000416 const bool is_cow =
417 (elements->map() == isolate->heap()->fixed_cow_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000418 Handle<FixedArray> copied_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000419 is_cow ? elements : isolate->factory()->CopyFixedArray(elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000420
421 Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000422 if (is_cow) {
423#ifdef DEBUG
424 // Copy-on-write arrays must be shallow (and simple).
425 for (int i = 0; i < content->length(); i++) {
426 ASSERT(!content->get(i)->IsFixedArray());
427 }
428#endif
429 } else {
430 for (int i = 0; i < content->length(); i++) {
431 if (content->get(i)->IsFixedArray()) {
432 // The value contains the constant_properties of a
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000433 // simple object or array literal.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000434 Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
435 Handle<Object> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000436 CreateLiteralBoilerplate(isolate, literals, fa);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000437 if (result.is_null()) return result;
438 content->set(i, *result);
439 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000440 }
441 }
442
443 // Set the elements.
444 Handle<JSArray>::cast(object)->SetContent(*content);
445 return object;
446}
447
448
449static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000450 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000451 Handle<FixedArray> literals,
452 Handle<FixedArray> array) {
453 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000454 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000455 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000456 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000457 return CreateObjectLiteralBoilerplate(isolate,
458 literals,
459 elements,
460 true,
461 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000462 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000463 return CreateObjectLiteralBoilerplate(isolate,
464 literals,
465 elements,
466 false,
467 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000468 case CompileTimeValue::ARRAY_LITERAL:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000469 return CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000470 default:
471 UNREACHABLE();
472 return Handle<Object>::null();
473 }
474}
475
476
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000477RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralBoilerplate) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000478 // Takes a FixedArray of elements containing the literal elements of
479 // the array literal and produces JSArray with those elements.
480 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000481 // which contains the context from which to get the Array function
482 // to use for creating the array literal.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000483 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000484 ASSERT(args.length() == 3);
485 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000486 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000487 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000488
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000489 Handle<Object> object =
490 CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000491 if (object.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000492
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000493 // Update the functions literal and return the boilerplate.
494 literals->set(literals_index, *object);
495 return *object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000496}
497
498
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000499RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000500 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000501 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000502 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000503 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000504 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000505 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000506 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
507 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000508
509 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000510 Handle<Object> boilerplate(literals->get(literals_index), isolate);
511 if (*boilerplate == isolate->heap()->undefined_value()) {
512 boilerplate = CreateObjectLiteralBoilerplate(isolate,
513 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000514 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000515 should_have_fast_elements,
516 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000517 if (boilerplate.is_null()) return Failure::Exception();
518 // Update the functions literal and return the boilerplate.
519 literals->set(literals_index, *boilerplate);
520 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000521 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000522}
523
524
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000525RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000526 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000527 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000528 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000529 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000530 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000531 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000532 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
533 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000534
535 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000536 Handle<Object> boilerplate(literals->get(literals_index), isolate);
537 if (*boilerplate == isolate->heap()->undefined_value()) {
538 boilerplate = CreateObjectLiteralBoilerplate(isolate,
539 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000540 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000541 should_have_fast_elements,
542 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000543 if (boilerplate.is_null()) return Failure::Exception();
544 // Update the functions literal and return the boilerplate.
545 literals->set(literals_index, *boilerplate);
546 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000547 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000548}
549
550
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000551RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000552 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000553 ASSERT(args.length() == 3);
554 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000555 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000556 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
557
558 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000559 Handle<Object> boilerplate(literals->get(literals_index), isolate);
560 if (*boilerplate == isolate->heap()->undefined_value()) {
561 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000562 if (boilerplate.is_null()) return Failure::Exception();
563 // Update the functions literal and return the boilerplate.
564 literals->set(literals_index, *boilerplate);
565 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000566 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000567}
568
569
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000570RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000571 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000572 ASSERT(args.length() == 3);
573 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000574 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000575 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
576
577 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000578 Handle<Object> boilerplate(literals->get(literals_index), isolate);
579 if (*boilerplate == isolate->heap()->undefined_value()) {
580 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000581 if (boilerplate.is_null()) return Failure::Exception();
582 // Update the functions literal and return the boilerplate.
583 literals->set(literals_index, *boilerplate);
584 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000585 if (JSObject::cast(*boilerplate)->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000586 isolate->heap()->fixed_cow_array_map()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000587 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000588 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000589 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000590}
591
592
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000593RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) {
594 ASSERT(args.length() == 2);
595 Object* handler = args[0];
596 Object* prototype = args[1];
597 Object* used_prototype =
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000598 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000599 return isolate->heap()->AllocateJSProxy(handler, used_prototype);
600}
601
602
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000603RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) {
604 ASSERT(args.length() == 1);
605 Object* obj = args[0];
606 return obj->IsJSProxy()
607 ? isolate->heap()->true_value() : isolate->heap()->false_value();
608}
609
610
611RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) {
612 ASSERT(args.length() == 1);
613 CONVERT_CHECKED(JSProxy, proxy, args[0]);
614 return proxy->handler();
615}
616
617
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000618RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000619 NoHandleAllocation ha;
620 ASSERT(args.length() == 1);
621 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000622 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000623 return JSObject::cast(obj)->class_name();
624}
625
ager@chromium.org7c537e22008-10-16 08:43:32 +0000626
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000627RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) {
628 NoHandleAllocation ha;
629 ASSERT(args.length() == 1);
630 Object* obj = args[0];
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000631 do {
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000632 obj = obj->GetPrototype();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000633 } while (obj->IsJSObject() &&
634 JSObject::cast(obj)->map()->is_hidden_prototype());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000635 return obj;
636}
637
638
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000639RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000640 NoHandleAllocation ha;
641 ASSERT(args.length() == 2);
642 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
643 Object* O = args[0];
644 Object* V = args[1];
645 while (true) {
646 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000647 if (prototype->IsNull()) return isolate->heap()->false_value();
648 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000649 V = prototype;
650 }
651}
652
653
ager@chromium.org9085a012009-05-11 19:22:57 +0000654// Inserts an object as the hidden prototype of another object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000655RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHiddenPrototype) {
ager@chromium.org9085a012009-05-11 19:22:57 +0000656 NoHandleAllocation ha;
657 ASSERT(args.length() == 2);
658 CONVERT_CHECKED(JSObject, jsobject, args[0]);
659 CONVERT_CHECKED(JSObject, proto, args[1]);
660
661 // Sanity checks. The old prototype (that we are replacing) could
662 // theoretically be null, but if it is not null then check that we
663 // didn't already install a hidden prototype here.
664 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
665 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
666 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
667
668 // Allocate up front before we start altering state in case we get a GC.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000669 Object* map_or_failure;
670 { MaybeObject* maybe_map_or_failure = proto->map()->CopyDropTransitions();
671 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
672 return maybe_map_or_failure;
673 }
674 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000675 Map* new_proto_map = Map::cast(map_or_failure);
676
lrn@chromium.org303ada72010-10-27 09:33:13 +0000677 { MaybeObject* maybe_map_or_failure = jsobject->map()->CopyDropTransitions();
678 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
679 return maybe_map_or_failure;
680 }
681 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000682 Map* new_map = Map::cast(map_or_failure);
683
684 // Set proto's prototype to be the old prototype of the object.
685 new_proto_map->set_prototype(jsobject->GetPrototype());
686 proto->set_map(new_proto_map);
687 new_proto_map->set_is_hidden_prototype();
688
689 // Set the object's prototype to proto.
690 new_map->set_prototype(proto);
691 jsobject->set_map(new_map);
692
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000693 return isolate->heap()->undefined_value();
ager@chromium.org9085a012009-05-11 19:22:57 +0000694}
695
696
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000697RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConstructCall) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000698 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000699 ASSERT(args.length() == 0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000700 JavaScriptFrameIterator it(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000701 return isolate->heap()->ToBoolean(it.frame()->IsConstructor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000702}
703
704
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000705// Recursively traverses hidden prototypes if property is not found
706static void GetOwnPropertyImplementation(JSObject* obj,
707 String* name,
708 LookupResult* result) {
709 obj->LocalLookupRealNamedProperty(name, result);
710
711 if (!result->IsProperty()) {
712 Object* proto = obj->GetPrototype();
713 if (proto->IsJSObject() &&
714 JSObject::cast(proto)->map()->is_hidden_prototype())
715 GetOwnPropertyImplementation(JSObject::cast(proto),
716 name, result);
717 }
718}
719
720
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000721static bool CheckAccessException(LookupResult* result,
722 v8::AccessType access_type) {
723 if (result->type() == CALLBACKS) {
724 Object* callback = result->GetCallbackObject();
725 if (callback->IsAccessorInfo()) {
726 AccessorInfo* info = AccessorInfo::cast(callback);
727 bool can_access =
728 (access_type == v8::ACCESS_HAS &&
729 (info->all_can_read() || info->all_can_write())) ||
730 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
731 (access_type == v8::ACCESS_SET && info->all_can_write());
732 return can_access;
733 }
734 }
735
736 return false;
737}
738
739
740static bool CheckAccess(JSObject* obj,
741 String* name,
742 LookupResult* result,
743 v8::AccessType access_type) {
744 ASSERT(result->IsProperty());
745
746 JSObject* holder = result->holder();
747 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000748 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000749 while (true) {
750 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000751 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000752 // Access check callback denied the access, but some properties
753 // can have a special permissions which override callbacks descision
754 // (currently see v8::AccessControl).
755 break;
756 }
757
758 if (current == holder) {
759 return true;
760 }
761
762 current = JSObject::cast(current->GetPrototype());
763 }
764
765 // API callbacks can have per callback access exceptions.
766 switch (result->type()) {
767 case CALLBACKS: {
768 if (CheckAccessException(result, access_type)) {
769 return true;
770 }
771 break;
772 }
773 case INTERCEPTOR: {
774 // If the object has an interceptor, try real named properties.
775 // Overwrite the result to fetch the correct property later.
776 holder->LookupRealNamedProperty(name, result);
777 if (result->IsProperty()) {
778 if (CheckAccessException(result, access_type)) {
779 return true;
780 }
781 }
782 break;
783 }
784 default:
785 break;
786 }
787
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000788 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000789 return false;
790}
791
792
793// TODO(1095): we should traverse hidden prototype hierachy as well.
794static bool CheckElementAccess(JSObject* obj,
795 uint32_t index,
796 v8::AccessType access_type) {
797 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000798 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000799 return false;
800 }
801
802 return true;
803}
804
805
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000806// Enumerator used as indices into the array returned from GetOwnProperty
807enum PropertyDescriptorIndices {
808 IS_ACCESSOR_INDEX,
809 VALUE_INDEX,
810 GETTER_INDEX,
811 SETTER_INDEX,
812 WRITABLE_INDEX,
813 ENUMERABLE_INDEX,
814 CONFIGURABLE_INDEX,
815 DESCRIPTOR_SIZE
816};
817
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000818// Returns an array with the property description:
819// if args[1] is not a property on args[0]
820// returns undefined
821// if args[1] is a data property on args[0]
822// [false, value, Writeable, Enumerable, Configurable]
823// if args[1] is an accessor on args[0]
824// [true, GetFunction, SetFunction, Enumerable, Configurable]
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000825RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000826 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000827 Heap* heap = isolate->heap();
828 HandleScope scope(isolate);
829 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
830 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000831 LookupResult result;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000832 CONVERT_ARG_CHECKED(JSObject, obj, 0);
833 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000834
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000835 // This could be an element.
836 uint32_t index;
837 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000838 switch (obj->HasLocalElement(index)) {
839 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000840 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000841
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000842 case JSObject::STRING_CHARACTER_ELEMENT: {
843 // Special handling of string objects according to ECMAScript 5
844 // 15.5.5.2. Note that this might be a string object with elements
845 // other than the actual string value. This is covered by the
846 // subsequent cases.
847 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
848 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000849 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000850
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000851 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000852 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000853 elms->set(WRITABLE_INDEX, heap->false_value());
854 elms->set(ENUMERABLE_INDEX, heap->false_value());
855 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000856 return *desc;
857 }
858
859 case JSObject::INTERCEPTED_ELEMENT:
860 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000861 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000862 Handle<Object> value = GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000863 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000864 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000865 elms->set(WRITABLE_INDEX, heap->true_value());
866 elms->set(ENUMERABLE_INDEX, heap->true_value());
867 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000868 return *desc;
869 }
870
871 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000872 Handle<JSObject> holder = obj;
873 if (obj->IsJSGlobalProxy()) {
874 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000875 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000876 ASSERT(proto->IsJSGlobalObject());
877 holder = Handle<JSObject>(JSObject::cast(proto));
878 }
whesse@chromium.org7b260152011-06-20 15:33:18 +0000879 FixedArray* elements = FixedArray::cast(holder->elements());
880 NumberDictionary* dictionary = NULL;
881 if (elements->map() == heap->non_strict_arguments_elements_map()) {
882 dictionary = NumberDictionary::cast(elements->get(1));
883 } else {
884 dictionary = NumberDictionary::cast(elements);
885 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000886 int entry = dictionary->FindEntry(index);
887 ASSERT(entry != NumberDictionary::kNotFound);
888 PropertyDetails details = dictionary->DetailsAt(entry);
889 switch (details.type()) {
890 case CALLBACKS: {
891 // This is an accessor property with getter and/or setter.
892 FixedArray* callbacks =
893 FixedArray::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000894 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000895 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
896 elms->set(GETTER_INDEX, callbacks->get(0));
897 }
898 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
899 elms->set(SETTER_INDEX, callbacks->get(1));
900 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000901 break;
902 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000903 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000904 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000905 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000906 Handle<Object> value = GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000907 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000908 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000909 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000910 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000911 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000912 default:
913 UNREACHABLE();
914 break;
915 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000916 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
917 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000918 return *desc;
919 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000920 }
921 }
922
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000923 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000924 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000925
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000926 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000927 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000928 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000929
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000930 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000931 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000932 }
933
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000934 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
935 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000936
937 bool is_js_accessor = (result.type() == CALLBACKS) &&
938 (result.GetCallbackObject()->IsFixedArray());
939
940 if (is_js_accessor) {
941 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000942 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000943
944 FixedArray* structure = FixedArray::cast(result.GetCallbackObject());
945 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
946 elms->set(GETTER_INDEX, structure->get(0));
947 }
948 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
949 elms->set(SETTER_INDEX, structure->get(1));
950 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000951 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000952 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
953 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000954
955 PropertyAttributes attrs;
956 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000957 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000958 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
959 if (!maybe_value->ToObject(&value)) return maybe_value;
960 }
961 elms->set(VALUE_INDEX, value);
962 }
963
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000964 return *desc;
965}
966
967
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000968RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000969 ASSERT(args.length() == 1);
970 CONVERT_CHECKED(JSObject, obj, args[0]);
971 return obj->PreventExtensions();
972}
973
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000974
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000975RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000976 ASSERT(args.length() == 1);
977 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000978 if (obj->IsJSGlobalProxy()) {
979 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000980 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000981 ASSERT(proto->IsJSGlobalObject());
982 obj = JSObject::cast(proto);
983 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000984 return obj->map()->is_extensible() ? isolate->heap()->true_value()
985 : isolate->heap()->false_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000986}
987
988
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000989RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000990 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000991 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000992 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
993 CONVERT_ARG_CHECKED(String, pattern, 1);
994 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000995 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
996 if (result.is_null()) return Failure::Exception();
997 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000998}
999
1000
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001001RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001002 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001003 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001004 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001005 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001006}
1007
1008
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001009RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001010 ASSERT(args.length() == 1);
1011 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001012 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001013 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001014}
1015
1016
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001017RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001018 ASSERT(args.length() == 2);
1019 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001020 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001021 int index = field->value();
1022 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1023 InstanceType type = templ->map()->instance_type();
1024 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1025 type == OBJECT_TEMPLATE_INFO_TYPE);
1026 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001027 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001028 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1029 } else {
1030 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1031 }
1032 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001033}
1034
1035
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001036RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001037 ASSERT(args.length() == 1);
1038 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001039 Map* old_map = object->map();
1040 bool needs_access_checks = old_map->is_access_check_needed();
1041 if (needs_access_checks) {
1042 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001043 Object* new_map;
1044 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1045 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1046 }
ager@chromium.org32912102009-01-16 10:38:43 +00001047
1048 Map::cast(new_map)->set_is_access_check_needed(false);
1049 object->set_map(Map::cast(new_map));
1050 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001051 return needs_access_checks ? isolate->heap()->true_value()
1052 : isolate->heap()->false_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001053}
1054
1055
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001056RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001057 ASSERT(args.length() == 1);
1058 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001059 Map* old_map = object->map();
1060 if (!old_map->is_access_check_needed()) {
1061 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001062 Object* new_map;
1063 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1064 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1065 }
ager@chromium.org32912102009-01-16 10:38:43 +00001066
1067 Map::cast(new_map)->set_is_access_check_needed(true);
1068 object->set_map(Map::cast(new_map));
1069 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001070 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001071}
1072
1073
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001074static Failure* ThrowRedeclarationError(Isolate* isolate,
1075 const char* type,
1076 Handle<String> name) {
1077 HandleScope scope(isolate);
1078 Handle<Object> type_handle =
1079 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001080 Handle<Object> args[2] = { type_handle, name };
1081 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001082 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1083 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001084}
1085
1086
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001087RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001088 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001089 HandleScope scope(isolate);
1090 Handle<GlobalObject> global = Handle<GlobalObject>(
1091 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001092
ager@chromium.org3811b432009-10-28 14:53:37 +00001093 Handle<Context> context = args.at<Context>(0);
1094 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001095 bool is_eval = args.smi_at(2) == 1;
1096 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(args.smi_at(3));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001097 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001098
1099 // Compute the property attributes. According to ECMA-262, section
1100 // 13, page 71, the property must be read-only and
1101 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1102 // property as read-only, so we don't either.
1103 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
1104
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001105 // Traverse the name/value pairs and set the properties.
1106 int length = pairs->length();
1107 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001108 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001109 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001110 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001111
1112 // We have to declare a global const property. To capture we only
1113 // assign to it when evaluating the assignment for "const x =
1114 // <expr>" the initial value is the hole.
1115 bool is_const_property = value->IsTheHole();
1116
1117 if (value->IsUndefined() || is_const_property) {
1118 // Lookup the property in the global object, and don't set the
1119 // value of the variable if the property is already there.
1120 LookupResult lookup;
1121 global->Lookup(*name, &lookup);
1122 if (lookup.IsProperty()) {
1123 // Determine if the property is local by comparing the holder
1124 // against the global object. The information will be used to
1125 // avoid throwing re-declaration errors when declaring
1126 // variables or constants that exist in the prototype chain.
1127 bool is_local = (*global == lookup.holder());
1128 // Get the property attributes and determine if the property is
1129 // read-only.
1130 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1131 bool is_read_only = (attributes & READ_ONLY) != 0;
1132 if (lookup.type() == INTERCEPTOR) {
1133 // If the interceptor says the property is there, we
1134 // just return undefined without overwriting the property.
1135 // Otherwise, we continue to setting the property.
1136 if (attributes != ABSENT) {
1137 // Check if the existing property conflicts with regards to const.
1138 if (is_local && (is_read_only || is_const_property)) {
1139 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001140 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001141 };
1142 // The property already exists without conflicting: Go to
1143 // the next declaration.
1144 continue;
1145 }
1146 // Fall-through and introduce the absent property by using
1147 // SetProperty.
1148 } else {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001149 // For const properties, we treat a callback with this name
1150 // even in the prototype as a conflicting declaration.
1151 if (is_const_property && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001152 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001153 }
1154 // Otherwise, we check for locally conflicting declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001155 if (is_local && (is_read_only || is_const_property)) {
1156 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001157 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001158 }
1159 // The property already exists without conflicting: Go to
1160 // the next declaration.
1161 continue;
1162 }
1163 }
1164 } else {
1165 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001166 Handle<SharedFunctionInfo> shared =
1167 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001168 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001169 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1170 context,
1171 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001172 value = function;
1173 }
1174
1175 LookupResult lookup;
1176 global->LocalLookup(*name, &lookup);
1177
1178 PropertyAttributes attributes = is_const_property
1179 ? static_cast<PropertyAttributes>(base | READ_ONLY)
1180 : base;
1181
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001182 // There's a local property that we need to overwrite because
1183 // we're either declaring a function or there's an interceptor
1184 // that claims the property is absent.
1185 //
1186 // Check for conflicting re-declarations. We cannot have
1187 // conflicting types in case of intercepted properties because
1188 // they are absent.
1189 if (lookup.IsProperty() &&
1190 (lookup.type() != INTERCEPTOR) &&
1191 (lookup.IsReadOnly() || is_const_property)) {
1192 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001193 return ThrowRedeclarationError(isolate, type, name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001194 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001195
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001196 // Safari does not allow the invocation of callback setters for
1197 // function declarations. To mimic this behavior, we do not allow
1198 // the invocation of setters for function values. This makes a
1199 // difference for global functions with the same names as event
1200 // handlers such as "function onload() {}". Firefox does call the
1201 // onload setter in those case and Safari does not. We follow
1202 // Safari for compatibility.
1203 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001204 // Do not change DONT_DELETE to false from true.
1205 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
1206 attributes = static_cast<PropertyAttributes>(
1207 attributes | (lookup.GetAttributes() & DONT_DELETE));
1208 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001209 RETURN_IF_EMPTY_HANDLE(isolate,
1210 SetLocalPropertyIgnoreAttributes(global,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001211 name,
1212 value,
1213 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001214 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001215 RETURN_IF_EMPTY_HANDLE(isolate,
1216 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001217 name,
1218 value,
1219 attributes,
1220 strict_mode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001221 }
1222 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001223
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001224 ASSERT(!isolate->has_pending_exception());
1225 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001226}
1227
1228
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001229RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001230 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001231 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001232
ager@chromium.org7c537e22008-10-16 08:43:32 +00001233 CONVERT_ARG_CHECKED(Context, context, 0);
1234 Handle<String> name(String::cast(args[1]));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001235 PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001236 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001237 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001238
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001239 // Declarations are always done in a function or global context.
1240 context = Handle<Context>(context->declaration_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001241
1242 int index;
1243 PropertyAttributes attributes;
1244 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001245 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001246 context->Lookup(name, flags, &index, &attributes);
1247
1248 if (attributes != ABSENT) {
1249 // The name was declared before; check for conflicting
1250 // re-declarations: This is similar to the code in parser.cc in
1251 // the AstBuildingParser::Declare function.
1252 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1253 // Functions are not read-only.
1254 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1255 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001256 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001257 }
1258
1259 // Initialize it if necessary.
1260 if (*initial_value != NULL) {
1261 if (index >= 0) {
1262 // The variable or constant context slot should always be in
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001263 // the function context or the arguments object.
1264 if (holder->IsContext()) {
1265 ASSERT(holder.is_identical_to(context));
1266 if (((attributes & READ_ONLY) == 0) ||
1267 context->get(index)->IsTheHole()) {
1268 context->set(index, *initial_value);
1269 }
1270 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001271 // The holder is an arguments object.
1272 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001273 Handle<Object> result = SetElement(arguments, index, initial_value,
1274 kNonStrictMode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001275 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001276 }
1277 } else {
1278 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001279 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001280 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001281 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001282 SetProperty(context_ext, name, initial_value,
1283 mode, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001284 }
1285 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001286
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001287 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001288 // The property is not in the function context. It needs to be
1289 // "declared" in the function context's extension context, or in the
1290 // global context.
1291 Handle<JSObject> context_ext;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001292 if (context->has_extension()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001293 // The function context's extension context exists - use it.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001294 context_ext = Handle<JSObject>(JSObject::cast(context->extension()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001295 } else {
1296 // The function context's extension context does not exists - allocate
1297 // it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001298 context_ext = isolate->factory()->NewJSObject(
1299 isolate->context_extension_function());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001300 // And store it in the extension slot.
1301 context->set_extension(*context_ext);
1302 }
1303 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001304
ager@chromium.org7c537e22008-10-16 08:43:32 +00001305 // Declare the property by setting it to the initial value if provided,
1306 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1307 // constant declarations).
1308 ASSERT(!context_ext->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001309 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001310 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001311 // Declaring a const context slot is a conflicting declaration if
1312 // there is a callback with that name in a prototype. It is
1313 // allowed to introduce const variables in
1314 // JSContextExtensionObjects. They are treated specially in
1315 // SetProperty and no setters are invoked for those since they are
1316 // not real JSObjects.
1317 if (initial_value->IsTheHole() &&
1318 !context_ext->IsJSContextExtensionObject()) {
1319 LookupResult lookup;
1320 context_ext->Lookup(*name, &lookup);
1321 if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001322 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001323 }
1324 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001325 RETURN_IF_EMPTY_HANDLE(isolate,
1326 SetProperty(context_ext, name, value, mode,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001327 kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001328 }
1329
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001330 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001331}
1332
1333
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001334RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001335 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001336 // args[0] == name
1337 // args[1] == strict_mode
1338 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001339
1340 // Determine if we need to assign to the variable if it already
1341 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001342 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1343 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001344
1345 CONVERT_ARG_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001346 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001347 RUNTIME_ASSERT(args[1]->IsSmi());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001348 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(args.smi_at(1));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001349 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001350
1351 // According to ECMA-262, section 12.2, page 62, the property must
1352 // not be deletable.
1353 PropertyAttributes attributes = DONT_DELETE;
1354
1355 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001356 // there, there is a property with this name in the prototype chain.
1357 // We follow Safari and Firefox behavior and only set the property
1358 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001359 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001360 // Note that objects can have hidden prototypes, so we need to traverse
1361 // the whole chain of hidden prototypes to do a 'local' lookup.
1362 JSObject* real_holder = global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001363 LookupResult lookup;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001364 while (true) {
1365 real_holder->LocalLookup(*name, &lookup);
1366 if (lookup.IsProperty()) {
1367 // Determine if this is a redeclaration of something read-only.
1368 if (lookup.IsReadOnly()) {
1369 // If we found readonly property on one of hidden prototypes,
1370 // just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001371 if (real_holder != isolate->context()->global()) break;
1372 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001373 }
1374
1375 // Determine if this is a redeclaration of an intercepted read-only
1376 // property and figure out if the property exists at all.
1377 bool found = true;
1378 PropertyType type = lookup.type();
1379 if (type == INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001380 HandleScope handle_scope(isolate);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001381 Handle<JSObject> holder(real_holder);
1382 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1383 real_holder = *holder;
1384 if (intercepted == ABSENT) {
1385 // The interceptor claims the property isn't there. We need to
1386 // make sure to introduce it.
1387 found = false;
1388 } else if ((intercepted & READ_ONLY) != 0) {
1389 // The property is present, but read-only. Since we're trying to
1390 // overwrite it with a variable declaration we must throw a
1391 // re-declaration error. However if we found readonly property
1392 // on one of hidden prototypes, just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001393 if (real_holder != isolate->context()->global()) break;
1394 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001395 }
1396 }
1397
1398 if (found && !assign) {
1399 // The global property is there and we're not assigning any value
1400 // to it. Just return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001401 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001402 }
1403
1404 // Assign the value (or undefined) to the property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001405 Object* value = (assign) ? args[2] : isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001406 return real_holder->SetProperty(
1407 &lookup, *name, value, attributes, strict_mode);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001408 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001409
1410 Object* proto = real_holder->GetPrototype();
1411 if (!proto->IsJSObject())
1412 break;
1413
1414 if (!JSObject::cast(proto)->map()->is_hidden_prototype())
1415 break;
1416
1417 real_holder = JSObject::cast(proto);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001418 }
1419
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001420 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001421 if (assign) {
1422 return global->SetProperty(*name, args[2], attributes, strict_mode);
1423 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001424 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001425}
1426
1427
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001428RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001429 // All constants are declared with an initial value. The name
1430 // of the constant is the first argument and the initial value
1431 // is the second.
1432 RUNTIME_ASSERT(args.length() == 2);
1433 CONVERT_ARG_CHECKED(String, name, 0);
1434 Handle<Object> value = args.at<Object>(1);
1435
1436 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001437 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001438
1439 // According to ECMA-262, section 12.2, page 62, the property must
1440 // not be deletable. Since it's a const, it must be READ_ONLY too.
1441 PropertyAttributes attributes =
1442 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1443
1444 // Lookup the property locally in the global object. If it isn't
1445 // there, we add the property and take special precautions to always
1446 // add it as a local property even in case of callbacks in the
1447 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001448 // We use SetLocalPropertyIgnoreAttributes instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001449 LookupResult lookup;
1450 global->LocalLookup(*name, &lookup);
1451 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001452 return global->SetLocalPropertyIgnoreAttributes(*name,
1453 *value,
1454 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001455 }
1456
1457 // Determine if this is a redeclaration of something not
1458 // read-only. In case the result is hidden behind an interceptor we
1459 // need to ask it for the property attributes.
1460 if (!lookup.IsReadOnly()) {
1461 if (lookup.type() != INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001462 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001463 }
1464
1465 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
1466
1467 // Throw re-declaration error if the intercepted property is present
1468 // but not read-only.
1469 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001470 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001471 }
1472
1473 // Restore global object from context (in case of GC) and continue
1474 // with setting the value because the property is either absent or
1475 // read-only. We also have to do redo the lookup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001476 HandleScope handle_scope(isolate);
1477 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001478
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001479 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001480 // property through an interceptor and only do it if it's
1481 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001482 // Passing non-strict mode because the property is writable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001483 RETURN_IF_EMPTY_HANDLE(isolate,
1484 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001485 name,
1486 value,
1487 attributes,
1488 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001489 return *value;
1490 }
1491
1492 // Set the value, but only we're assigning the initial value to a
1493 // constant. For now, we determine this by checking if the
1494 // current value is the hole.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001495 // Strict mode handling not needed (const disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001496 PropertyType type = lookup.type();
1497 if (type == FIELD) {
1498 FixedArray* properties = global->properties();
1499 int index = lookup.GetFieldIndex();
1500 if (properties->get(index)->IsTheHole()) {
1501 properties->set(index, *value);
1502 }
1503 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001504 if (global->GetNormalizedProperty(&lookup)->IsTheHole()) {
1505 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001506 }
1507 } else {
1508 // Ignore re-initialization of constants that have already been
1509 // assigned a function value.
1510 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1511 }
1512
1513 // Use the set value as the result of the operation.
1514 return *value;
1515}
1516
1517
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001518RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001519 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001520 ASSERT(args.length() == 3);
1521
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001522 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001523 ASSERT(!value->IsTheHole());
1524 CONVERT_ARG_CHECKED(Context, context, 1);
1525 Handle<String> name(String::cast(args[2]));
1526
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001527 // Initializations are always done in a function or global context.
1528 context = Handle<Context>(context->declaration_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001529
1530 int index;
1531 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001532 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001533 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001534 context->Lookup(name, flags, &index, &attributes);
1535
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001536 // In most situations, the property introduced by the const
1537 // declaration should be present in the context extension object.
1538 // However, because declaration and initialization are separate, the
1539 // property might have been deleted (if it was introduced by eval)
1540 // before we reach the initialization point.
1541 //
1542 // Example:
1543 //
1544 // function f() { eval("delete x; const x;"); }
1545 //
1546 // In that case, the initialization behaves like a normal assignment
1547 // to property 'x'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001548 if (index >= 0) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001549 if (holder->IsContext()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001550 // Property was found in a context. Perform the assignment if we
1551 // found some non-constant or an uninitialized constant.
1552 Handle<Context> context = Handle<Context>::cast(holder);
1553 if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
1554 context->set(index, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001555 }
1556 } else {
1557 // The holder is an arguments object.
1558 ASSERT((attributes & READ_ONLY) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001559 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001560 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001561 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001562 SetElement(arguments, index, value, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001563 }
1564 return *value;
1565 }
1566
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001567 // The property could not be found, we introduce it in the global
1568 // context.
1569 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001570 Handle<JSObject> global = Handle<JSObject>(
1571 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001572 // Strict mode not needed (const disallowed in strict mode).
1573 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001574 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001575 SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001576 return *value;
1577 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001578
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001579 // The property was present in a context extension object.
1580 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001581
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001582 if (*context_ext == context->extension()) {
1583 // This is the property that was introduced by the const
1584 // declaration. Set it if it hasn't been set before. NOTE: We
1585 // cannot use GetProperty() to get the current value as it
1586 // 'unholes' the value.
1587 LookupResult lookup;
1588 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
1589 ASSERT(lookup.IsProperty()); // the property was declared
1590 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1591
1592 PropertyType type = lookup.type();
1593 if (type == FIELD) {
1594 FixedArray* properties = context_ext->properties();
1595 int index = lookup.GetFieldIndex();
1596 if (properties->get(index)->IsTheHole()) {
1597 properties->set(index, *value);
1598 }
1599 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001600 if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) {
1601 context_ext->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001602 }
1603 } else {
1604 // We should not reach here. Any real, named property should be
1605 // either a field or a dictionary slot.
1606 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001607 }
1608 } else {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001609 // The property was found in a different context extension object.
1610 // Set it if it is not a read-only property.
1611 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001612 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001613 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001614 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001615 SetProperty(context_ext, name, value, attributes, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001616 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001617 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001618
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001619 return *value;
1620}
1621
1622
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001623RUNTIME_FUNCTION(MaybeObject*,
1624 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001625 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001626 ASSERT(args.length() == 2);
1627 CONVERT_ARG_CHECKED(JSObject, object, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001628 CONVERT_SMI_ARG_CHECKED(properties, 1);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001629 if (object->HasFastProperties()) {
1630 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1631 }
1632 return *object;
1633}
1634
1635
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001636RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001637 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001638 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001639 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1640 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001641 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001642 // length of a string, i.e. it is always a Smi. We check anyway for security.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001643 CONVERT_SMI_ARG_CHECKED(index, 2);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001644 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001645 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001646 RUNTIME_ASSERT(index >= 0);
1647 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001648 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001649 Handle<Object> result = RegExpImpl::Exec(regexp,
1650 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001651 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001652 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001653 if (result.is_null()) return Failure::Exception();
1654 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001655}
1656
1657
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001658RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001659 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001660 CONVERT_SMI_ARG_CHECKED(elements_count, 0);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001661 if (elements_count > JSArray::kMaxFastElementsLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001662 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001663 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001664 Object* new_object;
1665 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001666 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001667 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1668 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001669 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001670 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1671 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001672 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1673 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001674 {
1675 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001676 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001677 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001678 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001679 }
1680 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001681 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001682 array->set_elements(elements);
1683 array->set_length(Smi::FromInt(elements_count));
1684 // Write in-object properties after the length of the array.
1685 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1686 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1687 return array;
1688}
1689
1690
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001691RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001692 AssertNoAllocation no_alloc;
1693 ASSERT(args.length() == 5);
1694 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1695 CONVERT_CHECKED(String, source, args[1]);
1696
1697 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001698 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001699
1700 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001701 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001702
1703 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001704 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001705
1706 Map* map = regexp->map();
1707 Object* constructor = map->constructor();
1708 if (constructor->IsJSFunction() &&
1709 JSFunction::cast(constructor)->initial_map() == map) {
1710 // If we still have the original map, set in-object properties directly.
1711 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1712 // TODO(lrn): Consider skipping write barrier on booleans as well.
1713 // Both true and false should be in oldspace at all times.
1714 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1715 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1716 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1717 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1718 Smi::FromInt(0),
1719 SKIP_WRITE_BARRIER);
1720 return regexp;
1721 }
1722
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001723 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001724 PropertyAttributes final =
1725 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1726 PropertyAttributes writable =
1727 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001728 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001729 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001730 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001731 source,
1732 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001733 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001734 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001735 global,
1736 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001737 ASSERT(!result->IsFailure());
1738 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001739 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001740 ignoreCase,
1741 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001742 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001743 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001744 multiline,
1745 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001746 ASSERT(!result->IsFailure());
1747 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001748 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001749 Smi::FromInt(0),
1750 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001751 ASSERT(!result->IsFailure());
1752 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001753 return regexp;
1754}
1755
1756
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001757RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001758 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001759 ASSERT(args.length() == 1);
1760 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1761 // This is necessary to enable fast checks for absence of elements
1762 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001763 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001764 return Smi::FromInt(0);
1765}
1766
1767
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001768static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1769 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001770 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001771 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001772 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1773 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1774 Handle<JSFunction> optimized =
1775 isolate->factory()->NewFunction(key,
1776 JS_OBJECT_TYPE,
1777 JSObject::kHeaderSize,
1778 code,
1779 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001780 optimized->shared()->DontAdaptArguments();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001781 SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001782 return optimized;
1783}
1784
1785
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001786RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001787 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001788 ASSERT(args.length() == 1);
1789 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1790
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001791 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1792 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1793 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1794 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1795 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1796 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1797 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001798
1799 return *holder;
1800}
1801
1802
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001803RUNTIME_FUNCTION(MaybeObject*, Runtime_GetGlobalReceiver) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001804 // Returns a real global receiver, not one of builtins object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001805 Context* global_context =
1806 isolate->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001807 return global_context->global()->global_receiver();
1808}
1809
1810
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001811RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001812 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001813 ASSERT(args.length() == 4);
1814 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001815 int index = args.smi_at(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001816 Handle<String> pattern = args.at<String>(2);
1817 Handle<String> flags = args.at<String>(3);
1818
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001819 // Get the RegExp function from the context in the literals array.
1820 // This is the RegExp function from the context in which the
1821 // function was created. We do not use the RegExp function from the
1822 // current global context because this might be the RegExp function
1823 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001824 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001825 Handle<JSFunction>(
1826 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001827 // Compute the regular expression literal.
1828 bool has_pending_exception;
1829 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001830 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1831 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001832 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001833 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001834 return Failure::Exception();
1835 }
1836 literals->set(index, *regexp);
1837 return *regexp;
1838}
1839
1840
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001841RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001842 NoHandleAllocation ha;
1843 ASSERT(args.length() == 1);
1844
1845 CONVERT_CHECKED(JSFunction, f, args[0]);
1846 return f->shared()->name();
1847}
1848
1849
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001850RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001851 NoHandleAllocation ha;
1852 ASSERT(args.length() == 2);
1853
1854 CONVERT_CHECKED(JSFunction, f, args[0]);
1855 CONVERT_CHECKED(String, name, args[1]);
1856 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001857 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001858}
1859
1860
whesse@chromium.org7b260152011-06-20 15:33:18 +00001861RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetBound) {
1862 HandleScope scope(isolate);
1863 ASSERT(args.length() == 1);
1864
1865 CONVERT_CHECKED(JSFunction, fun, args[0]);
1866 fun->shared()->set_bound(true);
1867 return isolate->heap()->undefined_value();
1868}
1869
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001870RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001871 NoHandleAllocation ha;
1872 ASSERT(args.length() == 1);
1873
1874 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001875 Object* obj = f->RemovePrototype();
1876 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001877
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001878 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001879}
1880
1881
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001882RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001883 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001884 ASSERT(args.length() == 1);
1885
1886 CONVERT_CHECKED(JSFunction, fun, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001887 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
1888 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001889
1890 return *GetScriptWrapper(Handle<Script>::cast(script));
1891}
1892
1893
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001894RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001895 NoHandleAllocation ha;
1896 ASSERT(args.length() == 1);
1897
1898 CONVERT_CHECKED(JSFunction, f, args[0]);
1899 return f->shared()->GetSourceCode();
1900}
1901
1902
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001903RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001904 NoHandleAllocation ha;
1905 ASSERT(args.length() == 1);
1906
1907 CONVERT_CHECKED(JSFunction, fun, args[0]);
1908 int pos = fun->shared()->start_position();
1909 return Smi::FromInt(pos);
1910}
1911
1912
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001913RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001914 ASSERT(args.length() == 2);
1915
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001916 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001917 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
1918
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001919 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
1920
1921 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001922 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001923}
1924
1925
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001926RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001927 NoHandleAllocation ha;
1928 ASSERT(args.length() == 2);
1929
1930 CONVERT_CHECKED(JSFunction, fun, args[0]);
1931 CONVERT_CHECKED(String, name, args[1]);
1932 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001933 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001934}
1935
1936
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001937RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001938 NoHandleAllocation ha;
1939 ASSERT(args.length() == 2);
1940
1941 CONVERT_CHECKED(JSFunction, fun, args[0]);
1942 CONVERT_CHECKED(Smi, length, args[1]);
1943 fun->shared()->set_length(length->value());
1944 return length;
1945}
1946
1947
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001948RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001949 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001950 ASSERT(args.length() == 2);
1951
1952 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001953 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00001954 Object* obj;
1955 { MaybeObject* maybe_obj =
1956 Accessors::FunctionSetPrototype(fun, args[1], NULL);
1957 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1958 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001959 return args[0]; // return TOS
1960}
1961
1962
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001963RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001964 NoHandleAllocation ha;
1965 ASSERT(args.length() == 1);
1966
1967 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001968 return f->shared()->IsApiFunction() ? isolate->heap()->true_value()
1969 : isolate->heap()->false_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001970}
1971
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001972
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001973RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001974 NoHandleAllocation ha;
1975 ASSERT(args.length() == 1);
1976
1977 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001978 return f->IsBuiltin() ? isolate->heap()->true_value() :
1979 isolate->heap()->false_value();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001980}
1981
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001982
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001983RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001984 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001985 ASSERT(args.length() == 2);
1986
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001987 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001988 Handle<Object> code = args.at<Object>(1);
1989
1990 Handle<Context> context(target->context());
1991
1992 if (!code->IsNull()) {
1993 RUNTIME_ASSERT(code->IsJSFunction());
1994 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001995 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001996
1997 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001998 return Failure::Exception();
1999 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002000 // Since we don't store the source for this we should never
2001 // optimize this.
2002 shared->code()->set_optimizable(false);
2003
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002004 // Set the code, scope info, formal parameter count,
2005 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00002006 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002007 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002008 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002009 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002010 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002011 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002012 // Set the source code of the target function to undefined.
2013 // SetCode is only used for built-in constructors like String,
2014 // Array, and Object, and some web code
2015 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002016 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002017 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002018 // Clear the optimization hints related to the compiled code as these are no
2019 // longer valid when the code is overwritten.
2020 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002021 context = Handle<Context>(fun->context());
2022
2023 // Make sure we get a fresh copy of the literal vector to avoid
2024 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002025 int number_of_literals = fun->NumberOfLiterals();
2026 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002027 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002028 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002029 // Insert the object, regexp and array functions in the literals
2030 // array prefix. These are the functions that will be used when
2031 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002032 literals->set(JSFunction::kLiteralGlobalContextIndex,
2033 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002034 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002035 // It's okay to skip the write barrier here because the literals
2036 // are guaranteed to be in old space.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002037 target->set_literals(*literals, SKIP_WRITE_BARRIER);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002038 target->set_next_function_link(isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002039 }
2040
2041 target->set_context(*context);
2042 return *target;
2043}
2044
2045
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002046RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002047 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002048 ASSERT(args.length() == 2);
2049 CONVERT_ARG_CHECKED(JSFunction, function, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002050 CONVERT_SMI_ARG_CHECKED(num, 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002051 RUNTIME_ASSERT(num >= 0);
2052 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002053 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002054}
2055
2056
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002057MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2058 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002059 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002060 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002061 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002062 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002063 }
2064 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002065 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002066}
2067
2068
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002069RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002070 NoHandleAllocation ha;
2071 ASSERT(args.length() == 2);
2072
2073 CONVERT_CHECKED(String, subject, args[0]);
2074 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002075 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002076
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002077 uint32_t i = 0;
2078 if (index->IsSmi()) {
2079 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002080 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002081 i = value;
2082 } else {
2083 ASSERT(index->IsHeapNumber());
2084 double value = HeapNumber::cast(index)->value();
2085 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002086 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002087
2088 // Flatten the string. If someone wants to get a char at an index
2089 // in a cons string, it is likely that more indices will be
2090 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002091 Object* flat;
2092 { MaybeObject* maybe_flat = subject->TryFlatten();
2093 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2094 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002095 subject = String::cast(flat);
2096
2097 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002098 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002099 }
2100
2101 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002102}
2103
2104
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002105RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002106 NoHandleAllocation ha;
2107 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002108 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002109}
2110
lrn@chromium.org25156de2010-04-06 13:10:27 +00002111
2112class FixedArrayBuilder {
2113 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002114 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2115 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002116 length_(0) {
2117 // Require a non-zero initial size. Ensures that doubling the size to
2118 // extend the array will work.
2119 ASSERT(initial_capacity > 0);
2120 }
2121
2122 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2123 : array_(backing_store),
2124 length_(0) {
2125 // Require a non-zero initial size. Ensures that doubling the size to
2126 // extend the array will work.
2127 ASSERT(backing_store->length() > 0);
2128 }
2129
2130 bool HasCapacity(int elements) {
2131 int length = array_->length();
2132 int required_length = length_ + elements;
2133 return (length >= required_length);
2134 }
2135
2136 void EnsureCapacity(int elements) {
2137 int length = array_->length();
2138 int required_length = length_ + elements;
2139 if (length < required_length) {
2140 int new_length = length;
2141 do {
2142 new_length *= 2;
2143 } while (new_length < required_length);
2144 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002145 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002146 array_->CopyTo(0, *extended_array, 0, length_);
2147 array_ = extended_array;
2148 }
2149 }
2150
2151 void Add(Object* value) {
2152 ASSERT(length_ < capacity());
2153 array_->set(length_, value);
2154 length_++;
2155 }
2156
2157 void Add(Smi* value) {
2158 ASSERT(length_ < capacity());
2159 array_->set(length_, value);
2160 length_++;
2161 }
2162
2163 Handle<FixedArray> array() {
2164 return array_;
2165 }
2166
2167 int length() {
2168 return length_;
2169 }
2170
2171 int capacity() {
2172 return array_->length();
2173 }
2174
2175 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002176 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002177 result_array->set_length(Smi::FromInt(length_));
2178 return result_array;
2179 }
2180
2181 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
2182 target_array->set_elements(*array_);
2183 target_array->set_length(Smi::FromInt(length_));
2184 return target_array;
2185 }
2186
2187 private:
2188 Handle<FixedArray> array_;
2189 int length_;
2190};
2191
2192
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002193// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002194const int kStringBuilderConcatHelperLengthBits = 11;
2195const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002196
2197template <typename schar>
2198static inline void StringBuilderConcatHelper(String*,
2199 schar*,
2200 FixedArray*,
2201 int);
2202
lrn@chromium.org25156de2010-04-06 13:10:27 +00002203typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2204 StringBuilderSubstringLength;
2205typedef BitField<int,
2206 kStringBuilderConcatHelperLengthBits,
2207 kStringBuilderConcatHelperPositionBits>
2208 StringBuilderSubstringPosition;
2209
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002210
2211class ReplacementStringBuilder {
2212 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002213 ReplacementStringBuilder(Heap* heap,
2214 Handle<String> subject,
2215 int estimated_part_count)
2216 : heap_(heap),
2217 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002218 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002219 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002220 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002221 // Require a non-zero initial size. Ensures that doubling the size to
2222 // extend the array will work.
2223 ASSERT(estimated_part_count > 0);
2224 }
2225
lrn@chromium.org25156de2010-04-06 13:10:27 +00002226 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2227 int from,
2228 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002229 ASSERT(from >= 0);
2230 int length = to - from;
2231 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002232 if (StringBuilderSubstringLength::is_valid(length) &&
2233 StringBuilderSubstringPosition::is_valid(from)) {
2234 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2235 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002236 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002237 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002238 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002239 builder->Add(Smi::FromInt(-length));
2240 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002241 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002242 }
2243
2244
2245 void EnsureCapacity(int elements) {
2246 array_builder_.EnsureCapacity(elements);
2247 }
2248
2249
2250 void AddSubjectSlice(int from, int to) {
2251 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002252 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002253 }
2254
2255
2256 void AddString(Handle<String> string) {
2257 int length = string->length();
2258 ASSERT(length > 0);
2259 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002260 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002261 is_ascii_ = false;
2262 }
2263 IncrementCharacterCount(length);
2264 }
2265
2266
2267 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002268 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002269 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002270 }
2271
2272 Handle<String> joined_string;
2273 if (is_ascii_) {
ager@chromium.org04921a82011-06-27 13:21:41 +00002274 Handle<SeqAsciiString> seq = NewRawAsciiString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002275 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002276 char* char_buffer = seq->GetChars();
2277 StringBuilderConcatHelper(*subject_,
2278 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002279 *array_builder_.array(),
2280 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002281 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002282 } else {
2283 // Non-ASCII.
ager@chromium.org04921a82011-06-27 13:21:41 +00002284 Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002285 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002286 uc16* char_buffer = seq->GetChars();
2287 StringBuilderConcatHelper(*subject_,
2288 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002289 *array_builder_.array(),
2290 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002291 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002292 }
2293 return joined_string;
2294 }
2295
2296
2297 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002298 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002299 V8::FatalProcessOutOfMemory("String.replace result too large.");
2300 }
2301 character_count_ += by;
2302 }
2303
lrn@chromium.org25156de2010-04-06 13:10:27 +00002304 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002305 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002306 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002307
lrn@chromium.org25156de2010-04-06 13:10:27 +00002308 private:
ager@chromium.org04921a82011-06-27 13:21:41 +00002309 Handle<SeqAsciiString> NewRawAsciiString(int length) {
2310 return heap_->isolate()->factory()->NewRawAsciiString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002311 }
2312
2313
ager@chromium.org04921a82011-06-27 13:21:41 +00002314 Handle<SeqTwoByteString> NewRawTwoByteString(int length) {
2315 return heap_->isolate()->factory()->NewRawTwoByteString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002316 }
2317
2318
2319 void AddElement(Object* element) {
2320 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002321 ASSERT(array_builder_.capacity() > array_builder_.length());
2322 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002323 }
2324
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002325 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002326 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002327 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002328 int character_count_;
2329 bool is_ascii_;
2330};
2331
2332
2333class CompiledReplacement {
2334 public:
2335 CompiledReplacement()
2336 : parts_(1), replacement_substrings_(0) {}
2337
2338 void Compile(Handle<String> replacement,
2339 int capture_count,
2340 int subject_length);
2341
2342 void Apply(ReplacementStringBuilder* builder,
2343 int match_from,
2344 int match_to,
2345 Handle<JSArray> last_match_info);
2346
2347 // Number of distinct parts of the replacement pattern.
2348 int parts() {
2349 return parts_.length();
2350 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002351
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002352 private:
2353 enum PartType {
2354 SUBJECT_PREFIX = 1,
2355 SUBJECT_SUFFIX,
2356 SUBJECT_CAPTURE,
2357 REPLACEMENT_SUBSTRING,
2358 REPLACEMENT_STRING,
2359
2360 NUMBER_OF_PART_TYPES
2361 };
2362
2363 struct ReplacementPart {
2364 static inline ReplacementPart SubjectMatch() {
2365 return ReplacementPart(SUBJECT_CAPTURE, 0);
2366 }
2367 static inline ReplacementPart SubjectCapture(int capture_index) {
2368 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2369 }
2370 static inline ReplacementPart SubjectPrefix() {
2371 return ReplacementPart(SUBJECT_PREFIX, 0);
2372 }
2373 static inline ReplacementPart SubjectSuffix(int subject_length) {
2374 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2375 }
2376 static inline ReplacementPart ReplacementString() {
2377 return ReplacementPart(REPLACEMENT_STRING, 0);
2378 }
2379 static inline ReplacementPart ReplacementSubString(int from, int to) {
2380 ASSERT(from >= 0);
2381 ASSERT(to > from);
2382 return ReplacementPart(-from, to);
2383 }
2384
2385 // If tag <= 0 then it is the negation of a start index of a substring of
2386 // the replacement pattern, otherwise it's a value from PartType.
2387 ReplacementPart(int tag, int data)
2388 : tag(tag), data(data) {
2389 // Must be non-positive or a PartType value.
2390 ASSERT(tag < NUMBER_OF_PART_TYPES);
2391 }
2392 // Either a value of PartType or a non-positive number that is
2393 // the negation of an index into the replacement string.
2394 int tag;
2395 // The data value's interpretation depends on the value of tag:
2396 // tag == SUBJECT_PREFIX ||
2397 // tag == SUBJECT_SUFFIX: data is unused.
2398 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2399 // tag == REPLACEMENT_SUBSTRING ||
2400 // tag == REPLACEMENT_STRING: data is index into array of substrings
2401 // of the replacement string.
2402 // tag <= 0: Temporary representation of the substring of the replacement
2403 // string ranging over -tag .. data.
2404 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2405 // substring objects.
2406 int data;
2407 };
2408
2409 template<typename Char>
2410 static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
2411 Vector<Char> characters,
2412 int capture_count,
2413 int subject_length) {
2414 int length = characters.length();
2415 int last = 0;
2416 for (int i = 0; i < length; i++) {
2417 Char c = characters[i];
2418 if (c == '$') {
2419 int next_index = i + 1;
2420 if (next_index == length) { // No next character!
2421 break;
2422 }
2423 Char c2 = characters[next_index];
2424 switch (c2) {
2425 case '$':
2426 if (i > last) {
2427 // There is a substring before. Include the first "$".
2428 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2429 last = next_index + 1; // Continue after the second "$".
2430 } else {
2431 // Let the next substring start with the second "$".
2432 last = next_index;
2433 }
2434 i = next_index;
2435 break;
2436 case '`':
2437 if (i > last) {
2438 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2439 }
2440 parts->Add(ReplacementPart::SubjectPrefix());
2441 i = next_index;
2442 last = i + 1;
2443 break;
2444 case '\'':
2445 if (i > last) {
2446 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2447 }
2448 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2449 i = next_index;
2450 last = i + 1;
2451 break;
2452 case '&':
2453 if (i > last) {
2454 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2455 }
2456 parts->Add(ReplacementPart::SubjectMatch());
2457 i = next_index;
2458 last = i + 1;
2459 break;
2460 case '0':
2461 case '1':
2462 case '2':
2463 case '3':
2464 case '4':
2465 case '5':
2466 case '6':
2467 case '7':
2468 case '8':
2469 case '9': {
2470 int capture_ref = c2 - '0';
2471 if (capture_ref > capture_count) {
2472 i = next_index;
2473 continue;
2474 }
2475 int second_digit_index = next_index + 1;
2476 if (second_digit_index < length) {
2477 // Peek ahead to see if we have two digits.
2478 Char c3 = characters[second_digit_index];
2479 if ('0' <= c3 && c3 <= '9') { // Double digits.
2480 int double_digit_ref = capture_ref * 10 + c3 - '0';
2481 if (double_digit_ref <= capture_count) {
2482 next_index = second_digit_index;
2483 capture_ref = double_digit_ref;
2484 }
2485 }
2486 }
2487 if (capture_ref > 0) {
2488 if (i > last) {
2489 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2490 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002491 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002492 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2493 last = next_index + 1;
2494 }
2495 i = next_index;
2496 break;
2497 }
2498 default:
2499 i = next_index;
2500 break;
2501 }
2502 }
2503 }
2504 if (length > last) {
2505 if (last == 0) {
2506 parts->Add(ReplacementPart::ReplacementString());
2507 } else {
2508 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2509 }
2510 }
2511 }
2512
2513 ZoneList<ReplacementPart> parts_;
2514 ZoneList<Handle<String> > replacement_substrings_;
2515};
2516
2517
2518void CompiledReplacement::Compile(Handle<String> replacement,
2519 int capture_count,
2520 int subject_length) {
2521 ASSERT(replacement->IsFlat());
ager@chromium.org5ec48922009-05-05 07:25:34 +00002522 if (replacement->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002523 AssertNoAllocation no_alloc;
2524 ParseReplacementPattern(&parts_,
2525 replacement->ToAsciiVector(),
2526 capture_count,
2527 subject_length);
2528 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00002529 ASSERT(replacement->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002530 AssertNoAllocation no_alloc;
2531
2532 ParseReplacementPattern(&parts_,
2533 replacement->ToUC16Vector(),
2534 capture_count,
2535 subject_length);
2536 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002537 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002538 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002539 int substring_index = 0;
2540 for (int i = 0, n = parts_.length(); i < n; i++) {
2541 int tag = parts_[i].tag;
2542 if (tag <= 0) { // A replacement string slice.
2543 int from = -tag;
2544 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002545 replacement_substrings_.Add(
2546 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002547 parts_[i].tag = REPLACEMENT_SUBSTRING;
2548 parts_[i].data = substring_index;
2549 substring_index++;
2550 } else if (tag == REPLACEMENT_STRING) {
2551 replacement_substrings_.Add(replacement);
2552 parts_[i].data = substring_index;
2553 substring_index++;
2554 }
2555 }
2556}
2557
2558
2559void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2560 int match_from,
2561 int match_to,
2562 Handle<JSArray> last_match_info) {
2563 for (int i = 0, n = parts_.length(); i < n; i++) {
2564 ReplacementPart part = parts_[i];
2565 switch (part.tag) {
2566 case SUBJECT_PREFIX:
2567 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2568 break;
2569 case SUBJECT_SUFFIX: {
2570 int subject_length = part.data;
2571 if (match_to < subject_length) {
2572 builder->AddSubjectSlice(match_to, subject_length);
2573 }
2574 break;
2575 }
2576 case SUBJECT_CAPTURE: {
2577 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002578 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002579 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2580 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2581 if (from >= 0 && to > from) {
2582 builder->AddSubjectSlice(from, to);
2583 }
2584 break;
2585 }
2586 case REPLACEMENT_SUBSTRING:
2587 case REPLACEMENT_STRING:
2588 builder->AddString(replacement_substrings_[part.data]);
2589 break;
2590 default:
2591 UNREACHABLE();
2592 }
2593 }
2594}
2595
2596
2597
lrn@chromium.org303ada72010-10-27 09:33:13 +00002598MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002599 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002600 String* subject,
2601 JSRegExp* regexp,
2602 String* replacement,
2603 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002604 ASSERT(subject->IsFlat());
2605 ASSERT(replacement->IsFlat());
2606
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002607 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002608
2609 int length = subject->length();
2610 Handle<String> subject_handle(subject);
2611 Handle<JSRegExp> regexp_handle(regexp);
2612 Handle<String> replacement_handle(replacement);
2613 Handle<JSArray> last_match_info_handle(last_match_info);
2614 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2615 subject_handle,
2616 0,
2617 last_match_info_handle);
2618 if (match.is_null()) {
2619 return Failure::Exception();
2620 }
2621 if (match->IsNull()) {
2622 return *subject_handle;
2623 }
2624
2625 int capture_count = regexp_handle->CaptureCount();
2626
2627 // CompiledReplacement uses zone allocation.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002628 ZoneScope zone(isolate, DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002629 CompiledReplacement compiled_replacement;
2630 compiled_replacement.Compile(replacement_handle,
2631 capture_count,
2632 length);
2633
2634 bool is_global = regexp_handle->GetFlags().is_global();
2635
2636 // Guessing the number of parts that the final result string is built
2637 // from. Global regexps can match any number of times, so we guess
2638 // conservatively.
2639 int expected_parts =
2640 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002641 ReplacementStringBuilder builder(isolate->heap(),
2642 subject_handle,
2643 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002644
2645 // Index of end of last match.
2646 int prev = 0;
2647
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002648 // Number of parts added by compiled replacement plus preceeding
2649 // string and possibly suffix after last match. It is possible for
2650 // all components to use two elements when encoded as two smis.
2651 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002652 bool matched = true;
2653 do {
2654 ASSERT(last_match_info_handle->HasFastElements());
2655 // Increase the capacity of the builder before entering local handle-scope,
2656 // so its internal buffer can safely allocate a new handle if it grows.
2657 builder.EnsureCapacity(parts_added_per_loop);
2658
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002659 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002660 int start, end;
2661 {
2662 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002663 FixedArray* match_info_array =
2664 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002665
2666 ASSERT_EQ(capture_count * 2 + 2,
2667 RegExpImpl::GetLastCaptureCount(match_info_array));
2668 start = RegExpImpl::GetCapture(match_info_array, 0);
2669 end = RegExpImpl::GetCapture(match_info_array, 1);
2670 }
2671
2672 if (prev < start) {
2673 builder.AddSubjectSlice(prev, start);
2674 }
2675 compiled_replacement.Apply(&builder,
2676 start,
2677 end,
2678 last_match_info_handle);
2679 prev = end;
2680
2681 // Only continue checking for global regexps.
2682 if (!is_global) break;
2683
2684 // Continue from where the match ended, unless it was an empty match.
2685 int next = end;
2686 if (start == end) {
2687 next = end + 1;
2688 if (next > length) break;
2689 }
2690
2691 match = RegExpImpl::Exec(regexp_handle,
2692 subject_handle,
2693 next,
2694 last_match_info_handle);
2695 if (match.is_null()) {
2696 return Failure::Exception();
2697 }
2698 matched = !match->IsNull();
2699 } while (matched);
2700
2701 if (prev < length) {
2702 builder.AddSubjectSlice(prev, length);
2703 }
2704
2705 return *(builder.ToString());
2706}
2707
2708
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002709template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00002710MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002711 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002712 String* subject,
2713 JSRegExp* regexp,
2714 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002715 ASSERT(subject->IsFlat());
2716
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002717 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002718
2719 Handle<String> subject_handle(subject);
2720 Handle<JSRegExp> regexp_handle(regexp);
2721 Handle<JSArray> last_match_info_handle(last_match_info);
2722 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2723 subject_handle,
2724 0,
2725 last_match_info_handle);
2726 if (match.is_null()) return Failure::Exception();
2727 if (match->IsNull()) return *subject_handle;
2728
2729 ASSERT(last_match_info_handle->HasFastElements());
2730
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002731 int start, end;
2732 {
2733 AssertNoAllocation match_info_array_is_not_in_a_handle;
2734 FixedArray* match_info_array =
2735 FixedArray::cast(last_match_info_handle->elements());
2736
2737 start = RegExpImpl::GetCapture(match_info_array, 0);
2738 end = RegExpImpl::GetCapture(match_info_array, 1);
2739 }
2740
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00002741 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002742 int new_length = length - (end - start);
2743 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002744 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002745 }
2746 Handle<ResultSeqString> answer;
2747 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002748 answer = Handle<ResultSeqString>::cast(
2749 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002750 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002751 answer = Handle<ResultSeqString>::cast(
2752 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002753 }
2754
2755 // If the regexp isn't global, only match once.
2756 if (!regexp_handle->GetFlags().is_global()) {
2757 if (start > 0) {
2758 String::WriteToFlat(*subject_handle,
2759 answer->GetChars(),
2760 0,
2761 start);
2762 }
2763 if (end < length) {
2764 String::WriteToFlat(*subject_handle,
2765 answer->GetChars() + start,
2766 end,
2767 length);
2768 }
2769 return *answer;
2770 }
2771
2772 int prev = 0; // Index of end of last match.
2773 int next = 0; // Start of next search (prev unless last match was empty).
2774 int position = 0;
2775
2776 do {
2777 if (prev < start) {
2778 // Add substring subject[prev;start] to answer string.
2779 String::WriteToFlat(*subject_handle,
2780 answer->GetChars() + position,
2781 prev,
2782 start);
2783 position += start - prev;
2784 }
2785 prev = end;
2786 next = end;
2787 // Continue from where the match ended, unless it was an empty match.
2788 if (start == end) {
2789 next++;
2790 if (next > length) break;
2791 }
2792 match = RegExpImpl::Exec(regexp_handle,
2793 subject_handle,
2794 next,
2795 last_match_info_handle);
2796 if (match.is_null()) return Failure::Exception();
2797 if (match->IsNull()) break;
2798
2799 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002800 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002801 {
2802 AssertNoAllocation match_info_array_is_not_in_a_handle;
2803 FixedArray* match_info_array =
2804 FixedArray::cast(last_match_info_handle->elements());
2805 start = RegExpImpl::GetCapture(match_info_array, 0);
2806 end = RegExpImpl::GetCapture(match_info_array, 1);
2807 }
2808 } while (true);
2809
2810 if (prev < length) {
2811 // Add substring subject[prev;length] to answer string.
2812 String::WriteToFlat(*subject_handle,
2813 answer->GetChars() + position,
2814 prev,
2815 length);
2816 position += length - prev;
2817 }
2818
2819 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002820 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002821 }
2822
2823 // Shorten string and fill
2824 int string_size = ResultSeqString::SizeFor(position);
2825 int allocated_string_size = ResultSeqString::SizeFor(new_length);
2826 int delta = allocated_string_size - string_size;
2827
2828 answer->set_length(position);
2829 if (delta == 0) return *answer;
2830
2831 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002832 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002833
2834 return *answer;
2835}
2836
2837
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002838RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002839 ASSERT(args.length() == 4);
2840
2841 CONVERT_CHECKED(String, subject, args[0]);
2842 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002843 Object* flat_subject;
2844 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
2845 if (!maybe_flat_subject->ToObject(&flat_subject)) {
2846 return maybe_flat_subject;
2847 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002848 }
2849 subject = String::cast(flat_subject);
2850 }
2851
2852 CONVERT_CHECKED(String, replacement, args[2]);
2853 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002854 Object* flat_replacement;
2855 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
2856 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
2857 return maybe_flat_replacement;
2858 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002859 }
2860 replacement = String::cast(flat_replacement);
2861 }
2862
2863 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
2864 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
2865
2866 ASSERT(last_match_info->HasFastElements());
2867
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002868 if (replacement->length() == 0) {
2869 if (subject->HasOnlyAsciiChars()) {
2870 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002871 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002872 } else {
2873 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002874 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002875 }
2876 }
2877
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002878 return StringReplaceRegExpWithString(isolate,
2879 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002880 regexp,
2881 replacement,
2882 last_match_info);
2883}
2884
2885
ager@chromium.org7c537e22008-10-16 08:43:32 +00002886// Perform string match of pattern on subject, starting at start index.
2887// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002888// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002889int Runtime::StringMatch(Isolate* isolate,
2890 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00002891 Handle<String> pat,
2892 int start_index) {
2893 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002894 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002895
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002896 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002897 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002898
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002899 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00002900 if (start_index + pattern_length > subject_length) return -1;
2901
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002902 if (!sub->IsFlat()) FlattenString(sub);
2903 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00002904
ager@chromium.org7c537e22008-10-16 08:43:32 +00002905 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002906 // Extract flattened substrings of cons strings before determining asciiness.
2907 String* seq_sub = *sub;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002908 if (seq_sub->IsConsString()) seq_sub = ConsString::cast(seq_sub)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002909 String* seq_pat = *pat;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002910 if (seq_pat->IsConsString()) seq_pat = ConsString::cast(seq_pat)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002911
ager@chromium.org7c537e22008-10-16 08:43:32 +00002912 // dispatch on type of strings
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002913 if (seq_pat->IsAsciiRepresentation()) {
2914 Vector<const char> pat_vector = seq_pat->ToAsciiVector();
2915 if (seq_sub->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002916 return SearchString(isolate,
2917 seq_sub->ToAsciiVector(),
2918 pat_vector,
2919 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002920 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002921 return SearchString(isolate,
2922 seq_sub->ToUC16Vector(),
2923 pat_vector,
2924 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002925 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002926 Vector<const uc16> pat_vector = seq_pat->ToUC16Vector();
2927 if (seq_sub->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002928 return SearchString(isolate,
2929 seq_sub->ToAsciiVector(),
2930 pat_vector,
2931 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002932 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002933 return SearchString(isolate,
2934 seq_sub->ToUC16Vector(),
2935 pat_vector,
2936 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002937}
2938
2939
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002940RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002941 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002942 ASSERT(args.length() == 3);
2943
ager@chromium.org7c537e22008-10-16 08:43:32 +00002944 CONVERT_ARG_CHECKED(String, sub, 0);
2945 CONVERT_ARG_CHECKED(String, pat, 1);
2946
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002947 Object* index = args[2];
2948 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002949 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002950
ager@chromium.org870a0b62008-11-04 11:43:05 +00002951 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002952 int position =
2953 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002954 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002955}
2956
2957
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002958template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002959static int StringMatchBackwards(Vector<const schar> subject,
2960 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002961 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002962 int pattern_length = pattern.length();
2963 ASSERT(pattern_length >= 1);
2964 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002965
2966 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002967 for (int i = 0; i < pattern_length; i++) {
2968 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002969 if (c > String::kMaxAsciiCharCode) {
2970 return -1;
2971 }
2972 }
2973 }
2974
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002975 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002976 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002977 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002978 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002979 while (j < pattern_length) {
2980 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002981 break;
2982 }
2983 j++;
2984 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002985 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002986 return i;
2987 }
2988 }
2989 return -1;
2990}
2991
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002992RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002993 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002994 ASSERT(args.length() == 3);
2995
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002996 CONVERT_ARG_CHECKED(String, sub, 0);
2997 CONVERT_ARG_CHECKED(String, pat, 1);
2998
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002999 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003000 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003001 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003002
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003003 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003004 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003005
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003006 if (start_index + pat_length > sub_length) {
3007 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00003008 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003009
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003010 if (pat_length == 0) {
3011 return Smi::FromInt(start_index);
3012 }
3013
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003014 if (!sub->IsFlat()) FlattenString(sub);
3015 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003016
3017 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3018
3019 int position = -1;
3020
3021 if (pat->IsAsciiRepresentation()) {
3022 Vector<const char> pat_vector = pat->ToAsciiVector();
3023 if (sub->IsAsciiRepresentation()) {
3024 position = StringMatchBackwards(sub->ToAsciiVector(),
3025 pat_vector,
3026 start_index);
3027 } else {
3028 position = StringMatchBackwards(sub->ToUC16Vector(),
3029 pat_vector,
3030 start_index);
3031 }
3032 } else {
3033 Vector<const uc16> pat_vector = pat->ToUC16Vector();
3034 if (sub->IsAsciiRepresentation()) {
3035 position = StringMatchBackwards(sub->ToAsciiVector(),
3036 pat_vector,
3037 start_index);
3038 } else {
3039 position = StringMatchBackwards(sub->ToUC16Vector(),
3040 pat_vector,
3041 start_index);
3042 }
3043 }
3044
3045 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003046}
3047
3048
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003049RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003050 NoHandleAllocation ha;
3051 ASSERT(args.length() == 2);
3052
3053 CONVERT_CHECKED(String, str1, args[0]);
3054 CONVERT_CHECKED(String, str2, args[1]);
3055
3056 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003057 int str1_length = str1->length();
3058 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003059
3060 // Decide trivial cases without flattening.
3061 if (str1_length == 0) {
3062 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3063 return Smi::FromInt(-str2_length);
3064 } else {
3065 if (str2_length == 0) return Smi::FromInt(str1_length);
3066 }
3067
3068 int end = str1_length < str2_length ? str1_length : str2_length;
3069
3070 // No need to flatten if we are going to find the answer on the first
3071 // character. At this point we know there is at least one character
3072 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003073 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003074 if (d != 0) return Smi::FromInt(d);
3075
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003076 str1->TryFlatten();
3077 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003078
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003079 StringInputBuffer& buf1 =
3080 *isolate->runtime_state()->string_locale_compare_buf1();
3081 StringInputBuffer& buf2 =
3082 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003083
3084 buf1.Reset(str1);
3085 buf2.Reset(str2);
3086
3087 for (int i = 0; i < end; i++) {
3088 uint16_t char1 = buf1.GetNext();
3089 uint16_t char2 = buf2.GetNext();
3090 if (char1 != char2) return Smi::FromInt(char1 - char2);
3091 }
3092
3093 return Smi::FromInt(str1_length - str2_length);
3094}
3095
3096
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003097RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003098 NoHandleAllocation ha;
3099 ASSERT(args.length() == 3);
3100
3101 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003102 int start, end;
3103 // We have a fast integer-only case here to avoid a conversion to double in
3104 // the common case where from and to are Smis.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003105 if (args[1]->IsSmi() && args[2]->IsSmi()) {
3106 CONVERT_SMI_ARG_CHECKED(from_number, 1);
3107 CONVERT_SMI_ARG_CHECKED(to_number, 2);
3108 start = from_number;
3109 end = to_number;
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003110 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003111 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
3112 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003113 start = FastD2I(from_number);
3114 end = FastD2I(to_number);
3115 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003116 RUNTIME_ASSERT(end >= start);
3117 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003118 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003119 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003120 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003121}
3122
3123
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003124RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003125 ASSERT_EQ(3, args.length());
3126
3127 CONVERT_ARG_CHECKED(String, subject, 0);
3128 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3129 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
3130 HandleScope handles;
3131
3132 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3133
3134 if (match.is_null()) {
3135 return Failure::Exception();
3136 }
3137 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003138 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003139 }
3140 int length = subject->length();
3141
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003142 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003143 ZoneList<int> offsets(8);
ager@chromium.org04921a82011-06-27 13:21:41 +00003144 int start;
3145 int end;
ager@chromium.org41826e72009-03-30 13:30:57 +00003146 do {
ager@chromium.org41826e72009-03-30 13:30:57 +00003147 {
3148 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003149 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003150 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3151 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3152 }
3153 offsets.Add(start);
3154 offsets.Add(end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003155 if (start == end) if (++end > length) break;
3156 match = RegExpImpl::Exec(regexp, subject, end, regexp_info);
ager@chromium.org41826e72009-03-30 13:30:57 +00003157 if (match.is_null()) {
3158 return Failure::Exception();
3159 }
3160 } while (!match->IsNull());
3161 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003162 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org04921a82011-06-27 13:21:41 +00003163 Handle<String> substring = isolate->factory()->
3164 NewSubString(subject, offsets.at(0), offsets.at(1));
3165 elements->set(0, *substring);
3166 for (int i = 1; i < matches ; i++) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003167 int from = offsets.at(i * 2);
3168 int to = offsets.at(i * 2 + 1);
ager@chromium.org04921a82011-06-27 13:21:41 +00003169 Handle<String> substring = isolate->factory()->
3170 NewProperSubString(subject, from, to);
3171 elements->set(i, *substring);
ager@chromium.org41826e72009-03-30 13:30:57 +00003172 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003173 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003174 result->set_length(Smi::FromInt(matches));
3175 return *result;
3176}
3177
3178
lrn@chromium.org25156de2010-04-06 13:10:27 +00003179// Two smis before and after the match, for very long strings.
3180const int kMaxBuilderEntriesPerRegExpMatch = 5;
3181
3182
3183static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3184 Handle<JSArray> last_match_info,
3185 int match_start,
3186 int match_end) {
3187 // Fill last_match_info with a single capture.
3188 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3189 AssertNoAllocation no_gc;
3190 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3191 RegExpImpl::SetLastCaptureCount(elements, 2);
3192 RegExpImpl::SetLastInput(elements, *subject);
3193 RegExpImpl::SetLastSubject(elements, *subject);
3194 RegExpImpl::SetCapture(elements, 0, match_start);
3195 RegExpImpl::SetCapture(elements, 1, match_end);
3196}
3197
3198
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003199template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003200static bool SearchStringMultiple(Isolate* isolate,
3201 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003202 Vector<const PatternChar> pattern,
3203 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003204 FixedArrayBuilder* builder,
3205 int* match_pos) {
3206 int pos = *match_pos;
3207 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003208 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003209 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003210 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003211 while (pos <= max_search_start) {
3212 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3213 *match_pos = pos;
3214 return false;
3215 }
3216 // Position of end of previous match.
3217 int match_end = pos + pattern_length;
3218 int new_pos = search.Search(subject, match_end);
3219 if (new_pos >= 0) {
3220 // A match.
3221 if (new_pos > match_end) {
3222 ReplacementStringBuilder::AddSubjectSlice(builder,
3223 match_end,
3224 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003225 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003226 pos = new_pos;
3227 builder->Add(pattern_string);
3228 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003229 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003230 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003231 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003232
lrn@chromium.org25156de2010-04-06 13:10:27 +00003233 if (pos < max_search_start) {
3234 ReplacementStringBuilder::AddSubjectSlice(builder,
3235 pos + pattern_length,
3236 subject_length);
3237 }
3238 *match_pos = pos;
3239 return true;
3240}
3241
3242
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003243static bool SearchStringMultiple(Isolate* isolate,
3244 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003245 Handle<String> pattern,
3246 Handle<JSArray> last_match_info,
3247 FixedArrayBuilder* builder) {
3248 ASSERT(subject->IsFlat());
3249 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003250
3251 // Treating as if a previous match was before first character.
3252 int match_pos = -pattern->length();
3253
3254 for (;;) { // Break when search complete.
3255 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3256 AssertNoAllocation no_gc;
3257 if (subject->IsAsciiRepresentation()) {
3258 Vector<const char> subject_vector = subject->ToAsciiVector();
3259 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003260 if (SearchStringMultiple(isolate,
3261 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003262 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003263 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003264 builder,
3265 &match_pos)) break;
3266 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003267 if (SearchStringMultiple(isolate,
3268 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003269 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003270 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003271 builder,
3272 &match_pos)) break;
3273 }
3274 } else {
3275 Vector<const uc16> subject_vector = subject->ToUC16Vector();
3276 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003277 if (SearchStringMultiple(isolate,
3278 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003279 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003280 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003281 builder,
3282 &match_pos)) break;
3283 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003284 if (SearchStringMultiple(isolate,
3285 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003286 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003287 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003288 builder,
3289 &match_pos)) break;
3290 }
3291 }
3292 }
3293
3294 if (match_pos >= 0) {
3295 SetLastMatchInfoNoCaptures(subject,
3296 last_match_info,
3297 match_pos,
3298 match_pos + pattern->length());
3299 return true;
3300 }
3301 return false; // No matches at all.
3302}
3303
3304
3305static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003306 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003307 Handle<String> subject,
3308 Handle<JSRegExp> regexp,
3309 Handle<JSArray> last_match_array,
3310 FixedArrayBuilder* builder) {
3311 ASSERT(subject->IsFlat());
3312 int match_start = -1;
3313 int match_end = 0;
3314 int pos = 0;
3315 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3316 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3317
3318 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003319 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003320 int subject_length = subject->length();
ager@chromium.org04921a82011-06-27 13:21:41 +00003321 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003322
3323 for (;;) { // Break on failure, return on exception.
3324 RegExpImpl::IrregexpResult result =
3325 RegExpImpl::IrregexpExecOnce(regexp,
3326 subject,
3327 pos,
3328 register_vector);
3329 if (result == RegExpImpl::RE_SUCCESS) {
3330 match_start = register_vector[0];
3331 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3332 if (match_end < match_start) {
3333 ReplacementStringBuilder::AddSubjectSlice(builder,
3334 match_end,
3335 match_start);
3336 }
3337 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003338 HandleScope loop_scope(isolate);
ager@chromium.org04921a82011-06-27 13:21:41 +00003339 if (!first) {
3340 builder->Add(*isolate->factory()->NewProperSubString(subject,
3341 match_start,
3342 match_end));
3343 } else {
3344 builder->Add(*isolate->factory()->NewSubString(subject,
3345 match_start,
3346 match_end));
3347 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003348 if (match_start != match_end) {
3349 pos = match_end;
3350 } else {
3351 pos = match_end + 1;
3352 if (pos > subject_length) break;
3353 }
3354 } else if (result == RegExpImpl::RE_FAILURE) {
3355 break;
3356 } else {
3357 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3358 return result;
3359 }
ager@chromium.org04921a82011-06-27 13:21:41 +00003360 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003361 }
3362
3363 if (match_start >= 0) {
3364 if (match_end < subject_length) {
3365 ReplacementStringBuilder::AddSubjectSlice(builder,
3366 match_end,
3367 subject_length);
3368 }
3369 SetLastMatchInfoNoCaptures(subject,
3370 last_match_array,
3371 match_start,
3372 match_end);
3373 return RegExpImpl::RE_SUCCESS;
3374 } else {
3375 return RegExpImpl::RE_FAILURE; // No matches at all.
3376 }
3377}
3378
3379
3380static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003381 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003382 Handle<String> subject,
3383 Handle<JSRegExp> regexp,
3384 Handle<JSArray> last_match_array,
3385 FixedArrayBuilder* builder) {
3386
3387 ASSERT(subject->IsFlat());
3388 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3389 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3390
3391 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003392 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003393
3394 RegExpImpl::IrregexpResult result =
3395 RegExpImpl::IrregexpExecOnce(regexp,
3396 subject,
3397 0,
3398 register_vector);
3399
3400 int capture_count = regexp->CaptureCount();
3401 int subject_length = subject->length();
3402
3403 // Position to search from.
3404 int pos = 0;
3405 // End of previous match. Differs from pos if match was empty.
3406 int match_end = 0;
3407 if (result == RegExpImpl::RE_SUCCESS) {
3408 // Need to keep a copy of the previous match for creating last_match_info
3409 // at the end, so we have two vectors that we swap between.
3410 OffsetsVector registers2(required_registers);
3411 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00003412 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003413 do {
3414 int match_start = register_vector[0];
3415 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3416 if (match_end < match_start) {
3417 ReplacementStringBuilder::AddSubjectSlice(builder,
3418 match_end,
3419 match_start);
3420 }
3421 match_end = register_vector[1];
3422
3423 {
3424 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003425 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003426 // Arguments array to replace function is match, captures, index and
3427 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003428 Handle<FixedArray> elements =
3429 isolate->factory()->NewFixedArray(3 + capture_count);
ager@chromium.org04921a82011-06-27 13:21:41 +00003430 Handle<String> match;
3431 if (!first) {
3432 match = isolate->factory()->NewProperSubString(subject,
3433 match_start,
3434 match_end);
3435 } else {
3436 match = isolate->factory()->NewSubString(subject,
3437 match_start,
3438 match_end);
3439 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003440 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003441 for (int i = 1; i <= capture_count; i++) {
3442 int start = register_vector[i * 2];
3443 if (start >= 0) {
3444 int end = register_vector[i * 2 + 1];
3445 ASSERT(start <= end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003446 Handle<String> substring;
3447 if (!first) {
3448 substring = isolate->factory()->NewProperSubString(subject,
3449 start,
3450 end);
3451 } else {
3452 substring = isolate->factory()->NewSubString(subject, start, end);
3453 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003454 elements->set(i, *substring);
3455 } else {
3456 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003457 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003458 }
3459 }
3460 elements->set(capture_count + 1, Smi::FromInt(match_start));
3461 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003462 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003463 }
3464 // Swap register vectors, so the last successful match is in
3465 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003466 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003467 prev_register_vector = register_vector;
3468 register_vector = tmp;
3469
3470 if (match_end > match_start) {
3471 pos = match_end;
3472 } else {
3473 pos = match_end + 1;
3474 if (pos > subject_length) {
3475 break;
3476 }
3477 }
3478
3479 result = RegExpImpl::IrregexpExecOnce(regexp,
3480 subject,
3481 pos,
3482 register_vector);
ager@chromium.org04921a82011-06-27 13:21:41 +00003483 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003484 } while (result == RegExpImpl::RE_SUCCESS);
3485
3486 if (result != RegExpImpl::RE_EXCEPTION) {
3487 // Finished matching, with at least one match.
3488 if (match_end < subject_length) {
3489 ReplacementStringBuilder::AddSubjectSlice(builder,
3490 match_end,
3491 subject_length);
3492 }
3493
3494 int last_match_capture_count = (capture_count + 1) * 2;
3495 int last_match_array_size =
3496 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3497 last_match_array->EnsureSize(last_match_array_size);
3498 AssertNoAllocation no_gc;
3499 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3500 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3501 RegExpImpl::SetLastSubject(elements, *subject);
3502 RegExpImpl::SetLastInput(elements, *subject);
3503 for (int i = 0; i < last_match_capture_count; i++) {
3504 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3505 }
3506 return RegExpImpl::RE_SUCCESS;
3507 }
3508 }
3509 // No matches at all, return failure or exception result directly.
3510 return result;
3511}
3512
3513
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003514RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003515 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003516 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003517
3518 CONVERT_ARG_CHECKED(String, subject, 1);
3519 if (!subject->IsFlat()) { FlattenString(subject); }
3520 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3521 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3522 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3523
3524 ASSERT(last_match_info->HasFastElements());
3525 ASSERT(regexp->GetFlags().is_global());
3526 Handle<FixedArray> result_elements;
3527 if (result_array->HasFastElements()) {
3528 result_elements =
3529 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
ager@chromium.org04921a82011-06-27 13:21:41 +00003530 }
3531 if (result_elements.is_null() || result_elements->length() < 16) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003532 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003533 }
3534 FixedArrayBuilder builder(result_elements);
3535
3536 if (regexp->TypeTag() == JSRegExp::ATOM) {
3537 Handle<String> pattern(
3538 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003539 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003540 if (SearchStringMultiple(isolate, subject, pattern,
3541 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003542 return *builder.ToJSArray(result_array);
3543 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003544 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003545 }
3546
3547 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3548
3549 RegExpImpl::IrregexpResult result;
3550 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003551 result = SearchRegExpNoCaptureMultiple(isolate,
3552 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003553 regexp,
3554 last_match_info,
3555 &builder);
3556 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003557 result = SearchRegExpMultiple(isolate,
3558 subject,
3559 regexp,
3560 last_match_info,
3561 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003562 }
3563 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003564 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003565 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3566 return Failure::Exception();
3567}
3568
3569
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003570RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003571 NoHandleAllocation ha;
3572 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003573 CONVERT_SMI_ARG_CHECKED(radix, 1);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003574 RUNTIME_ASSERT(2 <= radix && radix <= 36);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003575
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003576 // Fast case where the result is a one character string.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003577 if (args[0]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003578 int value = args.smi_at(0);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003579 if (value >= 0 && value < radix) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003580 // Character array used for conversion.
3581 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003582 return isolate->heap()->
3583 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003584 }
3585 }
3586
3587 // Slow case.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003588 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003589 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003590 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003591 }
3592 if (isinf(value)) {
3593 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003594 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003595 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003596 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003597 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003598 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003599 MaybeObject* result =
3600 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003601 DeleteArray(str);
3602 return result;
3603}
3604
3605
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003606RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003607 NoHandleAllocation ha;
3608 ASSERT(args.length() == 2);
3609
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003610 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003611 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003612 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003613 }
3614 if (isinf(value)) {
3615 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003616 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003617 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003618 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003619 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003620 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003621 int f = FastD2I(f_number);
3622 RUNTIME_ASSERT(f >= 0);
3623 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003624 MaybeObject* res =
3625 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003626 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003627 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003628}
3629
3630
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003631RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003632 NoHandleAllocation ha;
3633 ASSERT(args.length() == 2);
3634
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003635 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003636 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003637 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003638 }
3639 if (isinf(value)) {
3640 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003641 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003642 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003643 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003644 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003645 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003646 int f = FastD2I(f_number);
3647 RUNTIME_ASSERT(f >= -1 && f <= 20);
3648 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003649 MaybeObject* res =
3650 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003651 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003652 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003653}
3654
3655
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003656RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003657 NoHandleAllocation ha;
3658 ASSERT(args.length() == 2);
3659
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003660 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003661 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003662 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003663 }
3664 if (isinf(value)) {
3665 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003666 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003667 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003668 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003669 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003670 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003671 int f = FastD2I(f_number);
3672 RUNTIME_ASSERT(f >= 1 && f <= 21);
3673 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003674 MaybeObject* res =
3675 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003676 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003677 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003678}
3679
3680
3681// Returns a single character string where first character equals
3682// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003683static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003684 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003685 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003686 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003687 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003688 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003689 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003690}
3691
3692
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003693MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
3694 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003695 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003696 // Handle [] indexing on Strings
3697 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003698 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
3699 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003700 }
3701
3702 // Handle [] indexing on String objects
3703 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003704 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
3705 Handle<Object> result =
3706 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
3707 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003708 }
3709
3710 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003711 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003712 return prototype->GetElement(index);
3713 }
3714
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003715 return GetElement(object, index);
3716}
3717
3718
lrn@chromium.org303ada72010-10-27 09:33:13 +00003719MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003720 return object->GetElement(index);
3721}
3722
3723
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003724MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
3725 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003726 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003727 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003728
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003729 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003730 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003731 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003732 isolate->factory()->NewTypeError("non_object_property_load",
3733 HandleVector(args, 2));
3734 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003735 }
3736
3737 // Check if the given key is an array index.
3738 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003739 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003740 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003741 }
3742
3743 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003744 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003745 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003746 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003747 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003748 bool has_pending_exception = false;
3749 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003750 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003751 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003752 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003753 }
3754
ager@chromium.org32912102009-01-16 10:38:43 +00003755 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003756 // the element if so.
3757 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003758 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003759 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003760 return object->GetProperty(*name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003761 }
3762}
3763
3764
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003765RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003766 NoHandleAllocation ha;
3767 ASSERT(args.length() == 2);
3768
3769 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003770 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003771
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003772 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003773}
3774
3775
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003776// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003777RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00003778 NoHandleAllocation ha;
3779 ASSERT(args.length() == 2);
3780
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003781 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00003782 // itself.
3783 //
3784 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00003785 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00003786 // global proxy object never has properties. This is the case
3787 // because the global proxy object forwards everything to its hidden
3788 // prototype including local lookups.
3789 //
3790 // Additionally, we need to make sure that we do not cache results
3791 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003792 if (args[0]->IsJSObject() &&
3793 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00003794 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003795 args[1]->IsString()) {
3796 JSObject* receiver = JSObject::cast(args[0]);
3797 String* key = String::cast(args[1]);
3798 if (receiver->HasFastProperties()) {
3799 // Attempt to use lookup cache.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003800 Map* receiver_map = receiver->map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003801 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
3802 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003803 if (offset != -1) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003804 Object* value = receiver->FastPropertyAt(offset);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003805 return value->IsTheHole() ? isolate->heap()->undefined_value() : value;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003806 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003807 // Lookup cache miss. Perform lookup and update the cache if appropriate.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003808 LookupResult result;
3809 receiver->LocalLookup(key, &result);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00003810 if (result.IsProperty() && result.type() == FIELD) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003811 int offset = result.GetFieldIndex();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003812 keyed_lookup_cache->Update(receiver_map, key, offset);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003813 return receiver->FastPropertyAt(offset);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003814 }
3815 } else {
3816 // Attempt dictionary lookup.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00003817 StringDictionary* dictionary = receiver->property_dictionary();
3818 int entry = dictionary->FindEntry(key);
3819 if ((entry != StringDictionary::kNotFound) &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003820 (dictionary->DetailsAt(entry).type() == NORMAL)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003821 Object* value = dictionary->ValueAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003822 if (!receiver->IsGlobalObject()) return value;
3823 value = JSGlobalPropertyCell::cast(value)->value();
3824 if (!value->IsTheHole()) return value;
3825 // If value is the hole do the general lookup.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003826 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003827 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003828 } else if (args[0]->IsString() && args[1]->IsSmi()) {
3829 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003830 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003831 Handle<String> str = args.at<String>(0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003832 int index = args.smi_at(1);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003833 if (index >= 0 && index < str->length()) {
3834 Handle<Object> result = GetCharAt(str, index);
3835 return *result;
3836 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003837 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003838
3839 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003840 return Runtime::GetObjectProperty(isolate,
3841 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00003842 args.at<Object>(1));
3843}
3844
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003845// Implements part of 8.12.9 DefineOwnProperty.
3846// There are 3 cases that lead here:
3847// Step 4b - define a new accessor property.
3848// Steps 9c & 12 - replace an existing data property with an accessor property.
3849// Step 12 - update an existing accessor property with an accessor or generic
3850// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003851RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003852 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003853 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00003854 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3855 CONVERT_CHECKED(String, name, args[1]);
3856 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003857 Object* fun = args[3];
3858 RUNTIME_ASSERT(fun->IsJSFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00003859 CONVERT_CHECKED(Smi, flag_attr, args[4]);
3860 int unchecked = flag_attr->value();
3861 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3862 RUNTIME_ASSERT(!obj->IsNull());
3863 LookupResult result;
3864 obj->LocalLookupRealNamedProperty(name, &result);
3865
3866 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3867 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
3868 // delete it to avoid running into trouble in DefineAccessor, which
3869 // handles this incorrectly if the property is readonly (does nothing)
3870 if (result.IsProperty() &&
3871 (result.type() == FIELD || result.type() == NORMAL
3872 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003873 Object* ok;
3874 { MaybeObject* maybe_ok =
3875 obj->DeleteProperty(name, JSObject::NORMAL_DELETION);
3876 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3877 }
ager@chromium.org5c838252010-02-19 08:53:10 +00003878 }
3879 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
3880}
3881
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003882// Implements part of 8.12.9 DefineOwnProperty.
3883// There are 3 cases that lead here:
3884// Step 4a - define a new data property.
3885// Steps 9b & 12 - replace an existing accessor property with a data property.
3886// Step 12 - update an existing data property with a data or generic
3887// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003888RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003889 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003890 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00003891 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
3892 CONVERT_ARG_CHECKED(String, name, 1);
3893 Handle<Object> obj_value = args.at<Object>(2);
3894
3895 CONVERT_CHECKED(Smi, flag, args[3]);
3896 int unchecked = flag->value();
3897 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3898
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003899 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3900
3901 // Check if this is an element.
3902 uint32_t index;
3903 bool is_element = name->AsArrayIndex(&index);
3904
3905 // Special case for elements if any of the flags are true.
3906 // If elements are in fast case we always implicitly assume that:
3907 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
3908 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
3909 is_element) {
3910 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003911 if (js_object->IsJSGlobalProxy()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003912 // We do not need to do access checks here since these has already
3913 // been performed by the call to GetOwnProperty.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003914 Handle<Object> proto(js_object->GetPrototype());
3915 // If proxy is detached, ignore the assignment. Alternatively,
3916 // we could throw an exception.
3917 if (proto->IsNull()) return *obj_value;
3918 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003919 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +00003920 Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003921 // Make sure that we never go back to fast case.
3922 dictionary->set_requires_slow_elements();
3923 PropertyDetails details = PropertyDetails(attr, NORMAL);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003924 Handle<NumberDictionary> extended_dictionary =
3925 NumberDictionarySet(dictionary, index, obj_value, details);
3926 if (*extended_dictionary != *dictionary) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00003927 if (js_object->GetElementsKind() ==
3928 JSObject::NON_STRICT_ARGUMENTS_ELEMENTS) {
3929 FixedArray::cast(js_object->elements())->set(1, *extended_dictionary);
3930 } else {
3931 js_object->set_elements(*extended_dictionary);
3932 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003933 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003934 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003935 }
3936
ager@chromium.org5c838252010-02-19 08:53:10 +00003937 LookupResult result;
whesse@chromium.org7b260152011-06-20 15:33:18 +00003938 js_object->LocalLookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00003939
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00003940 // To be compatible with safari we do not change the value on API objects
3941 // in defineProperty. Firefox disagrees here, and actually changes the value.
3942 if (result.IsProperty() &&
3943 (result.type() == CALLBACKS) &&
3944 result.GetCallbackObject()->IsAccessorInfo()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003945 return isolate->heap()->undefined_value();
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00003946 }
3947
ager@chromium.org5c838252010-02-19 08:53:10 +00003948 // Take special care when attributes are different and there is already
3949 // a property. For simplicity we normalize the property which enables us
3950 // to not worry about changing the instance_descriptor and creating a new
3951 // map. The current version of SetObjectProperty does not handle attributes
3952 // correctly in the case where a property is a field and is reset with
3953 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003954 if (result.IsProperty() &&
3955 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003956 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003957 if (js_object->IsJSGlobalProxy()) {
3958 // Since the result is a property, the prototype will exist so
3959 // we don't have to check for null.
3960 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003961 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003962 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00003963 // Use IgnoreAttributes version since a readonly property may be
3964 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003965 return js_object->SetLocalPropertyIgnoreAttributes(*name,
3966 *obj_value,
3967 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003968 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003969
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003970 return Runtime::ForceSetObjectProperty(isolate,
3971 js_object,
3972 name,
3973 obj_value,
3974 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003975}
3976
3977
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003978// Special case for elements if any of the flags are true.
3979// If elements are in fast case we always implicitly assume that:
3980// DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
3981static MaybeObject* NormalizeObjectSetElement(Isolate* isolate,
3982 Handle<JSObject> js_object,
3983 uint32_t index,
3984 Handle<Object> value,
3985 PropertyAttributes attr) {
3986 // Normalize the elements to enable attributes on the property.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00003987 Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003988 // Make sure that we never go back to fast case.
3989 dictionary->set_requires_slow_elements();
3990 PropertyDetails details = PropertyDetails(attr, NORMAL);
3991 Handle<NumberDictionary> extended_dictionary =
3992 NumberDictionarySet(dictionary, index, value, details);
3993 if (*extended_dictionary != *dictionary) {
3994 js_object->set_elements(*extended_dictionary);
3995 }
3996 return *value;
3997}
3998
3999
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004000MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
4001 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004002 Handle<Object> key,
4003 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004004 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004005 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004006 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004007
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004008 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004009 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004010 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004011 isolate->factory()->NewTypeError("non_object_property_store",
4012 HandleVector(args, 2));
4013 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004014 }
4015
4016 // If the object isn't a JavaScript object, we ignore the store.
4017 if (!object->IsJSObject()) return *value;
4018
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004019 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
4020
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004021 // Check if the given key is an array index.
4022 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004023 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004024 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4025 // of a string using [] notation. We need to support this too in
4026 // JavaScript.
4027 // In the case of a String object we just need to redirect the assignment to
4028 // the underlying string if the index is in range. Since the underlying
4029 // string does nothing with the assignment then we can ignore such
4030 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004031 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004032 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004033 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004034
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004035 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4036 return NormalizeObjectSetElement(isolate, js_object, index, value, attr);
4037 }
4038
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004039 Handle<Object> result = SetElement(js_object, index, value, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004040 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004041 return *value;
4042 }
4043
4044 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004045 Handle<Object> result;
4046 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004047 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4048 return NormalizeObjectSetElement(isolate,
4049 js_object,
4050 index,
4051 value,
4052 attr);
4053 }
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004054 result = SetElement(js_object, index, value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004055 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004056 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004057 key_string->TryFlatten();
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004058 result = SetProperty(js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004059 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004060 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004061 return *value;
4062 }
4063
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004064 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004065 bool has_pending_exception = false;
4066 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4067 if (has_pending_exception) return Failure::Exception();
4068 Handle<String> name = Handle<String>::cast(converted);
4069
4070 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004071 return js_object->SetElement(index, *value, strict_mode, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004072 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004073 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004074 }
4075}
4076
4077
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004078MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4079 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004080 Handle<Object> key,
4081 Handle<Object> value,
4082 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004083 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004084
4085 // Check if the given key is an array index.
4086 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004087 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004088 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4089 // of a string using [] notation. We need to support this too in
4090 // JavaScript.
4091 // In the case of a String object we just need to redirect the assignment to
4092 // the underlying string if the index is in range. Since the underlying
4093 // string does nothing with the assignment then we can ignore such
4094 // assignments.
4095 if (js_object->IsStringObjectWithCharacterAt(index)) {
4096 return *value;
4097 }
4098
whesse@chromium.org7b260152011-06-20 15:33:18 +00004099 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004100 }
4101
4102 if (key->IsString()) {
4103 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004104 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004105 } else {
4106 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004107 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004108 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4109 *value,
4110 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004111 }
4112 }
4113
4114 // Call-back into JavaScript to convert the key to a string.
4115 bool has_pending_exception = false;
4116 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4117 if (has_pending_exception) return Failure::Exception();
4118 Handle<String> name = Handle<String>::cast(converted);
4119
4120 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004121 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004122 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004123 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004124 }
4125}
4126
4127
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004128MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
4129 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004130 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004131 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004132
4133 // Check if the given key is an array index.
4134 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004135 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004136 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4137 // characters of a string using [] notation. In the case of a
4138 // String object we just need to redirect the deletion to the
4139 // underlying string if the index is in range. Since the
4140 // underlying string does nothing with the deletion, we can ignore
4141 // such deletions.
4142 if (js_object->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004143 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004144 }
4145
4146 return js_object->DeleteElement(index, JSObject::FORCE_DELETION);
4147 }
4148
4149 Handle<String> key_string;
4150 if (key->IsString()) {
4151 key_string = Handle<String>::cast(key);
4152 } else {
4153 // Call-back into JavaScript to convert the key to a string.
4154 bool has_pending_exception = false;
4155 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4156 if (has_pending_exception) return Failure::Exception();
4157 key_string = Handle<String>::cast(converted);
4158 }
4159
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004160 key_string->TryFlatten();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004161 return js_object->DeleteProperty(*key_string, JSObject::FORCE_DELETION);
4162}
4163
4164
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004165RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004166 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004167 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004168
4169 Handle<Object> object = args.at<Object>(0);
4170 Handle<Object> key = args.at<Object>(1);
4171 Handle<Object> value = args.at<Object>(2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004172 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004173 RUNTIME_ASSERT(
4174 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004175 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004176 PropertyAttributes attributes =
4177 static_cast<PropertyAttributes>(unchecked_attributes);
4178
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004179 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004180 if (args.length() == 5) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004181 CONVERT_SMI_ARG_CHECKED(strict_unchecked, 4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004182 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
4183 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004184 strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004185 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004186
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004187 return Runtime::SetObjectProperty(isolate,
4188 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004189 key,
4190 value,
4191 attributes,
4192 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004193}
4194
4195
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004196// Set the native flag on the function.
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004197// This is used to decide if we should transform null and undefined
4198// into the global object when doing call and apply.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004199RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004200 NoHandleAllocation ha;
4201 RUNTIME_ASSERT(args.length() == 1);
4202
4203 Handle<Object> object = args.at<Object>(0);
4204
4205 if (object->IsJSFunction()) {
4206 JSFunction* func = JSFunction::cast(*object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004207 func->shared()->set_native(true);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004208 }
4209 return isolate->heap()->undefined_value();
4210}
4211
4212
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004213// Set a local property, even if it is READ_ONLY. If the property does not
4214// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004215RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004216 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004217 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004218 CONVERT_CHECKED(JSObject, object, args[0]);
4219 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004220 // Compute attributes.
4221 PropertyAttributes attributes = NONE;
4222 if (args.length() == 4) {
4223 CONVERT_CHECKED(Smi, value_obj, args[3]);
4224 int unchecked_value = value_obj->value();
4225 // Only attribute bits should be set.
4226 RUNTIME_ASSERT(
4227 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4228 attributes = static_cast<PropertyAttributes>(unchecked_value);
4229 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004230
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004231 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004232 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004233}
4234
4235
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004236RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004237 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004238 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004239
4240 CONVERT_CHECKED(JSObject, object, args[0]);
4241 CONVERT_CHECKED(String, key, args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004242 CONVERT_SMI_ARG_CHECKED(strict, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004243 return object->DeleteProperty(key, (strict == kStrictMode)
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004244 ? JSObject::STRICT_DELETION
4245 : JSObject::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004246}
4247
4248
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004249static Object* HasLocalPropertyImplementation(Isolate* isolate,
4250 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004251 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004252 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004253 // Handle hidden prototypes. If there's a hidden prototype above this thing
4254 // then we have to check it for properties, because they are supposed to
4255 // look like they are on this object.
4256 Handle<Object> proto(object->GetPrototype());
4257 if (proto->IsJSObject() &&
4258 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004259 return HasLocalPropertyImplementation(isolate,
4260 Handle<JSObject>::cast(proto),
4261 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004262 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004263 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004264}
4265
4266
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004267RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004268 NoHandleAllocation ha;
4269 ASSERT(args.length() == 2);
4270 CONVERT_CHECKED(String, key, args[1]);
4271
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004272 uint32_t index;
4273 const bool key_is_array_index = key->AsArrayIndex(&index);
4274
ager@chromium.org9085a012009-05-11 19:22:57 +00004275 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004276 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004277 if (obj->IsJSObject()) {
4278 JSObject* object = JSObject::cast(obj);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004279 // Fast case: either the key is a real named property or it is not
4280 // an array index and there are no interceptors or hidden
4281 // prototypes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004282 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004283 Map* map = object->map();
4284 if (!key_is_array_index &&
4285 !map->has_named_interceptor() &&
4286 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4287 return isolate->heap()->false_value();
4288 }
4289 // Slow case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004290 HandleScope scope(isolate);
4291 return HasLocalPropertyImplementation(isolate,
4292 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004293 Handle<String>(key));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004294 } else if (obj->IsString() && key_is_array_index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004295 // Well, there is one exception: Handle [] on strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004296 String* string = String::cast(obj);
4297 if (index < static_cast<uint32_t>(string->length())) {
4298 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004299 }
4300 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004301 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004302}
4303
4304
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004305RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004306 NoHandleAllocation na;
4307 ASSERT(args.length() == 2);
4308
4309 // Only JS objects can have properties.
4310 if (args[0]->IsJSObject()) {
4311 JSObject* object = JSObject::cast(args[0]);
4312 CONVERT_CHECKED(String, key, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004313 if (object->HasProperty(key)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004314 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004315 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004316}
4317
4318
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004319RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004320 NoHandleAllocation na;
4321 ASSERT(args.length() == 2);
4322
4323 // Only JS objects can have elements.
4324 if (args[0]->IsJSObject()) {
4325 JSObject* object = JSObject::cast(args[0]);
4326 CONVERT_CHECKED(Smi, index_obj, args[1]);
4327 uint32_t index = index_obj->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004328 if (object->HasElement(index)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004329 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004330 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004331}
4332
4333
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004334RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004335 NoHandleAllocation ha;
4336 ASSERT(args.length() == 2);
4337
4338 CONVERT_CHECKED(JSObject, object, args[0]);
4339 CONVERT_CHECKED(String, key, args[1]);
4340
4341 uint32_t index;
4342 if (key->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004343 return isolate->heap()->ToBoolean(object->HasElement(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004344 }
4345
ager@chromium.org870a0b62008-11-04 11:43:05 +00004346 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004347 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004348}
4349
4350
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004351RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004352 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004353 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004354 CONVERT_ARG_CHECKED(JSObject, object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004355 return *GetKeysFor(object);
4356}
4357
4358
4359// Returns either a FixedArray as Runtime_GetPropertyNames,
4360// or, if the given object has an enum cache that contains
4361// all enumerable properties of the object and its prototypes
4362// have none, the map of the object. This is used to speed up
4363// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004364RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004365 ASSERT(args.length() == 1);
4366
4367 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4368
4369 if (raw_object->IsSimpleEnum()) return raw_object->map();
4370
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004371 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004372 Handle<JSObject> object(raw_object);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004373 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
4374 INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004375
4376 // Test again, since cache may have been built by preceding call.
4377 if (object->IsSimpleEnum()) return object->map();
4378
4379 return *content;
4380}
4381
4382
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004383// Find the length of the prototype chain that is to to handled as one. If a
4384// prototype object is hidden it is to be viewed as part of the the object it
4385// is prototype for.
4386static int LocalPrototypeChainLength(JSObject* obj) {
4387 int count = 1;
4388 Object* proto = obj->GetPrototype();
4389 while (proto->IsJSObject() &&
4390 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4391 count++;
4392 proto = JSObject::cast(proto)->GetPrototype();
4393 }
4394 return count;
4395}
4396
4397
4398// Return the names of the local named properties.
4399// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004400RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004401 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004402 ASSERT(args.length() == 1);
4403 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004404 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004405 }
4406 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4407
4408 // Skip the global proxy as it has no properties and always delegates to the
4409 // real global object.
4410 if (obj->IsJSGlobalProxy()) {
4411 // Only collect names if access is permitted.
4412 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004413 !isolate->MayNamedAccess(*obj,
4414 isolate->heap()->undefined_value(),
4415 v8::ACCESS_KEYS)) {
4416 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4417 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004418 }
4419 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4420 }
4421
4422 // Find the number of objects making up this.
4423 int length = LocalPrototypeChainLength(*obj);
4424
4425 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004426 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004427 int total_property_count = 0;
4428 Handle<JSObject> jsproto = obj;
4429 for (int i = 0; i < length; i++) {
4430 // Only collect names if access is permitted.
4431 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004432 !isolate->MayNamedAccess(*jsproto,
4433 isolate->heap()->undefined_value(),
4434 v8::ACCESS_KEYS)) {
4435 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4436 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004437 }
4438 int n;
4439 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4440 local_property_count[i] = n;
4441 total_property_count += n;
4442 if (i < length - 1) {
4443 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4444 }
4445 }
4446
4447 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004448 Handle<FixedArray> names =
4449 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004450
4451 // Get the property names.
4452 jsproto = obj;
4453 int proto_with_hidden_properties = 0;
4454 for (int i = 0; i < length; i++) {
4455 jsproto->GetLocalPropertyNames(*names,
4456 i == 0 ? 0 : local_property_count[i - 1]);
4457 if (!GetHiddenProperties(jsproto, false)->IsUndefined()) {
4458 proto_with_hidden_properties++;
4459 }
4460 if (i < length - 1) {
4461 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4462 }
4463 }
4464
4465 // Filter out name of hidden propeties object.
4466 if (proto_with_hidden_properties > 0) {
4467 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004468 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004469 names->length() - proto_with_hidden_properties);
4470 int dest_pos = 0;
4471 for (int i = 0; i < total_property_count; i++) {
4472 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004473 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004474 continue;
4475 }
4476 names->set(dest_pos++, name);
4477 }
4478 }
4479
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004480 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004481}
4482
4483
4484// Return the names of the local indexed properties.
4485// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004486RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004487 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004488 ASSERT(args.length() == 1);
4489 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004490 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004491 }
4492 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4493
4494 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004495 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004496 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004497 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004498}
4499
4500
4501// Return information on whether an object has a named or indexed interceptor.
4502// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004503RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004504 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004505 ASSERT(args.length() == 1);
4506 if (!args[0]->IsJSObject()) {
4507 return Smi::FromInt(0);
4508 }
4509 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4510
4511 int result = 0;
4512 if (obj->HasNamedInterceptor()) result |= 2;
4513 if (obj->HasIndexedInterceptor()) result |= 1;
4514
4515 return Smi::FromInt(result);
4516}
4517
4518
4519// Return property names from named interceptor.
4520// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004521RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004522 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004523 ASSERT(args.length() == 1);
4524 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4525
4526 if (obj->HasNamedInterceptor()) {
4527 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4528 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4529 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004530 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004531}
4532
4533
4534// Return element names from indexed interceptor.
4535// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004536RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004537 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004538 ASSERT(args.length() == 1);
4539 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4540
4541 if (obj->HasIndexedInterceptor()) {
4542 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4543 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4544 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004545 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004546}
4547
4548
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004549RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004550 ASSERT_EQ(args.length(), 1);
4551 CONVERT_CHECKED(JSObject, raw_object, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004552 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004553 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004554
4555 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00004556 // Do access checks before going to the global object.
4557 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004558 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00004559 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004560 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
4561 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00004562 }
4563
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004564 Handle<Object> proto(object->GetPrototype());
4565 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004566 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004567 object = Handle<JSObject>::cast(proto);
4568 }
4569
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004570 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4571 LOCAL_ONLY);
4572 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4573 // property array and since the result is mutable we have to create
4574 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004575 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004576 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004577 for (int i = 0; i < length; i++) {
4578 Object* entry = contents->get(i);
4579 if (entry->IsString()) {
4580 copy->set(i, entry);
4581 } else {
4582 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004583 HandleScope scope(isolate);
4584 Handle<Object> entry_handle(entry, isolate);
4585 Handle<Object> entry_str =
4586 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004587 copy->set(i, *entry_str);
4588 }
4589 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004590 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004591}
4592
4593
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004594RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004595 NoHandleAllocation ha;
4596 ASSERT(args.length() == 1);
4597
4598 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00004599 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004600 it.AdvanceToArgumentsFrame();
4601 JavaScriptFrame* frame = it.frame();
4602
4603 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00004604 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004605
4606 // Try to convert the key to an index. If successful and within
4607 // index return the the argument from the frame.
4608 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004609 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004610 return frame->GetParameter(index);
4611 }
4612
4613 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004614 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004615 bool exception = false;
4616 Handle<Object> converted =
4617 Execution::ToString(args.at<Object>(0), &exception);
4618 if (exception) return Failure::Exception();
4619 Handle<String> key = Handle<String>::cast(converted);
4620
4621 // Try to convert the string key into an array index.
4622 if (key->AsArrayIndex(&index)) {
4623 if (index < n) {
4624 return frame->GetParameter(index);
4625 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004626 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004627 }
4628 }
4629
4630 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004631 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
4632 if (key->Equals(isolate->heap()->callee_symbol())) {
4633 Object* function = frame->function();
4634 if (function->IsJSFunction() &&
4635 JSFunction::cast(function)->shared()->strict_mode()) {
4636 return isolate->Throw(*isolate->factory()->NewTypeError(
4637 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
4638 }
4639 return function;
4640 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004641
4642 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004643 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004644}
4645
4646
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004647RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004648 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004649
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004650 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004651 Handle<Object> object = args.at<Object>(0);
4652 if (object->IsJSObject()) {
4653 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00004654 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004655 MaybeObject* ok = js_object->TransformToFastProperties(0);
4656 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00004657 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004658 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004659 return *object;
4660}
4661
4662
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004663RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004664 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004665
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004666 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004667 Handle<Object> object = args.at<Object>(0);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004668 if (object->IsJSObject() && !object->IsJSGlobalProxy()) {
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004669 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004670 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004671 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004672 return *object;
4673}
4674
4675
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004676RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004677 NoHandleAllocation ha;
4678 ASSERT(args.length() == 1);
4679
4680 return args[0]->ToBoolean();
4681}
4682
4683
4684// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
4685// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004686RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004687 NoHandleAllocation ha;
4688
4689 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004690 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004691 HeapObject* heap_obj = HeapObject::cast(obj);
4692
4693 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004694 if (heap_obj->map()->is_undetectable()) {
4695 return isolate->heap()->undefined_symbol();
4696 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004697
4698 InstanceType instance_type = heap_obj->map()->instance_type();
4699 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004700 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004701 }
4702
4703 switch (instance_type) {
4704 case ODDBALL_TYPE:
4705 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004706 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004707 }
4708 if (heap_obj->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004709 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004710 }
4711 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004712 return isolate->heap()->undefined_symbol();
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00004713 case JS_FUNCTION_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004714 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004715 default:
4716 // For any kind of object not handled above, the spec rule for
4717 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004718 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004719 }
4720}
4721
4722
lrn@chromium.org25156de2010-04-06 13:10:27 +00004723static bool AreDigits(const char*s, int from, int to) {
4724 for (int i = from; i < to; i++) {
4725 if (s[i] < '0' || s[i] > '9') return false;
4726 }
4727
4728 return true;
4729}
4730
4731
4732static int ParseDecimalInteger(const char*s, int from, int to) {
4733 ASSERT(to - from < 10); // Overflow is not possible.
4734 ASSERT(from < to);
4735 int d = s[from] - '0';
4736
4737 for (int i = from + 1; i < to; i++) {
4738 d = 10 * d + (s[i] - '0');
4739 }
4740
4741 return d;
4742}
4743
4744
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004745RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004746 NoHandleAllocation ha;
4747 ASSERT(args.length() == 1);
4748 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004749 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004750
4751 // Fast case: short integer or some sorts of junk values.
4752 int len = subject->length();
4753 if (subject->IsSeqAsciiString()) {
4754 if (len == 0) return Smi::FromInt(0);
4755
4756 char const* data = SeqAsciiString::cast(subject)->GetChars();
4757 bool minus = (data[0] == '-');
4758 int start_pos = (minus ? 1 : 0);
4759
4760 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004761 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004762 } else if (data[start_pos] > '9') {
4763 // Fast check for a junk value. A valid string may start from a
4764 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
4765 // the 'I' character ('Infinity'). All of that have codes not greater than
4766 // '9' except 'I'.
4767 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004768 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004769 }
4770 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
4771 // The maximal/minimal smi has 10 digits. If the string has less digits we
4772 // know it will fit into the smi-data type.
4773 int d = ParseDecimalInteger(data, start_pos, len);
4774 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004775 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004776 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004777 } else if (!subject->HasHashCode() &&
4778 len <= String::kMaxArrayIndexSize &&
4779 (len == 1 || data[0] != '0')) {
4780 // String hash is not calculated yet but all the data are present.
4781 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004782 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004783#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004784 subject->Hash(); // Force hash calculation.
4785 ASSERT_EQ(static_cast<int>(subject->hash_field()),
4786 static_cast<int>(hash));
4787#endif
4788 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004789 }
4790 return Smi::FromInt(d);
4791 }
4792 }
4793
4794 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00004795 return isolate->heap()->NumberFromDouble(
4796 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004797}
4798
4799
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004800RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004801 NoHandleAllocation ha;
4802 ASSERT(args.length() == 1);
4803
4804 CONVERT_CHECKED(JSArray, codes, args[0]);
4805 int length = Smi::cast(codes->length())->value();
4806
4807 // Check if the string can be ASCII.
4808 int i;
4809 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004810 Object* element;
4811 { MaybeObject* maybe_element = codes->GetElement(i);
4812 // We probably can't get an exception here, but just in order to enforce
4813 // the checking of inputs in the runtime calls we check here.
4814 if (!maybe_element->ToObject(&element)) return maybe_element;
4815 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004816 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
4817 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
4818 break;
4819 }
4820
lrn@chromium.org303ada72010-10-27 09:33:13 +00004821 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004822 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004823 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004824 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004825 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004826 }
4827
lrn@chromium.org303ada72010-10-27 09:33:13 +00004828 Object* object = NULL;
4829 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004830 String* result = String::cast(object);
4831 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004832 Object* element;
4833 { MaybeObject* maybe_element = codes->GetElement(i);
4834 if (!maybe_element->ToObject(&element)) return maybe_element;
4835 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004836 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004837 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004838 }
4839 return result;
4840}
4841
4842
4843// kNotEscaped is generated by the following:
4844//
4845// #!/bin/perl
4846// for (my $i = 0; $i < 256; $i++) {
4847// print "\n" if $i % 16 == 0;
4848// my $c = chr($i);
4849// my $escaped = 1;
4850// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
4851// print $escaped ? "0, " : "1, ";
4852// }
4853
4854
4855static bool IsNotEscaped(uint16_t character) {
4856 // Only for 8 bit characters, the rest are always escaped (in a different way)
4857 ASSERT(character < 256);
4858 static const char kNotEscaped[256] = {
4859 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4860 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4861 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
4862 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
4863 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4864 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
4865 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4866 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
4867 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4868 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4869 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4870 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4871 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4872 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4873 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4874 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4875 };
4876 return kNotEscaped[character] != 0;
4877}
4878
4879
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004880RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004881 const char hex_chars[] = "0123456789ABCDEF";
4882 NoHandleAllocation ha;
4883 ASSERT(args.length() == 1);
4884 CONVERT_CHECKED(String, source, args[0]);
4885
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004886 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004887
4888 int escaped_length = 0;
4889 int length = source->length();
4890 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004891 Access<StringInputBuffer> buffer(
4892 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004893 buffer->Reset(source);
4894 while (buffer->has_more()) {
4895 uint16_t character = buffer->GetNext();
4896 if (character >= 256) {
4897 escaped_length += 6;
4898 } else if (IsNotEscaped(character)) {
4899 escaped_length++;
4900 } else {
4901 escaped_length += 3;
4902 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004903 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004904 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004905 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004906 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004907 return Failure::OutOfMemoryException();
4908 }
4909 }
4910 }
4911 // No length change implies no change. Return original string if no change.
4912 if (escaped_length == length) {
4913 return source;
4914 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004915 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004916 { MaybeObject* maybe_o =
4917 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004918 if (!maybe_o->ToObject(&o)) return maybe_o;
4919 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004920 String* destination = String::cast(o);
4921 int dest_position = 0;
4922
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004923 Access<StringInputBuffer> buffer(
4924 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004925 buffer->Rewind();
4926 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00004927 uint16_t chr = buffer->GetNext();
4928 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004929 destination->Set(dest_position, '%');
4930 destination->Set(dest_position+1, 'u');
4931 destination->Set(dest_position+2, hex_chars[chr >> 12]);
4932 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
4933 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
4934 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004935 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00004936 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004937 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004938 dest_position++;
4939 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004940 destination->Set(dest_position, '%');
4941 destination->Set(dest_position+1, hex_chars[chr >> 4]);
4942 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004943 dest_position += 3;
4944 }
4945 }
4946 return destination;
4947}
4948
4949
4950static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
4951 static const signed char kHexValue['g'] = {
4952 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4953 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4954 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4955 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
4956 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4957 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4958 -1, 10, 11, 12, 13, 14, 15 };
4959
4960 if (character1 > 'f') return -1;
4961 int hi = kHexValue[character1];
4962 if (hi == -1) return -1;
4963 if (character2 > 'f') return -1;
4964 int lo = kHexValue[character2];
4965 if (lo == -1) return -1;
4966 return (hi << 4) + lo;
4967}
4968
4969
ager@chromium.org870a0b62008-11-04 11:43:05 +00004970static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00004971 int i,
4972 int length,
4973 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004974 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00004975 int32_t hi = 0;
4976 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004977 if (character == '%' &&
4978 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004979 source->Get(i + 1) == 'u' &&
4980 (hi = TwoDigitHex(source->Get(i + 2),
4981 source->Get(i + 3))) != -1 &&
4982 (lo = TwoDigitHex(source->Get(i + 4),
4983 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004984 *step = 6;
4985 return (hi << 8) + lo;
4986 } else if (character == '%' &&
4987 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004988 (lo = TwoDigitHex(source->Get(i + 1),
4989 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004990 *step = 3;
4991 return lo;
4992 } else {
4993 *step = 1;
4994 return character;
4995 }
4996}
4997
4998
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004999RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005000 NoHandleAllocation ha;
5001 ASSERT(args.length() == 1);
5002 CONVERT_CHECKED(String, source, args[0]);
5003
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005004 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005005
5006 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005007 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005008
5009 int unescaped_length = 0;
5010 for (int i = 0; i < length; unescaped_length++) {
5011 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005012 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005013 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005014 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005015 i += step;
5016 }
5017
5018 // No length change implies no change. Return original string if no change.
5019 if (unescaped_length == length)
5020 return source;
5021
lrn@chromium.org303ada72010-10-27 09:33:13 +00005022 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005023 { MaybeObject* maybe_o =
5024 ascii ?
5025 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
5026 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005027 if (!maybe_o->ToObject(&o)) return maybe_o;
5028 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005029 String* destination = String::cast(o);
5030
5031 int dest_position = 0;
5032 for (int i = 0; i < length; dest_position++) {
5033 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005034 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005035 i += step;
5036 }
5037 return destination;
5038}
5039
5040
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005041static const unsigned int kQuoteTableLength = 128u;
5042
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005043static const int kJsonQuotesCharactersPerEntry = 8;
5044static const char* const JsonQuotes =
5045 "\\u0000 \\u0001 \\u0002 \\u0003 "
5046 "\\u0004 \\u0005 \\u0006 \\u0007 "
5047 "\\b \\t \\n \\u000b "
5048 "\\f \\r \\u000e \\u000f "
5049 "\\u0010 \\u0011 \\u0012 \\u0013 "
5050 "\\u0014 \\u0015 \\u0016 \\u0017 "
5051 "\\u0018 \\u0019 \\u001a \\u001b "
5052 "\\u001c \\u001d \\u001e \\u001f "
5053 " ! \\\" # "
5054 "$ % & ' "
5055 "( ) * + "
5056 ", - . / "
5057 "0 1 2 3 "
5058 "4 5 6 7 "
5059 "8 9 : ; "
5060 "< = > ? "
5061 "@ A B C "
5062 "D E F G "
5063 "H I J K "
5064 "L M N O "
5065 "P Q R S "
5066 "T U V W "
5067 "X Y Z [ "
5068 "\\\\ ] ^ _ "
5069 "` a b c "
5070 "d e f g "
5071 "h i j k "
5072 "l m n o "
5073 "p q r s "
5074 "t u v w "
5075 "x y z { "
5076 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005077
5078
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005079// For a string that is less than 32k characters it should always be
5080// possible to allocate it in new space.
5081static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5082
5083
5084// Doing JSON quoting cannot make the string more than this many times larger.
5085static const int kJsonQuoteWorstCaseBlowup = 6;
5086
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005087static const int kSpaceForQuotesAndComma = 3;
5088static const int kSpaceForBrackets = 2;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005089
5090// Covers the entire ASCII range (all other characters are unchanged by JSON
5091// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005092static const byte JsonQuoteLengths[kQuoteTableLength] = {
5093 6, 6, 6, 6, 6, 6, 6, 6,
5094 2, 2, 2, 6, 2, 2, 6, 6,
5095 6, 6, 6, 6, 6, 6, 6, 6,
5096 6, 6, 6, 6, 6, 6, 6, 6,
5097 1, 1, 2, 1, 1, 1, 1, 1,
5098 1, 1, 1, 1, 1, 1, 1, 1,
5099 1, 1, 1, 1, 1, 1, 1, 1,
5100 1, 1, 1, 1, 1, 1, 1, 1,
5101 1, 1, 1, 1, 1, 1, 1, 1,
5102 1, 1, 1, 1, 1, 1, 1, 1,
5103 1, 1, 1, 1, 1, 1, 1, 1,
5104 1, 1, 1, 1, 2, 1, 1, 1,
5105 1, 1, 1, 1, 1, 1, 1, 1,
5106 1, 1, 1, 1, 1, 1, 1, 1,
5107 1, 1, 1, 1, 1, 1, 1, 1,
5108 1, 1, 1, 1, 1, 1, 1, 1,
5109};
5110
5111
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005112template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005113MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005114
5115
5116template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005117MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5118 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005119}
5120
5121
5122template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005123MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5124 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005125}
5126
5127
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005128template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005129static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5130 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005131 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005132 const Char* read_cursor = characters.start();
5133 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005134 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005135 int quoted_length = kSpaceForQuotes;
5136 while (read_cursor < end) {
5137 Char c = *(read_cursor++);
5138 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5139 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005140 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005141 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005142 }
5143 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005144 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5145 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005146 Object* new_object;
5147 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005148 return new_alloc;
5149 }
5150 StringType* new_string = StringType::cast(new_object);
5151
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005152 Char* write_cursor = reinterpret_cast<Char*>(
5153 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005154 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005155 *(write_cursor++) = '"';
5156
5157 read_cursor = characters.start();
5158 while (read_cursor < end) {
5159 Char c = *(read_cursor++);
5160 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5161 *(write_cursor++) = c;
5162 } else {
5163 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5164 const char* replacement = JsonQuotes +
5165 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5166 for (int i = 0; i < len; i++) {
5167 *write_cursor++ = *replacement++;
5168 }
5169 }
5170 }
5171 *(write_cursor++) = '"';
5172 return new_string;
5173}
5174
5175
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005176template <typename SinkChar, typename SourceChar>
5177static inline SinkChar* WriteQuoteJsonString(
5178 Isolate* isolate,
5179 SinkChar* write_cursor,
5180 Vector<const SourceChar> characters) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005181 // SinkChar is only char if SourceChar is guaranteed to be char.
5182 ASSERT(sizeof(SinkChar) >= sizeof(SourceChar));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005183 const SourceChar* read_cursor = characters.start();
5184 const SourceChar* end = read_cursor + characters.length();
5185 *(write_cursor++) = '"';
5186 while (read_cursor < end) {
5187 SourceChar c = *(read_cursor++);
5188 if (sizeof(SourceChar) > 1u &&
5189 static_cast<unsigned>(c) >= kQuoteTableLength) {
5190 *(write_cursor++) = static_cast<SinkChar>(c);
5191 } else {
5192 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5193 const char* replacement = JsonQuotes +
5194 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5195 write_cursor[0] = replacement[0];
5196 if (len > 1) {
5197 write_cursor[1] = replacement[1];
5198 if (len > 2) {
5199 ASSERT(len == 6);
5200 write_cursor[2] = replacement[2];
5201 write_cursor[3] = replacement[3];
5202 write_cursor[4] = replacement[4];
5203 write_cursor[5] = replacement[5];
5204 }
5205 }
5206 write_cursor += len;
5207 }
5208 }
5209 *(write_cursor++) = '"';
5210 return write_cursor;
5211}
5212
5213
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005214template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005215static MaybeObject* QuoteJsonString(Isolate* isolate,
5216 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005217 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005218 isolate->counters()->quote_json_char_count()->Increment(length);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005219 int worst_case_length =
5220 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005221 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005222 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005223 }
5224
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005225 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5226 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005227 Object* new_object;
5228 if (!new_alloc->ToObject(&new_object)) {
5229 return new_alloc;
5230 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005231 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005232 // Even if our string is small enough to fit in new space we still have to
5233 // handle it being allocated in old space as may happen in the third
5234 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5235 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005236 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005237 }
5238 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005239 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005240
5241 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5242 Char* write_cursor = reinterpret_cast<Char*>(
5243 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005244 if (comma) *(write_cursor++) = ',';
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005245 write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
5246 write_cursor,
5247 characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005248 int final_length = static_cast<int>(
5249 write_cursor - reinterpret_cast<Char*>(
5250 new_string->address() + SeqAsciiString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005251 isolate->heap()->new_space()->
5252 template ShrinkStringAtAllocationBoundary<StringType>(
5253 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005254 return new_string;
5255}
5256
5257
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005258RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005259 NoHandleAllocation ha;
5260 CONVERT_CHECKED(String, str, args[0]);
5261 if (!str->IsFlat()) {
5262 MaybeObject* try_flatten = str->TryFlatten();
5263 Object* flat;
5264 if (!try_flatten->ToObject(&flat)) {
5265 return try_flatten;
5266 }
5267 str = String::cast(flat);
5268 ASSERT(str->IsFlat());
5269 }
5270 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005271 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
5272 str->ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005273 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005274 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
5275 str->ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005276 }
5277}
5278
5279
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005280RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005281 NoHandleAllocation ha;
5282 CONVERT_CHECKED(String, str, args[0]);
5283 if (!str->IsFlat()) {
5284 MaybeObject* try_flatten = str->TryFlatten();
5285 Object* flat;
5286 if (!try_flatten->ToObject(&flat)) {
5287 return try_flatten;
5288 }
5289 str = String::cast(flat);
5290 ASSERT(str->IsFlat());
5291 }
5292 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005293 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
5294 str->ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005295 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005296 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
5297 str->ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005298 }
5299}
5300
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005301
5302template <typename Char, typename StringType>
5303static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
5304 FixedArray* array,
5305 int worst_case_length) {
5306 int length = array->length();
5307
5308 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5309 worst_case_length);
5310 Object* new_object;
5311 if (!new_alloc->ToObject(&new_object)) {
5312 return new_alloc;
5313 }
5314 if (!isolate->heap()->new_space()->Contains(new_object)) {
5315 // Even if our string is small enough to fit in new space we still have to
5316 // handle it being allocated in old space as may happen in the third
5317 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5318 // CEntryStub::GenerateCore.
5319 return isolate->heap()->undefined_value();
5320 }
5321 AssertNoAllocation no_gc;
5322 StringType* new_string = StringType::cast(new_object);
5323 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5324
5325 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5326 Char* write_cursor = reinterpret_cast<Char*>(
5327 new_string->address() + SeqAsciiString::kHeaderSize);
5328 *(write_cursor++) = '[';
5329 for (int i = 0; i < length; i++) {
5330 if (i != 0) *(write_cursor++) = ',';
5331 String* str = String::cast(array->get(i));
5332 if (str->IsTwoByteRepresentation()) {
5333 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
5334 write_cursor,
5335 str->ToUC16Vector());
5336 } else {
5337 write_cursor = WriteQuoteJsonString<Char, char>(isolate,
5338 write_cursor,
5339 str->ToAsciiVector());
5340 }
5341 }
5342 *(write_cursor++) = ']';
5343
5344 int final_length = static_cast<int>(
5345 write_cursor - reinterpret_cast<Char*>(
5346 new_string->address() + SeqAsciiString::kHeaderSize));
5347 isolate->heap()->new_space()->
5348 template ShrinkStringAtAllocationBoundary<StringType>(
5349 new_string, final_length);
5350 return new_string;
5351}
5352
5353
5354RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
5355 NoHandleAllocation ha;
5356 ASSERT(args.length() == 1);
5357 CONVERT_CHECKED(JSArray, array, args[0]);
5358
5359 if (!array->HasFastElements()) return isolate->heap()->undefined_value();
5360 FixedArray* elements = FixedArray::cast(array->elements());
5361 int n = elements->length();
5362 bool ascii = true;
5363 int total_length = 0;
5364
5365 for (int i = 0; i < n; i++) {
5366 Object* elt = elements->get(i);
5367 if (!elt->IsString()) return isolate->heap()->undefined_value();
5368 String* element = String::cast(elt);
5369 if (!element->IsFlat()) return isolate->heap()->undefined_value();
5370 total_length += element->length();
5371 if (ascii && element->IsTwoByteRepresentation()) {
5372 ascii = false;
5373 }
5374 }
5375
5376 int worst_case_length =
5377 kSpaceForBrackets + n * kSpaceForQuotesAndComma
5378 + total_length * kJsonQuoteWorstCaseBlowup;
5379
5380 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5381 return isolate->heap()->undefined_value();
5382 }
5383
5384 if (ascii) {
5385 return QuoteJsonStringArray<char, SeqAsciiString>(isolate,
5386 elements,
5387 worst_case_length);
5388 } else {
5389 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
5390 elements,
5391 worst_case_length);
5392 }
5393}
5394
5395
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005396RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005397 NoHandleAllocation ha;
5398
5399 CONVERT_CHECKED(String, s, args[0]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005400 CONVERT_SMI_ARG_CHECKED(radix, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005401
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005402 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005403
lrn@chromium.org25156de2010-04-06 13:10:27 +00005404 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005405 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005406 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005407}
5408
5409
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005410RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005411 NoHandleAllocation ha;
5412 CONVERT_CHECKED(String, str, args[0]);
5413
5414 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005415 double value = StringToDouble(isolate->unicode_cache(),
5416 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005417
5418 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005419 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005420}
5421
5422
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005423template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005424MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005425 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005426 String* s,
5427 int length,
5428 int input_string_length,
5429 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005430 // We try this twice, once with the assumption that the result is no longer
5431 // than the input and, if that assumption breaks, again with the exact
5432 // length. This may not be pretty, but it is nicer than what was here before
5433 // and I hereby claim my vaffel-is.
5434 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005435 // Allocate the resulting string.
5436 //
5437 // NOTE: This assumes that the upper/lower case of an ascii
5438 // character is also ascii. This is currently the case, but it
5439 // might break in the future if we implement more context and locale
5440 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005441 Object* o;
5442 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005443 ? isolate->heap()->AllocateRawAsciiString(length)
5444 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005445 if (!maybe_o->ToObject(&o)) return maybe_o;
5446 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005447 String* result = String::cast(o);
5448 bool has_changed_character = false;
5449
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005450 // Convert all characters to upper case, assuming that they will fit
5451 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005452 Access<StringInputBuffer> buffer(
5453 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005454 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005455 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005456 // We can assume that the string is not empty
5457 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005458 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005459 bool has_next = buffer->has_more();
5460 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005461 int char_length = mapping->get(current, next, chars);
5462 if (char_length == 0) {
5463 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005464 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005465 i++;
5466 } else if (char_length == 1) {
5467 // Common case: converting the letter resulted in one character.
5468 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005469 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005470 has_changed_character = true;
5471 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005472 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005473 // We've assumed that the result would be as long as the
5474 // input but here is a character that converts to several
5475 // characters. No matter, we calculate the exact length
5476 // of the result and try the whole thing again.
5477 //
5478 // Note that this leaves room for optimization. We could just
5479 // memcpy what we already have to the result string. Also,
5480 // the result string is the last object allocated we could
5481 // "realloc" it and probably, in the vast majority of cases,
5482 // extend the existing string to be able to hold the full
5483 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00005484 int next_length = 0;
5485 if (has_next) {
5486 next_length = mapping->get(next, 0, chars);
5487 if (next_length == 0) next_length = 1;
5488 }
5489 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005490 while (buffer->has_more()) {
5491 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005492 // NOTE: we use 0 as the next character here because, while
5493 // the next character may affect what a character converts to,
5494 // it does not in any case affect the length of what it convert
5495 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005496 int char_length = mapping->get(current, 0, chars);
5497 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00005498 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005499 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005500 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005501 return Failure::OutOfMemoryException();
5502 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005503 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005504 // Try again with the real length.
5505 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005506 } else {
5507 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005508 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005509 i++;
5510 }
5511 has_changed_character = true;
5512 }
5513 current = next;
5514 }
5515 if (has_changed_character) {
5516 return result;
5517 } else {
5518 // If we didn't actually change anything in doing the conversion
5519 // we simple return the result and let the converted string
5520 // become garbage; there is no reason to keep two identical strings
5521 // alive.
5522 return s;
5523 }
5524}
5525
5526
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005527namespace {
5528
lrn@chromium.org303ada72010-10-27 09:33:13 +00005529static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
5530
5531
5532// Given a word and two range boundaries returns a word with high bit
5533// set in every byte iff the corresponding input byte was strictly in
5534// the range (m, n). All the other bits in the result are cleared.
5535// This function is only useful when it can be inlined and the
5536// boundaries are statically known.
5537// Requires: all bytes in the input word and the boundaries must be
5538// ascii (less than 0x7F).
5539static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
5540 // Every byte in an ascii string is less than or equal to 0x7F.
5541 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
5542 // Use strict inequalities since in edge cases the function could be
5543 // further simplified.
5544 ASSERT(0 < m && m < n && n < 0x7F);
5545 // Has high bit set in every w byte less than n.
5546 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
5547 // Has high bit set in every w byte greater than m.
5548 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
5549 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
5550}
5551
5552
5553enum AsciiCaseConversion {
5554 ASCII_TO_LOWER,
5555 ASCII_TO_UPPER
5556};
5557
5558
5559template <AsciiCaseConversion dir>
5560struct FastAsciiConverter {
5561 static bool Convert(char* dst, char* src, int length) {
5562#ifdef DEBUG
5563 char* saved_dst = dst;
5564 char* saved_src = src;
5565#endif
5566 // We rely on the distance between upper and lower case letters
5567 // being a known power of 2.
5568 ASSERT('a' - 'A' == (1 << 5));
5569 // Boundaries for the range of input characters than require conversion.
5570 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
5571 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
5572 bool changed = false;
5573 char* const limit = src + length;
5574#ifdef V8_HOST_CAN_READ_UNALIGNED
5575 // Process the prefix of the input that requires no conversion one
5576 // (machine) word at a time.
5577 while (src <= limit - sizeof(uintptr_t)) {
5578 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5579 if (AsciiRangeMask(w, lo, hi) != 0) {
5580 changed = true;
5581 break;
5582 }
5583 *reinterpret_cast<uintptr_t*>(dst) = w;
5584 src += sizeof(uintptr_t);
5585 dst += sizeof(uintptr_t);
5586 }
5587 // Process the remainder of the input performing conversion when
5588 // required one word at a time.
5589 while (src <= limit - sizeof(uintptr_t)) {
5590 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5591 uintptr_t m = AsciiRangeMask(w, lo, hi);
5592 // The mask has high (7th) bit set in every byte that needs
5593 // conversion and we know that the distance between cases is
5594 // 1 << 5.
5595 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
5596 src += sizeof(uintptr_t);
5597 dst += sizeof(uintptr_t);
5598 }
5599#endif
5600 // Process the last few bytes of the input (or the whole input if
5601 // unaligned access is not supported).
5602 while (src < limit) {
5603 char c = *src;
5604 if (lo < c && c < hi) {
5605 c ^= (1 << 5);
5606 changed = true;
5607 }
5608 *dst = c;
5609 ++src;
5610 ++dst;
5611 }
5612#ifdef DEBUG
5613 CheckConvert(saved_dst, saved_src, length, changed);
5614#endif
5615 return changed;
5616 }
5617
5618#ifdef DEBUG
5619 static void CheckConvert(char* dst, char* src, int length, bool changed) {
5620 bool expected_changed = false;
5621 for (int i = 0; i < length; i++) {
5622 if (dst[i] == src[i]) continue;
5623 expected_changed = true;
5624 if (dir == ASCII_TO_LOWER) {
5625 ASSERT('A' <= src[i] && src[i] <= 'Z');
5626 ASSERT(dst[i] == src[i] + ('a' - 'A'));
5627 } else {
5628 ASSERT(dir == ASCII_TO_UPPER);
5629 ASSERT('a' <= src[i] && src[i] <= 'z');
5630 ASSERT(dst[i] == src[i] - ('a' - 'A'));
5631 }
5632 }
5633 ASSERT(expected_changed == changed);
5634 }
5635#endif
5636};
5637
5638
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005639struct ToLowerTraits {
5640 typedef unibrow::ToLowercase UnibrowConverter;
5641
lrn@chromium.org303ada72010-10-27 09:33:13 +00005642 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005643};
5644
5645
5646struct ToUpperTraits {
5647 typedef unibrow::ToUppercase UnibrowConverter;
5648
lrn@chromium.org303ada72010-10-27 09:33:13 +00005649 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005650};
5651
5652} // namespace
5653
5654
5655template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005656MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005657 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005658 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005659 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005660 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005661 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005662 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005663
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005664 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005665 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005666 if (length == 0) return s;
5667
5668 // Simpler handling of ascii strings.
5669 //
5670 // NOTE: This assumes that the upper/lower case of an ascii
5671 // character is also ascii. This is currently the case, but it
5672 // might break in the future if we implement more context and locale
5673 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005674 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005675 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005676 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005677 if (!maybe_o->ToObject(&o)) return maybe_o;
5678 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005679 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005680 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005681 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005682 return has_changed_character ? result : s;
5683 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005684
lrn@chromium.org303ada72010-10-27 09:33:13 +00005685 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005686 { MaybeObject* maybe_answer =
5687 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005688 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5689 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005690 if (answer->IsSmi()) {
5691 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005692 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005693 ConvertCaseHelper(isolate,
5694 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005695 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5696 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005697 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005698 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005699}
5700
5701
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005702RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005703 return ConvertCase<ToLowerTraits>(
5704 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005705}
5706
5707
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005708RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005709 return ConvertCase<ToUpperTraits>(
5710 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005711}
5712
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005713
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005714static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
5715 return unibrow::WhiteSpace::Is(c) || c == 0x200b;
5716}
5717
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005718
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005719RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005720 NoHandleAllocation ha;
5721 ASSERT(args.length() == 3);
5722
5723 CONVERT_CHECKED(String, s, args[0]);
5724 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
5725 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
5726
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005727 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005728 int length = s->length();
5729
5730 int left = 0;
5731 if (trimLeft) {
5732 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
5733 left++;
5734 }
5735 }
5736
5737 int right = length;
5738 if (trimRight) {
5739 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
5740 right--;
5741 }
5742 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005743 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005744}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005745
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005746
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005747void FindAsciiStringIndices(Vector<const char> subject,
5748 char pattern,
5749 ZoneList<int>* indices,
5750 unsigned int limit) {
5751 ASSERT(limit > 0);
5752 // Collect indices of pattern in subject using memchr.
5753 // Stop after finding at most limit values.
5754 const char* subject_start = reinterpret_cast<const char*>(subject.start());
5755 const char* subject_end = subject_start + subject.length();
5756 const char* pos = subject_start;
5757 while (limit > 0) {
5758 pos = reinterpret_cast<const char*>(
5759 memchr(pos, pattern, subject_end - pos));
5760 if (pos == NULL) return;
5761 indices->Add(static_cast<int>(pos - subject_start));
5762 pos++;
5763 limit--;
5764 }
5765}
5766
5767
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005768template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005769void FindStringIndices(Isolate* isolate,
5770 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005771 Vector<const PatternChar> pattern,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005772 ZoneList<int>* indices,
5773 unsigned int limit) {
5774 ASSERT(limit > 0);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005775 // Collect indices of pattern in subject.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005776 // Stop after finding at most limit values.
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005777 int pattern_length = pattern.length();
5778 int index = 0;
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005779 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005780 while (limit > 0) {
5781 index = search.Search(subject, index);
5782 if (index < 0) return;
5783 indices->Add(index);
5784 index += pattern_length;
5785 limit--;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005786 }
5787}
5788
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005789
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005790RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005791 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005792 HandleScope handle_scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005793 CONVERT_ARG_CHECKED(String, subject, 0);
5794 CONVERT_ARG_CHECKED(String, pattern, 1);
5795 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
5796
5797 int subject_length = subject->length();
5798 int pattern_length = pattern->length();
5799 RUNTIME_ASSERT(pattern_length > 0);
5800
5801 // The limit can be very large (0xffffffffu), but since the pattern
5802 // isn't empty, we can never create more parts than ~half the length
5803 // of the subject.
5804
5805 if (!subject->IsFlat()) FlattenString(subject);
5806
5807 static const int kMaxInitialListCapacity = 16;
5808
danno@chromium.org40cb8782011-05-25 07:58:50 +00005809 ZoneScope scope(isolate, DELETE_ON_EXIT);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005810
5811 // Find (up to limit) indices of separator and end-of-string in subject
5812 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
5813 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005814 if (!pattern->IsFlat()) FlattenString(pattern);
5815
5816 // No allocation block.
5817 {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005818 AssertNoAllocation nogc;
5819 if (subject->IsAsciiRepresentation()) {
5820 Vector<const char> subject_vector = subject->ToAsciiVector();
5821 if (pattern->IsAsciiRepresentation()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005822 Vector<const char> pattern_vector = pattern->ToAsciiVector();
5823 if (pattern_vector.length() == 1) {
5824 FindAsciiStringIndices(subject_vector,
5825 pattern_vector[0],
5826 &indices,
5827 limit);
5828 } else {
5829 FindStringIndices(isolate,
5830 subject_vector,
5831 pattern_vector,
5832 &indices,
5833 limit);
5834 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005835 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005836 FindStringIndices(isolate,
5837 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005838 pattern->ToUC16Vector(),
5839 &indices,
5840 limit);
5841 }
5842 } else {
5843 Vector<const uc16> subject_vector = subject->ToUC16Vector();
5844 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005845 FindStringIndices(isolate,
5846 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005847 pattern->ToAsciiVector(),
5848 &indices,
5849 limit);
5850 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005851 FindStringIndices(isolate,
5852 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005853 pattern->ToUC16Vector(),
5854 &indices,
5855 limit);
5856 }
5857 }
5858 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005859
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005860 if (static_cast<uint32_t>(indices.length()) < limit) {
5861 indices.Add(subject_length);
5862 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005863
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005864 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005865
5866 // Create JSArray of substrings separated by separator.
5867 int part_count = indices.length();
5868
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005869 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005870 result->set_length(Smi::FromInt(part_count));
5871
5872 ASSERT(result->HasFastElements());
5873
5874 if (part_count == 1 && indices.at(0) == subject_length) {
5875 FixedArray::cast(result->elements())->set(0, *subject);
5876 return *result;
5877 }
5878
5879 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
5880 int part_start = 0;
5881 for (int i = 0; i < part_count; i++) {
5882 HandleScope local_loop_handle;
5883 int part_end = indices.at(i);
5884 Handle<String> substring =
ager@chromium.org04921a82011-06-27 13:21:41 +00005885 isolate->factory()->NewProperSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005886 elements->set(i, *substring);
5887 part_start = part_end + pattern_length;
5888 }
5889
5890 return *result;
5891}
5892
5893
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005894// Copies ascii characters to the given fixed array looking up
5895// one-char strings in the cache. Gives up on the first char that is
5896// not in the cache and fills the remainder with smi zeros. Returns
5897// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005898static int CopyCachedAsciiCharsToArray(Heap* heap,
5899 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005900 FixedArray* elements,
5901 int length) {
5902 AssertNoAllocation nogc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005903 FixedArray* ascii_cache = heap->single_character_string_cache();
5904 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005905 int i;
5906 for (i = 0; i < length; ++i) {
5907 Object* value = ascii_cache->get(chars[i]);
5908 if (value == undefined) break;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005909 ASSERT(!heap->InNewSpace(value));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005910 elements->set(i, value, SKIP_WRITE_BARRIER);
5911 }
5912 if (i < length) {
5913 ASSERT(Smi::FromInt(0) == 0);
5914 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
5915 }
5916#ifdef DEBUG
5917 for (int j = 0; j < length; ++j) {
5918 Object* element = elements->get(j);
5919 ASSERT(element == Smi::FromInt(0) ||
5920 (element->IsString() && String::cast(element)->LooksValid()));
5921 }
5922#endif
5923 return i;
5924}
5925
5926
5927// Converts a String to JSArray.
5928// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005929RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005930 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005931 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005932 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005933 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005934
5935 s->TryFlatten();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005936 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005937
5938 Handle<FixedArray> elements;
5939 if (s->IsFlat() && s->IsAsciiRepresentation()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005940 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005941 { MaybeObject* maybe_obj =
5942 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005943 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5944 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005945 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005946
5947 Vector<const char> chars = s->ToAsciiVector();
5948 // Note, this will initialize all elements (not only the prefix)
5949 // to prevent GC from seeing partially initialized array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005950 int num_copied_from_cache = CopyCachedAsciiCharsToArray(isolate->heap(),
5951 chars.start(),
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005952 *elements,
5953 length);
5954
5955 for (int i = num_copied_from_cache; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005956 Handle<Object> str = LookupSingleCharacterStringFromCode(chars[i]);
5957 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005958 }
5959 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005960 elements = isolate->factory()->NewFixedArray(length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005961 for (int i = 0; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005962 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
5963 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005964 }
5965 }
5966
5967#ifdef DEBUG
5968 for (int i = 0; i < length; ++i) {
5969 ASSERT(String::cast(elements->get(i))->length() == 1);
5970 }
5971#endif
5972
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005973 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005974}
5975
5976
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005977RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005978 NoHandleAllocation ha;
5979 ASSERT(args.length() == 1);
5980 CONVERT_CHECKED(String, value, args[0]);
5981 return value->ToObject();
5982}
5983
5984
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005985bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005986 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005987 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005988 return char_length == 0;
5989}
5990
5991
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005992RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005993 NoHandleAllocation ha;
5994 ASSERT(args.length() == 1);
5995
5996 Object* number = args[0];
5997 RUNTIME_ASSERT(number->IsNumber());
5998
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005999 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006000}
6001
6002
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006003RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00006004 NoHandleAllocation ha;
6005 ASSERT(args.length() == 1);
6006
6007 Object* number = args[0];
6008 RUNTIME_ASSERT(number->IsNumber());
6009
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006010 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00006011}
6012
6013
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006014RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006015 NoHandleAllocation ha;
6016 ASSERT(args.length() == 1);
6017
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006018 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006019
6020 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6021 if (number > 0 && number <= Smi::kMaxValue) {
6022 return Smi::FromInt(static_cast<int>(number));
6023 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006024 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006025}
6026
6027
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006028RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006029 NoHandleAllocation ha;
6030 ASSERT(args.length() == 1);
6031
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006032 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006033
6034 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6035 if (number > 0 && number <= Smi::kMaxValue) {
6036 return Smi::FromInt(static_cast<int>(number));
6037 }
6038
6039 double double_value = DoubleToInteger(number);
6040 // Map both -0 and +0 to +0.
6041 if (double_value == 0) double_value = 0;
6042
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006043 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006044}
6045
6046
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006047RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006048 NoHandleAllocation ha;
6049 ASSERT(args.length() == 1);
6050
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006051 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006052 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006053}
6054
6055
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006056RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006057 NoHandleAllocation ha;
6058 ASSERT(args.length() == 1);
6059
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006060 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006061
6062 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6063 if (number > 0 && number <= Smi::kMaxValue) {
6064 return Smi::FromInt(static_cast<int>(number));
6065 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006066 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006067}
6068
6069
ager@chromium.org870a0b62008-11-04 11:43:05 +00006070// Converts a Number to a Smi, if possible. Returns NaN if the number is not
6071// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006072RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00006073 NoHandleAllocation ha;
6074 ASSERT(args.length() == 1);
6075
6076 Object* obj = args[0];
6077 if (obj->IsSmi()) {
6078 return obj;
6079 }
6080 if (obj->IsHeapNumber()) {
6081 double value = HeapNumber::cast(obj)->value();
6082 int int_value = FastD2I(value);
6083 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
6084 return Smi::FromInt(int_value);
6085 }
6086 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006087 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006088}
6089
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006090
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006091RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006092 NoHandleAllocation ha;
6093 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006094 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006095}
6096
6097
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006098RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006099 NoHandleAllocation ha;
6100 ASSERT(args.length() == 2);
6101
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006102 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6103 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006104 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006105}
6106
6107
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006108RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006109 NoHandleAllocation ha;
6110 ASSERT(args.length() == 2);
6111
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006112 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6113 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006114 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006115}
6116
6117
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006118RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006119 NoHandleAllocation ha;
6120 ASSERT(args.length() == 2);
6121
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006122 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6123 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006124 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006125}
6126
6127
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006128RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006129 NoHandleAllocation ha;
6130 ASSERT(args.length() == 1);
6131
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006132 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006133 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006134}
6135
6136
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006137RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006138 NoHandleAllocation ha;
6139 ASSERT(args.length() == 0);
6140
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006141 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006142}
6143
6144
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006145RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006146 NoHandleAllocation ha;
6147 ASSERT(args.length() == 2);
6148
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006149 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6150 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006151 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006152}
6153
6154
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006155RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006156 NoHandleAllocation ha;
6157 ASSERT(args.length() == 2);
6158
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006159 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6160 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006161
ager@chromium.org3811b432009-10-28 14:53:37 +00006162 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006163 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006164 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006165}
6166
6167
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006168RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006169 NoHandleAllocation ha;
6170 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006171 CONVERT_CHECKED(String, str1, args[0]);
6172 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006173 isolate->counters()->string_add_runtime()->Increment();
6174 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006175}
6176
6177
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006178template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006179static inline void StringBuilderConcatHelper(String* special,
6180 sinkchar* sink,
6181 FixedArray* fixed_array,
6182 int array_length) {
6183 int position = 0;
6184 for (int i = 0; i < array_length; i++) {
6185 Object* element = fixed_array->get(i);
6186 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006187 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006188 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006189 int pos;
6190 int len;
6191 if (encoded_slice > 0) {
6192 // Position and length encoded in one smi.
6193 pos = StringBuilderSubstringPosition::decode(encoded_slice);
6194 len = StringBuilderSubstringLength::decode(encoded_slice);
6195 } else {
6196 // Position and length encoded in two smis.
6197 Object* obj = fixed_array->get(++i);
6198 ASSERT(obj->IsSmi());
6199 pos = Smi::cast(obj)->value();
6200 len = -encoded_slice;
6201 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00006202 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00006203 sink + position,
6204 pos,
6205 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006206 position += len;
6207 } else {
6208 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006209 int element_length = string->length();
6210 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006211 position += element_length;
6212 }
6213 }
6214}
6215
6216
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006217RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006218 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006219 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006220 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006221 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006222 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006223 return Failure::OutOfMemoryException();
6224 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006225 int array_length = args.smi_at(1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006226 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006227
6228 // This assumption is used by the slice encoding in one or two smis.
6229 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6230
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006231 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006232 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006233 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006234 }
6235 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006236 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006237 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006238 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006239
6240 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006241 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006242 } else if (array_length == 1) {
6243 Object* first = fixed_array->get(0);
6244 if (first->IsString()) return first;
6245 }
6246
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006247 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006248 int position = 0;
6249 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006250 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006251 Object* elt = fixed_array->get(i);
6252 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006253 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006254 int smi_value = Smi::cast(elt)->value();
6255 int pos;
6256 int len;
6257 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006258 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006259 pos = StringBuilderSubstringPosition::decode(smi_value);
6260 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006261 } else {
6262 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006263 len = -smi_value;
6264 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006265 i++;
6266 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006267 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006268 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006269 Object* next_smi = fixed_array->get(i);
6270 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006271 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006272 }
6273 pos = Smi::cast(next_smi)->value();
6274 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006275 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006276 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006277 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006278 ASSERT(pos >= 0);
6279 ASSERT(len >= 0);
6280 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006281 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006282 }
6283 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006284 } else if (elt->IsString()) {
6285 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006286 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006287 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006288 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006289 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006290 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006291 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006292 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006293 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006294 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006295 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006296 return Failure::OutOfMemoryException();
6297 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006298 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006299 }
6300
6301 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006302 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006303
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006304 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006305 { MaybeObject* maybe_object =
6306 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006307 if (!maybe_object->ToObject(&object)) return maybe_object;
6308 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006309 SeqAsciiString* answer = SeqAsciiString::cast(object);
6310 StringBuilderConcatHelper(special,
6311 answer->GetChars(),
6312 fixed_array,
6313 array_length);
6314 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006315 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006316 { MaybeObject* maybe_object =
6317 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006318 if (!maybe_object->ToObject(&object)) return maybe_object;
6319 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006320 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6321 StringBuilderConcatHelper(special,
6322 answer->GetChars(),
6323 fixed_array,
6324 array_length);
6325 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006326 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006327}
6328
6329
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006330RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006331 NoHandleAllocation ha;
6332 ASSERT(args.length() == 3);
6333 CONVERT_CHECKED(JSArray, array, args[0]);
6334 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006335 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006336 return Failure::OutOfMemoryException();
6337 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006338 int array_length = args.smi_at(1);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006339 CONVERT_CHECKED(String, separator, args[2]);
6340
6341 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006342 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006343 }
6344 FixedArray* fixed_array = FixedArray::cast(array->elements());
6345 if (fixed_array->length() < array_length) {
6346 array_length = fixed_array->length();
6347 }
6348
6349 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006350 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006351 } else if (array_length == 1) {
6352 Object* first = fixed_array->get(0);
6353 if (first->IsString()) return first;
6354 }
6355
6356 int separator_length = separator->length();
6357 int max_nof_separators =
6358 (String::kMaxLength + separator_length - 1) / separator_length;
6359 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006360 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006361 return Failure::OutOfMemoryException();
6362 }
6363 int length = (array_length - 1) * separator_length;
6364 for (int i = 0; i < array_length; i++) {
6365 Object* element_obj = fixed_array->get(i);
6366 if (!element_obj->IsString()) {
6367 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006368 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006369 }
6370 String* element = String::cast(element_obj);
6371 int increment = element->length();
6372 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006373 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006374 return Failure::OutOfMemoryException();
6375 }
6376 length += increment;
6377 }
6378
6379 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006380 { MaybeObject* maybe_object =
6381 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006382 if (!maybe_object->ToObject(&object)) return maybe_object;
6383 }
6384 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6385
6386 uc16* sink = answer->GetChars();
6387#ifdef DEBUG
6388 uc16* end = sink + length;
6389#endif
6390
6391 String* first = String::cast(fixed_array->get(0));
6392 int first_length = first->length();
6393 String::WriteToFlat(first, sink, 0, first_length);
6394 sink += first_length;
6395
6396 for (int i = 1; i < array_length; i++) {
6397 ASSERT(sink + separator_length <= end);
6398 String::WriteToFlat(separator, sink, 0, separator_length);
6399 sink += separator_length;
6400
6401 String* element = String::cast(fixed_array->get(i));
6402 int element_length = element->length();
6403 ASSERT(sink + element_length <= end);
6404 String::WriteToFlat(element, sink, 0, element_length);
6405 sink += element_length;
6406 }
6407 ASSERT(sink == end);
6408
6409 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6410 return answer;
6411}
6412
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006413template <typename Char>
6414static void JoinSparseArrayWithSeparator(FixedArray* elements,
6415 int elements_length,
6416 uint32_t array_length,
6417 String* separator,
6418 Vector<Char> buffer) {
6419 int previous_separator_position = 0;
6420 int separator_length = separator->length();
6421 int cursor = 0;
6422 for (int i = 0; i < elements_length; i += 2) {
6423 int position = NumberToInt32(elements->get(i));
6424 String* string = String::cast(elements->get(i + 1));
6425 int string_length = string->length();
6426 if (string->length() > 0) {
6427 while (previous_separator_position < position) {
6428 String::WriteToFlat<Char>(separator, &buffer[cursor],
6429 0, separator_length);
6430 cursor += separator_length;
6431 previous_separator_position++;
6432 }
6433 String::WriteToFlat<Char>(string, &buffer[cursor],
6434 0, string_length);
6435 cursor += string->length();
6436 }
6437 }
6438 if (separator_length > 0) {
6439 // Array length must be representable as a signed 32-bit number,
6440 // otherwise the total string length would have been too large.
6441 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6442 int last_array_index = static_cast<int>(array_length - 1);
6443 while (previous_separator_position < last_array_index) {
6444 String::WriteToFlat<Char>(separator, &buffer[cursor],
6445 0, separator_length);
6446 cursor += separator_length;
6447 previous_separator_position++;
6448 }
6449 }
6450 ASSERT(cursor <= buffer.length());
6451}
6452
6453
6454RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6455 NoHandleAllocation ha;
6456 ASSERT(args.length() == 3);
6457 CONVERT_CHECKED(JSArray, elements_array, args[0]);
6458 RUNTIME_ASSERT(elements_array->HasFastElements());
6459 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
6460 CONVERT_CHECKED(String, separator, args[2]);
6461 // elements_array is fast-mode JSarray of alternating positions
6462 // (increasing order) and strings.
6463 // array_length is length of original array (used to add separators);
6464 // separator is string to put between elements. Assumed to be non-empty.
6465
6466 // Find total length of join result.
6467 int string_length = 0;
6468 bool is_ascii = true;
6469 int max_string_length = SeqAsciiString::kMaxLength;
6470 bool overflow = false;
6471 CONVERT_NUMBER_CHECKED(int, elements_length,
6472 Int32, elements_array->length());
6473 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
6474 FixedArray* elements = FixedArray::cast(elements_array->elements());
6475 for (int i = 0; i < elements_length; i += 2) {
6476 RUNTIME_ASSERT(elements->get(i)->IsNumber());
6477 CONVERT_CHECKED(String, string, elements->get(i + 1));
6478 int length = string->length();
6479 if (is_ascii && !string->IsAsciiRepresentation()) {
6480 is_ascii = false;
6481 max_string_length = SeqTwoByteString::kMaxLength;
6482 }
6483 if (length > max_string_length ||
6484 max_string_length - length < string_length) {
6485 overflow = true;
6486 break;
6487 }
6488 string_length += length;
6489 }
6490 int separator_length = separator->length();
6491 if (!overflow && separator_length > 0) {
6492 if (array_length <= 0x7fffffffu) {
6493 int separator_count = static_cast<int>(array_length) - 1;
6494 int remaining_length = max_string_length - string_length;
6495 if ((remaining_length / separator_length) >= separator_count) {
6496 string_length += separator_length * (array_length - 1);
6497 } else {
6498 // Not room for the separators within the maximal string length.
6499 overflow = true;
6500 }
6501 } else {
6502 // Nonempty separator and at least 2^31-1 separators necessary
6503 // means that the string is too large to create.
6504 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
6505 overflow = true;
6506 }
6507 }
6508 if (overflow) {
6509 // Throw OutOfMemory exception for creating too large a string.
6510 V8::FatalProcessOutOfMemory("Array join result too large.");
6511 }
6512
6513 if (is_ascii) {
6514 MaybeObject* result_allocation =
6515 isolate->heap()->AllocateRawAsciiString(string_length);
6516 if (result_allocation->IsFailure()) return result_allocation;
6517 SeqAsciiString* result_string =
6518 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
6519 JoinSparseArrayWithSeparator<char>(elements,
6520 elements_length,
6521 array_length,
6522 separator,
6523 Vector<char>(result_string->GetChars(),
6524 string_length));
6525 return result_string;
6526 } else {
6527 MaybeObject* result_allocation =
6528 isolate->heap()->AllocateRawTwoByteString(string_length);
6529 if (result_allocation->IsFailure()) return result_allocation;
6530 SeqTwoByteString* result_string =
6531 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
6532 JoinSparseArrayWithSeparator<uc16>(elements,
6533 elements_length,
6534 array_length,
6535 separator,
6536 Vector<uc16>(result_string->GetChars(),
6537 string_length));
6538 return result_string;
6539 }
6540}
6541
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006542
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006543RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006544 NoHandleAllocation ha;
6545 ASSERT(args.length() == 2);
6546
6547 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6548 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006549 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006550}
6551
6552
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006553RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006554 NoHandleAllocation ha;
6555 ASSERT(args.length() == 2);
6556
6557 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6558 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006559 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006560}
6561
6562
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006563RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006564 NoHandleAllocation ha;
6565 ASSERT(args.length() == 2);
6566
6567 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6568 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006569 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006570}
6571
6572
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006573RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006574 NoHandleAllocation ha;
6575 ASSERT(args.length() == 1);
6576
6577 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006578 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006579}
6580
6581
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006582RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006583 NoHandleAllocation ha;
6584 ASSERT(args.length() == 2);
6585
6586 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6587 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006588 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006589}
6590
6591
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006592RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006593 NoHandleAllocation ha;
6594 ASSERT(args.length() == 2);
6595
6596 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
6597 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006598 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006599}
6600
6601
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006602RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006603 NoHandleAllocation ha;
6604 ASSERT(args.length() == 2);
6605
6606 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6607 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006608 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006609}
6610
6611
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006612RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006613 NoHandleAllocation ha;
6614 ASSERT(args.length() == 2);
6615
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006616 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6617 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006618 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
6619 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
6620 if (x == y) return Smi::FromInt(EQUAL);
6621 Object* result;
6622 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
6623 result = Smi::FromInt(EQUAL);
6624 } else {
6625 result = Smi::FromInt(NOT_EQUAL);
6626 }
6627 return result;
6628}
6629
6630
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006631RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006632 NoHandleAllocation ha;
6633 ASSERT(args.length() == 2);
6634
6635 CONVERT_CHECKED(String, x, args[0]);
6636 CONVERT_CHECKED(String, y, args[1]);
6637
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006638 bool not_equal = !x->Equals(y);
6639 // This is slightly convoluted because the value that signifies
6640 // equality is 0 and inequality is 1 so we have to negate the result
6641 // from String::Equals.
6642 ASSERT(not_equal == 0 || not_equal == 1);
6643 STATIC_CHECK(EQUAL == 0);
6644 STATIC_CHECK(NOT_EQUAL == 1);
6645 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006646}
6647
6648
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006649RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006650 NoHandleAllocation ha;
6651 ASSERT(args.length() == 3);
6652
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006653 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6654 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006655 if (isnan(x) || isnan(y)) return args[2];
6656 if (x == y) return Smi::FromInt(EQUAL);
6657 if (isless(x, y)) return Smi::FromInt(LESS);
6658 return Smi::FromInt(GREATER);
6659}
6660
6661
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006662// Compare two Smis as if they were converted to strings and then
6663// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006664RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006665 NoHandleAllocation ha;
6666 ASSERT(args.length() == 2);
6667
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006668 // Extract the integer values from the Smis.
6669 CONVERT_CHECKED(Smi, x, args[0]);
6670 CONVERT_CHECKED(Smi, y, args[1]);
6671 int x_value = x->value();
6672 int y_value = y->value();
6673
6674 // If the integers are equal so are the string representations.
6675 if (x_value == y_value) return Smi::FromInt(EQUAL);
6676
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006677 // If one of the integers is zero the normal integer order is the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006678 // same as the lexicographic order of the string representations.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006679 if (x_value == 0 || y_value == 0)
6680 return Smi::FromInt(x_value < y_value ? LESS : GREATER);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006681
ager@chromium.org32912102009-01-16 10:38:43 +00006682 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006683 // smallest because the char code of '-' is less than the char code
6684 // of any digit. Otherwise, we make both values positive.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006685
6686 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
6687 // architectures using 32-bit Smis.
6688 uint32_t x_scaled = x_value;
6689 uint32_t y_scaled = y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006690 if (x_value < 0 || y_value < 0) {
6691 if (y_value >= 0) return Smi::FromInt(LESS);
6692 if (x_value >= 0) return Smi::FromInt(GREATER);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006693 x_scaled = -x_value;
6694 y_scaled = -y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006695 }
6696
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006697 static const uint32_t kPowersOf10[] = {
6698 1, 10, 100, 1000, 10*1000, 100*1000,
6699 1000*1000, 10*1000*1000, 100*1000*1000,
6700 1000*1000*1000
6701 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006702
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006703 // If the integers have the same number of decimal digits they can be
6704 // compared directly as the numeric order is the same as the
6705 // lexicographic order. If one integer has fewer digits, it is scaled
6706 // by some power of 10 to have the same number of digits as the longer
6707 // integer. If the scaled integers are equal it means the shorter
6708 // integer comes first in the lexicographic order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006709
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006710 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
6711 int x_log2 = IntegerLog2(x_scaled);
6712 int x_log10 = ((x_log2 + 1) * 1233) >> 12;
6713 x_log10 -= x_scaled < kPowersOf10[x_log10];
6714
6715 int y_log2 = IntegerLog2(y_scaled);
6716 int y_log10 = ((y_log2 + 1) * 1233) >> 12;
6717 y_log10 -= y_scaled < kPowersOf10[y_log10];
6718
6719 int tie = EQUAL;
6720
6721 if (x_log10 < y_log10) {
6722 // X has fewer digits. We would like to simply scale up X but that
6723 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
6724 // be scaled up to 9_000_000_000. So we scale up by the next
6725 // smallest power and scale down Y to drop one digit. It is OK to
6726 // drop one digit from the longer integer since the final digit is
6727 // past the length of the shorter integer.
6728 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
6729 y_scaled /= 10;
6730 tie = LESS;
6731 } else if (y_log10 < x_log10) {
6732 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
6733 x_scaled /= 10;
6734 tie = GREATER;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006735 }
6736
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006737 if (x_scaled < y_scaled) return Smi::FromInt(LESS);
6738 if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
6739 return Smi::FromInt(tie);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006740}
6741
6742
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006743static Object* StringInputBufferCompare(RuntimeState* state,
6744 String* x,
6745 String* y) {
6746 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
6747 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006748 bufx.Reset(x);
6749 bufy.Reset(y);
6750 while (bufx.has_more() && bufy.has_more()) {
6751 int d = bufx.GetNext() - bufy.GetNext();
6752 if (d < 0) return Smi::FromInt(LESS);
6753 else if (d > 0) return Smi::FromInt(GREATER);
6754 }
6755
6756 // x is (non-trivial) prefix of y:
6757 if (bufy.has_more()) return Smi::FromInt(LESS);
6758 // y is prefix of x:
6759 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
6760}
6761
6762
6763static Object* FlatStringCompare(String* x, String* y) {
6764 ASSERT(x->IsFlat());
6765 ASSERT(y->IsFlat());
6766 Object* equal_prefix_result = Smi::FromInt(EQUAL);
6767 int prefix_length = x->length();
6768 if (y->length() < prefix_length) {
6769 prefix_length = y->length();
6770 equal_prefix_result = Smi::FromInt(GREATER);
6771 } else if (y->length() > prefix_length) {
6772 equal_prefix_result = Smi::FromInt(LESS);
6773 }
6774 int r;
6775 if (x->IsAsciiRepresentation()) {
6776 Vector<const char> x_chars = x->ToAsciiVector();
6777 if (y->IsAsciiRepresentation()) {
6778 Vector<const char> y_chars = y->ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006779 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006780 } else {
6781 Vector<const uc16> y_chars = y->ToUC16Vector();
6782 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6783 }
6784 } else {
6785 Vector<const uc16> x_chars = x->ToUC16Vector();
6786 if (y->IsAsciiRepresentation()) {
6787 Vector<const char> y_chars = y->ToAsciiVector();
6788 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6789 } else {
6790 Vector<const uc16> y_chars = y->ToUC16Vector();
6791 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6792 }
6793 }
6794 Object* result;
6795 if (r == 0) {
6796 result = equal_prefix_result;
6797 } else {
6798 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
6799 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006800 ASSERT(result ==
6801 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006802 return result;
6803}
6804
6805
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006806RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006807 NoHandleAllocation ha;
6808 ASSERT(args.length() == 2);
6809
6810 CONVERT_CHECKED(String, x, args[0]);
6811 CONVERT_CHECKED(String, y, args[1]);
6812
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006813 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006814
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006815 // A few fast case tests before we flatten.
6816 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006817 if (y->length() == 0) {
6818 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006819 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006820 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006821 return Smi::FromInt(LESS);
6822 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006823
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006824 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006825 if (d < 0) return Smi::FromInt(LESS);
6826 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006827
lrn@chromium.org303ada72010-10-27 09:33:13 +00006828 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006829 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006830 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6831 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006832 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006833 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6834 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006835
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006836 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006837 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006838}
6839
6840
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006841RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006842 NoHandleAllocation ha;
6843 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006844 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006845
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006846 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006847 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006848}
6849
6850
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006851RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006852 NoHandleAllocation ha;
6853 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006854 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006855
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006856 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006857 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006858}
6859
6860
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006861RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006862 NoHandleAllocation ha;
6863 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006864 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006865
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006866 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006867 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006868}
6869
6870
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006871static const double kPiDividedBy4 = 0.78539816339744830962;
6872
6873
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006874RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006875 NoHandleAllocation ha;
6876 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006877 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006878
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006879 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6880 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006881 double result;
6882 if (isinf(x) && isinf(y)) {
6883 // Make sure that the result in case of two infinite arguments
6884 // is a multiple of Pi / 4. The sign of the result is determined
6885 // by the first argument (x) and the sign of the second argument
6886 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006887 int multiplier = (x < 0) ? -1 : 1;
6888 if (y < 0) multiplier *= 3;
6889 result = multiplier * kPiDividedBy4;
6890 } else {
6891 result = atan2(x, y);
6892 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006893 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006894}
6895
6896
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006897RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006898 NoHandleAllocation ha;
6899 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006900 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006901
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006902 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006903 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006904}
6905
6906
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006907RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006908 NoHandleAllocation ha;
6909 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006910 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006911
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006912 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006913 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006914}
6915
6916
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006917RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006918 NoHandleAllocation ha;
6919 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006920 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006921
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006922 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006923 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006924}
6925
6926
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006927RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006928 NoHandleAllocation ha;
6929 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006930 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006931
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006932 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006933 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006934}
6935
6936
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006937RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006938 NoHandleAllocation ha;
6939 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006940 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006941
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006942 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006943 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006944}
6945
6946
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006947RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006948 NoHandleAllocation ha;
6949 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006950 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006951
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006952 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006953
6954 // If the second argument is a smi, it is much faster to call the
6955 // custom powi() function than the generic pow().
6956 if (args[1]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006957 int y = args.smi_at(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006958 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006959 }
6960
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006961 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006962 return isolate->heap()->AllocateHeapNumber(power_double_double(x, y));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006963}
6964
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006965// Fast version of Math.pow if we know that y is not an integer and
6966// y is not -0.5 or 0.5. Used as slowcase from codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006967RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006968 NoHandleAllocation ha;
6969 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006970 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6971 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006972 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006973 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006974 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006975 return isolate->heap()->nan_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006976 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006977 return isolate->heap()->AllocateHeapNumber(pow(x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006978 }
6979}
6980
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006981
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006982RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006983 NoHandleAllocation ha;
6984 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006985 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006986
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006987 if (!args[0]->IsHeapNumber()) {
6988 // Must be smi. Return the argument unchanged for all the other types
6989 // to make fuzz-natives test happy.
6990 return args[0];
6991 }
6992
6993 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
6994
6995 double value = number->value();
6996 int exponent = number->get_exponent();
6997 int sign = number->get_sign();
6998
danno@chromium.org160a7b02011-04-18 15:51:38 +00006999 if (exponent < -1) {
7000 // Number in range ]-0.5..0.5[. These always round to +/-zero.
7001 if (sign) return isolate->heap()->minus_zero_value();
7002 return Smi::FromInt(0);
7003 }
7004
7005 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
7006 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
7007 // agument holds for 32-bit smis).
7008 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007009 return Smi::FromInt(static_cast<int>(value + 0.5));
7010 }
7011
7012 // If the magnitude is big enough, there's no place for fraction part. If we
7013 // try to add 0.5 to this number, 1.0 will be added instead.
7014 if (exponent >= 52) {
7015 return number;
7016 }
7017
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007018 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007019
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007020 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007021 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007022}
7023
7024
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007025RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007026 NoHandleAllocation ha;
7027 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007028 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007029
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007030 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007031 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007032}
7033
7034
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007035RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007036 NoHandleAllocation ha;
7037 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007038 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007039
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007040 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007041 return isolate->heap()->AllocateHeapNumber(sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007042}
7043
7044
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007045RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007046 NoHandleAllocation ha;
7047 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007048 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007049
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007050 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007051 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007052}
7053
7054
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007055static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007056 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
7057 181, 212, 243, 273, 304, 334};
7058 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
7059 182, 213, 244, 274, 305, 335};
7060
7061 year += month / 12;
7062 month %= 12;
7063 if (month < 0) {
7064 year--;
7065 month += 12;
7066 }
7067
7068 ASSERT(month >= 0);
7069 ASSERT(month < 12);
7070
7071 // year_delta is an arbitrary number such that:
7072 // a) year_delta = -1 (mod 400)
7073 // b) year + year_delta > 0 for years in the range defined by
7074 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
7075 // Jan 1 1970. This is required so that we don't run into integer
7076 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007077 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007078 // operations.
7079 static const int year_delta = 399999;
7080 static const int base_day = 365 * (1970 + year_delta) +
7081 (1970 + year_delta) / 4 -
7082 (1970 + year_delta) / 100 +
7083 (1970 + year_delta) / 400;
7084
7085 int year1 = year + year_delta;
7086 int day_from_year = 365 * year1 +
7087 year1 / 4 -
7088 year1 / 100 +
7089 year1 / 400 -
7090 base_day;
7091
7092 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007093 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007094 }
7095
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007096 return day_from_year + day_from_month_leap[month] + day - 1;
7097}
7098
7099
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007100RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007101 NoHandleAllocation ha;
7102 ASSERT(args.length() == 3);
7103
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007104 CONVERT_SMI_ARG_CHECKED(year, 0);
7105 CONVERT_SMI_ARG_CHECKED(month, 1);
7106 CONVERT_SMI_ARG_CHECKED(date, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007107
7108 return Smi::FromInt(MakeDay(year, month, date));
7109}
7110
7111
7112static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
7113static const int kDaysIn4Years = 4 * 365 + 1;
7114static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
7115static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
7116static const int kDays1970to2000 = 30 * 365 + 7;
7117static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
7118 kDays1970to2000;
7119static const int kYearsOffset = 400000;
7120
7121static const char kDayInYear[] = {
7122 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7123 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7124 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7125 22, 23, 24, 25, 26, 27, 28,
7126 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7127 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7128 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7129 22, 23, 24, 25, 26, 27, 28, 29, 30,
7130 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7131 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7132 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7133 22, 23, 24, 25, 26, 27, 28, 29, 30,
7134 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7135 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7136 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7137 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7138 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7139 22, 23, 24, 25, 26, 27, 28, 29, 30,
7140 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7141 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7142 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7143 22, 23, 24, 25, 26, 27, 28, 29, 30,
7144 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7145 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7146
7147 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7148 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7149 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7150 22, 23, 24, 25, 26, 27, 28,
7151 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7152 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7153 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7154 22, 23, 24, 25, 26, 27, 28, 29, 30,
7155 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7156 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7157 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7158 22, 23, 24, 25, 26, 27, 28, 29, 30,
7159 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7160 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7161 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7162 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7163 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7164 22, 23, 24, 25, 26, 27, 28, 29, 30,
7165 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7166 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7167 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7168 22, 23, 24, 25, 26, 27, 28, 29, 30,
7169 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7170 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7171
7172 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7173 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7174 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7175 22, 23, 24, 25, 26, 27, 28, 29,
7176 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7177 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7178 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7179 22, 23, 24, 25, 26, 27, 28, 29, 30,
7180 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7181 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7182 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7183 22, 23, 24, 25, 26, 27, 28, 29, 30,
7184 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7185 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7186 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7187 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7188 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7189 22, 23, 24, 25, 26, 27, 28, 29, 30,
7190 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7191 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7192 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7193 22, 23, 24, 25, 26, 27, 28, 29, 30,
7194 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7195 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7196
7197 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7198 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7199 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7200 22, 23, 24, 25, 26, 27, 28,
7201 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7202 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7203 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7204 22, 23, 24, 25, 26, 27, 28, 29, 30,
7205 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7206 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7207 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7208 22, 23, 24, 25, 26, 27, 28, 29, 30,
7209 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7210 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7211 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7212 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7213 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7214 22, 23, 24, 25, 26, 27, 28, 29, 30,
7215 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7216 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7217 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7218 22, 23, 24, 25, 26, 27, 28, 29, 30,
7219 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7220 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
7221
7222static const char kMonthInYear[] = {
7223 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7224 0, 0, 0, 0, 0, 0,
7225 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7226 1, 1, 1,
7227 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7228 2, 2, 2, 2, 2, 2,
7229 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7230 3, 3, 3, 3, 3,
7231 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7232 4, 4, 4, 4, 4, 4,
7233 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7234 5, 5, 5, 5, 5,
7235 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7236 6, 6, 6, 6, 6, 6,
7237 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7238 7, 7, 7, 7, 7, 7,
7239 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7240 8, 8, 8, 8, 8,
7241 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7242 9, 9, 9, 9, 9, 9,
7243 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7244 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7245 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7246 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7247
7248 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7249 0, 0, 0, 0, 0, 0,
7250 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7251 1, 1, 1,
7252 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7253 2, 2, 2, 2, 2, 2,
7254 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7255 3, 3, 3, 3, 3,
7256 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7257 4, 4, 4, 4, 4, 4,
7258 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7259 5, 5, 5, 5, 5,
7260 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7261 6, 6, 6, 6, 6, 6,
7262 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7263 7, 7, 7, 7, 7, 7,
7264 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7265 8, 8, 8, 8, 8,
7266 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7267 9, 9, 9, 9, 9, 9,
7268 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7269 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7270 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7271 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7272
7273 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7274 0, 0, 0, 0, 0, 0,
7275 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7276 1, 1, 1, 1,
7277 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7278 2, 2, 2, 2, 2, 2,
7279 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7280 3, 3, 3, 3, 3,
7281 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7282 4, 4, 4, 4, 4, 4,
7283 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7284 5, 5, 5, 5, 5,
7285 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7286 6, 6, 6, 6, 6, 6,
7287 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7288 7, 7, 7, 7, 7, 7,
7289 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7290 8, 8, 8, 8, 8,
7291 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7292 9, 9, 9, 9, 9, 9,
7293 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7294 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7295 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7296 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7297
7298 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7299 0, 0, 0, 0, 0, 0,
7300 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7301 1, 1, 1,
7302 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7303 2, 2, 2, 2, 2, 2,
7304 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7305 3, 3, 3, 3, 3,
7306 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7307 4, 4, 4, 4, 4, 4,
7308 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7309 5, 5, 5, 5, 5,
7310 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7311 6, 6, 6, 6, 6, 6,
7312 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7313 7, 7, 7, 7, 7, 7,
7314 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7315 8, 8, 8, 8, 8,
7316 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7317 9, 9, 9, 9, 9, 9,
7318 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7319 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7320 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7321 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
7322
7323
7324// This function works for dates from 1970 to 2099.
7325static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007326 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007327#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007328 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007329#endif
7330
7331 year = 1970 + (4 * date + 2) / kDaysIn4Years;
7332 date %= kDaysIn4Years;
7333
7334 month = kMonthInYear[date];
7335 day = kDayInYear[date];
7336
7337 ASSERT(MakeDay(year, month, day) == save_date);
7338}
7339
7340
7341static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007342 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007343#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007344 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007345#endif
7346
7347 date += kDaysOffset;
7348 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
7349 date %= kDaysIn400Years;
7350
7351 ASSERT(MakeDay(year, 0, 1) + date == save_date);
7352
7353 date--;
7354 int yd1 = date / kDaysIn100Years;
7355 date %= kDaysIn100Years;
7356 year += 100 * yd1;
7357
7358 date++;
7359 int yd2 = date / kDaysIn4Years;
7360 date %= kDaysIn4Years;
7361 year += 4 * yd2;
7362
7363 date--;
7364 int yd3 = date / 365;
7365 date %= 365;
7366 year += yd3;
7367
7368 bool is_leap = (!yd1 || yd2) && !yd3;
7369
7370 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007371 ASSERT(is_leap || (date >= 0));
7372 ASSERT((date < 365) || (is_leap && (date < 366)));
7373 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
7374 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
7375 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007376
7377 if (is_leap) {
7378 day = kDayInYear[2*365 + 1 + date];
7379 month = kMonthInYear[2*365 + 1 + date];
7380 } else {
7381 day = kDayInYear[date];
7382 month = kMonthInYear[date];
7383 }
7384
7385 ASSERT(MakeDay(year, month, day) == save_date);
7386}
7387
7388
7389static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007390 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007391 if (date >= 0 && date < 32 * kDaysIn4Years) {
7392 DateYMDFromTimeAfter1970(date, year, month, day);
7393 } else {
7394 DateYMDFromTimeSlow(date, year, month, day);
7395 }
7396}
7397
7398
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007399RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007400 NoHandleAllocation ha;
7401 ASSERT(args.length() == 2);
7402
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007403 CONVERT_DOUBLE_ARG_CHECKED(t, 0);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007404 CONVERT_CHECKED(JSArray, res_array, args[1]);
7405
7406 int year, month, day;
7407 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7408
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007409 RUNTIME_ASSERT(res_array->elements()->map() ==
7410 isolate->heap()->fixed_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007411 FixedArray* elms = FixedArray::cast(res_array->elements());
7412 RUNTIME_ASSERT(elms->length() == 3);
7413
7414 elms->set(0, Smi::FromInt(year));
7415 elms->set(1, Smi::FromInt(month));
7416 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007417
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007418 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007419}
7420
7421
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007422RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007423 HandleScope scope(isolate);
7424 ASSERT(args.length() == 3);
7425
7426 Handle<JSFunction> callee = args.at<JSFunction>(0);
7427 Object** parameters = reinterpret_cast<Object**>(args[1]);
7428 const int argument_count = Smi::cast(args[2])->value();
7429
7430 Handle<JSObject> result =
7431 isolate->factory()->NewArgumentsObject(callee, argument_count);
7432 // Allocate the elements if needed.
7433 int parameter_count = callee->shared()->formal_parameter_count();
7434 if (argument_count > 0) {
7435 if (parameter_count > 0) {
7436 int mapped_count = Min(argument_count, parameter_count);
7437 Handle<FixedArray> parameter_map =
7438 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
7439 parameter_map->set_map(
7440 isolate->heap()->non_strict_arguments_elements_map());
7441
7442 Handle<Map> old_map(result->map());
7443 Handle<Map> new_map =
7444 isolate->factory()->CopyMapDropTransitions(old_map);
7445 new_map->set_elements_kind(JSObject::NON_STRICT_ARGUMENTS_ELEMENTS);
7446
7447 result->set_map(*new_map);
7448 result->set_elements(*parameter_map);
7449
7450 // Store the context and the arguments array at the beginning of the
7451 // parameter map.
7452 Handle<Context> context(isolate->context());
7453 Handle<FixedArray> arguments =
7454 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7455 parameter_map->set(0, *context);
7456 parameter_map->set(1, *arguments);
7457
7458 // Loop over the actual parameters backwards.
7459 int index = argument_count - 1;
7460 while (index >= mapped_count) {
7461 // These go directly in the arguments array and have no
7462 // corresponding slot in the parameter map.
7463 arguments->set(index, *(parameters - index - 1));
7464 --index;
7465 }
7466
7467 ScopeInfo<> scope_info(callee->shared()->scope_info());
7468 while (index >= 0) {
7469 // Detect duplicate names to the right in the parameter list.
7470 Handle<String> name = scope_info.parameter_name(index);
7471 int context_slot_count = scope_info.number_of_context_slots();
7472 bool duplicate = false;
7473 for (int j = index + 1; j < parameter_count; ++j) {
7474 if (scope_info.parameter_name(j).is_identical_to(name)) {
7475 duplicate = true;
7476 break;
7477 }
7478 }
7479
7480 if (duplicate) {
7481 // This goes directly in the arguments array with a hole in the
7482 // parameter map.
7483 arguments->set(index, *(parameters - index - 1));
7484 parameter_map->set_the_hole(index + 2);
7485 } else {
7486 // The context index goes in the parameter map with a hole in the
7487 // arguments array.
7488 int context_index = -1;
7489 for (int j = Context::MIN_CONTEXT_SLOTS;
7490 j < context_slot_count;
7491 ++j) {
7492 if (scope_info.context_slot_name(j).is_identical_to(name)) {
7493 context_index = j;
7494 break;
7495 }
7496 }
7497 ASSERT(context_index >= 0);
7498 arguments->set_the_hole(index);
7499 parameter_map->set(index + 2, Smi::FromInt(context_index));
7500 }
7501
7502 --index;
7503 }
7504 } else {
7505 // If there is no aliasing, the arguments object elements are not
7506 // special in any way.
7507 Handle<FixedArray> elements =
7508 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7509 result->set_elements(*elements);
7510 for (int i = 0; i < argument_count; ++i) {
7511 elements->set(i, *(parameters - i - 1));
7512 }
7513 }
7514 }
7515 return *result;
7516}
7517
7518
7519RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007520 NoHandleAllocation ha;
7521 ASSERT(args.length() == 3);
7522
7523 JSFunction* callee = JSFunction::cast(args[0]);
7524 Object** parameters = reinterpret_cast<Object**>(args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007525 const int length = args.smi_at(2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007526
lrn@chromium.org303ada72010-10-27 09:33:13 +00007527 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007528 { MaybeObject* maybe_result =
7529 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007530 if (!maybe_result->ToObject(&result)) return maybe_result;
7531 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007532 // Allocate the elements if needed.
7533 if (length > 0) {
7534 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007535 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007536 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007537 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7538 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007539
7540 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007541 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007542 array->set_map(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007543 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007544
7545 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007546 for (int i = 0; i < length; i++) {
7547 array->set(i, *--parameters, mode);
7548 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007549 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007550 }
7551 return result;
7552}
7553
7554
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007555RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007556 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007557 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00007558 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007559 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007560 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007561
whesse@chromium.org7b260152011-06-20 15:33:18 +00007562 // The caller ensures that we pretenure closures that are assigned
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007563 // directly to properties.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007564 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007565 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007566 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
7567 context,
7568 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007569 return *result;
7570}
7571
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007572
7573static SmartPointer<Object**> GetNonBoundArguments(int bound_argc,
7574 int* total_argc) {
7575 // Find frame containing arguments passed to the caller.
7576 JavaScriptFrameIterator it;
7577 JavaScriptFrame* frame = it.frame();
7578 List<JSFunction*> functions(2);
7579 frame->GetFunctions(&functions);
7580 if (functions.length() > 1) {
7581 int inlined_frame_index = functions.length() - 1;
7582 JSFunction* inlined_function = functions[inlined_frame_index];
7583 int args_count = inlined_function->shared()->formal_parameter_count();
7584 ScopedVector<SlotRef> args_slots(args_count);
7585 SlotRef::ComputeSlotMappingForArguments(frame,
7586 inlined_frame_index,
7587 &args_slots);
7588
7589 *total_argc = bound_argc + args_count;
7590 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7591 for (int i = 0; i < args_count; i++) {
7592 Handle<Object> val = args_slots[i].GetValue();
7593 param_data[bound_argc + i] = val.location();
7594 }
7595 return param_data;
7596 } else {
7597 it.AdvanceToArgumentsFrame();
7598 frame = it.frame();
7599 int args_count = frame->ComputeParametersCount();
7600
7601 *total_argc = bound_argc + args_count;
7602 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7603 for (int i = 0; i < args_count; i++) {
7604 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
7605 param_data[bound_argc + i] = val.location();
7606 }
7607 return param_data;
7608 }
7609}
7610
7611
7612RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007613 HandleScope scope(isolate);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007614 ASSERT(args.length() == 2);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007615 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007616 CONVERT_ARG_CHECKED(JSFunction, function, 0);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007617
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007618 // Second argument is either null or an array of bound arguments.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007619 Handle<FixedArray> bound_args;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007620 int bound_argc = 0;
7621 if (!args[1]->IsNull()) {
7622 CONVERT_ARG_CHECKED(JSArray, params, 1);
7623 RUNTIME_ASSERT(params->HasFastElements());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007624 bound_args = Handle<FixedArray>(FixedArray::cast(params->elements()));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007625 bound_argc = Smi::cast(params->length())->value();
7626 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007627
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007628 int total_argc = 0;
7629 SmartPointer<Object**> param_data =
7630 GetNonBoundArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007631 for (int i = 0; i < bound_argc; i++) {
7632 Handle<Object> val = Handle<Object>(bound_args->get(i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007633 param_data[i] = val.location();
7634 }
7635
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007636 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007637 Handle<Object> result =
7638 Execution::New(function, total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007639 if (exception) {
7640 return Failure::Exception();
7641 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007642
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007643 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007644 return *result;
7645}
7646
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007647
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007648static void TrySettingInlineConstructStub(Isolate* isolate,
7649 Handle<JSFunction> function) {
7650 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00007651 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007652 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00007653 }
7654 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007655 ConstructStubCompiler compiler;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00007656 MaybeObject* code = compiler.CompileConstructStub(*function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007657 if (!code->IsFailure()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007658 function->shared()->set_construct_stub(
7659 Code::cast(code->ToObjectUnchecked()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007660 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007661 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007662}
7663
7664
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007665RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007666 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007667 ASSERT(args.length() == 1);
7668
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007669 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007670
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007671 // If the constructor isn't a proper function we throw a type error.
7672 if (!constructor->IsJSFunction()) {
7673 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7674 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007675 isolate->factory()->NewTypeError("not_constructor", arguments);
7676 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007677 }
7678
7679 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007680
7681 // If function should not have prototype, construction is not allowed. In this
7682 // case generated code bailouts here, since function has no initial_map.
whesse@chromium.org7b260152011-06-20 15:33:18 +00007683 if (!function->should_have_prototype() && !function->shared()->bound()) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007684 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7685 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007686 isolate->factory()->NewTypeError("not_constructor", arguments);
7687 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007688 }
7689
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007690#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007691 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007692 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007693 if (debug->StepInActive()) {
7694 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007695 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007696#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007697
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007698 if (function->has_initial_map()) {
7699 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007700 // The 'Function' function ignores the receiver object when
7701 // called using 'new' and creates a new JSFunction object that
7702 // is returned. The receiver object is only used for error
7703 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007704 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007705 // allocate JSFunctions since it does not properly initialize
7706 // the shared part of the function. Since the receiver is
7707 // ignored anyway, we use the global object as the receiver
7708 // instead of a new JSFunction object. This way, errors are
7709 // reported the same way whether or not 'Function' is called
7710 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007711 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007712 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007713 }
7714
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007715 // The function should be compiled for the optimization hints to be
7716 // available. We cannot use EnsureCompiled because that forces a
7717 // compilation through the shared function info which makes it
7718 // impossible for us to optimize.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007719 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007720 if (!function->is_compiled()) CompileLazy(function, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007721
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007722 if (!function->has_initial_map() &&
7723 shared->IsInobjectSlackTrackingInProgress()) {
7724 // The tracking is already in progress for another function. We can only
7725 // track one initial_map at a time, so we force the completion before the
7726 // function is called as a constructor for the first time.
7727 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007728 }
7729
7730 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007731 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
7732 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007733 // Delay setting the stub if inobject slack tracking is in progress.
7734 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007735 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007736 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007737
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007738 isolate->counters()->constructed_objects()->Increment();
7739 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007740
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007741 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007742}
7743
7744
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007745RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007746 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007747 ASSERT(args.length() == 1);
7748
7749 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7750 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007751 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007752
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007753 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007754}
7755
7756
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007757RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007758 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007759 ASSERT(args.length() == 1);
7760
7761 Handle<JSFunction> function = args.at<JSFunction>(0);
7762#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00007763 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007764 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007765 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007766 PrintF("]\n");
7767 }
7768#endif
7769
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007770 // Compile the target function. Here we compile using CompileLazyInLoop in
7771 // order to get the optimized version. This helps code like delta-blue
7772 // that calls performance-critical routines through constructors. A
7773 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
7774 // direct call. Since the in-loop tracking takes place through CallICs
7775 // this means that things called through constructors are never known to
7776 // be in loops. We compile them as if they are in loops here just in case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007777 ASSERT(!function->is_compiled());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007778 if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007779 return Failure::Exception();
7780 }
7781
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007782 // All done. Return the compiled code.
7783 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007784 return function->code();
7785}
7786
7787
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007788RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007789 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007790 ASSERT(args.length() == 1);
7791 Handle<JSFunction> function = args.at<JSFunction>(0);
7792 // If the function is not optimizable or debugger is active continue using the
7793 // code from the full compiler.
7794 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007795 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007796 if (FLAG_trace_opt) {
7797 PrintF("[failed to optimize ");
7798 function->PrintName();
7799 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
7800 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007801 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007802 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007803 function->ReplaceCode(function->shared()->code());
7804 return function->code();
7805 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007806 if (CompileOptimized(function, AstNode::kNoNumber, CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007807 return function->code();
7808 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007809 if (FLAG_trace_opt) {
7810 PrintF("[failed to optimize ");
7811 function->PrintName();
7812 PrintF(": optimized compilation failed]\n");
7813 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007814 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007815 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007816}
7817
7818
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007819RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007820 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007821 ASSERT(args.length() == 1);
7822 RUNTIME_ASSERT(args[0]->IsSmi());
7823 Deoptimizer::BailoutType type =
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007824 static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007825 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
7826 ASSERT(isolate->heap()->IsAllocationAllowed());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007827 int frames = deoptimizer->output_count();
7828
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007829 deoptimizer->MaterializeHeapNumbers();
7830 delete deoptimizer;
7831
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007832 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007833 JavaScriptFrame* frame = NULL;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007834 for (int i = 0; i < frames - 1; i++) it.Advance();
7835 frame = it.frame();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007836
7837 RUNTIME_ASSERT(frame->function()->IsJSFunction());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007838 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007839 Handle<Object> arguments;
7840 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007841 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007842 if (arguments.is_null()) {
7843 // FunctionGetArguments can't throw an exception, so cast away the
7844 // doubt with an assert.
7845 arguments = Handle<Object>(
7846 Accessors::FunctionGetArguments(*function,
7847 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007848 ASSERT(*arguments != isolate->heap()->null_value());
7849 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007850 }
7851 frame->SetExpression(i, *arguments);
7852 }
7853 }
7854
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007855 if (type == Deoptimizer::EAGER) {
7856 RUNTIME_ASSERT(function->IsOptimized());
7857 } else {
7858 RUNTIME_ASSERT(!function->IsOptimized());
7859 }
7860
7861 // Avoid doing too much work when running with --always-opt and keep
7862 // the optimized code around.
7863 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007864 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007865 }
7866
7867 // Count the number of optimized activations of the function.
7868 int activations = 0;
7869 while (!it.done()) {
7870 JavaScriptFrame* frame = it.frame();
7871 if (frame->is_optimized() && frame->function() == *function) {
7872 activations++;
7873 }
7874 it.Advance();
7875 }
7876
7877 // TODO(kasperl): For now, we cannot support removing the optimized
7878 // code when we have recursive invocations of the same function.
7879 if (activations == 0) {
7880 if (FLAG_trace_deopt) {
7881 PrintF("[removing optimized code for: ");
7882 function->PrintName();
7883 PrintF("]\n");
7884 }
7885 function->ReplaceCode(function->shared()->code());
7886 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007887 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007888}
7889
7890
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007891RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007892 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007893 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007894 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007895}
7896
7897
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007898RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007899 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007900 ASSERT(args.length() == 1);
7901 CONVERT_ARG_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007902 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007903
7904 Deoptimizer::DeoptimizeFunction(*function);
7905
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007906 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007907}
7908
7909
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007910RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
7911#if defined(USE_SIMULATOR)
7912 return isolate->heap()->true_value();
7913#else
7914 return isolate->heap()->false_value();
7915#endif
7916}
7917
7918
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00007919RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
7920 HandleScope scope(isolate);
7921 ASSERT(args.length() == 1);
7922 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7923 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
7924 function->MarkForLazyRecompilation();
7925 return isolate->heap()->undefined_value();
7926}
7927
7928
lrn@chromium.org1c092762011-05-09 09:42:16 +00007929RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
7930 HandleScope scope(isolate);
7931 ASSERT(args.length() == 1);
7932 if (!V8::UseCrankshaft()) {
7933 return Smi::FromInt(4); // 4 == "never".
7934 }
7935 if (FLAG_always_opt) {
7936 return Smi::FromInt(3); // 3 == "always".
7937 }
7938 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7939 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
7940 : Smi::FromInt(2); // 2 == "no".
7941}
7942
7943
7944RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
7945 HandleScope scope(isolate);
7946 ASSERT(args.length() == 1);
7947 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7948 return Smi::FromInt(function->shared()->opt_count());
7949}
7950
7951
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007952RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007953 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007954 ASSERT(args.length() == 1);
7955 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7956
7957 // We're not prepared to handle a function with arguments object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00007958 ASSERT(!function->shared()->uses_arguments());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007959
7960 // We have hit a back edge in an unoptimized frame for a function that was
7961 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007962 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007963 // Keep track of whether we've succeeded in optimizing.
7964 bool succeeded = unoptimized->optimizable();
7965 if (succeeded) {
7966 // If we are trying to do OSR when there are already optimized
7967 // activations of the function, it means (a) the function is directly or
7968 // indirectly recursive and (b) an optimized invocation has been
7969 // deoptimized so that we are currently in an unoptimized activation.
7970 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007971 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007972 while (succeeded && !it.done()) {
7973 JavaScriptFrame* frame = it.frame();
7974 succeeded = !frame->is_optimized() || frame->function() != *function;
7975 it.Advance();
7976 }
7977 }
7978
7979 int ast_id = AstNode::kNoNumber;
7980 if (succeeded) {
7981 // The top JS function is this one, the PC is somewhere in the
7982 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007983 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007984 JavaScriptFrame* frame = it.frame();
7985 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007986 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007987 ASSERT(unoptimized->contains(frame->pc()));
7988
7989 // Use linear search of the unoptimized code's stack check table to find
7990 // the AST id matching the PC.
7991 Address start = unoptimized->instruction_start();
7992 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007993 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007994 uint32_t table_length = Memory::uint32_at(table_cursor);
7995 table_cursor += kIntSize;
7996 for (unsigned i = 0; i < table_length; ++i) {
7997 // Table entries are (AST id, pc offset) pairs.
7998 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
7999 if (pc_offset == target_pc_offset) {
8000 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
8001 break;
8002 }
8003 table_cursor += 2 * kIntSize;
8004 }
8005 ASSERT(ast_id != AstNode::kNoNumber);
8006 if (FLAG_trace_osr) {
8007 PrintF("[replacing on-stack at AST id %d in ", ast_id);
8008 function->PrintName();
8009 PrintF("]\n");
8010 }
8011
8012 // Try to compile the optimized code. A true return value from
8013 // CompileOptimized means that compilation succeeded, not necessarily
8014 // that optimization succeeded.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008015 if (CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
8016 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008017 DeoptimizationInputData* data = DeoptimizationInputData::cast(
8018 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008019 if (data->OsrPcOffset()->value() >= 0) {
8020 if (FLAG_trace_osr) {
8021 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008022 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008023 }
8024 ASSERT(data->OsrAstId()->value() == ast_id);
8025 } else {
8026 // We may never generate the desired OSR entry if we emit an
8027 // early deoptimize.
8028 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008029 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008030 } else {
8031 succeeded = false;
8032 }
8033 }
8034
8035 // Revert to the original stack checks in the original unoptimized code.
8036 if (FLAG_trace_osr) {
8037 PrintF("[restoring original stack checks in ");
8038 function->PrintName();
8039 PrintF("]\n");
8040 }
8041 StackCheckStub check_stub;
8042 Handle<Code> check_code = check_stub.GetCode();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00008043 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008044 Deoptimizer::RevertStackCheckCode(*unoptimized,
8045 *check_code,
8046 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008047
8048 // Allow OSR only at nesting level zero again.
8049 unoptimized->set_allow_osr_at_loop_nesting_level(0);
8050
8051 // If the optimization attempt succeeded, return the AST id tagged as a
8052 // smi. This tells the builtin that we need to translate the unoptimized
8053 // frame to an optimized one.
8054 if (succeeded) {
8055 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
8056 return Smi::FromInt(ast_id);
8057 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008058 if (function->IsMarkedForLazyRecompilation()) {
8059 function->ReplaceCode(function->shared()->code());
8060 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008061 return Smi::FromInt(-1);
8062 }
8063}
8064
8065
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008066RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008067 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008068 ASSERT(args.length() == 1);
8069 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8070 return *Execution::GetFunctionDelegate(args.at<Object>(0));
8071}
8072
8073
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008074RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008075 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008076 ASSERT(args.length() == 1);
8077 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8078 return *Execution::GetConstructorDelegate(args.at<Object>(0));
8079}
8080
8081
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008082RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008083 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00008084 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008085
kasper.lund7276f142008-07-30 08:49:36 +00008086 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00008087 int length = function->shared()->scope_info()->NumberOfContextSlots();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008088 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008089 { MaybeObject* maybe_result =
8090 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008091 if (!maybe_result->ToObject(&result)) return maybe_result;
8092 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008093
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008094 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008095
kasper.lund7276f142008-07-30 08:49:36 +00008096 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008097}
8098
lrn@chromium.org303ada72010-10-27 09:33:13 +00008099
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008100RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
8101 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008102 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008103 JSObject* extension_object;
8104 if (args[0]->IsJSObject()) {
8105 extension_object = JSObject::cast(args[0]);
8106 } else {
8107 // Convert the object to a proper JavaScript object.
8108 MaybeObject* maybe_js_object = args[0]->ToObject();
8109 if (!maybe_js_object->To(&extension_object)) {
8110 if (Failure::cast(maybe_js_object)->IsInternalError()) {
8111 HandleScope scope(isolate);
8112 Handle<Object> handle = args.at<Object>(0);
8113 Handle<Object> result =
8114 isolate->factory()->NewTypeError("with_expression",
8115 HandleVector(&handle, 1));
8116 return isolate->Throw(*result);
8117 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008118 return maybe_js_object;
8119 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008120 }
8121 }
8122
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008123 JSFunction* function;
8124 if (args[1]->IsSmi()) {
8125 // A smi sentinel indicates a context nested inside global code rather
8126 // than some function. There is a canonical empty function that can be
8127 // gotten from the global context.
8128 function = isolate->context()->global_context()->closure();
8129 } else {
8130 function = JSFunction::cast(args[1]);
8131 }
8132
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008133 Context* context;
8134 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008135 isolate->heap()->AllocateWithContext(function,
8136 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008137 extension_object);
8138 if (!maybe_context->To(&context)) return maybe_context;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008139 isolate->set_context(context);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008140 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008141}
8142
8143
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008144RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008145 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008146 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008147 String* name = String::cast(args[0]);
8148 Object* thrown_object = args[1];
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008149 JSFunction* function;
8150 if (args[2]->IsSmi()) {
8151 // A smi sentinel indicates a context nested inside global code rather
8152 // than some function. There is a canonical empty function that can be
8153 // gotten from the global context.
8154 function = isolate->context()->global_context()->closure();
8155 } else {
8156 function = JSFunction::cast(args[2]);
8157 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008158 Context* context;
8159 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008160 isolate->heap()->AllocateCatchContext(function,
8161 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008162 name,
8163 thrown_object);
8164 if (!maybe_context->To(&context)) return maybe_context;
8165 isolate->set_context(context);
8166 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008167}
8168
8169
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008170RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008171 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008172 ASSERT(args.length() == 2);
8173
8174 CONVERT_ARG_CHECKED(Context, context, 0);
8175 CONVERT_ARG_CHECKED(String, name, 1);
8176
8177 int index;
8178 PropertyAttributes attributes;
8179 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008180 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008181
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008182 // If the slot was not found the result is true.
8183 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008184 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008185 }
8186
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008187 // If the slot was found in a context, it should be DONT_DELETE.
8188 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008189 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008190 }
8191
8192 // The slot was found in a JSObject, either a context extension object,
8193 // the global object, or an arguments object. Try to delete it
8194 // (respecting DONT_DELETE). For consistency with V8's usual behavior,
8195 // which allows deleting all parameters in functions that mention
8196 // 'arguments', we do this even for the case of slots found on an
8197 // arguments object. The slot was found on an arguments object if the
8198 // index is non-negative.
8199 Handle<JSObject> object = Handle<JSObject>::cast(holder);
8200 if (index >= 0) {
8201 return object->DeleteElement(index, JSObject::NORMAL_DELETION);
8202 } else {
8203 return object->DeleteProperty(*name, JSObject::NORMAL_DELETION);
8204 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008205}
8206
8207
ager@chromium.orga1645e22009-09-09 19:27:10 +00008208// A mechanism to return a pair of Object pointers in registers (if possible).
8209// How this is achieved is calling convention-dependent.
8210// All currently supported x86 compiles uses calling conventions that are cdecl
8211// variants where a 64-bit value is returned in two 32-bit registers
8212// (edx:eax on ia32, r1:r0 on ARM).
8213// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
8214// In Win64 calling convention, a struct of two pointers is returned in memory,
8215// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008216#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008217struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008218 MaybeObject* x;
8219 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008220};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008221
lrn@chromium.org303ada72010-10-27 09:33:13 +00008222static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008223 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008224 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
8225 // In Win64 they are assigned to a hidden first argument.
8226 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008227}
8228#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008229typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008230static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008231 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008232 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008233}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008234#endif
8235
8236
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008237static inline MaybeObject* Unhole(Heap* heap,
8238 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00008239 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008240 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
8241 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008242 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008243}
8244
8245
danno@chromium.org40cb8782011-05-25 07:58:50 +00008246static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
8247 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008248 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008249 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008250 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008251 JSFunction* context_extension_function =
8252 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008253 // If the holder isn't a context extension object, we just return it
8254 // as the receiver. This allows arguments objects to be used as
8255 // receivers, but only if they are put in the context scope chain
8256 // explicitly via a with-statement.
8257 Object* constructor = holder->map()->constructor();
8258 if (constructor != context_extension_function) return holder;
danno@chromium.org40cb8782011-05-25 07:58:50 +00008259 // Fall back to using the global object as the implicit receiver if
8260 // the property turns out to be a local variable allocated in a
8261 // context extension object - introduced via eval. Implicit global
8262 // receivers are indicated with the hole value.
8263 return isolate->heap()->the_hole_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008264}
8265
8266
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008267static ObjectPair LoadContextSlotHelper(Arguments args,
8268 Isolate* isolate,
8269 bool throw_error) {
8270 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00008271 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008272
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008273 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008274 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008275 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008276 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008277 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008278
8279 int index;
8280 PropertyAttributes attributes;
8281 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008282 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008283
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008284 // If the index is non-negative, the slot has been found in a local
8285 // variable or a parameter. Read it from the context object or the
8286 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008287 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008288 // If the "property" we were looking for is a local variable or an
8289 // argument in a context, the receiver is the global object; see
8290 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008291 //
8292 // Use the hole as the receiver to signal that the receiver is
8293 // implicit and that the global receiver should be used.
8294 Handle<Object> receiver = isolate->factory()->the_hole_value();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008295 MaybeObject* value = (holder->IsContext())
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008296 ? Context::cast(*holder)->get(index)
8297 : JSObject::cast(*holder)->GetElement(index);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008298 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008299 }
8300
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008301 // If the holder is found, we read the property from it.
8302 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008303 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008304 JSObject* object = JSObject::cast(*holder);
danno@chromium.org40cb8782011-05-25 07:58:50 +00008305 Object* receiver;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008306 if (object->IsGlobalObject()) {
8307 receiver = GlobalObject::cast(object)->global_receiver();
8308 } else if (context->is_exception_holder(*holder)) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008309 // Use the hole as the receiver to signal that the receiver is
8310 // implicit and that the global receiver should be used.
8311 receiver = isolate->heap()->the_hole_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008312 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008313 receiver = ComputeReceiverForNonGlobal(isolate, object);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008314 }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008315
8316 // GetProperty below can cause GC.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008317 Handle<Object> receiver_handle(receiver);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008318
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008319 // No need to unhole the value here. This is taken care of by the
8320 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008321 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008322 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008323 }
8324
8325 if (throw_error) {
8326 // The property doesn't exist - throw exception.
8327 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008328 isolate->factory()->NewReferenceError("not_defined",
8329 HandleVector(&name, 1));
8330 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008331 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008332 // The property doesn't exist - return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008333 return MakePair(isolate->heap()->undefined_value(),
8334 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008335 }
8336}
8337
8338
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008339RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008340 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008341}
8342
8343
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008344RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008345 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008346}
8347
8348
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008349RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008350 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008351 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008352
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008353 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008354 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008355 CONVERT_ARG_CHECKED(String, name, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008356 CONVERT_SMI_ARG_CHECKED(strict_unchecked, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008357 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
8358 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008359 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008360
8361 int index;
8362 PropertyAttributes attributes;
8363 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008364 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008365
8366 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008367 if (holder->IsContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008368 // Ignore if read_only variable.
8369 if ((attributes & READ_ONLY) == 0) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008370 // Context is a fixed array and set cannot fail.
8371 Context::cast(*holder)->set(index, *value);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008372 } else if (strict_mode == kStrictMode) {
8373 // Setting read only property in strict mode.
8374 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008375 isolate->factory()->NewTypeError("strict_cannot_assign",
8376 HandleVector(&name, 1));
8377 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008378 }
8379 } else {
8380 ASSERT((attributes & READ_ONLY) == 0);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008381 Handle<Object> result =
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008382 SetElement(Handle<JSObject>::cast(holder), index, value, strict_mode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008383 if (result.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008384 ASSERT(isolate->has_pending_exception());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008385 return Failure::Exception();
8386 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008387 }
8388 return *value;
8389 }
8390
8391 // Slow case: The property is not in a FixedArray context.
8392 // It is either in an JSObject extension context or it was not found.
8393 Handle<JSObject> context_ext;
8394
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008395 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008396 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008397 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008398 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008399 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008400 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008401
8402 if (strict_mode == kStrictMode) {
8403 // Throw in strict mode (assignment to undefined variable).
8404 Handle<Object> error =
8405 isolate->factory()->NewReferenceError(
8406 "not_defined", HandleVector(&name, 1));
8407 return isolate->Throw(*error);
8408 }
8409 // In non-strict mode, the property is stored in the global context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008410 attributes = NONE;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008411 context_ext = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008412 }
8413
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008414 // Set the property, but ignore if read_only variable on the context
8415 // extension object itself.
8416 if ((attributes & READ_ONLY) == 0 ||
8417 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008418 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008419 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008420 SetProperty(context_ext, name, value, NONE, strict_mode));
8421 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008422 // Setting read only property in strict mode.
8423 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008424 isolate->factory()->NewTypeError(
8425 "strict_cannot_assign", HandleVector(&name, 1));
8426 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008427 }
8428 return *value;
8429}
8430
8431
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008432RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008433 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008434 ASSERT(args.length() == 1);
8435
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008436 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008437}
8438
8439
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008440RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008441 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008442 ASSERT(args.length() == 1);
8443
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008444 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008445}
8446
8447
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008448RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008449 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008450 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008451}
8452
8453
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008454RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008455 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008456 ASSERT(args.length() == 1);
8457
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008458 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008459 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008460 isolate->factory()->NewReferenceError("not_defined",
8461 HandleVector(&name, 1));
8462 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008463}
8464
8465
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008466RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00008467 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008468
8469 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008470 if (isolate->stack_guard()->IsStackOverflow()) {
8471 NoHandleAllocation na;
8472 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008473 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008474
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008475 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008476}
8477
8478
8479// NOTE: These PrintXXX functions are defined for all builds (not just
8480// DEBUG builds) because we may want to be able to trace function
8481// calls in all modes.
8482static void PrintString(String* str) {
8483 // not uncommon to have empty strings
8484 if (str->length() > 0) {
8485 SmartPointer<char> s =
8486 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
8487 PrintF("%s", *s);
8488 }
8489}
8490
8491
8492static void PrintObject(Object* obj) {
8493 if (obj->IsSmi()) {
8494 PrintF("%d", Smi::cast(obj)->value());
8495 } else if (obj->IsString() || obj->IsSymbol()) {
8496 PrintString(String::cast(obj));
8497 } else if (obj->IsNumber()) {
8498 PrintF("%g", obj->Number());
8499 } else if (obj->IsFailure()) {
8500 PrintF("<failure>");
8501 } else if (obj->IsUndefined()) {
8502 PrintF("<undefined>");
8503 } else if (obj->IsNull()) {
8504 PrintF("<null>");
8505 } else if (obj->IsTrue()) {
8506 PrintF("<true>");
8507 } else if (obj->IsFalse()) {
8508 PrintF("<false>");
8509 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00008510 PrintF("%p", reinterpret_cast<void*>(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008511 }
8512}
8513
8514
8515static int StackSize() {
8516 int n = 0;
8517 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
8518 return n;
8519}
8520
8521
8522static void PrintTransition(Object* result) {
8523 // indentation
8524 { const int nmax = 80;
8525 int n = StackSize();
8526 if (n <= nmax)
8527 PrintF("%4d:%*s", n, n, "");
8528 else
8529 PrintF("%4d:%*s", n, nmax, "...");
8530 }
8531
8532 if (result == NULL) {
8533 // constructor calls
8534 JavaScriptFrameIterator it;
8535 JavaScriptFrame* frame = it.frame();
8536 if (frame->IsConstructor()) PrintF("new ");
8537 // function name
8538 Object* fun = frame->function();
8539 if (fun->IsJSFunction()) {
8540 PrintObject(JSFunction::cast(fun)->shared()->name());
8541 } else {
8542 PrintObject(fun);
8543 }
8544 // function arguments
8545 // (we are intentionally only printing the actually
8546 // supplied parameters, not all parameters required)
8547 PrintF("(this=");
8548 PrintObject(frame->receiver());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008549 const int length = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008550 for (int i = 0; i < length; i++) {
8551 PrintF(", ");
8552 PrintObject(frame->GetParameter(i));
8553 }
8554 PrintF(") {\n");
8555
8556 } else {
8557 // function result
8558 PrintF("} -> ");
8559 PrintObject(result);
8560 PrintF("\n");
8561 }
8562}
8563
8564
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008565RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008566 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008567 NoHandleAllocation ha;
8568 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008569 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008570}
8571
8572
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008573RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008574 NoHandleAllocation ha;
8575 PrintTransition(args[0]);
8576 return args[0]; // return TOS
8577}
8578
8579
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008580RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008581 NoHandleAllocation ha;
8582 ASSERT(args.length() == 1);
8583
8584#ifdef DEBUG
8585 if (args[0]->IsString()) {
8586 // If we have a string, assume it's a code "marker"
8587 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008588 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008589 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008590 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
8591 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008592 } else {
8593 PrintF("DebugPrint: ");
8594 }
8595 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008596 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008597 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008598 HeapObject::cast(args[0])->map()->Print();
8599 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008600#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008601 // ShortPrint is available in release mode. Print is not.
8602 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008603#endif
8604 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00008605 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008606
8607 return args[0]; // return TOS
8608}
8609
8610
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008611RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008612 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008613 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008614 isolate->PrintStack();
8615 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008616}
8617
8618
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008619RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008620 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008621 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008622
8623 // According to ECMA-262, section 15.9.1, page 117, the precision of
8624 // the number in a Date object representing a particular instant in
8625 // time is milliseconds. Therefore, we floor the result of getting
8626 // the OS time.
8627 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008628 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008629}
8630
8631
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008632RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008633 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008634 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008635
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008636 CONVERT_ARG_CHECKED(String, str, 0);
8637 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008638
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008639 CONVERT_ARG_CHECKED(JSArray, output, 1);
8640 RUNTIME_ASSERT(output->HasFastElements());
8641
8642 AssertNoAllocation no_allocation;
8643
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008644 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008645 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
8646 bool result;
ager@chromium.org5ec48922009-05-05 07:25:34 +00008647 if (str->IsAsciiRepresentation()) {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008648 result = DateParser::Parse(str->ToAsciiVector(),
8649 output_array,
8650 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008651 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00008652 ASSERT(str->IsTwoByteRepresentation());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008653 result = DateParser::Parse(str->ToUC16Vector(),
8654 output_array,
8655 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008656 }
8657
8658 if (result) {
8659 return *output;
8660 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008661 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008662 }
8663}
8664
8665
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008666RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008667 NoHandleAllocation ha;
8668 ASSERT(args.length() == 1);
8669
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008670 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00008671 const char* zone = OS::LocalTimezone(x);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008672 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008673}
8674
8675
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008676RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008677 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008678 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008679
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008680 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008681}
8682
8683
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008684RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008685 NoHandleAllocation ha;
8686 ASSERT(args.length() == 1);
8687
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008688 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008689 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008690}
8691
8692
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008693RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008694 ASSERT(args.length() == 1);
8695 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008696 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008697 return JSGlobalObject::cast(global)->global_receiver();
8698}
8699
8700
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008701RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008702 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008703 ASSERT_EQ(1, args.length());
8704 CONVERT_ARG_CHECKED(String, source, 0);
8705
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00008706 source = Handle<String>(source->TryFlattenGetString());
8707 // Optimized fast case where we only have ascii characters.
8708 Handle<Object> result;
8709 if (source->IsSeqAsciiString()) {
8710 result = JsonParser<true>::Parse(source);
8711 } else {
8712 result = JsonParser<false>::Parse(source);
8713 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008714 if (result.is_null()) {
8715 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008716 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008717 return Failure::Exception();
8718 }
8719 return *result;
8720}
8721
8722
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008723bool CodeGenerationFromStringsAllowed(Isolate* isolate,
8724 Handle<Context> context) {
8725 if (context->allow_code_gen_from_strings()->IsFalse()) {
8726 // Check with callback if set.
8727 AllowCodeGenerationFromStringsCallback callback =
8728 isolate->allow_code_gen_callback();
8729 if (callback == NULL) {
8730 // No callback set and code generation disallowed.
8731 return false;
8732 } else {
8733 // Callback set. Let it decide if code generation is allowed.
8734 VMState state(isolate, EXTERNAL);
8735 return callback(v8::Utils::ToLocal(context));
8736 }
8737 }
8738 return true;
8739}
8740
8741
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008742RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008743 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008744 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00008745 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008746
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008747 // Extract global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008748 Handle<Context> context(isolate->context()->global_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008749
8750 // Check if global context allows code generation from
8751 // strings. Throw an exception if it doesn't.
8752 if (!CodeGenerationFromStringsAllowed(isolate, context)) {
8753 return isolate->Throw(*isolate->factory()->NewError(
8754 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
8755 }
8756
8757 // Compile source string in the global context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008758 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
8759 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008760 true,
8761 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008762 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008763 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008764 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8765 context,
8766 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008767 return *fun;
8768}
8769
8770
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008771static ObjectPair CompileGlobalEval(Isolate* isolate,
8772 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008773 Handle<Object> receiver,
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00008774 StrictModeFlag strict_mode) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008775 Handle<Context> context = Handle<Context>(isolate->context());
8776 Handle<Context> global_context = Handle<Context>(context->global_context());
8777
8778 // Check if global context allows code generation from
8779 // strings. Throw an exception if it doesn't.
8780 if (!CodeGenerationFromStringsAllowed(isolate, global_context)) {
8781 isolate->Throw(*isolate->factory()->NewError(
8782 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
8783 return MakePair(Failure::Exception(), NULL);
8784 }
8785
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008786 // Deal with a normal eval call with a string argument. Compile it
8787 // and return the compiled function bound in the local context.
8788 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
8789 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008790 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008791 context->IsGlobalContext(),
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00008792 strict_mode);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008793 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008794 Handle<JSFunction> compiled =
8795 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008796 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008797 return MakePair(*compiled, *receiver);
8798}
8799
8800
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008801RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008802 ASSERT(args.length() == 4);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008803
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008804 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008805 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008806 Handle<Object> receiver; // Will be overwritten.
8807
8808 // Compute the calling context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008809 Handle<Context> context = Handle<Context>(isolate->context(), isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008810#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008811 // Make sure Isolate::context() agrees with the old code that traversed
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008812 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008813 StackFrameLocator locator;
8814 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008815 ASSERT(Context::cast(frame->context()) == *context);
8816#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008817
8818 // Find where the 'eval' symbol is bound. It is unaliased only if
8819 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008820 int index = -1;
8821 PropertyAttributes attributes = ABSENT;
8822 while (true) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008823 receiver = context->Lookup(isolate->factory()->eval_symbol(),
8824 FOLLOW_PROTOTYPE_CHAIN,
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008825 &index, &attributes);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008826 // Stop search when eval is found or when the global context is
8827 // reached.
8828 if (attributes != ABSENT || context->IsGlobalContext()) break;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008829 context = Handle<Context>(context->previous(), isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008830 }
8831
iposva@chromium.org245aa852009-02-10 00:49:54 +00008832 // If eval could not be resolved, it has been deleted and we need to
8833 // throw a reference error.
8834 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008835 Handle<Object> name = isolate->factory()->eval_symbol();
iposva@chromium.org245aa852009-02-10 00:49:54 +00008836 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008837 isolate->factory()->NewReferenceError("not_defined",
8838 HandleVector(&name, 1));
8839 return MakePair(isolate->Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008840 }
8841
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008842 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008843 // 'eval' is not bound in the global context. Just call the function
8844 // with the given arguments. This is not necessarily the global eval.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00008845 if (receiver->IsContext() || receiver->IsJSContextExtensionObject()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008846 receiver = isolate->factory()->the_hole_value();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008847 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008848 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008849 }
8850
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008851 // 'eval' is bound in the global context, but it may have been overwritten.
8852 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008853 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008854 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008855 return MakePair(*callee, isolate->heap()->the_hole_value());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008856 }
8857
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008858 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008859 return CompileGlobalEval(isolate,
8860 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008861 args.at<Object>(2),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008862 static_cast<StrictModeFlag>(args.smi_at(3)));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008863}
8864
8865
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008866RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEvalNoLookup) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008867 ASSERT(args.length() == 4);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008868
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008869 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008870 Handle<Object> callee = args.at<Object>(0);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008871
8872 // 'eval' is bound in the global context, but it may have been overwritten.
8873 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008874 if (*callee != isolate->global_context()->global_eval_fun() ||
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008875 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008876 return MakePair(*callee, isolate->heap()->the_hole_value());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008877 }
8878
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008879 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008880 return CompileGlobalEval(isolate,
8881 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008882 args.at<Object>(2),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008883 static_cast<StrictModeFlag>(args.smi_at(3)));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008884}
8885
8886
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008887RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008888 // This utility adjusts the property attributes for newly created Function
8889 // object ("new Function(...)") by changing the map.
8890 // All it does is changing the prototype property to enumerable
8891 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008892 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008893 ASSERT(args.length() == 1);
8894 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008895
8896 Handle<Map> map = func->shared()->strict_mode()
8897 ? isolate->strict_mode_function_instance_map()
8898 : isolate->function_instance_map();
8899
8900 ASSERT(func->map()->instance_type() == map->instance_type());
8901 ASSERT(func->map()->instance_size() == map->instance_size());
8902 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008903 return *func;
8904}
8905
8906
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008907RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008908 // Allocate a block of memory in NewSpace (filled with a filler).
8909 // Use as fallback for allocation in generated code when NewSpace
8910 // is full.
8911 ASSERT(args.length() == 1);
8912 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
8913 int size = size_smi->value();
8914 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
8915 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008916 Heap* heap = isolate->heap();
8917 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008918 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008919 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008920 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008921 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008922 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008923 }
8924 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008925 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008926}
8927
8928
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008929// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008930// array. Returns true if the element was pushed on the stack and
8931// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008932RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008933 ASSERT(args.length() == 2);
8934 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008935 CONVERT_CHECKED(JSObject, element, args[1]);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008936 RUNTIME_ASSERT(array->HasFastElements());
8937 int length = Smi::cast(array->length())->value();
8938 FixedArray* elements = FixedArray::cast(array->elements());
8939 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008940 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008941 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008942 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008943 // Strict not needed. Used for cycle detection in Array join implementation.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008944 { MaybeObject* maybe_obj =
8945 array->SetFastElement(length, element, kNonStrictMode, true);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008946 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8947 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008948 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008949}
8950
8951
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008952/**
8953 * A simple visitor visits every element of Array's.
8954 * The backend storage can be a fixed array for fast elements case,
8955 * or a dictionary for sparse array. Since Dictionary is a subtype
8956 * of FixedArray, the class can be used by both fast and slow cases.
8957 * The second parameter of the constructor, fast_elements, specifies
8958 * whether the storage is a FixedArray or Dictionary.
8959 *
8960 * An index limit is used to deal with the situation that a result array
8961 * length overflows 32-bit non-negative integer.
8962 */
8963class ArrayConcatVisitor {
8964 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008965 ArrayConcatVisitor(Isolate* isolate,
8966 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008967 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008968 isolate_(isolate),
8969 storage_(Handle<FixedArray>::cast(
8970 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008971 index_offset_(0u),
8972 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008973
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008974 ~ArrayConcatVisitor() {
8975 clear_storage();
8976 }
8977
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008978 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008979 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008980 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008981
8982 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008983 if (index < static_cast<uint32_t>(storage_->length())) {
8984 storage_->set(index, *elm);
8985 return;
8986 }
8987 // Our initial estimate of length was foiled, possibly by
8988 // getters on the arrays increasing the length of later arrays
8989 // during iteration.
8990 // This shouldn't happen in anything but pathological cases.
8991 SetDictionaryMode(index);
8992 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008993 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008994 ASSERT(!fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008995 Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008996 Handle<NumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008997 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008998 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008999 // Dictionary needed to grow.
9000 clear_storage();
9001 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009002 }
9003}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009004
9005 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009006 if (JSObject::kMaxElementCount - index_offset_ < delta) {
9007 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009008 } else {
9009 index_offset_ += delta;
9010 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009011 }
9012
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009013 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009014 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009015 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009016 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009017 Handle<Map> map;
9018 if (fast_elements_) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009019 map = isolate_->factory()->GetFastElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009020 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009021 map = isolate_->factory()->GetSlowElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009022 }
9023 array->set_map(*map);
9024 array->set_length(*length);
9025 array->set_elements(*storage_);
9026 return array;
9027 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00009028
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009029 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009030 // Convert storage to dictionary mode.
9031 void SetDictionaryMode(uint32_t index) {
9032 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009033 Handle<FixedArray> current_storage(*storage_);
9034 Handle<NumberDictionary> slow_storage(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009035 isolate_->factory()->NewNumberDictionary(current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009036 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
9037 for (uint32_t i = 0; i < current_length; i++) {
9038 HandleScope loop_scope;
9039 Handle<Object> element(current_storage->get(i));
9040 if (!element->IsTheHole()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009041 Handle<NumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009042 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009043 if (!new_storage.is_identical_to(slow_storage)) {
9044 slow_storage = loop_scope.CloseAndEscape(new_storage);
9045 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009046 }
9047 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009048 clear_storage();
9049 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009050 fast_elements_ = false;
9051 }
9052
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009053 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009054 isolate_->global_handles()->Destroy(
9055 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009056 }
9057
9058 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009059 storage_ = Handle<FixedArray>::cast(
9060 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009061 }
9062
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009063 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009064 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009065 // Index after last seen index. Always less than or equal to
9066 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009067 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009068 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009069};
9070
9071
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009072static uint32_t EstimateElementCount(Handle<JSArray> array) {
9073 uint32_t length = static_cast<uint32_t>(array->length()->Number());
9074 int element_count = 0;
9075 switch (array->GetElementsKind()) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009076 case JSObject::FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009077 // Fast elements can't have lengths that are not representable by
9078 // a 32-bit signed integer.
9079 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
9080 int fast_length = static_cast<int>(length);
9081 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
9082 for (int i = 0; i < fast_length; i++) {
9083 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009084 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009085 break;
9086 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009087 case JSObject::DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009088 Handle<NumberDictionary> dictionary(
9089 NumberDictionary::cast(array->elements()));
9090 int capacity = dictionary->Capacity();
9091 for (int i = 0; i < capacity; i++) {
9092 Handle<Object> key(dictionary->KeyAt(i));
9093 if (dictionary->IsKey(*key)) {
9094 element_count++;
9095 }
9096 }
9097 break;
9098 }
9099 default:
9100 // External arrays are always dense.
9101 return length;
9102 }
9103 // As an estimate, we assume that the prototype doesn't contain any
9104 // inherited elements.
9105 return element_count;
9106}
9107
9108
9109
9110template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009111static void IterateExternalArrayElements(Isolate* isolate,
9112 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009113 bool elements_are_ints,
9114 bool elements_are_guaranteed_smis,
9115 ArrayConcatVisitor* visitor) {
9116 Handle<ExternalArrayClass> array(
9117 ExternalArrayClass::cast(receiver->elements()));
9118 uint32_t len = static_cast<uint32_t>(array->length());
9119
9120 ASSERT(visitor != NULL);
9121 if (elements_are_ints) {
9122 if (elements_are_guaranteed_smis) {
9123 for (uint32_t j = 0; j < len; j++) {
9124 HandleScope loop_scope;
9125 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j))));
9126 visitor->visit(j, e);
9127 }
9128 } else {
9129 for (uint32_t j = 0; j < len; j++) {
9130 HandleScope loop_scope;
9131 int64_t val = static_cast<int64_t>(array->get(j));
9132 if (Smi::IsValid(static_cast<intptr_t>(val))) {
9133 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
9134 visitor->visit(j, e);
9135 } else {
9136 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009137 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009138 visitor->visit(j, e);
9139 }
9140 }
9141 }
9142 } else {
9143 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009144 HandleScope loop_scope(isolate);
9145 Handle<Object> e = isolate->factory()->NewNumber(array->get(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009146 visitor->visit(j, e);
9147 }
9148 }
9149}
9150
9151
9152// Used for sorting indices in a List<uint32_t>.
9153static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
9154 uint32_t a = *ap;
9155 uint32_t b = *bp;
9156 return (a == b) ? 0 : (a < b) ? -1 : 1;
9157}
9158
9159
9160static void CollectElementIndices(Handle<JSObject> object,
9161 uint32_t range,
9162 List<uint32_t>* indices) {
9163 JSObject::ElementsKind kind = object->GetElementsKind();
9164 switch (kind) {
9165 case JSObject::FAST_ELEMENTS: {
9166 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
9167 uint32_t length = static_cast<uint32_t>(elements->length());
9168 if (range < length) length = range;
9169 for (uint32_t i = 0; i < length; i++) {
9170 if (!elements->get(i)->IsTheHole()) {
9171 indices->Add(i);
9172 }
9173 }
9174 break;
9175 }
9176 case JSObject::DICTIONARY_ELEMENTS: {
9177 Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009178 uint32_t capacity = dict->Capacity();
9179 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009180 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009181 Handle<Object> k(dict->KeyAt(j));
9182 if (dict->IsKey(*k)) {
9183 ASSERT(k->IsNumber());
9184 uint32_t index = static_cast<uint32_t>(k->Number());
9185 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009186 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009187 }
9188 }
9189 }
9190 break;
9191 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009192 default: {
9193 int dense_elements_length;
9194 switch (kind) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009195 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009196 dense_elements_length =
9197 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009198 break;
9199 }
9200 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009201 dense_elements_length =
9202 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009203 break;
9204 }
9205 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009206 dense_elements_length =
9207 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009208 break;
9209 }
9210 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009211 dense_elements_length =
9212 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009213 break;
9214 }
9215 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009216 dense_elements_length =
9217 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009218 break;
9219 }
9220 case JSObject::EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009221 dense_elements_length =
9222 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009223 break;
9224 }
9225 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009226 dense_elements_length =
9227 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009228 break;
9229 }
9230 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009231 dense_elements_length =
9232 ExternalFloatArray::cast(object->elements())->length();
9233 break;
9234 }
9235 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
9236 dense_elements_length =
9237 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009238 break;
9239 }
9240 default:
9241 UNREACHABLE();
9242 dense_elements_length = 0;
9243 break;
9244 }
9245 uint32_t length = static_cast<uint32_t>(dense_elements_length);
9246 if (range <= length) {
9247 length = range;
9248 // We will add all indices, so we might as well clear it first
9249 // and avoid duplicates.
9250 indices->Clear();
9251 }
9252 for (uint32_t i = 0; i < length; i++) {
9253 indices->Add(i);
9254 }
9255 if (length == range) return; // All indices accounted for already.
9256 break;
9257 }
9258 }
9259
9260 Handle<Object> prototype(object->GetPrototype());
9261 if (prototype->IsJSObject()) {
9262 // The prototype will usually have no inherited element indices,
9263 // but we have to check.
9264 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
9265 }
9266}
9267
9268
9269/**
9270 * A helper function that visits elements of a JSArray in numerical
9271 * order.
9272 *
9273 * The visitor argument called for each existing element in the array
9274 * with the element index and the element's value.
9275 * Afterwards it increments the base-index of the visitor by the array
9276 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009277 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009278 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009279static bool IterateElements(Isolate* isolate,
9280 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009281 ArrayConcatVisitor* visitor) {
9282 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
9283 switch (receiver->GetElementsKind()) {
9284 case JSObject::FAST_ELEMENTS: {
9285 // Run through the elements FixedArray and use HasElement and GetElement
9286 // to check the prototype for missing elements.
9287 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
9288 int fast_length = static_cast<int>(length);
9289 ASSERT(fast_length <= elements->length());
9290 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009291 HandleScope loop_scope(isolate);
9292 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009293 if (!element_value->IsTheHole()) {
9294 visitor->visit(j, element_value);
9295 } else if (receiver->HasElement(j)) {
9296 // Call GetElement on receiver, not its prototype, or getters won't
9297 // have the correct receiver.
9298 element_value = GetElement(receiver, j);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009299 if (element_value.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009300 visitor->visit(j, element_value);
9301 }
9302 }
9303 break;
9304 }
9305 case JSObject::DICTIONARY_ELEMENTS: {
9306 Handle<NumberDictionary> dict(receiver->element_dictionary());
9307 List<uint32_t> indices(dict->Capacity() / 2);
9308 // Collect all indices in the object and the prototypes less
9309 // than length. This might introduce duplicates in the indices list.
9310 CollectElementIndices(receiver, length, &indices);
9311 indices.Sort(&compareUInt32);
9312 int j = 0;
9313 int n = indices.length();
9314 while (j < n) {
9315 HandleScope loop_scope;
9316 uint32_t index = indices[j];
9317 Handle<Object> element = GetElement(receiver, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009318 if (element.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009319 visitor->visit(index, element);
9320 // Skip to next different index (i.e., omit duplicates).
9321 do {
9322 j++;
9323 } while (j < n && indices[j] == index);
9324 }
9325 break;
9326 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009327 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
9328 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
9329 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009330 for (uint32_t j = 0; j < length; j++) {
9331 Handle<Smi> e(Smi::FromInt(pixels->get(j)));
9332 visitor->visit(j, e);
9333 }
9334 break;
9335 }
9336 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
9337 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009338 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009339 break;
9340 }
9341 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
9342 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009343 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009344 break;
9345 }
9346 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
9347 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009348 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009349 break;
9350 }
9351 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
9352 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009353 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009354 break;
9355 }
9356 case JSObject::EXTERNAL_INT_ELEMENTS: {
9357 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009358 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009359 break;
9360 }
9361 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
9362 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009363 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009364 break;
9365 }
9366 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
9367 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009368 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009369 break;
9370 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009371 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
9372 IterateExternalArrayElements<ExternalDoubleArray, double>(
9373 isolate, receiver, false, false, visitor);
9374 break;
9375 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009376 default:
9377 UNREACHABLE();
9378 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009379 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009380 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009381 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009382}
9383
9384
9385/**
9386 * Array::concat implementation.
9387 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009388 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009389 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009390 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009391RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009392 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009393 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009394
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009395 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
9396 int argument_count = static_cast<int>(arguments->length()->Number());
9397 RUNTIME_ASSERT(arguments->HasFastElements());
9398 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009399
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009400 // Pass 1: estimate the length and number of elements of the result.
9401 // The actual length can be larger if any of the arguments have getters
9402 // that mutate other arguments (but will otherwise be precise).
9403 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009404
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009405 uint32_t estimate_result_length = 0;
9406 uint32_t estimate_nof_elements = 0;
9407 {
9408 for (int i = 0; i < argument_count; i++) {
9409 HandleScope loop_scope;
9410 Handle<Object> obj(elements->get(i));
9411 uint32_t length_estimate;
9412 uint32_t element_estimate;
9413 if (obj->IsJSArray()) {
9414 Handle<JSArray> array(Handle<JSArray>::cast(obj));
9415 length_estimate =
9416 static_cast<uint32_t>(array->length()->Number());
9417 element_estimate =
9418 EstimateElementCount(array);
9419 } else {
9420 length_estimate = 1;
9421 element_estimate = 1;
9422 }
9423 // Avoid overflows by capping at kMaxElementCount.
9424 if (JSObject::kMaxElementCount - estimate_result_length <
9425 length_estimate) {
9426 estimate_result_length = JSObject::kMaxElementCount;
9427 } else {
9428 estimate_result_length += length_estimate;
9429 }
9430 if (JSObject::kMaxElementCount - estimate_nof_elements <
9431 element_estimate) {
9432 estimate_nof_elements = JSObject::kMaxElementCount;
9433 } else {
9434 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009435 }
9436 }
9437 }
9438
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009439 // If estimated number of elements is more than half of length, a
9440 // fixed array (fast case) is more time and space-efficient than a
9441 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009442 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009443
9444 Handle<FixedArray> storage;
9445 if (fast_case) {
9446 // The backing storage array must have non-existing elements to
9447 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009448 storage = isolate->factory()->NewFixedArrayWithHoles(
9449 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009450 } else {
9451 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
9452 uint32_t at_least_space_for = estimate_nof_elements +
9453 (estimate_nof_elements >> 2);
9454 storage = Handle<FixedArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009455 isolate->factory()->NewNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009456 }
9457
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009458 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009459
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009460 for (int i = 0; i < argument_count; i++) {
9461 Handle<Object> obj(elements->get(i));
9462 if (obj->IsJSArray()) {
9463 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009464 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009465 return Failure::Exception();
9466 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009467 } else {
9468 visitor.visit(0, obj);
9469 visitor.increase_index_offset(1);
9470 }
9471 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009472
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009473 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009474}
9475
9476
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009477// This will not allocate (flatten the string), but it may run
9478// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009479RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009480 NoHandleAllocation ha;
9481 ASSERT(args.length() == 1);
9482
9483 CONVERT_CHECKED(String, string, args[0]);
9484 StringInputBuffer buffer(string);
9485 while (buffer.has_more()) {
9486 uint16_t character = buffer.GetNext();
9487 PrintF("%c", character);
9488 }
9489 return string;
9490}
9491
ager@chromium.org5ec48922009-05-05 07:25:34 +00009492// Moves all own elements of an object, that are below a limit, to positions
9493// starting at zero. All undefined values are placed after non-undefined values,
9494// and are followed by non-existing element. Does not change the length
9495// property.
9496// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009497RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00009498 ASSERT(args.length() == 2);
9499 CONVERT_CHECKED(JSObject, object, args[0]);
9500 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
9501 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009502}
9503
9504
9505// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009506RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009507 ASSERT(args.length() == 2);
9508 CONVERT_CHECKED(JSArray, from, args[0]);
9509 CONVERT_CHECKED(JSArray, to, args[1]);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009510 HeapObject* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00009511 MaybeObject* maybe_new_map;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009512 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
9513 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009514 maybe_new_map = to->map()->GetFastElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009515 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009516 maybe_new_map = to->map()->GetSlowElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009517 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009518 Object* new_map;
9519 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009520 to->set_map(Map::cast(new_map));
9521 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009522 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009523 Object* obj;
9524 { MaybeObject* maybe_obj = from->ResetElements();
9525 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9526 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009527 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009528 return to;
9529}
9530
9531
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009532// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009533RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009534 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009535 CONVERT_CHECKED(JSObject, object, args[0]);
9536 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009537 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009538 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009539 } else if (object->IsJSArray()) {
9540 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009541 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009542 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009543 }
9544}
9545
9546
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009547RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009548 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009549
9550 ASSERT_EQ(3, args.length());
9551
ager@chromium.orgac091b72010-05-05 07:34:42 +00009552 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009553 Handle<Object> key1 = args.at<Object>(1);
9554 Handle<Object> key2 = args.at<Object>(2);
9555
9556 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009557 if (!key1->ToArrayIndex(&index1)
9558 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009559 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009560 }
9561
ager@chromium.orgac091b72010-05-05 07:34:42 +00009562 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
9563 Handle<Object> tmp1 = GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009564 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009565 Handle<Object> tmp2 = GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009566 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009567
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009568 RETURN_IF_EMPTY_HANDLE(isolate,
9569 SetElement(jsobject, index1, tmp2, kStrictMode));
9570 RETURN_IF_EMPTY_HANDLE(isolate,
9571 SetElement(jsobject, index2, tmp1, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +00009572
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009573 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009574}
9575
9576
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009577// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009578// might have elements. Can either return keys (positive integers) or
9579// intervals (pair of a negative integer (-start-1) followed by a
9580// positive (length)) or undefined values.
9581// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009582RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009583 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009584 HandleScope scope(isolate);
ager@chromium.org5ec48922009-05-05 07:25:34 +00009585 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009586 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009587 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009588 // Create an array and get all the keys into it, then remove all the
9589 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009590 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009591 int keys_length = keys->length();
9592 for (int i = 0; i < keys_length; i++) {
9593 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009594 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009595 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009596 // Zap invalid keys.
9597 keys->set_undefined(i);
9598 }
9599 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009600 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009601 } else {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009602 ASSERT(array->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009603 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009604 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009605 single_interval->set(0, Smi::FromInt(-1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009606 uint32_t actual_length =
9607 static_cast<uint32_t>(FixedArray::cast(array->elements())->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +00009608 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009609 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009610 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009611 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009612 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009613 }
9614}
9615
9616
9617// DefineAccessor takes an optional final argument which is the
9618// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
9619// to the way accessors are implemented, it is set for both the getter
9620// and setter on the first call to DefineAccessor and ignored on
9621// subsequent calls.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009622RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009623 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
9624 // Compute attributes.
9625 PropertyAttributes attributes = NONE;
9626 if (args.length() == 5) {
9627 CONVERT_CHECKED(Smi, attrs, args[4]);
9628 int value = attrs->value();
9629 // Only attribute bits should be set.
9630 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
9631 attributes = static_cast<PropertyAttributes>(value);
9632 }
9633
9634 CONVERT_CHECKED(JSObject, obj, args[0]);
9635 CONVERT_CHECKED(String, name, args[1]);
9636 CONVERT_CHECKED(Smi, flag, args[2]);
9637 CONVERT_CHECKED(JSFunction, fun, args[3]);
9638 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
9639}
9640
9641
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009642RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009643 ASSERT(args.length() == 3);
9644 CONVERT_CHECKED(JSObject, obj, args[0]);
9645 CONVERT_CHECKED(String, name, args[1]);
9646 CONVERT_CHECKED(Smi, flag, args[2]);
9647 return obj->LookupAccessor(name, flag->value() == 0);
9648}
9649
9650
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009651#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009652RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009653 ASSERT(args.length() == 0);
9654 return Execution::DebugBreakHelper();
9655}
9656
9657
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009658// Helper functions for wrapping and unwrapping stack frame ids.
9659static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009660 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009661 return Smi::FromInt(id >> 2);
9662}
9663
9664
9665static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
9666 return static_cast<StackFrame::Id>(wrapped->value() << 2);
9667}
9668
9669
9670// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00009671// args[0]: debug event listener function to set or null or undefined for
9672// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009673// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009674RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009675 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009676 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
9677 args[0]->IsUndefined() ||
9678 args[0]->IsNull());
9679 Handle<Object> callback = args.at<Object>(0);
9680 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009681 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009682
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009683 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009684}
9685
9686
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009687RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +00009688 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009689 isolate->stack_guard()->DebugBreak();
9690 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009691}
9692
9693
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009694static MaybeObject* DebugLookupResultValue(Heap* heap,
9695 Object* receiver,
9696 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +00009697 LookupResult* result,
9698 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009699 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009700 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009701 case NORMAL:
9702 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009703 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009704 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009705 }
9706 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009707 case FIELD:
9708 value =
9709 JSObject::cast(
9710 result->holder())->FastPropertyAt(result->GetFieldIndex());
9711 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009712 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009713 }
9714 return value;
9715 case CONSTANT_FUNCTION:
9716 return result->GetConstantFunction();
9717 case CALLBACKS: {
9718 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00009719 if (structure->IsForeign() || structure->IsAccessorInfo()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009720 MaybeObject* maybe_value = receiver->GetPropertyWithCallback(
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009721 receiver, structure, name, result->holder());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009722 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009723 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009724 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009725 maybe_value = heap->isolate()->pending_exception();
9726 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009727 if (caught_exception != NULL) {
9728 *caught_exception = true;
9729 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009730 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009731 }
9732 return value;
9733 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009734 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009735 }
9736 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009737 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009738 case MAP_TRANSITION:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00009739 case EXTERNAL_ARRAY_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009740 case CONSTANT_TRANSITION:
9741 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009742 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009743 default:
9744 UNREACHABLE();
9745 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009746 UNREACHABLE();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009747 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009748}
9749
9750
ager@chromium.org32912102009-01-16 10:38:43 +00009751// Get debugger related details for an object property.
9752// args[0]: object holding property
9753// args[1]: name of the property
9754//
9755// The array returned contains the following information:
9756// 0: Property value
9757// 1: Property details
9758// 2: Property value is exception
9759// 3: Getter function if defined
9760// 4: Setter function if defined
9761// Items 2-4 are only filled if the property has either a getter or a setter
9762// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009763RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009764 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009765
9766 ASSERT(args.length() == 2);
9767
9768 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9769 CONVERT_ARG_CHECKED(String, name, 1);
9770
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009771 // Make sure to set the current context to the context before the debugger was
9772 // entered (if the debugger is entered). The reason for switching context here
9773 // is that for some property lookups (accessors and interceptors) callbacks
9774 // into the embedding application can occour, and the embedding application
9775 // could have the assumption that its own global context is the current
9776 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009777 SaveContext save(isolate);
9778 if (isolate->debug()->InDebugger()) {
9779 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009780 }
9781
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009782 // Skip the global proxy as it has no properties and always delegates to the
9783 // real global object.
9784 if (obj->IsJSGlobalProxy()) {
9785 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
9786 }
9787
9788
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009789 // Check if the name is trivially convertible to an index and get the element
9790 // if so.
9791 uint32_t index;
9792 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009793 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009794 Object* element_or_char;
9795 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009796 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009797 if (!maybe_element_or_char->ToObject(&element_or_char)) {
9798 return maybe_element_or_char;
9799 }
9800 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009801 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009802 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009803 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009804 }
9805
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009806 // Find the number of objects making up this.
9807 int length = LocalPrototypeChainLength(*obj);
9808
9809 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009810 Handle<JSObject> jsproto = obj;
9811 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009812 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009813 jsproto->LocalLookup(*name, &result);
9814 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009815 // LookupResult is not GC safe as it holds raw object pointers.
9816 // GC can happen later in this code so put the required fields into
9817 // local variables using handles when required for later use.
9818 PropertyType result_type = result.type();
9819 Handle<Object> result_callback_obj;
9820 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009821 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
9822 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009823 }
9824 Smi* property_details = result.GetPropertyDetails().AsSmi();
9825 // DebugLookupResultValue can cause GC so details from LookupResult needs
9826 // to be copied to handles before this.
9827 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009828 Object* raw_value;
9829 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009830 DebugLookupResultValue(isolate->heap(), *obj, *name,
9831 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009832 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
9833 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009834 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009835
9836 // If the callback object is a fixed array then it contains JavaScript
9837 // getter and/or setter.
9838 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
9839 result_callback_obj->IsFixedArray();
9840 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009841 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009842 details->set(0, *value);
9843 details->set(1, property_details);
9844 if (hasJavaScriptAccessors) {
9845 details->set(2,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009846 caught_exception ? isolate->heap()->true_value()
9847 : isolate->heap()->false_value());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009848 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
9849 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
9850 }
9851
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009852 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009853 }
9854 if (i < length - 1) {
9855 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
9856 }
9857 }
9858
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009859 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009860}
9861
9862
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009863RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009864 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009865
9866 ASSERT(args.length() == 2);
9867
9868 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9869 CONVERT_ARG_CHECKED(String, name, 1);
9870
9871 LookupResult result;
9872 obj->Lookup(*name, &result);
9873 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009874 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009875 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009876 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009877}
9878
9879
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009880// Return the property type calculated from the property details.
9881// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009882RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009883 ASSERT(args.length() == 1);
9884 CONVERT_CHECKED(Smi, details, args[0]);
9885 PropertyType type = PropertyDetails(details).type();
9886 return Smi::FromInt(static_cast<int>(type));
9887}
9888
9889
9890// Return the property attribute calculated from the property details.
9891// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009892RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009893 ASSERT(args.length() == 1);
9894 CONVERT_CHECKED(Smi, details, args[0]);
9895 PropertyAttributes attributes = PropertyDetails(details).attributes();
9896 return Smi::FromInt(static_cast<int>(attributes));
9897}
9898
9899
9900// Return the property insertion index calculated from the property details.
9901// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009902RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009903 ASSERT(args.length() == 1);
9904 CONVERT_CHECKED(Smi, details, args[0]);
9905 int index = PropertyDetails(details).index();
9906 return Smi::FromInt(index);
9907}
9908
9909
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009910// Return property value from named interceptor.
9911// args[0]: object
9912// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009913RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009914 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009915 ASSERT(args.length() == 2);
9916 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9917 RUNTIME_ASSERT(obj->HasNamedInterceptor());
9918 CONVERT_ARG_CHECKED(String, name, 1);
9919
9920 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009921 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009922}
9923
9924
9925// Return element value from indexed interceptor.
9926// args[0]: object
9927// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009928RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009929 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009930 ASSERT(args.length() == 2);
9931 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9932 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
9933 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
9934
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009935 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009936}
9937
9938
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009939RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009940 ASSERT(args.length() >= 1);
9941 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +00009942 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009943 if (isolate->debug()->break_id() == 0 ||
9944 break_id != isolate->debug()->break_id()) {
9945 return isolate->Throw(
9946 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009947 }
9948
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009949 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009950}
9951
9952
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009953RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009954 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009955 ASSERT(args.length() == 1);
9956
9957 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009958 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009959 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
9960 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +00009961 if (!maybe_result->ToObject(&result)) return maybe_result;
9962 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009963
9964 // Count all frames which are relevant to debugging stack trace.
9965 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009966 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009967 if (id == StackFrame::NO_ID) {
9968 // If there is no JavaScript stack frame count is 0.
9969 return Smi::FromInt(0);
9970 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +00009971
9972 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
9973 n += it.frame()->GetInlineCount();
9974 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009975 return Smi::FromInt(n);
9976}
9977
9978
9979static const int kFrameDetailsFrameIdIndex = 0;
9980static const int kFrameDetailsReceiverIndex = 1;
9981static const int kFrameDetailsFunctionIndex = 2;
9982static const int kFrameDetailsArgumentCountIndex = 3;
9983static const int kFrameDetailsLocalCountIndex = 4;
9984static const int kFrameDetailsSourcePositionIndex = 5;
9985static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009986static const int kFrameDetailsAtReturnIndex = 7;
ricow@chromium.org4f693d62011-07-04 14:01:31 +00009987static const int kFrameDetailsFlagsIndex = 8;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009988static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009989
9990// Return an array with frame details
9991// args[0]: number: break id
9992// args[1]: number: frame index
9993//
9994// The array returned contains the following information:
9995// 0: Frame id
9996// 1: Receiver
9997// 2: Function
9998// 3: Argument count
9999// 4: Local count
10000// 5: Source position
10001// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010002// 7: Is at return
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010003// 8: Flags
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010004// Arguments name, value
10005// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010006// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010007RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010008 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010009 ASSERT(args.length() == 2);
10010
10011 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010012 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010013 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10014 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010015 if (!maybe_check->ToObject(&check)) return maybe_check;
10016 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010017 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010018 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010019
10020 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010021 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010022 if (id == StackFrame::NO_ID) {
10023 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010024 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010025 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010026
10027 int deoptimized_frame_index = -1; // Frame index in optimized frame.
10028 DeoptimizedFrameInfo* deoptimized_frame = NULL;
10029
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010030 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010031 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010032 for (; !it.done(); it.Advance()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010033 if (index < count + it.frame()->GetInlineCount()) break;
10034 count += it.frame()->GetInlineCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010035 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010036 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010037
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010038 if (it.frame()->is_optimized()) {
10039 deoptimized_frame_index =
10040 it.frame()->GetInlineCount() - (index - count) - 1;
10041 deoptimized_frame = Deoptimizer::DebuggerInspectableFrame(
10042 it.frame(),
10043 deoptimized_frame_index,
10044 isolate);
10045 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010046
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010047 // Traverse the saved contexts chain to find the active context for the
10048 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010049 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010050 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010051 save = save->prev();
10052 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010053 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010054
10055 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010056 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010057
10058 // Find source position.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010059 int position =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010060 it.frame()->LookupCode()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010061
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010062 // Check for constructor frame. Inlined frames cannot be construct calls.
10063 bool inlined_frame =
10064 it.frame()->is_optimized() && deoptimized_frame_index != 0;
10065 bool constructor = !inlined_frame && it.frame()->IsConstructor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010066
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010067 // Get scope info and read from it for local variable information.
10068 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +000010069 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010070 ASSERT(*scope_info != SerializedScopeInfo::Empty());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010071 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010072
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010073 // Get the locals names and values into a temporary array.
10074 //
10075 // TODO(1240907): Hide compiler-introduced stack variables
10076 // (e.g. .result)? For users of the debugger, they will probably be
10077 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010078 Handle<FixedArray> locals =
10079 isolate->factory()->NewFixedArray(info.NumberOfLocals() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010080
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010081 // Fill in the values of the locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010082 int i = 0;
10083 for (; i < info.number_of_stack_slots(); ++i) {
10084 // Use the value from the stack.
10085 locals->set(i * 2, *info.LocalName(i));
10086 if (it.frame()->is_optimized()) {
10087 // Get the value from the deoptimized frame.
10088 locals->set(i * 2 + 1,
10089 deoptimized_frame->GetExpression(i));
10090 } else {
10091 // Get the value from the stack.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010092 locals->set(i * 2 + 1, it.frame()->GetExpression(i));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010093 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010094 }
10095 if (i < info.NumberOfLocals()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010096 // Get the context containing declarations.
10097 Handle<Context> context(
10098 Context::cast(it.frame()->context())->declaration_context());
10099 for (; i < info.NumberOfLocals(); ++i) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010100 Handle<String> name = info.LocalName(i);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010101 locals->set(i * 2, *name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010102 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010103 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010104 }
10105 }
10106
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010107 // Check whether this frame is positioned at return. If not top
10108 // frame or if the frame is optimized it cannot be at a return.
10109 bool at_return = false;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010110 if (!it.frame()->is_optimized() && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010111 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010112 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010113
10114 // If positioned just before return find the value to be returned and add it
10115 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010116 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010117 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010118 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010119 Address internal_frame_sp = NULL;
10120 while (!it2.done()) {
10121 if (it2.frame()->is_internal()) {
10122 internal_frame_sp = it2.frame()->sp();
10123 } else {
10124 if (it2.frame()->is_java_script()) {
10125 if (it2.frame()->id() == it.frame()->id()) {
10126 // The internal frame just before the JavaScript frame contains the
10127 // value to return on top. A debug break at return will create an
10128 // internal frame to store the return value (eax/rax/r0) before
10129 // entering the debug break exit frame.
10130 if (internal_frame_sp != NULL) {
10131 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010132 Handle<Object>(Memory::Object_at(internal_frame_sp),
10133 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010134 break;
10135 }
10136 }
10137 }
10138
10139 // Indicate that the previous frame was not an internal frame.
10140 internal_frame_sp = NULL;
10141 }
10142 it2.Advance();
10143 }
10144 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010145
10146 // Now advance to the arguments adapter frame (if any). It contains all
10147 // the provided parameters whereas the function frame always have the number
10148 // of arguments matching the functions parameters. The rest of the
10149 // information (except for what is collected above) is the same.
10150 it.AdvanceToArgumentsFrame();
10151
10152 // Find the number of arguments to fill. At least fill the number of
10153 // parameters for the function and fill more if more parameters are provided.
10154 int argument_count = info.number_of_parameters();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010155 if (it.frame()->is_optimized()) {
10156 ASSERT_EQ(argument_count, deoptimized_frame->parameters_count());
10157 } else {
10158 if (argument_count < it.frame()->ComputeParametersCount()) {
10159 argument_count = it.frame()->ComputeParametersCount();
10160 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010161 }
10162
10163 // Calculate the size of the result.
10164 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010165 2 * (argument_count + info.NumberOfLocals()) +
10166 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010167 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010168
10169 // Add the frame id.
10170 details->set(kFrameDetailsFrameIdIndex, *frame_id);
10171
10172 // Add the function (same as in function frame).
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010173 if (it.frame()->is_optimized()) {
10174 // Get the function from the deoptimized frame.
10175 details->set(kFrameDetailsFunctionIndex, deoptimized_frame->GetFunction());
10176 } else {
10177 // Get the function from the stack.
10178 details->set(kFrameDetailsFunctionIndex, it.frame()->function());
10179 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010180
10181 // Add the arguments count.
10182 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
10183
10184 // Add the locals count
10185 details->set(kFrameDetailsLocalCountIndex,
10186 Smi::FromInt(info.NumberOfLocals()));
10187
10188 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +000010189 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010190 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
10191 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010192 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010193 }
10194
10195 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010196 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010197
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010198 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010199 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010200
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010201 // Add flags to indicate information on whether this frame is
10202 // bit 0: invoked in the debugger context.
10203 // bit 1: optimized frame.
10204 // bit 2: inlined in optimized frame
10205 int flags = 0;
10206 if (*save->context() == *isolate->debug()->debug_context()) {
10207 flags |= 1 << 0;
10208 }
10209 if (it.frame()->is_optimized()) {
10210 flags |= 1 << 1;
10211 if (deoptimized_frame_index > 0) {
10212 flags |= 1 << 2;
10213 }
10214 }
10215 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010216
10217 // Fill the dynamic part.
10218 int details_index = kFrameDetailsFirstDynamicIndex;
10219
10220 // Add arguments name and value.
10221 for (int i = 0; i < argument_count; i++) {
10222 // Name of the argument.
10223 if (i < info.number_of_parameters()) {
10224 details->set(details_index++, *info.parameter_name(i));
10225 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010226 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010227 }
10228
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010229 // Parameter value.
10230 if (it.frame()->is_optimized()) {
10231 // Get the value from the deoptimized frame.
10232 details->set(details_index++, deoptimized_frame->GetParameter(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010233 } else {
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010234 if (i < it.frame()->ComputeParametersCount()) {
10235 // Get the value from the stack.
10236 details->set(details_index++, it.frame()->GetParameter(i));
10237 } else {
10238 details->set(details_index++, heap->undefined_value());
10239 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010240 }
10241 }
10242
10243 // Add locals name and value from the temporary copy from the function frame.
10244 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
10245 details->set(details_index++, locals->get(i));
10246 }
10247
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010248 // Add the value being returned.
10249 if (at_return) {
10250 details->set(details_index++, *return_value);
10251 }
10252
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010253 // Add the receiver (same as in function frame).
10254 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
10255 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010256 Handle<Object> receiver(it.frame()->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010257 if (!receiver->IsJSObject()) {
10258 // If the receiver is NOT a JSObject we have hit an optimization
10259 // where a value object is not converted into a wrapped JS objects.
10260 // To hide this optimization from the debugger, we wrap the receiver
10261 // by creating correct wrapper object based on the calling frame's
10262 // global context.
10263 it.Advance();
10264 Handle<Context> calling_frames_global_context(
10265 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010266 receiver =
10267 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010268 }
10269 details->set(kFrameDetailsReceiverIndex, *receiver);
10270
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010271 // Get rid of the calculated deoptimized frame if any.
10272 if (deoptimized_frame != NULL) {
10273 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame,
10274 isolate);
10275 }
10276
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010277 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010278 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010279}
10280
10281
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010282// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010283static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010284 Isolate* isolate,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010285 Handle<SerializedScopeInfo> serialized_scope_info,
10286 ScopeInfo<>& scope_info,
10287 Handle<Context> context,
10288 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010289 // Fill all context locals to the context extension.
10290 for (int i = Context::MIN_CONTEXT_SLOTS;
10291 i < scope_info.number_of_context_slots();
10292 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +000010293 int context_index = serialized_scope_info->ContextSlotIndex(
10294 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010295
whesse@chromium.org7b260152011-06-20 15:33:18 +000010296 RETURN_IF_EMPTY_HANDLE_VALUE(
10297 isolate,
10298 SetProperty(scope_object,
10299 scope_info.context_slot_name(i),
10300 Handle<Object>(context->get(context_index), isolate),
10301 NONE,
10302 kNonStrictMode),
10303 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010304 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010305
10306 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010307}
10308
10309
10310// Create a plain JSObject which materializes the local scope for the specified
10311// frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010312static Handle<JSObject> MaterializeLocalScope(Isolate* isolate,
10313 JavaScriptFrame* frame) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010314 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010315 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +000010316 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
10317 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010318
10319 // Allocate and initialize a JSObject with all the arguments, stack locals
10320 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010321 Handle<JSObject> local_scope =
10322 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010323
10324 // First fill all parameters.
10325 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010326 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010327 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010328 SetProperty(local_scope,
10329 scope_info.parameter_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010330 Handle<Object>(frame->GetParameter(i), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010331 NONE,
10332 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010333 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010334 }
10335
10336 // Second fill all stack locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010337 for (int i = 0; i < scope_info.number_of_stack_slots(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010338 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010339 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010340 SetProperty(local_scope,
10341 scope_info.stack_slot_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010342 Handle<Object>(frame->GetExpression(i), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010343 NONE,
10344 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010345 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010346 }
10347
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010348 if (scope_info.number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
10349 // Third fill all context locals.
10350 Handle<Context> frame_context(Context::cast(frame->context()));
10351 Handle<Context> function_context(frame_context->declaration_context());
10352 if (!CopyContextLocalsToScopeObject(isolate,
10353 serialized_scope_info, scope_info,
10354 function_context, local_scope)) {
10355 return Handle<JSObject>();
10356 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010357
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010358 // Finally copy any properties from the function context extension.
10359 // These will be variables introduced by eval.
10360 if (function_context->closure() == *function) {
10361 if (function_context->has_extension() &&
10362 !function_context->IsGlobalContext()) {
10363 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
10364 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
10365 for (int i = 0; i < keys->length(); i++) {
10366 // Names of variables introduced by eval are strings.
10367 ASSERT(keys->get(i)->IsString());
10368 Handle<String> key(String::cast(keys->get(i)));
10369 RETURN_IF_EMPTY_HANDLE_VALUE(
10370 isolate,
10371 SetProperty(local_scope,
10372 key,
10373 GetProperty(ext, key),
10374 NONE,
10375 kNonStrictMode),
10376 Handle<JSObject>());
10377 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010378 }
10379 }
10380 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010381
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010382 return local_scope;
10383}
10384
10385
10386// Create a plain JSObject which materializes the closure content for the
10387// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010388static Handle<JSObject> MaterializeClosure(Isolate* isolate,
10389 Handle<Context> context) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010390 ASSERT(context->IsFunctionContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010391
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010392 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +000010393 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
10394 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010395
10396 // Allocate and initialize a JSObject with all the content of theis function
10397 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010398 Handle<JSObject> closure_scope =
10399 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010400
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010401 // Fill all context locals to the context extension.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010402 if (!CopyContextLocalsToScopeObject(isolate,
10403 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010404 context, closure_scope)) {
10405 return Handle<JSObject>();
10406 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010407
10408 // Finally copy any properties from the function context extension. This will
10409 // be variables introduced by eval.
10410 if (context->has_extension()) {
10411 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010412 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010413 for (int i = 0; i < keys->length(); i++) {
10414 // Names of variables introduced by eval are strings.
10415 ASSERT(keys->get(i)->IsString());
10416 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010417 RETURN_IF_EMPTY_HANDLE_VALUE(
10418 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010419 SetProperty(closure_scope,
10420 key,
10421 GetProperty(ext, key),
10422 NONE,
10423 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010424 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010425 }
10426 }
10427
10428 return closure_scope;
10429}
10430
10431
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010432// Create a plain JSObject which materializes the scope for the specified
10433// catch context.
10434static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
10435 Handle<Context> context) {
10436 ASSERT(context->IsCatchContext());
10437 Handle<String> name(String::cast(context->extension()));
10438 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX));
10439 Handle<JSObject> catch_scope =
10440 isolate->factory()->NewJSObject(isolate->object_function());
10441 RETURN_IF_EMPTY_HANDLE_VALUE(
10442 isolate,
10443 SetProperty(catch_scope, name, thrown_object, NONE, kNonStrictMode),
10444 Handle<JSObject>());
10445 return catch_scope;
10446}
10447
10448
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010449// Iterate over the actual scopes visible from a stack frame. All scopes are
10450// backed by an actual context except the local scope, which is inserted
10451// "artifically" in the context chain.
10452class ScopeIterator {
10453 public:
10454 enum ScopeType {
10455 ScopeTypeGlobal = 0,
10456 ScopeTypeLocal,
10457 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000010458 ScopeTypeClosure,
ager@chromium.orga1645e22009-09-09 19:27:10 +000010459 ScopeTypeCatch
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010460 };
10461
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010462 ScopeIterator(Isolate* isolate, JavaScriptFrame* frame)
10463 : isolate_(isolate),
10464 frame_(frame),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010465 function_(JSFunction::cast(frame->function())),
10466 context_(Context::cast(frame->context())),
10467 local_done_(false),
10468 at_local_(false) {
10469
10470 // Check whether the first scope is actually a local scope.
10471 if (context_->IsGlobalContext()) {
10472 // If there is a stack slot for .result then this local scope has been
10473 // created for evaluating top level code and it is not a real local scope.
10474 // Checking for the existence of .result seems fragile, but the scope info
10475 // saved with the code object does not otherwise have that information.
ager@chromium.orgb5737492010-07-15 09:29:43 +000010476 int index = function_->shared()->scope_info()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010477 StackSlotIndex(isolate_->heap()->result_symbol());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010478 at_local_ = index < 0;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010479 } else if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010480 at_local_ = true;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010481 } else if (context_->closure() != *function_) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010482 // The context_ is a with or catch block from the outer function.
10483 ASSERT(context_->IsWithContext() || context_->IsCatchContext());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010484 at_local_ = true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010485 }
10486 }
10487
10488 // More scopes?
10489 bool Done() { return context_.is_null(); }
10490
10491 // Move to the next scope.
10492 void Next() {
10493 // If at a local scope mark the local scope as passed.
10494 if (at_local_) {
10495 at_local_ = false;
10496 local_done_ = true;
10497
10498 // If the current context is not associated with the local scope the
10499 // current context is the next real scope, so don't move to the next
10500 // context in this case.
10501 if (context_->closure() != *function_) {
10502 return;
10503 }
10504 }
10505
10506 // The global scope is always the last in the chain.
10507 if (context_->IsGlobalContext()) {
10508 context_ = Handle<Context>();
10509 return;
10510 }
10511
10512 // Move to the next context.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010513 context_ = Handle<Context>(context_->previous(), isolate_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010514
10515 // If passing the local scope indicate that the current scope is now the
10516 // local scope.
10517 if (!local_done_ &&
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010518 (context_->IsGlobalContext() || context_->IsFunctionContext())) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010519 at_local_ = true;
10520 }
10521 }
10522
10523 // Return the type of the current scope.
10524 int Type() {
10525 if (at_local_) {
10526 return ScopeTypeLocal;
10527 }
10528 if (context_->IsGlobalContext()) {
10529 ASSERT(context_->global()->IsGlobalObject());
10530 return ScopeTypeGlobal;
10531 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010532 if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010533 return ScopeTypeClosure;
10534 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010535 if (context_->IsCatchContext()) {
ager@chromium.orga1645e22009-09-09 19:27:10 +000010536 return ScopeTypeCatch;
10537 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010538 ASSERT(context_->IsWithContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010539 return ScopeTypeWith;
10540 }
10541
10542 // Return the JavaScript object with the content of the current scope.
10543 Handle<JSObject> ScopeObject() {
10544 switch (Type()) {
10545 case ScopeIterator::ScopeTypeGlobal:
10546 return Handle<JSObject>(CurrentContext()->global());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010547 case ScopeIterator::ScopeTypeLocal:
10548 // Materialize the content of the local scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010549 return MaterializeLocalScope(isolate_, frame_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010550 case ScopeIterator::ScopeTypeWith:
10551 // Return the with object.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010552 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
10553 case ScopeIterator::ScopeTypeCatch:
10554 return MaterializeCatchScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010555 case ScopeIterator::ScopeTypeClosure:
10556 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010557 return MaterializeClosure(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010558 }
10559 UNREACHABLE();
10560 return Handle<JSObject>();
10561 }
10562
10563 // Return the context for this scope. For the local context there might not
10564 // be an actual context.
10565 Handle<Context> CurrentContext() {
10566 if (at_local_ && context_->closure() != *function_) {
10567 return Handle<Context>();
10568 }
10569 return context_;
10570 }
10571
10572#ifdef DEBUG
10573 // Debug print of the content of the current scope.
10574 void DebugPrint() {
10575 switch (Type()) {
10576 case ScopeIterator::ScopeTypeGlobal:
10577 PrintF("Global:\n");
10578 CurrentContext()->Print();
10579 break;
10580
10581 case ScopeIterator::ScopeTypeLocal: {
10582 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010583 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010584 scope_info.Print();
10585 if (!CurrentContext().is_null()) {
10586 CurrentContext()->Print();
10587 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010588 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010589 if (extension->IsJSContextExtensionObject()) {
10590 extension->Print();
10591 }
10592 }
10593 }
10594 break;
10595 }
10596
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010597 case ScopeIterator::ScopeTypeWith:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010598 PrintF("With:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010599 CurrentContext()->extension()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010600 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010601
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010602 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orga1645e22009-09-09 19:27:10 +000010603 PrintF("Catch:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010604 CurrentContext()->extension()->Print();
10605 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
ager@chromium.orga1645e22009-09-09 19:27:10 +000010606 break;
ager@chromium.orga1645e22009-09-09 19:27:10 +000010607
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010608 case ScopeIterator::ScopeTypeClosure:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010609 PrintF("Closure:\n");
10610 CurrentContext()->Print();
10611 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010612 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010613 if (extension->IsJSContextExtensionObject()) {
10614 extension->Print();
10615 }
10616 }
10617 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010618
10619 default:
10620 UNREACHABLE();
10621 }
10622 PrintF("\n");
10623 }
10624#endif
10625
10626 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010627 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010628 JavaScriptFrame* frame_;
10629 Handle<JSFunction> function_;
10630 Handle<Context> context_;
10631 bool local_done_;
10632 bool at_local_;
10633
10634 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
10635};
10636
10637
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010638RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010639 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010640 ASSERT(args.length() == 2);
10641
10642 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010643 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010644 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10645 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010646 if (!maybe_check->ToObject(&check)) return maybe_check;
10647 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010648 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10649
10650 // Get the frame where the debugging is performed.
10651 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010652 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010653 JavaScriptFrame* frame = it.frame();
10654
10655 // Count the visible scopes.
10656 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010657 for (ScopeIterator it(isolate, frame); !it.Done(); it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010658 n++;
10659 }
10660
10661 return Smi::FromInt(n);
10662}
10663
10664
10665static const int kScopeDetailsTypeIndex = 0;
10666static const int kScopeDetailsObjectIndex = 1;
10667static const int kScopeDetailsSize = 2;
10668
10669// Return an array with scope details
10670// args[0]: number: break id
10671// args[1]: number: frame index
10672// args[2]: number: scope index
10673//
10674// The array returned contains the following information:
10675// 0: Scope type
10676// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010677RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010678 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010679 ASSERT(args.length() == 3);
10680
10681 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010682 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010683 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10684 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010685 if (!maybe_check->ToObject(&check)) return maybe_check;
10686 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010687 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10688 CONVERT_NUMBER_CHECKED(int, index, Int32, args[2]);
10689
10690 // Get the frame where the debugging is performed.
10691 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010692 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010693 JavaScriptFrame* frame = frame_it.frame();
10694
10695 // Find the requested scope.
10696 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010697 ScopeIterator it(isolate, frame);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010698 for (; !it.Done() && n < index; it.Next()) {
10699 n++;
10700 }
10701 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010702 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010703 }
10704
10705 // Calculate the size of the result.
10706 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010707 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010708
10709 // Fill in scope details.
10710 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010711 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010712 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010713 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010714
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010715 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010716}
10717
10718
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010719RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010720 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010721 ASSERT(args.length() == 0);
10722
10723#ifdef DEBUG
10724 // Print the scopes for the top frame.
10725 StackFrameLocator locator;
10726 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010727 for (ScopeIterator it(isolate, frame); !it.Done(); it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010728 it.DebugPrint();
10729 }
10730#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010731 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010732}
10733
10734
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010735RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010736 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010737 ASSERT(args.length() == 1);
10738
10739 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010740 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010741 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10742 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010743 if (!maybe_result->ToObject(&result)) return maybe_result;
10744 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010745
10746 // Count all archived V8 threads.
10747 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010748 for (ThreadState* thread =
10749 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010750 thread != NULL;
10751 thread = thread->Next()) {
10752 n++;
10753 }
10754
10755 // Total number of threads is current thread and archived threads.
10756 return Smi::FromInt(n + 1);
10757}
10758
10759
10760static const int kThreadDetailsCurrentThreadIndex = 0;
10761static const int kThreadDetailsThreadIdIndex = 1;
10762static const int kThreadDetailsSize = 2;
10763
10764// Return an array with thread details
10765// args[0]: number: break id
10766// args[1]: number: thread index
10767//
10768// The array returned contains the following information:
10769// 0: Is current thread?
10770// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010771RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010772 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010773 ASSERT(args.length() == 2);
10774
10775 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010776 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010777 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10778 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010779 if (!maybe_check->ToObject(&check)) return maybe_check;
10780 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010781 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
10782
10783 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010784 Handle<FixedArray> details =
10785 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010786
10787 // Thread index 0 is current thread.
10788 if (index == 0) {
10789 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010790 details->set(kThreadDetailsCurrentThreadIndex,
10791 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010792 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010793 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010794 } else {
10795 // Find the thread with the requested index.
10796 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010797 ThreadState* thread =
10798 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010799 while (index != n && thread != NULL) {
10800 thread = thread->Next();
10801 n++;
10802 }
10803 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010804 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010805 }
10806
10807 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010808 details->set(kThreadDetailsCurrentThreadIndex,
10809 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010810 details->set(kThreadDetailsThreadIdIndex,
10811 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010812 }
10813
10814 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010815 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010816}
10817
10818
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010819// Sets the disable break state
10820// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010821RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010822 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010823 ASSERT(args.length() == 1);
10824 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010825 isolate->debug()->set_disable_break(disable_break);
10826 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010827}
10828
10829
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010830RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010831 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010832 ASSERT(args.length() == 1);
10833
ager@chromium.org5aa501c2009-06-23 07:57:28 +000010834 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
10835 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010836 // Find the number of break points
10837 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010838 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010839 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010840 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010841 Handle<FixedArray>::cast(break_locations));
10842}
10843
10844
10845// Set a break point in a function
10846// args[0]: function
10847// args[1]: number: break source position (within the function source)
10848// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010849RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010850 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010851 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000010852 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
10853 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010854 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10855 RUNTIME_ASSERT(source_position >= 0);
10856 Handle<Object> break_point_object_arg = args.at<Object>(2);
10857
10858 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010859 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
10860 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010861
lrn@chromium.org32d961d2010-06-30 09:09:34 +000010862 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010863}
10864
10865
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010866Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
10867 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000010868 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010869 // Iterate the heap looking for SharedFunctionInfo generated from the
10870 // script. The inner most SharedFunctionInfo containing the source position
10871 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010872 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010873 // which is found is not compiled it is compiled and the heap is iterated
10874 // again as the compilation might create inner functions from the newly
10875 // compiled function and the actual requested break point might be in one of
10876 // these functions.
10877 bool done = false;
10878 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000010879 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010880 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010881 while (!done) {
10882 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010883 for (HeapObject* obj = iterator.next();
10884 obj != NULL; obj = iterator.next()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010885 if (obj->IsSharedFunctionInfo()) {
10886 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
10887 if (shared->script() == *script) {
10888 // If the SharedFunctionInfo found has the requested script data and
10889 // contains the source position it is a candidate.
10890 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +000010891 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010892 start_position = shared->start_position();
10893 }
10894 if (start_position <= position &&
10895 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +000010896 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010897 // candidate this is the new candidate.
10898 if (target.is_null()) {
10899 target_start_position = start_position;
10900 target = shared;
10901 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +000010902 if (target_start_position == start_position &&
10903 shared->end_position() == target->end_position()) {
10904 // If a top-level function contain only one function
10905 // declartion the source for the top-level and the function is
10906 // the same. In that case prefer the non top-level function.
10907 if (!shared->is_toplevel()) {
10908 target_start_position = start_position;
10909 target = shared;
10910 }
10911 } else if (target_start_position <= start_position &&
10912 shared->end_position() <= target->end_position()) {
10913 // This containment check includes equality as a function inside
10914 // a top-level function can share either start or end position
10915 // with the top-level function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010916 target_start_position = start_position;
10917 target = shared;
10918 }
10919 }
10920 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010921 }
10922 }
10923 }
10924
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010925 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010926 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010927 }
10928
10929 // If the candidate found is compiled we are done. NOTE: when lazy
10930 // compilation of inner functions is introduced some additional checking
10931 // needs to be done here to compile inner functions.
10932 done = target->is_compiled();
10933 if (!done) {
10934 // If the candidate is not compiled compile it to reveal any inner
10935 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010936 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010937 }
10938 }
10939
10940 return *target;
10941}
10942
10943
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010944// Changes the state of a break point in a script and returns source position
10945// where break point was set. NOTE: Regarding performance see the NOTE for
10946// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010947// args[0]: script to set break point in
10948// args[1]: number: break source position (within the script source)
10949// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010950RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010951 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010952 ASSERT(args.length() == 3);
10953 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
10954 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10955 RUNTIME_ASSERT(source_position >= 0);
10956 Handle<Object> break_point_object_arg = args.at<Object>(2);
10957
10958 // Get the script from the script wrapper.
10959 RUNTIME_ASSERT(wrapper->value()->IsScript());
10960 Handle<Script> script(Script::cast(wrapper->value()));
10961
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000010962 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010963 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010964 if (!result->IsUndefined()) {
10965 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
10966 // Find position within function. The script position might be before the
10967 // source position of the first function.
10968 int position;
10969 if (shared->start_position() > source_position) {
10970 position = 0;
10971 } else {
10972 position = source_position - shared->start_position();
10973 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010974 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010975 position += shared->start_position();
10976 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010977 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010978 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010979}
10980
10981
10982// Clear a break point
10983// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010984RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010985 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010986 ASSERT(args.length() == 1);
10987 Handle<Object> break_point_object_arg = args.at<Object>(0);
10988
10989 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010990 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010991
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010992 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010993}
10994
10995
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010996// Change the state of break on exceptions.
10997// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
10998// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010999RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011000 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011001 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011002 RUNTIME_ASSERT(args[0]->IsNumber());
11003 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011004
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011005 // If the number doesn't match an enum value, the ChangeBreakOnException
11006 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011007 ExceptionBreakType type =
11008 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011009 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011010 isolate->debug()->ChangeBreakOnException(type, enable);
11011 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011012}
11013
11014
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011015// Returns the state of break on exceptions
11016// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011017RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011018 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011019 ASSERT(args.length() == 1);
11020 RUNTIME_ASSERT(args[0]->IsNumber());
11021
11022 ExceptionBreakType type =
11023 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011024 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011025 return Smi::FromInt(result);
11026}
11027
11028
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011029// Prepare for stepping
11030// args[0]: break id for checking execution state
11031// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000011032// args[2]: number of times to perform the step, for step out it is the number
11033// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011034RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011035 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011036 ASSERT(args.length() == 3);
11037 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011038 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011039 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11040 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011041 if (!maybe_check->ToObject(&check)) return maybe_check;
11042 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011043 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011044 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011045 }
11046
11047 // Get the step action and check validity.
11048 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
11049 if (step_action != StepIn &&
11050 step_action != StepNext &&
11051 step_action != StepOut &&
11052 step_action != StepInMin &&
11053 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011054 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011055 }
11056
11057 // Get the number of steps.
11058 int step_count = NumberToInt32(args[2]);
11059 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011060 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011061 }
11062
ager@chromium.orga1645e22009-09-09 19:27:10 +000011063 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011064 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011065
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011066 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011067 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
11068 step_count);
11069 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011070}
11071
11072
11073// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011074RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011075 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011076 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011077 isolate->debug()->ClearStepping();
11078 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011079}
11080
11081
11082// Creates a copy of the with context chain. The copy of the context chain is
11083// is linked to the function context supplied.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011084static Handle<Context> CopyWithContextChain(Isolate* isolate,
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011085 Handle<JSFunction> function,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011086 Handle<Context> current,
11087 Handle<Context> base) {
11088 // At the end of the chain. Return the base context to link to.
11089 if (current->IsFunctionContext() || current->IsGlobalContext()) {
11090 return base;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011091 }
11092
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011093 // Recursively copy the with and catch contexts.
11094 HandleScope scope(isolate);
11095 Handle<Context> previous(current->previous());
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011096 Handle<Context> new_previous =
11097 CopyWithContextChain(isolate, function, previous, base);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011098 Handle<Context> new_current;
11099 if (current->IsCatchContext()) {
11100 Handle<String> name(String::cast(current->extension()));
11101 Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
11102 new_current =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011103 isolate->factory()->NewCatchContext(function,
11104 new_previous,
11105 name,
11106 thrown_object);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011107 } else {
11108 Handle<JSObject> extension(JSObject::cast(current->extension()));
11109 new_current =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011110 isolate->factory()->NewWithContext(function, new_previous, extension);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011111 }
11112 return scope.CloseAndEscape(new_current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011113}
11114
11115
11116// Helper function to find or create the arguments object for
11117// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011118static Handle<Object> GetArgumentsObject(Isolate* isolate,
11119 JavaScriptFrame* frame,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011120 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +000011121 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011122 const ScopeInfo<>* sinfo,
11123 Handle<Context> function_context) {
11124 // Try to find the value of 'arguments' to pass as parameter. If it is not
11125 // found (that is the debugged function does not reference 'arguments' and
11126 // does not support eval) then create an 'arguments' object.
11127 int index;
11128 if (sinfo->number_of_stack_slots() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011129 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011130 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011131 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011132 }
11133 }
11134
11135 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011136 index = scope_info->ContextSlotIndex(isolate->heap()->arguments_symbol(),
11137 NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011138 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011139 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011140 }
11141 }
11142
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000011143 const int length = frame->ComputeParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011144 Handle<JSObject> arguments =
11145 isolate->factory()->NewArgumentsObject(function, length);
11146 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011147
11148 AssertNoAllocation no_gc;
11149 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011150 for (int i = 0; i < length; i++) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000011151 array->set(i, frame->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011152 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000011153 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011154 return arguments;
11155}
11156
11157
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011158static const char kSourceStr[] =
11159 "(function(arguments,__source__){return eval(__source__);})";
11160
11161
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011162// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000011163// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011164// extension part has all the parameters and locals of the function on the
11165// stack frame. A function which calls eval with the code to evaluate is then
11166// compiled in this context and called in this context. As this context
11167// replaces the context of the function on the stack frame a new (empty)
11168// function is created as well to be used as the closure for the context.
11169// This function and the context acts as replacements for the function on the
11170// stack frame presenting the same view of the values of parameters and
11171// local variables as if the piece of JavaScript was evaluated at the point
11172// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011173RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011174 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011175
11176 // Check the execution state and decode arguments frame and source to be
11177 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011178 ASSERT(args.length() == 5);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011179 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011180 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11181 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011182 if (!maybe_check_result->ToObject(&check_result)) {
11183 return maybe_check_result;
11184 }
11185 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011186 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
11187 CONVERT_ARG_CHECKED(String, source, 2);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011188 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011189 Handle<Object> additional_context(args[4]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011190
11191 // Handle the processing of break.
11192 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011193
11194 // Get the frame where the debugging is performed.
11195 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011196 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011197 JavaScriptFrame* frame = it.frame();
11198 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +000011199 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011200 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011201
11202 // Traverse the saved contexts chain to find the active context for the
11203 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011204 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000011205 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011206 save = save->prev();
11207 }
11208 ASSERT(save != NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011209 SaveContext savex(isolate);
11210 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011211
11212 // Create the (empty) function replacing the function on the stack frame for
11213 // the purpose of evaluating in the context created below. It is important
11214 // that this function does not describe any parameters and local variables
11215 // in the context. If it does then this will cause problems with the lookup
11216 // in Context::Lookup, where context slots for parameters and local variables
11217 // are looked at before the extension object.
11218 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011219 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
11220 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011221 go_between->set_context(function->context());
11222#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011223 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011224 ASSERT(go_between_sinfo.number_of_parameters() == 0);
11225 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
11226#endif
11227
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011228 // Materialize the content of the local scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011229 Handle<JSObject> local_scope = MaterializeLocalScope(isolate, frame);
11230 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011231
11232 // Allocate a new context for the debug evaluation and set the extension
11233 // object build.
11234 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011235 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
11236 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011237 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011238 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011239 Handle<Context> frame_context(Context::cast(frame->context()));
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011240 Handle<Context> function_context(frame_context->declaration_context());
11241 context = CopyWithContextChain(isolate, go_between, frame_context, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011242
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011243 if (additional_context->IsJSObject()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011244 Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011245 context =
11246 isolate->factory()->NewWithContext(go_between, context, extension);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011247 }
11248
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011249 // Wrap the evaluation statement in a new function compiled in the newly
11250 // created context. The function has one parameter which has to be called
11251 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000011252 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011253 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011254
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011255 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011256 isolate->factory()->NewStringFromAscii(
11257 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011258
11259 // Currently, the eval code will be executed in non-strict mode,
11260 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011261 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000011262 Compiler::CompileEval(function_source,
11263 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011264 context->IsGlobalContext(),
11265 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011266 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011267 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011268 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011269
11270 // Invoke the result of the compilation to get the evaluation function.
11271 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011272 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011273 Handle<Object> evaluation_function =
11274 Execution::Call(compiled_function, receiver, 0, NULL,
11275 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011276 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011277
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011278 Handle<Object> arguments = GetArgumentsObject(isolate, frame,
11279 function, scope_info,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011280 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011281
11282 // Invoke the evaluation function and return the result.
11283 const int argc = 2;
11284 Object** argv[argc] = { arguments.location(),
11285 Handle<Object>::cast(source).location() };
11286 Handle<Object> result =
11287 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
11288 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011289 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011290
11291 // Skip the global proxy as it has no properties and always delegates to the
11292 // real global object.
11293 if (result->IsJSGlobalProxy()) {
11294 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
11295 }
11296
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011297 return *result;
11298}
11299
11300
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011301RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011302 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011303
11304 // Check the execution state and decode arguments frame and source to be
11305 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011306 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011307 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011308 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11309 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011310 if (!maybe_check_result->ToObject(&check_result)) {
11311 return maybe_check_result;
11312 }
11313 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011314 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011315 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011316 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011317
11318 // Handle the processing of break.
11319 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011320
11321 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011322 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011323 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011324 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011325 top = top->prev();
11326 }
11327 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011328 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011329 }
11330
11331 // Get the global context now set to the top context from before the
11332 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011333 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011334
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011335 bool is_global = true;
11336
11337 if (additional_context->IsJSObject()) {
11338 // Create a function context first, than put 'with' context on top of it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011339 Handle<JSFunction> go_between = isolate->factory()->NewFunction(
11340 isolate->factory()->empty_string(),
11341 isolate->factory()->undefined_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011342 go_between->set_context(*context);
11343 context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011344 isolate->factory()->NewFunctionContext(
11345 Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011346 context->set_extension(JSObject::cast(*additional_context));
11347 is_global = false;
11348 }
11349
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011350 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011351 // Currently, the eval code will be executed in non-strict mode,
11352 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011353 Handle<SharedFunctionInfo> shared =
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011354 Compiler::CompileEval(source, context, is_global, kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011355 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011356 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011357 Handle<JSFunction>(
11358 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
11359 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011360
11361 // Invoke the result of the compilation to get the evaluation function.
11362 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011363 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011364 Handle<Object> result =
11365 Execution::Call(compiled_function, receiver, 0, NULL,
11366 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011367 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011368 return *result;
11369}
11370
11371
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011372RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011373 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011374 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011375
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011376 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011377 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011378
11379 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000011380 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000011381 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
11382 // Get the script wrapper in a local handle before calling GetScriptWrapper,
11383 // because using
11384 // instances->set(i, *GetScriptWrapper(script))
11385 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
11386 // already have deferenced the instances handle.
11387 Handle<JSValue> wrapper = GetScriptWrapper(script);
11388 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011389 }
11390
11391 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011392 Handle<JSObject> result =
11393 isolate->factory()->NewJSObject(isolate->array_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011394 Handle<JSArray>::cast(result)->SetContent(*instances);
11395 return *result;
11396}
11397
11398
11399// Helper function used by Runtime_DebugReferencedBy below.
11400static int DebugReferencedBy(JSObject* target,
11401 Object* instance_filter, int max_references,
11402 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011403 JSFunction* arguments_function) {
11404 NoHandleAllocation ha;
11405 AssertNoAllocation no_alloc;
11406
11407 // Iterate the heap.
11408 int count = 0;
11409 JSObject* last = NULL;
11410 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011411 HeapObject* heap_obj = NULL;
11412 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011413 (max_references == 0 || count < max_references)) {
11414 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011415 if (heap_obj->IsJSObject()) {
11416 // Skip context extension objects and argument arrays as these are
11417 // checked in the context of functions using them.
11418 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000011419 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011420 obj->map()->constructor() == arguments_function) {
11421 continue;
11422 }
11423
11424 // Check if the JS object has a reference to the object looked for.
11425 if (obj->ReferencesObject(target)) {
11426 // Check instance filter if supplied. This is normally used to avoid
11427 // references from mirror objects (see Runtime_IsInPrototypeChain).
11428 if (!instance_filter->IsUndefined()) {
11429 Object* V = obj;
11430 while (true) {
11431 Object* prototype = V->GetPrototype();
11432 if (prototype->IsNull()) {
11433 break;
11434 }
11435 if (instance_filter == prototype) {
11436 obj = NULL; // Don't add this object.
11437 break;
11438 }
11439 V = prototype;
11440 }
11441 }
11442
11443 if (obj != NULL) {
11444 // Valid reference found add to instance array if supplied an update
11445 // count.
11446 if (instances != NULL && count < instances_size) {
11447 instances->set(count, obj);
11448 }
11449 last = obj;
11450 count++;
11451 }
11452 }
11453 }
11454 }
11455
11456 // Check for circular reference only. This can happen when the object is only
11457 // referenced from mirrors and has a circular reference in which case the
11458 // object is not really alive and would have been garbage collected if not
11459 // referenced from the mirror.
11460 if (count == 1 && last == target) {
11461 count = 0;
11462 }
11463
11464 // Return the number of referencing objects found.
11465 return count;
11466}
11467
11468
11469// Scan the heap for objects with direct references to an object
11470// args[0]: the object to find references to
11471// args[1]: constructor function for instances to exclude (Mirror)
11472// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011473RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011474 ASSERT(args.length() == 3);
11475
11476 // First perform a full GC in order to avoid references from dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011477 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011478
11479 // Check parameters.
11480 CONVERT_CHECKED(JSObject, target, args[0]);
11481 Object* instance_filter = args[1];
11482 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
11483 instance_filter->IsJSObject());
11484 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
11485 RUNTIME_ASSERT(max_references >= 0);
11486
11487 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011488 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011489 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011490 JSFunction* arguments_function =
11491 JSFunction::cast(arguments_boilerplate->map()->constructor());
11492
11493 // Get the number of referencing objects.
11494 int count;
11495 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000011496 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011497
11498 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011499 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011500 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011501 if (!maybe_object->ToObject(&object)) return maybe_object;
11502 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011503 FixedArray* instances = FixedArray::cast(object);
11504
11505 // Fill the referencing objects.
11506 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000011507 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011508
11509 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011510 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011511 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
11512 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011513 if (!maybe_result->ToObject(&result)) return maybe_result;
11514 }
11515 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011516 return result;
11517}
11518
11519
11520// Helper function used by Runtime_DebugConstructedBy below.
11521static int DebugConstructedBy(JSFunction* constructor, int max_references,
11522 FixedArray* instances, int instances_size) {
11523 AssertNoAllocation no_alloc;
11524
11525 // Iterate the heap.
11526 int count = 0;
11527 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011528 HeapObject* heap_obj = NULL;
11529 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011530 (max_references == 0 || count < max_references)) {
11531 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011532 if (heap_obj->IsJSObject()) {
11533 JSObject* obj = JSObject::cast(heap_obj);
11534 if (obj->map()->constructor() == constructor) {
11535 // Valid reference found add to instance array if supplied an update
11536 // count.
11537 if (instances != NULL && count < instances_size) {
11538 instances->set(count, obj);
11539 }
11540 count++;
11541 }
11542 }
11543 }
11544
11545 // Return the number of referencing objects found.
11546 return count;
11547}
11548
11549
11550// Scan the heap for objects constructed by a specific function.
11551// args[0]: the constructor to find instances of
11552// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011553RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011554 ASSERT(args.length() == 2);
11555
11556 // First perform a full GC in order to avoid dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011557 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011558
11559 // Check parameters.
11560 CONVERT_CHECKED(JSFunction, constructor, args[0]);
11561 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
11562 RUNTIME_ASSERT(max_references >= 0);
11563
11564 // Get the number of referencing objects.
11565 int count;
11566 count = DebugConstructedBy(constructor, max_references, NULL, 0);
11567
11568 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011569 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011570 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011571 if (!maybe_object->ToObject(&object)) return maybe_object;
11572 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011573 FixedArray* instances = FixedArray::cast(object);
11574
11575 // Fill the referencing objects.
11576 count = DebugConstructedBy(constructor, max_references, instances, count);
11577
11578 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011579 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011580 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
11581 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011582 if (!maybe_result->ToObject(&result)) return maybe_result;
11583 }
11584 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011585 return result;
11586}
11587
11588
ager@chromium.orgddb913d2009-01-27 10:01:48 +000011589// Find the effective prototype object as returned by __proto__.
11590// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011591RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011592 ASSERT(args.length() == 1);
11593
11594 CONVERT_CHECKED(JSObject, obj, args[0]);
11595
ager@chromium.orgddb913d2009-01-27 10:01:48 +000011596 // Use the __proto__ accessor.
11597 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011598}
11599
11600
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011601RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000011602 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011603 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011604 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011605}
11606
11607
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011608RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011609#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011610 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011611 ASSERT(args.length() == 1);
11612 // Get the function and make sure it is compiled.
11613 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011614 Handle<SharedFunctionInfo> shared(func->shared());
11615 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011616 return Failure::Exception();
11617 }
11618 func->code()->PrintLn();
11619#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011620 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011621}
ager@chromium.org9085a012009-05-11 19:22:57 +000011622
11623
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011624RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011625#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011626 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011627 ASSERT(args.length() == 1);
11628 // Get the function and make sure it is compiled.
11629 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011630 Handle<SharedFunctionInfo> shared(func->shared());
11631 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011632 return Failure::Exception();
11633 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011634 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011635#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011636 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011637}
11638
11639
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011640RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000011641 NoHandleAllocation ha;
11642 ASSERT(args.length() == 1);
11643
11644 CONVERT_CHECKED(JSFunction, f, args[0]);
11645 return f->shared()->inferred_name();
11646}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011647
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011648
11649static int FindSharedFunctionInfosForScript(Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011650 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011651 AssertNoAllocation no_allocations;
11652
11653 int counter = 0;
11654 int buffer_size = buffer->length();
11655 HeapIterator iterator;
11656 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
11657 ASSERT(obj != NULL);
11658 if (!obj->IsSharedFunctionInfo()) {
11659 continue;
11660 }
11661 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
11662 if (shared->script() != script) {
11663 continue;
11664 }
11665 if (counter < buffer_size) {
11666 buffer->set(counter, shared);
11667 }
11668 counter++;
11669 }
11670 return counter;
11671}
11672
11673// For a script finds all SharedFunctionInfo's in the heap that points
11674// to this script. Returns JSArray of SharedFunctionInfo wrapped
11675// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011676RUNTIME_FUNCTION(MaybeObject*,
11677 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011678 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011679 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011680 CONVERT_CHECKED(JSValue, script_value, args[0]);
11681
11682 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
11683
11684 const int kBufferSize = 32;
11685
11686 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011687 array = isolate->factory()->NewFixedArray(kBufferSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011688 int number = FindSharedFunctionInfosForScript(*script, *array);
11689 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011690 array = isolate->factory()->NewFixedArray(number);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011691 FindSharedFunctionInfosForScript(*script, *array);
11692 }
11693
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011694 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011695 result->set_length(Smi::FromInt(number));
11696
11697 LiveEdit::WrapSharedFunctionInfos(result);
11698
11699 return *result;
11700}
11701
11702// For a script calculates compilation information about all its functions.
11703// The script source is explicitly specified by the second argument.
11704// The source of the actual script is not used, however it is important that
11705// all generated code keeps references to this particular instance of script.
11706// Returns a JSArray of compilation infos. The array is ordered so that
11707// each function with all its descendant is always stored in a continues range
11708// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011709RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011710 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011711 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011712 CONVERT_CHECKED(JSValue, script, args[0]);
11713 CONVERT_ARG_CHECKED(String, source, 1);
11714 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
11715
11716 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
11717
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011718 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011719 return Failure::Exception();
11720 }
11721
11722 return result;
11723}
11724
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011725// Changes the source of the script to a new_source.
11726// If old_script_name is provided (i.e. is a String), also creates a copy of
11727// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011728RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011729 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011730 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011731 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
11732 CONVERT_ARG_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011733 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011734
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011735 CONVERT_CHECKED(Script, original_script_pointer,
11736 original_script_value->value());
11737 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011738
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011739 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
11740 new_source,
11741 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011742
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011743 if (old_script->IsScript()) {
11744 Handle<Script> script_handle(Script::cast(old_script));
11745 return *(GetScriptWrapper(script_handle));
11746 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011747 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011748 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011749}
11750
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011751
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011752RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011753 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011754 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011755 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
11756 return LiveEdit::FunctionSourceUpdated(shared_info);
11757}
11758
11759
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011760// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011761RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011762 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011763 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011764 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
11765 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
11766
ager@chromium.orgac091b72010-05-05 07:34:42 +000011767 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011768}
11769
11770// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011771RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011772 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011773 HandleScope scope(isolate);
11774 Handle<Object> function_object(args[0], isolate);
11775 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011776
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011777 if (function_object->IsJSValue()) {
11778 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
11779 if (script_object->IsJSValue()) {
11780 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011781 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011782 }
11783
11784 LiveEdit::SetFunctionScript(function_wrapper, script_object);
11785 } else {
11786 // Just ignore this. We may not have a SharedFunctionInfo for some functions
11787 // and we check it in this function.
11788 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011789
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011790 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011791}
11792
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011793
11794// In a code of a parent function replaces original function as embedded object
11795// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011796RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011797 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011798 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011799
11800 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
11801 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
11802 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
11803
11804 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
11805 subst_wrapper);
11806
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011807 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011808}
11809
11810
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011811// Updates positions of a shared function info (first parameter) according
11812// to script source change. Text change is described in second parameter as
11813// array of groups of 3 numbers:
11814// (change_begin, change_end, change_end_new_position).
11815// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011816RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011817 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011818 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011819 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
11820 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
11821
ager@chromium.orgac091b72010-05-05 07:34:42 +000011822 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011823}
11824
11825
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011826// For array of SharedFunctionInfo's (each wrapped in JSValue)
11827// checks that none of them have activations on stacks (of any thread).
11828// Returns array of the same length with corresponding results of
11829// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011830RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000011831 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011832 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011833 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000011834 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011835
ager@chromium.org357bf652010-04-12 11:30:10 +000011836 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011837}
11838
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000011839// Compares 2 strings line-by-line, then token-wise and returns diff in form
11840// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
11841// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011842RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011843 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011844 HandleScope scope(isolate);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011845 CONVERT_ARG_CHECKED(String, s1, 0);
11846 CONVERT_ARG_CHECKED(String, s2, 1);
11847
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000011848 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011849}
11850
11851
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011852// A testing entry. Returns statement position which is the closest to
11853// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011854RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011855 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011856 HandleScope scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011857 CONVERT_ARG_CHECKED(JSFunction, function, 0);
11858 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11859
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011860 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011861
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011862 if (code->kind() != Code::FUNCTION &&
11863 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011864 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011865 }
11866
11867 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011868 int closest_pc = 0;
11869 int distance = kMaxInt;
11870 while (!it.done()) {
11871 int statement_position = static_cast<int>(it.rinfo()->data());
11872 // Check if this break point is closer that what was previously found.
11873 if (source_position <= statement_position &&
11874 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000011875 closest_pc =
11876 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011877 distance = statement_position - source_position;
11878 // Check whether we can't get any closer.
11879 if (distance == 0) break;
11880 }
11881 it.next();
11882 }
11883
11884 return Smi::FromInt(closest_pc);
11885}
11886
11887
ager@chromium.org357bf652010-04-12 11:30:10 +000011888// Calls specified function with or without entering the debugger.
11889// This is used in unit tests to run code as if debugger is entered or simply
11890// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011891RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000011892 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011893 HandleScope scope(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +000011894 CONVERT_ARG_CHECKED(JSFunction, function, 0);
11895 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
11896
11897 Handle<Object> result;
11898 bool pending_exception;
11899 {
11900 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011901 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000011902 &pending_exception);
11903 } else {
11904 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011905 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000011906 &pending_exception);
11907 }
11908 }
11909 if (!pending_exception) {
11910 return *result;
11911 } else {
11912 return Failure::Exception();
11913 }
11914}
11915
11916
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011917// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011918RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011919 CONVERT_CHECKED(String, arg, args[0]);
11920 SmartPointer<char> flags =
11921 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
11922 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011923 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011924}
11925
11926
11927// Performs a GC.
11928// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011929RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011930 isolate->heap()->CollectAllGarbage(true);
11931 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011932}
11933
11934
11935// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011936RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011937 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011938 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011939 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011940 }
11941 return Smi::FromInt(usage);
11942}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011943
11944
11945// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011946RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011947#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011948 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011949#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011950 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011951#endif
11952}
11953
11954
11955// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011956RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011957#ifdef LIVE_OBJECT_LIST
11958 return LiveObjectList::Capture();
11959#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011960 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011961#endif
11962}
11963
11964
11965// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011966RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011967#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011968 CONVERT_SMI_ARG_CHECKED(id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011969 bool success = LiveObjectList::Delete(id);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011970 return success ? isolate->heap()->true_value() :
11971 isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011972#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011973 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011974#endif
11975}
11976
11977
11978// Generates the response to a debugger request for a dump of the objects
11979// contained in the difference between the captured live object lists
11980// specified by id1 and id2.
11981// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
11982// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011983RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011984#ifdef LIVE_OBJECT_LIST
11985 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011986 CONVERT_SMI_ARG_CHECKED(id1, 0);
11987 CONVERT_SMI_ARG_CHECKED(id2, 1);
11988 CONVERT_SMI_ARG_CHECKED(start, 2);
11989 CONVERT_SMI_ARG_CHECKED(count, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011990 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
11991 EnterDebugger enter_debugger;
11992 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
11993#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011994 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011995#endif
11996}
11997
11998
11999// Gets the specified object as requested by the debugger.
12000// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012001RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012002#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012003 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012004 Object* result = LiveObjectList::GetObj(obj_id);
12005 return result;
12006#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012007 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012008#endif
12009}
12010
12011
12012// Gets the obj id for the specified address if valid.
12013// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012014RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012015#ifdef LIVE_OBJECT_LIST
12016 HandleScope scope;
12017 CONVERT_ARG_CHECKED(String, address, 0);
12018 Object* result = LiveObjectList::GetObjId(address);
12019 return result;
12020#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012021 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012022#endif
12023}
12024
12025
12026// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012027RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012028#ifdef LIVE_OBJECT_LIST
12029 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012030 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012031 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
12032 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
12033 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
12034 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
12035 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
12036
12037 Handle<JSObject> instance_filter;
12038 if (args[1]->IsJSObject()) {
12039 instance_filter = args.at<JSObject>(1);
12040 }
12041 bool verbose = false;
12042 if (args[2]->IsBoolean()) {
12043 verbose = args[2]->IsTrue();
12044 }
12045 int start = 0;
12046 if (args[3]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012047 start = args.smi_at(3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012048 }
12049 int limit = Smi::kMaxValue;
12050 if (args[4]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012051 limit = args.smi_at(4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012052 }
12053
12054 return LiveObjectList::GetObjRetainers(obj_id,
12055 instance_filter,
12056 verbose,
12057 start,
12058 limit,
12059 filter_obj);
12060#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012061 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012062#endif
12063}
12064
12065
12066// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012067RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012068#ifdef LIVE_OBJECT_LIST
12069 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012070 CONVERT_SMI_ARG_CHECKED(obj_id1, 0);
12071 CONVERT_SMI_ARG_CHECKED(obj_id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012072 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
12073
12074 Handle<JSObject> instance_filter;
12075 if (args[2]->IsJSObject()) {
12076 instance_filter = args.at<JSObject>(2);
12077 }
12078
12079 Object* result =
12080 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
12081 return result;
12082#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012083 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012084#endif
12085}
12086
12087
12088// Generates the response to a debugger request for a list of all
12089// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012090RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012091#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012092 CONVERT_SMI_ARG_CHECKED(start, 0);
12093 CONVERT_SMI_ARG_CHECKED(count, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012094 return LiveObjectList::Info(start, count);
12095#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012096 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012097#endif
12098}
12099
12100
12101// Gets a dump of the specified object as requested by the debugger.
12102// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012103RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012104#ifdef LIVE_OBJECT_LIST
12105 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012106 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012107 Object* result = LiveObjectList::PrintObj(obj_id);
12108 return result;
12109#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012110 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012111#endif
12112}
12113
12114
12115// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012116RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012117#ifdef LIVE_OBJECT_LIST
12118 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012119 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012120#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012121 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012122#endif
12123}
12124
12125
12126// Generates the response to a debugger request for a summary of the types
12127// of objects in the difference between the captured live object lists
12128// specified by id1 and id2.
12129// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12130// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012131RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012132#ifdef LIVE_OBJECT_LIST
12133 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012134 CONVERT_SMI_ARG_CHECKED(id1, 0);
12135 CONVERT_SMI_ARG_CHECKED(id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012136 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
12137
12138 EnterDebugger enter_debugger;
12139 return LiveObjectList::Summarize(id1, id2, filter_obj);
12140#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012141 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012142#endif
12143}
12144
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012145#endif // ENABLE_DEBUGGER_SUPPORT
12146
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012147
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012148#ifdef ENABLE_LOGGING_AND_PROFILING
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012149RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012150 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012151 v8::V8::ResumeProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012152 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012153}
12154
12155
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012156RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012157 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012158 v8::V8::PauseProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012159 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012160}
12161
12162#endif // ENABLE_LOGGING_AND_PROFILING
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012163
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012164// Finds the script object from the script data. NOTE: This operation uses
12165// heap traversal to find the function generated for the source position
12166// for the requested break point. For lazily compiled functions several heap
12167// traversals might be required rendering this operation as a rather slow
12168// operation. However for setting break points which is normally done through
12169// some kind of user interaction the performance is not crucial.
12170static Handle<Object> Runtime_GetScriptFromScriptName(
12171 Handle<String> script_name) {
12172 // Scan the heap for Script objects to find the script with the requested
12173 // script data.
12174 Handle<Script> script;
12175 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012176 HeapObject* obj = NULL;
12177 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012178 // If a script is found check if it has the script data requested.
12179 if (obj->IsScript()) {
12180 if (Script::cast(obj)->name()->IsString()) {
12181 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
12182 script = Handle<Script>(Script::cast(obj));
12183 }
12184 }
12185 }
12186 }
12187
12188 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012189 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012190
12191 // Return the script found.
12192 return GetScriptWrapper(script);
12193}
12194
12195
12196// Get the script object from script data. NOTE: Regarding performance
12197// see the NOTE for GetScriptFromScriptData.
12198// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012199RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012200 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012201
12202 ASSERT(args.length() == 1);
12203
12204 CONVERT_CHECKED(String, script_name, args[0]);
12205
12206 // Find the requested script.
12207 Handle<Object> result =
12208 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
12209 return *result;
12210}
12211
12212
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012213// Determines whether the given stack frame should be displayed in
12214// a stack trace. The caller is the error constructor that asked
12215// for the stack trace to be collected. The first time a construct
12216// call to this function is encountered it is skipped. The seen_caller
12217// in/out parameter is used to remember if the caller has been seen
12218// yet.
12219static bool ShowFrameInStackTrace(StackFrame* raw_frame, Object* caller,
12220 bool* seen_caller) {
12221 // Only display JS frames.
12222 if (!raw_frame->is_java_script())
12223 return false;
12224 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
12225 Object* raw_fun = frame->function();
12226 // Not sure when this can happen but skip it just in case.
12227 if (!raw_fun->IsJSFunction())
12228 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012229 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012230 *seen_caller = true;
12231 return false;
12232 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012233 // Skip all frames until we've seen the caller. Also, skip the most
12234 // obvious builtin calls. Some builtin calls (such as Number.ADD
12235 // which is invoked using 'call') are very difficult to recognize
12236 // so we're leaving them in for now.
12237 return *seen_caller && !frame->receiver()->IsJSBuiltinsObject();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012238}
12239
12240
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012241// Collect the raw data for a stack trace. Returns an array of 4
12242// element segments each containing a receiver, function, code and
12243// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012244RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012245 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012246 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012247 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
12248
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012249 HandleScope scope(isolate);
12250 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012251
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000012252 limit = Max(limit, 0); // Ensure that limit is not negative.
12253 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012254 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012255 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012256
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012257 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012258 // If the caller parameter is a function we skip frames until we're
12259 // under it before starting to collect.
12260 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012261 int cursor = 0;
12262 int frames_seen = 0;
12263 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012264 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012265 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012266 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012267 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012268 // Set initial size to the maximum inlining level + 1 for the outermost
12269 // function.
12270 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012271 frame->Summarize(&frames);
12272 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012273 if (cursor + 4 > elements->length()) {
12274 int new_capacity = JSObject::NewElementsCapacity(elements->length());
12275 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012276 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012277 for (int i = 0; i < cursor; i++) {
12278 new_elements->set(i, elements->get(i));
12279 }
12280 elements = new_elements;
12281 }
12282 ASSERT(cursor + 4 <= elements->length());
12283
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012284 Handle<Object> recv = frames[i].receiver();
12285 Handle<JSFunction> fun = frames[i].function();
12286 Handle<Code> code = frames[i].code();
12287 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012288 elements->set(cursor++, *recv);
12289 elements->set(cursor++, *fun);
12290 elements->set(cursor++, *code);
12291 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012292 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012293 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012294 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012295 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012296 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012297 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012298 return *result;
12299}
12300
12301
ager@chromium.org3811b432009-10-28 14:53:37 +000012302// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012303RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000012304 ASSERT_EQ(args.length(), 0);
12305
12306 NoHandleAllocation ha;
12307
12308 const char* version_string = v8::V8::GetVersion();
12309
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012310 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
12311 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000012312}
12313
12314
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012315RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012316 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012317 OS::PrintError("abort: %s\n",
12318 reinterpret_cast<char*>(args[0]) + args.smi_at(1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012319 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012320 OS::Abort();
12321 UNREACHABLE();
12322 return NULL;
12323}
12324
12325
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012326RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012327 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012328 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012329 Object* key = args[1];
12330
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012331 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012332 Object* o = cache->get(finger_index);
12333 if (o == key) {
12334 // The fastest case: hit the same place again.
12335 return cache->get(finger_index + 1);
12336 }
12337
12338 for (int i = finger_index - 2;
12339 i >= JSFunctionResultCache::kEntriesIndex;
12340 i -= 2) {
12341 o = cache->get(i);
12342 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012343 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012344 return cache->get(i + 1);
12345 }
12346 }
12347
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012348 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012349 ASSERT(size <= cache->length());
12350
12351 for (int i = size - 2; i > finger_index; i -= 2) {
12352 o = cache->get(i);
12353 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012354 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012355 return cache->get(i + 1);
12356 }
12357 }
12358
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012359 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012360 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012361
12362 Handle<JSFunctionResultCache> cache_handle(cache);
12363 Handle<Object> key_handle(key);
12364 Handle<Object> value;
12365 {
12366 Handle<JSFunction> factory(JSFunction::cast(
12367 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
12368 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012369 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012370 // This handle is nor shared, nor used later, so it's safe.
12371 Object** argv[] = { key_handle.location() };
12372 bool pending_exception = false;
12373 value = Execution::Call(factory,
12374 receiver,
12375 1,
12376 argv,
12377 &pending_exception);
12378 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012379 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012380
12381#ifdef DEBUG
12382 cache_handle->JSFunctionResultCacheVerify();
12383#endif
12384
12385 // Function invocation may have cleared the cache. Reread all the data.
12386 finger_index = cache_handle->finger_index();
12387 size = cache_handle->size();
12388
12389 // If we have spare room, put new data into it, otherwise evict post finger
12390 // entry which is likely to be the least recently used.
12391 int index = -1;
12392 if (size < cache_handle->length()) {
12393 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
12394 index = size;
12395 } else {
12396 index = finger_index + JSFunctionResultCache::kEntrySize;
12397 if (index == cache_handle->length()) {
12398 index = JSFunctionResultCache::kEntriesIndex;
12399 }
12400 }
12401
12402 ASSERT(index % 2 == 0);
12403 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
12404 ASSERT(index < cache_handle->length());
12405
12406 cache_handle->set(index, *key_handle);
12407 cache_handle->set(index + 1, *value);
12408 cache_handle->set_finger_index(index);
12409
12410#ifdef DEBUG
12411 cache_handle->JSFunctionResultCacheVerify();
12412#endif
12413
12414 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012415}
12416
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012417
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012418RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012419 HandleScope scope(isolate);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012420 CONVERT_ARG_CHECKED(String, type, 0);
12421 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012422 return *isolate->factory()->NewJSMessageObject(
12423 type,
12424 arguments,
12425 0,
12426 0,
12427 isolate->factory()->undefined_value(),
12428 isolate->factory()->undefined_value(),
12429 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012430}
12431
12432
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012433RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012434 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12435 return message->type();
12436}
12437
12438
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012439RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012440 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12441 return message->arguments();
12442}
12443
12444
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012445RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012446 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12447 return Smi::FromInt(message->start_position());
12448}
12449
12450
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012451RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012452 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12453 return message->script();
12454}
12455
12456
kasper.lund44510672008-07-25 07:37:58 +000012457#ifdef DEBUG
12458// ListNatives is ONLY used by the fuzz-natives.js in debug mode
12459// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012460RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000012461 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012462 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012463#define COUNT_ENTRY(Name, argc, ressize) + 1
12464 int entry_count = 0
12465 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
12466 INLINE_FUNCTION_LIST(COUNT_ENTRY)
12467 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
12468#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012469 Factory* factory = isolate->factory();
12470 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012471 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012472 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000012473#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012474 { \
12475 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012476 Handle<String> name; \
12477 /* Inline runtime functions have an underscore in front of the name. */ \
12478 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012479 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012480 Vector<const char>("_" #Name, StrLength("_" #Name))); \
12481 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012482 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012483 Vector<const char>(#Name, StrLength(#Name))); \
12484 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012485 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012486 pair_elements->set(0, *name); \
12487 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012488 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012489 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012490 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012491 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012492 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012493 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012494 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012495 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012496#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012497 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012498 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012499 return *result;
12500}
kasper.lund44510672008-07-25 07:37:58 +000012501#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012502
12503
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012504RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012505 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000012506 CONVERT_CHECKED(String, format, args[0]);
12507 CONVERT_CHECKED(JSArray, elms, args[1]);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012508 Vector<const char> chars = format->ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012509 LOGGER->LogRuntime(chars, elms);
12510 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012511}
12512
12513
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012514RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012515 UNREACHABLE(); // implemented as macro in the parser
12516 return NULL;
12517}
12518
12519
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012520#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
12521 RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \
12522 CONVERT_CHECKED(JSObject, obj, args[0]); \
12523 return isolate->heap()->ToBoolean(obj->Has##Name()); \
12524 }
12525
12526ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements)
12527ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
12528ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
12529ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements)
12530ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
12531ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements)
12532ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements)
12533ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements)
12534ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements)
12535ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements)
12536ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements)
12537ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements)
12538ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements)
12539
12540#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
12541
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012542// ----------------------------------------------------------------------------
12543// Implementation of Runtime
12544
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012545#define F(name, number_of_args, result_size) \
12546 { Runtime::k##name, Runtime::RUNTIME, #name, \
12547 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012548
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012549
12550#define I(name, number_of_args, result_size) \
12551 { Runtime::kInline##name, Runtime::INLINE, \
12552 "_" #name, NULL, number_of_args, result_size },
12553
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012554static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012555 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012556 INLINE_FUNCTION_LIST(I)
12557 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012558};
12559
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012560
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012561MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
12562 Object* dictionary) {
12563 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012564 ASSERT(dictionary != NULL);
12565 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
12566 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000012567 Object* name_symbol;
12568 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012569 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012570 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
12571 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012572 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012573 { MaybeObject* maybe_dictionary = string_dictionary->Add(
12574 String::cast(name_symbol),
12575 Smi::FromInt(i),
12576 PropertyDetails(NONE, NORMAL));
12577 if (!maybe_dictionary->ToObject(&dictionary)) {
12578 // Non-recoverable failure. Calling code must restart heap
12579 // initialization.
12580 return maybe_dictionary;
12581 }
12582 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012583 }
12584 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012585}
12586
12587
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012588const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
12589 Heap* heap = name->GetHeap();
12590 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012591 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012592 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012593 int function_index = Smi::cast(smi_index)->value();
12594 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012595 }
12596 return NULL;
12597}
12598
12599
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012600const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012601 return &(kIntrinsicFunctions[static_cast<int>(id)]);
12602}
12603
12604
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012605void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012606 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012607 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012608 if (failure->IsRetryAfterGC()) {
12609 // Try to do a garbage collection; ignore it if it fails. The C
12610 // entry stub will throw an out-of-memory exception in that case.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012611 isolate->heap()->CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012612 } else {
12613 // Handle last resort GC and make sure to allow future allocations
12614 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012615 isolate->counters()->gc_last_resort_from_js()->Increment();
12616 isolate->heap()->CollectAllGarbage(false);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012617 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012618}
12619
12620
12621} } // namespace v8::internal