blob: df99fdc671ff48d25e3e0cb75c6cbd8d04a7f1b1 [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];
631 obj = obj->GetPrototype();
632 while (obj->IsJSObject() &&
633 JSObject::cast(obj)->map()->is_hidden_prototype()) {
634 obj = obj->GetPrototype();
635 }
636 return obj;
637}
638
639
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000640RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000641 NoHandleAllocation ha;
642 ASSERT(args.length() == 2);
643 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
644 Object* O = args[0];
645 Object* V = args[1];
646 while (true) {
647 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000648 if (prototype->IsNull()) return isolate->heap()->false_value();
649 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000650 V = prototype;
651 }
652}
653
654
ager@chromium.org9085a012009-05-11 19:22:57 +0000655// Inserts an object as the hidden prototype of another object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000656RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHiddenPrototype) {
ager@chromium.org9085a012009-05-11 19:22:57 +0000657 NoHandleAllocation ha;
658 ASSERT(args.length() == 2);
659 CONVERT_CHECKED(JSObject, jsobject, args[0]);
660 CONVERT_CHECKED(JSObject, proto, args[1]);
661
662 // Sanity checks. The old prototype (that we are replacing) could
663 // theoretically be null, but if it is not null then check that we
664 // didn't already install a hidden prototype here.
665 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
666 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
667 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
668
669 // Allocate up front before we start altering state in case we get a GC.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000670 Object* map_or_failure;
671 { MaybeObject* maybe_map_or_failure = proto->map()->CopyDropTransitions();
672 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
673 return maybe_map_or_failure;
674 }
675 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000676 Map* new_proto_map = Map::cast(map_or_failure);
677
lrn@chromium.org303ada72010-10-27 09:33:13 +0000678 { MaybeObject* maybe_map_or_failure = jsobject->map()->CopyDropTransitions();
679 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
680 return maybe_map_or_failure;
681 }
682 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000683 Map* new_map = Map::cast(map_or_failure);
684
685 // Set proto's prototype to be the old prototype of the object.
686 new_proto_map->set_prototype(jsobject->GetPrototype());
687 proto->set_map(new_proto_map);
688 new_proto_map->set_is_hidden_prototype();
689
690 // Set the object's prototype to proto.
691 new_map->set_prototype(proto);
692 jsobject->set_map(new_map);
693
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000694 return isolate->heap()->undefined_value();
ager@chromium.org9085a012009-05-11 19:22:57 +0000695}
696
697
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000698RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConstructCall) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000699 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000700 ASSERT(args.length() == 0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000701 JavaScriptFrameIterator it(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000702 return isolate->heap()->ToBoolean(it.frame()->IsConstructor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000703}
704
705
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000706// Recursively traverses hidden prototypes if property is not found
707static void GetOwnPropertyImplementation(JSObject* obj,
708 String* name,
709 LookupResult* result) {
710 obj->LocalLookupRealNamedProperty(name, result);
711
712 if (!result->IsProperty()) {
713 Object* proto = obj->GetPrototype();
714 if (proto->IsJSObject() &&
715 JSObject::cast(proto)->map()->is_hidden_prototype())
716 GetOwnPropertyImplementation(JSObject::cast(proto),
717 name, result);
718 }
719}
720
721
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000722static bool CheckAccessException(LookupResult* result,
723 v8::AccessType access_type) {
724 if (result->type() == CALLBACKS) {
725 Object* callback = result->GetCallbackObject();
726 if (callback->IsAccessorInfo()) {
727 AccessorInfo* info = AccessorInfo::cast(callback);
728 bool can_access =
729 (access_type == v8::ACCESS_HAS &&
730 (info->all_can_read() || info->all_can_write())) ||
731 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
732 (access_type == v8::ACCESS_SET && info->all_can_write());
733 return can_access;
734 }
735 }
736
737 return false;
738}
739
740
741static bool CheckAccess(JSObject* obj,
742 String* name,
743 LookupResult* result,
744 v8::AccessType access_type) {
745 ASSERT(result->IsProperty());
746
747 JSObject* holder = result->holder();
748 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000749 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000750 while (true) {
751 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000752 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000753 // Access check callback denied the access, but some properties
754 // can have a special permissions which override callbacks descision
755 // (currently see v8::AccessControl).
756 break;
757 }
758
759 if (current == holder) {
760 return true;
761 }
762
763 current = JSObject::cast(current->GetPrototype());
764 }
765
766 // API callbacks can have per callback access exceptions.
767 switch (result->type()) {
768 case CALLBACKS: {
769 if (CheckAccessException(result, access_type)) {
770 return true;
771 }
772 break;
773 }
774 case INTERCEPTOR: {
775 // If the object has an interceptor, try real named properties.
776 // Overwrite the result to fetch the correct property later.
777 holder->LookupRealNamedProperty(name, result);
778 if (result->IsProperty()) {
779 if (CheckAccessException(result, access_type)) {
780 return true;
781 }
782 }
783 break;
784 }
785 default:
786 break;
787 }
788
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000789 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000790 return false;
791}
792
793
794// TODO(1095): we should traverse hidden prototype hierachy as well.
795static bool CheckElementAccess(JSObject* obj,
796 uint32_t index,
797 v8::AccessType access_type) {
798 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000799 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000800 return false;
801 }
802
803 return true;
804}
805
806
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000807// Enumerator used as indices into the array returned from GetOwnProperty
808enum PropertyDescriptorIndices {
809 IS_ACCESSOR_INDEX,
810 VALUE_INDEX,
811 GETTER_INDEX,
812 SETTER_INDEX,
813 WRITABLE_INDEX,
814 ENUMERABLE_INDEX,
815 CONFIGURABLE_INDEX,
816 DESCRIPTOR_SIZE
817};
818
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000819// Returns an array with the property description:
820// if args[1] is not a property on args[0]
821// returns undefined
822// if args[1] is a data property on args[0]
823// [false, value, Writeable, Enumerable, Configurable]
824// if args[1] is an accessor on args[0]
825// [true, GetFunction, SetFunction, Enumerable, Configurable]
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000826RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000827 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000828 Heap* heap = isolate->heap();
829 HandleScope scope(isolate);
830 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
831 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000832 LookupResult result;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000833 CONVERT_ARG_CHECKED(JSObject, obj, 0);
834 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000835
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000836 // This could be an element.
837 uint32_t index;
838 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000839 switch (obj->HasLocalElement(index)) {
840 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000841 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000842
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000843 case JSObject::STRING_CHARACTER_ELEMENT: {
844 // Special handling of string objects according to ECMAScript 5
845 // 15.5.5.2. Note that this might be a string object with elements
846 // other than the actual string value. This is covered by the
847 // subsequent cases.
848 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
849 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000850 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000851
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000852 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000853 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000854 elms->set(WRITABLE_INDEX, heap->false_value());
855 elms->set(ENUMERABLE_INDEX, heap->false_value());
856 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000857 return *desc;
858 }
859
860 case JSObject::INTERCEPTED_ELEMENT:
861 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000862 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000863 Handle<Object> value = GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000864 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000865 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000866 elms->set(WRITABLE_INDEX, heap->true_value());
867 elms->set(ENUMERABLE_INDEX, heap->true_value());
868 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000869 return *desc;
870 }
871
872 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000873 Handle<JSObject> holder = obj;
874 if (obj->IsJSGlobalProxy()) {
875 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000876 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000877 ASSERT(proto->IsJSGlobalObject());
878 holder = Handle<JSObject>(JSObject::cast(proto));
879 }
whesse@chromium.org7b260152011-06-20 15:33:18 +0000880 FixedArray* elements = FixedArray::cast(holder->elements());
881 NumberDictionary* dictionary = NULL;
882 if (elements->map() == heap->non_strict_arguments_elements_map()) {
883 dictionary = NumberDictionary::cast(elements->get(1));
884 } else {
885 dictionary = NumberDictionary::cast(elements);
886 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000887 int entry = dictionary->FindEntry(index);
888 ASSERT(entry != NumberDictionary::kNotFound);
889 PropertyDetails details = dictionary->DetailsAt(entry);
890 switch (details.type()) {
891 case CALLBACKS: {
892 // This is an accessor property with getter and/or setter.
893 FixedArray* callbacks =
894 FixedArray::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000895 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000896 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
897 elms->set(GETTER_INDEX, callbacks->get(0));
898 }
899 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
900 elms->set(SETTER_INDEX, callbacks->get(1));
901 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000902 break;
903 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000904 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000905 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000906 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000907 Handle<Object> value = GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000908 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000909 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000910 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000911 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000912 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000913 default:
914 UNREACHABLE();
915 break;
916 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000917 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
918 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000919 return *desc;
920 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000921 }
922 }
923
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000924 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000925 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000926
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000927 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000928 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000929 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000930
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000931 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000932 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000933 }
934
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000935 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
936 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000937
938 bool is_js_accessor = (result.type() == CALLBACKS) &&
939 (result.GetCallbackObject()->IsFixedArray());
940
941 if (is_js_accessor) {
942 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000943 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000944
945 FixedArray* structure = FixedArray::cast(result.GetCallbackObject());
946 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
947 elms->set(GETTER_INDEX, structure->get(0));
948 }
949 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
950 elms->set(SETTER_INDEX, structure->get(1));
951 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000952 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000953 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
954 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000955
956 PropertyAttributes attrs;
957 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000958 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +0000959 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
960 if (!maybe_value->ToObject(&value)) return maybe_value;
961 }
962 elms->set(VALUE_INDEX, value);
963 }
964
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000965 return *desc;
966}
967
968
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000969RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000970 ASSERT(args.length() == 1);
971 CONVERT_CHECKED(JSObject, obj, args[0]);
972 return obj->PreventExtensions();
973}
974
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000975
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000976RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000977 ASSERT(args.length() == 1);
978 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000979 if (obj->IsJSGlobalProxy()) {
980 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000981 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000982 ASSERT(proto->IsJSGlobalObject());
983 obj = JSObject::cast(proto);
984 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000985 return obj->map()->is_extensible() ? isolate->heap()->true_value()
986 : isolate->heap()->false_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000987}
988
989
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000990RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000991 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000992 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000993 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
994 CONVERT_ARG_CHECKED(String, pattern, 1);
995 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000996 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
997 if (result.is_null()) return Failure::Exception();
998 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000999}
1000
1001
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001002RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001003 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001004 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001005 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001006 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001007}
1008
1009
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001010RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001011 ASSERT(args.length() == 1);
1012 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001013 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001014 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001015}
1016
1017
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001018RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001019 ASSERT(args.length() == 2);
1020 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001021 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001022 int index = field->value();
1023 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1024 InstanceType type = templ->map()->instance_type();
1025 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1026 type == OBJECT_TEMPLATE_INFO_TYPE);
1027 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001028 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001029 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1030 } else {
1031 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1032 }
1033 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001034}
1035
1036
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001037RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001038 ASSERT(args.length() == 1);
1039 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001040 Map* old_map = object->map();
1041 bool needs_access_checks = old_map->is_access_check_needed();
1042 if (needs_access_checks) {
1043 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001044 Object* new_map;
1045 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1046 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1047 }
ager@chromium.org32912102009-01-16 10:38:43 +00001048
1049 Map::cast(new_map)->set_is_access_check_needed(false);
1050 object->set_map(Map::cast(new_map));
1051 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001052 return needs_access_checks ? isolate->heap()->true_value()
1053 : isolate->heap()->false_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001054}
1055
1056
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001057RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001058 ASSERT(args.length() == 1);
1059 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001060 Map* old_map = object->map();
1061 if (!old_map->is_access_check_needed()) {
1062 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001063 Object* new_map;
1064 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1065 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1066 }
ager@chromium.org32912102009-01-16 10:38:43 +00001067
1068 Map::cast(new_map)->set_is_access_check_needed(true);
1069 object->set_map(Map::cast(new_map));
1070 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001071 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001072}
1073
1074
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001075static Failure* ThrowRedeclarationError(Isolate* isolate,
1076 const char* type,
1077 Handle<String> name) {
1078 HandleScope scope(isolate);
1079 Handle<Object> type_handle =
1080 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001081 Handle<Object> args[2] = { type_handle, name };
1082 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001083 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1084 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001085}
1086
1087
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001088RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001089 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001090 HandleScope scope(isolate);
1091 Handle<GlobalObject> global = Handle<GlobalObject>(
1092 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001093
ager@chromium.org3811b432009-10-28 14:53:37 +00001094 Handle<Context> context = args.at<Context>(0);
1095 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001096 bool is_eval = args.smi_at(2) == 1;
1097 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(args.smi_at(3));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001098 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001099
1100 // Compute the property attributes. According to ECMA-262, section
1101 // 13, page 71, the property must be read-only and
1102 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1103 // property as read-only, so we don't either.
1104 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
1105
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001106 // Traverse the name/value pairs and set the properties.
1107 int length = pairs->length();
1108 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001109 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001110 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001111 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001112
1113 // We have to declare a global const property. To capture we only
1114 // assign to it when evaluating the assignment for "const x =
1115 // <expr>" the initial value is the hole.
1116 bool is_const_property = value->IsTheHole();
1117
1118 if (value->IsUndefined() || is_const_property) {
1119 // Lookup the property in the global object, and don't set the
1120 // value of the variable if the property is already there.
1121 LookupResult lookup;
1122 global->Lookup(*name, &lookup);
1123 if (lookup.IsProperty()) {
1124 // Determine if the property is local by comparing the holder
1125 // against the global object. The information will be used to
1126 // avoid throwing re-declaration errors when declaring
1127 // variables or constants that exist in the prototype chain.
1128 bool is_local = (*global == lookup.holder());
1129 // Get the property attributes and determine if the property is
1130 // read-only.
1131 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1132 bool is_read_only = (attributes & READ_ONLY) != 0;
1133 if (lookup.type() == INTERCEPTOR) {
1134 // If the interceptor says the property is there, we
1135 // just return undefined without overwriting the property.
1136 // Otherwise, we continue to setting the property.
1137 if (attributes != ABSENT) {
1138 // Check if the existing property conflicts with regards to const.
1139 if (is_local && (is_read_only || is_const_property)) {
1140 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001141 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001142 };
1143 // The property already exists without conflicting: Go to
1144 // the next declaration.
1145 continue;
1146 }
1147 // Fall-through and introduce the absent property by using
1148 // SetProperty.
1149 } else {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001150 // For const properties, we treat a callback with this name
1151 // even in the prototype as a conflicting declaration.
1152 if (is_const_property && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001153 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001154 }
1155 // Otherwise, we check for locally conflicting declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001156 if (is_local && (is_read_only || is_const_property)) {
1157 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001158 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001159 }
1160 // The property already exists without conflicting: Go to
1161 // the next declaration.
1162 continue;
1163 }
1164 }
1165 } else {
1166 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001167 Handle<SharedFunctionInfo> shared =
1168 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001169 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001170 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1171 context,
1172 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001173 value = function;
1174 }
1175
1176 LookupResult lookup;
1177 global->LocalLookup(*name, &lookup);
1178
1179 PropertyAttributes attributes = is_const_property
1180 ? static_cast<PropertyAttributes>(base | READ_ONLY)
1181 : base;
1182
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001183 // There's a local property that we need to overwrite because
1184 // we're either declaring a function or there's an interceptor
1185 // that claims the property is absent.
1186 //
1187 // Check for conflicting re-declarations. We cannot have
1188 // conflicting types in case of intercepted properties because
1189 // they are absent.
1190 if (lookup.IsProperty() &&
1191 (lookup.type() != INTERCEPTOR) &&
1192 (lookup.IsReadOnly() || is_const_property)) {
1193 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001194 return ThrowRedeclarationError(isolate, type, name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001195 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001196
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001197 // Safari does not allow the invocation of callback setters for
1198 // function declarations. To mimic this behavior, we do not allow
1199 // the invocation of setters for function values. This makes a
1200 // difference for global functions with the same names as event
1201 // handlers such as "function onload() {}". Firefox does call the
1202 // onload setter in those case and Safari does not. We follow
1203 // Safari for compatibility.
1204 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001205 // Do not change DONT_DELETE to false from true.
1206 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
1207 attributes = static_cast<PropertyAttributes>(
1208 attributes | (lookup.GetAttributes() & DONT_DELETE));
1209 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001210 RETURN_IF_EMPTY_HANDLE(isolate,
1211 SetLocalPropertyIgnoreAttributes(global,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001212 name,
1213 value,
1214 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001215 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001216 RETURN_IF_EMPTY_HANDLE(isolate,
1217 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001218 name,
1219 value,
1220 attributes,
1221 strict_mode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001222 }
1223 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001224
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001225 ASSERT(!isolate->has_pending_exception());
1226 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001227}
1228
1229
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001230RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001231 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001232 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001233
ager@chromium.org7c537e22008-10-16 08:43:32 +00001234 CONVERT_ARG_CHECKED(Context, context, 0);
1235 Handle<String> name(String::cast(args[1]));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001236 PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001237 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001238 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001239
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001240 // Declarations are always done in a function or global context.
1241 context = Handle<Context>(context->declaration_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001242
1243 int index;
1244 PropertyAttributes attributes;
1245 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001246 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001247 context->Lookup(name, flags, &index, &attributes);
1248
1249 if (attributes != ABSENT) {
1250 // The name was declared before; check for conflicting
1251 // re-declarations: This is similar to the code in parser.cc in
1252 // the AstBuildingParser::Declare function.
1253 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1254 // Functions are not read-only.
1255 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1256 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001257 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001258 }
1259
1260 // Initialize it if necessary.
1261 if (*initial_value != NULL) {
1262 if (index >= 0) {
1263 // The variable or constant context slot should always be in
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001264 // the function context or the arguments object.
1265 if (holder->IsContext()) {
1266 ASSERT(holder.is_identical_to(context));
1267 if (((attributes & READ_ONLY) == 0) ||
1268 context->get(index)->IsTheHole()) {
1269 context->set(index, *initial_value);
1270 }
1271 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001272 // The holder is an arguments object.
1273 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001274 Handle<Object> result = SetElement(arguments, index, initial_value,
1275 kNonStrictMode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001276 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001277 }
1278 } else {
1279 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001280 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001281 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001282 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001283 SetProperty(context_ext, name, initial_value,
1284 mode, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001285 }
1286 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001287
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001288 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001289 // The property is not in the function context. It needs to be
1290 // "declared" in the function context's extension context, or in the
1291 // global context.
1292 Handle<JSObject> context_ext;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001293 if (context->has_extension()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001294 // The function context's extension context exists - use it.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001295 context_ext = Handle<JSObject>(JSObject::cast(context->extension()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001296 } else {
1297 // The function context's extension context does not exists - allocate
1298 // it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001299 context_ext = isolate->factory()->NewJSObject(
1300 isolate->context_extension_function());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001301 // And store it in the extension slot.
1302 context->set_extension(*context_ext);
1303 }
1304 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001305
ager@chromium.org7c537e22008-10-16 08:43:32 +00001306 // Declare the property by setting it to the initial value if provided,
1307 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1308 // constant declarations).
1309 ASSERT(!context_ext->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001310 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001311 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001312 // Declaring a const context slot is a conflicting declaration if
1313 // there is a callback with that name in a prototype. It is
1314 // allowed to introduce const variables in
1315 // JSContextExtensionObjects. They are treated specially in
1316 // SetProperty and no setters are invoked for those since they are
1317 // not real JSObjects.
1318 if (initial_value->IsTheHole() &&
1319 !context_ext->IsJSContextExtensionObject()) {
1320 LookupResult lookup;
1321 context_ext->Lookup(*name, &lookup);
1322 if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001323 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001324 }
1325 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001326 RETURN_IF_EMPTY_HANDLE(isolate,
1327 SetProperty(context_ext, name, value, mode,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001328 kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001329 }
1330
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001331 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001332}
1333
1334
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001335RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001336 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001337 // args[0] == name
1338 // args[1] == strict_mode
1339 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001340
1341 // Determine if we need to assign to the variable if it already
1342 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001343 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1344 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001345
1346 CONVERT_ARG_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001347 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001348 RUNTIME_ASSERT(args[1]->IsSmi());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001349 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(args.smi_at(1));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001350 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001351
1352 // According to ECMA-262, section 12.2, page 62, the property must
1353 // not be deletable.
1354 PropertyAttributes attributes = DONT_DELETE;
1355
1356 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001357 // there, there is a property with this name in the prototype chain.
1358 // We follow Safari and Firefox behavior and only set the property
1359 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001360 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001361 // Note that objects can have hidden prototypes, so we need to traverse
1362 // the whole chain of hidden prototypes to do a 'local' lookup.
1363 JSObject* real_holder = global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001364 LookupResult lookup;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001365 while (true) {
1366 real_holder->LocalLookup(*name, &lookup);
1367 if (lookup.IsProperty()) {
1368 // Determine if this is a redeclaration of something read-only.
1369 if (lookup.IsReadOnly()) {
1370 // If we found readonly property on one of hidden prototypes,
1371 // just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001372 if (real_holder != isolate->context()->global()) break;
1373 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001374 }
1375
1376 // Determine if this is a redeclaration of an intercepted read-only
1377 // property and figure out if the property exists at all.
1378 bool found = true;
1379 PropertyType type = lookup.type();
1380 if (type == INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001381 HandleScope handle_scope(isolate);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001382 Handle<JSObject> holder(real_holder);
1383 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1384 real_holder = *holder;
1385 if (intercepted == ABSENT) {
1386 // The interceptor claims the property isn't there. We need to
1387 // make sure to introduce it.
1388 found = false;
1389 } else if ((intercepted & READ_ONLY) != 0) {
1390 // The property is present, but read-only. Since we're trying to
1391 // overwrite it with a variable declaration we must throw a
1392 // re-declaration error. However if we found readonly property
1393 // on one of hidden prototypes, just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001394 if (real_holder != isolate->context()->global()) break;
1395 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001396 }
1397 }
1398
1399 if (found && !assign) {
1400 // The global property is there and we're not assigning any value
1401 // to it. Just return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001402 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001403 }
1404
1405 // Assign the value (or undefined) to the property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001406 Object* value = (assign) ? args[2] : isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001407 return real_holder->SetProperty(
1408 &lookup, *name, value, attributes, strict_mode);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001409 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001410
1411 Object* proto = real_holder->GetPrototype();
1412 if (!proto->IsJSObject())
1413 break;
1414
1415 if (!JSObject::cast(proto)->map()->is_hidden_prototype())
1416 break;
1417
1418 real_holder = JSObject::cast(proto);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001419 }
1420
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001421 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001422 if (assign) {
1423 return global->SetProperty(*name, args[2], attributes, strict_mode);
1424 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001425 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001426}
1427
1428
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001429RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001430 // All constants are declared with an initial value. The name
1431 // of the constant is the first argument and the initial value
1432 // is the second.
1433 RUNTIME_ASSERT(args.length() == 2);
1434 CONVERT_ARG_CHECKED(String, name, 0);
1435 Handle<Object> value = args.at<Object>(1);
1436
1437 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001438 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001439
1440 // According to ECMA-262, section 12.2, page 62, the property must
1441 // not be deletable. Since it's a const, it must be READ_ONLY too.
1442 PropertyAttributes attributes =
1443 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1444
1445 // Lookup the property locally in the global object. If it isn't
1446 // there, we add the property and take special precautions to always
1447 // add it as a local property even in case of callbacks in the
1448 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001449 // We use SetLocalPropertyIgnoreAttributes instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001450 LookupResult lookup;
1451 global->LocalLookup(*name, &lookup);
1452 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001453 return global->SetLocalPropertyIgnoreAttributes(*name,
1454 *value,
1455 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001456 }
1457
1458 // Determine if this is a redeclaration of something not
1459 // read-only. In case the result is hidden behind an interceptor we
1460 // need to ask it for the property attributes.
1461 if (!lookup.IsReadOnly()) {
1462 if (lookup.type() != INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001463 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001464 }
1465
1466 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
1467
1468 // Throw re-declaration error if the intercepted property is present
1469 // but not read-only.
1470 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001471 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001472 }
1473
1474 // Restore global object from context (in case of GC) and continue
1475 // with setting the value because the property is either absent or
1476 // read-only. We also have to do redo the lookup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001477 HandleScope handle_scope(isolate);
1478 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001479
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001480 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001481 // property through an interceptor and only do it if it's
1482 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001483 // Passing non-strict mode because the property is writable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001484 RETURN_IF_EMPTY_HANDLE(isolate,
1485 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001486 name,
1487 value,
1488 attributes,
1489 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001490 return *value;
1491 }
1492
1493 // Set the value, but only we're assigning the initial value to a
1494 // constant. For now, we determine this by checking if the
1495 // current value is the hole.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001496 // Strict mode handling not needed (const disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001497 PropertyType type = lookup.type();
1498 if (type == FIELD) {
1499 FixedArray* properties = global->properties();
1500 int index = lookup.GetFieldIndex();
1501 if (properties->get(index)->IsTheHole()) {
1502 properties->set(index, *value);
1503 }
1504 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001505 if (global->GetNormalizedProperty(&lookup)->IsTheHole()) {
1506 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001507 }
1508 } else {
1509 // Ignore re-initialization of constants that have already been
1510 // assigned a function value.
1511 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1512 }
1513
1514 // Use the set value as the result of the operation.
1515 return *value;
1516}
1517
1518
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001519RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001520 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001521 ASSERT(args.length() == 3);
1522
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001523 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001524 ASSERT(!value->IsTheHole());
1525 CONVERT_ARG_CHECKED(Context, context, 1);
1526 Handle<String> name(String::cast(args[2]));
1527
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001528 // Initializations are always done in a function or global context.
1529 context = Handle<Context>(context->declaration_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001530
1531 int index;
1532 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001533 ContextLookupFlags flags = FOLLOW_CHAINS;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001534 Handle<Object> holder =
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001535 context->Lookup(name, flags, &index, &attributes);
1536
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001537 // In most situations, the property introduced by the const
1538 // declaration should be present in the context extension object.
1539 // However, because declaration and initialization are separate, the
1540 // property might have been deleted (if it was introduced by eval)
1541 // before we reach the initialization point.
1542 //
1543 // Example:
1544 //
1545 // function f() { eval("delete x; const x;"); }
1546 //
1547 // In that case, the initialization behaves like a normal assignment
1548 // to property 'x'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001549 if (index >= 0) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001550 if (holder->IsContext()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001551 // Property was found in a context. Perform the assignment if we
1552 // found some non-constant or an uninitialized constant.
1553 Handle<Context> context = Handle<Context>::cast(holder);
1554 if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
1555 context->set(index, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001556 }
1557 } else {
1558 // The holder is an arguments object.
1559 ASSERT((attributes & READ_ONLY) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001560 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001561 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001562 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001563 SetElement(arguments, index, value, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001564 }
1565 return *value;
1566 }
1567
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001568 // The property could not be found, we introduce it in the global
1569 // context.
1570 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001571 Handle<JSObject> global = Handle<JSObject>(
1572 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001573 // Strict mode not needed (const disallowed in strict mode).
1574 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001575 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001576 SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001577 return *value;
1578 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001579
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001580 // The property was present in a context extension object.
1581 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001582
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001583 if (*context_ext == context->extension()) {
1584 // This is the property that was introduced by the const
1585 // declaration. Set it if it hasn't been set before. NOTE: We
1586 // cannot use GetProperty() to get the current value as it
1587 // 'unholes' the value.
1588 LookupResult lookup;
1589 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
1590 ASSERT(lookup.IsProperty()); // the property was declared
1591 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1592
1593 PropertyType type = lookup.type();
1594 if (type == FIELD) {
1595 FixedArray* properties = context_ext->properties();
1596 int index = lookup.GetFieldIndex();
1597 if (properties->get(index)->IsTheHole()) {
1598 properties->set(index, *value);
1599 }
1600 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001601 if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) {
1602 context_ext->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001603 }
1604 } else {
1605 // We should not reach here. Any real, named property should be
1606 // either a field or a dictionary slot.
1607 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001608 }
1609 } else {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001610 // The property was found in a different context extension object.
1611 // Set it if it is not a read-only property.
1612 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001613 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001614 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001615 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001616 SetProperty(context_ext, name, value, attributes, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001617 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001618 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001619
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001620 return *value;
1621}
1622
1623
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001624RUNTIME_FUNCTION(MaybeObject*,
1625 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001626 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001627 ASSERT(args.length() == 2);
1628 CONVERT_ARG_CHECKED(JSObject, object, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001629 CONVERT_SMI_ARG_CHECKED(properties, 1);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001630 if (object->HasFastProperties()) {
1631 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1632 }
1633 return *object;
1634}
1635
1636
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001637RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001638 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001639 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001640 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1641 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001642 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001643 // length of a string, i.e. it is always a Smi. We check anyway for security.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001644 CONVERT_SMI_ARG_CHECKED(index, 2);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001645 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001646 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001647 RUNTIME_ASSERT(index >= 0);
1648 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001649 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001650 Handle<Object> result = RegExpImpl::Exec(regexp,
1651 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001652 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001653 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001654 if (result.is_null()) return Failure::Exception();
1655 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001656}
1657
1658
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001659RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001660 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001661 CONVERT_SMI_ARG_CHECKED(elements_count, 0);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001662 if (elements_count > JSArray::kMaxFastElementsLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001663 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001664 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001665 Object* new_object;
1666 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001667 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001668 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1669 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001670 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001671 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1672 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001673 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1674 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001675 {
1676 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001677 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001678 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001679 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001680 }
1681 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001682 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001683 array->set_elements(elements);
1684 array->set_length(Smi::FromInt(elements_count));
1685 // Write in-object properties after the length of the array.
1686 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1687 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1688 return array;
1689}
1690
1691
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001692RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001693 AssertNoAllocation no_alloc;
1694 ASSERT(args.length() == 5);
1695 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1696 CONVERT_CHECKED(String, source, args[1]);
1697
1698 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001699 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001700
1701 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001702 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001703
1704 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001705 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001706
1707 Map* map = regexp->map();
1708 Object* constructor = map->constructor();
1709 if (constructor->IsJSFunction() &&
1710 JSFunction::cast(constructor)->initial_map() == map) {
1711 // If we still have the original map, set in-object properties directly.
1712 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1713 // TODO(lrn): Consider skipping write barrier on booleans as well.
1714 // Both true and false should be in oldspace at all times.
1715 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1716 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1717 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1718 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1719 Smi::FromInt(0),
1720 SKIP_WRITE_BARRIER);
1721 return regexp;
1722 }
1723
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001724 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001725 PropertyAttributes final =
1726 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1727 PropertyAttributes writable =
1728 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001729 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001730 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001731 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001732 source,
1733 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001734 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001735 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001736 global,
1737 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001738 ASSERT(!result->IsFailure());
1739 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001740 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001741 ignoreCase,
1742 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001743 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001744 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001745 multiline,
1746 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001747 ASSERT(!result->IsFailure());
1748 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001749 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001750 Smi::FromInt(0),
1751 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001752 ASSERT(!result->IsFailure());
1753 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001754 return regexp;
1755}
1756
1757
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001758RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001759 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001760 ASSERT(args.length() == 1);
1761 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1762 // This is necessary to enable fast checks for absence of elements
1763 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001764 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001765 return Smi::FromInt(0);
1766}
1767
1768
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001769static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1770 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001771 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001772 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001773 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1774 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1775 Handle<JSFunction> optimized =
1776 isolate->factory()->NewFunction(key,
1777 JS_OBJECT_TYPE,
1778 JSObject::kHeaderSize,
1779 code,
1780 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001781 optimized->shared()->DontAdaptArguments();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001782 SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001783 return optimized;
1784}
1785
1786
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001787RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001788 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001789 ASSERT(args.length() == 1);
1790 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1791
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001792 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1793 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1794 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1795 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1796 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1797 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1798 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001799
1800 return *holder;
1801}
1802
1803
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001804RUNTIME_FUNCTION(MaybeObject*, Runtime_GetGlobalReceiver) {
ager@chromium.org357bf652010-04-12 11:30:10 +00001805 // Returns a real global receiver, not one of builtins object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001806 Context* global_context =
1807 isolate->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001808 return global_context->global()->global_receiver();
1809}
1810
1811
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001812RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001813 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001814 ASSERT(args.length() == 4);
1815 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001816 int index = args.smi_at(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001817 Handle<String> pattern = args.at<String>(2);
1818 Handle<String> flags = args.at<String>(3);
1819
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001820 // Get the RegExp function from the context in the literals array.
1821 // This is the RegExp function from the context in which the
1822 // function was created. We do not use the RegExp function from the
1823 // current global context because this might be the RegExp function
1824 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001825 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001826 Handle<JSFunction>(
1827 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001828 // Compute the regular expression literal.
1829 bool has_pending_exception;
1830 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001831 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1832 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001833 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001834 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001835 return Failure::Exception();
1836 }
1837 literals->set(index, *regexp);
1838 return *regexp;
1839}
1840
1841
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001842RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001843 NoHandleAllocation ha;
1844 ASSERT(args.length() == 1);
1845
1846 CONVERT_CHECKED(JSFunction, f, args[0]);
1847 return f->shared()->name();
1848}
1849
1850
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001851RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001852 NoHandleAllocation ha;
1853 ASSERT(args.length() == 2);
1854
1855 CONVERT_CHECKED(JSFunction, f, args[0]);
1856 CONVERT_CHECKED(String, name, args[1]);
1857 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001858 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001859}
1860
1861
whesse@chromium.org7b260152011-06-20 15:33:18 +00001862RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetBound) {
1863 HandleScope scope(isolate);
1864 ASSERT(args.length() == 1);
1865
1866 CONVERT_CHECKED(JSFunction, fun, args[0]);
1867 fun->shared()->set_bound(true);
1868 return isolate->heap()->undefined_value();
1869}
1870
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001871RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001872 NoHandleAllocation ha;
1873 ASSERT(args.length() == 1);
1874
1875 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001876 Object* obj = f->RemovePrototype();
1877 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001878
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001879 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001880}
1881
1882
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001883RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001884 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001885 ASSERT(args.length() == 1);
1886
1887 CONVERT_CHECKED(JSFunction, fun, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001888 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
1889 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001890
1891 return *GetScriptWrapper(Handle<Script>::cast(script));
1892}
1893
1894
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001895RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001896 NoHandleAllocation ha;
1897 ASSERT(args.length() == 1);
1898
1899 CONVERT_CHECKED(JSFunction, f, args[0]);
1900 return f->shared()->GetSourceCode();
1901}
1902
1903
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001904RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001905 NoHandleAllocation ha;
1906 ASSERT(args.length() == 1);
1907
1908 CONVERT_CHECKED(JSFunction, fun, args[0]);
1909 int pos = fun->shared()->start_position();
1910 return Smi::FromInt(pos);
1911}
1912
1913
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001914RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001915 ASSERT(args.length() == 2);
1916
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001917 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001918 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
1919
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001920 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
1921
1922 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001923 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001924}
1925
1926
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001927RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001928 NoHandleAllocation ha;
1929 ASSERT(args.length() == 2);
1930
1931 CONVERT_CHECKED(JSFunction, fun, args[0]);
1932 CONVERT_CHECKED(String, name, args[1]);
1933 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001934 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001935}
1936
1937
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001938RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001939 NoHandleAllocation ha;
1940 ASSERT(args.length() == 2);
1941
1942 CONVERT_CHECKED(JSFunction, fun, args[0]);
1943 CONVERT_CHECKED(Smi, length, args[1]);
1944 fun->shared()->set_length(length->value());
1945 return length;
1946}
1947
1948
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001949RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001950 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001951 ASSERT(args.length() == 2);
1952
1953 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001954 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00001955 Object* obj;
1956 { MaybeObject* maybe_obj =
1957 Accessors::FunctionSetPrototype(fun, args[1], NULL);
1958 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
1959 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001960 return args[0]; // return TOS
1961}
1962
1963
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001964RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001965 NoHandleAllocation ha;
1966 ASSERT(args.length() == 1);
1967
1968 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001969 return f->shared()->IsApiFunction() ? isolate->heap()->true_value()
1970 : isolate->heap()->false_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001971}
1972
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001973
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001974RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001975 NoHandleAllocation ha;
1976 ASSERT(args.length() == 1);
1977
1978 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001979 return f->IsBuiltin() ? isolate->heap()->true_value() :
1980 isolate->heap()->false_value();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00001981}
1982
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001983
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001984RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001985 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001986 ASSERT(args.length() == 2);
1987
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001988 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001989 Handle<Object> code = args.at<Object>(1);
1990
1991 Handle<Context> context(target->context());
1992
1993 if (!code->IsNull()) {
1994 RUNTIME_ASSERT(code->IsJSFunction());
1995 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001996 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001997
1998 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001999 return Failure::Exception();
2000 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002001 // Since we don't store the source for this we should never
2002 // optimize this.
2003 shared->code()->set_optimizable(false);
2004
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002005 // Set the code, scope info, formal parameter count,
2006 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00002007 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002008 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002009 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002010 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002011 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002012 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002013 // Set the source code of the target function to undefined.
2014 // SetCode is only used for built-in constructors like String,
2015 // Array, and Object, and some web code
2016 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002017 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002018 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002019 // Clear the optimization hints related to the compiled code as these are no
2020 // longer valid when the code is overwritten.
2021 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002022 context = Handle<Context>(fun->context());
2023
2024 // Make sure we get a fresh copy of the literal vector to avoid
2025 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002026 int number_of_literals = fun->NumberOfLiterals();
2027 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002028 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002029 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002030 // Insert the object, regexp and array functions in the literals
2031 // array prefix. These are the functions that will be used when
2032 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002033 literals->set(JSFunction::kLiteralGlobalContextIndex,
2034 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002035 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002036 // It's okay to skip the write barrier here because the literals
2037 // are guaranteed to be in old space.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002038 target->set_literals(*literals, SKIP_WRITE_BARRIER);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002039 target->set_next_function_link(isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002040 }
2041
2042 target->set_context(*context);
2043 return *target;
2044}
2045
2046
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002047RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002048 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002049 ASSERT(args.length() == 2);
2050 CONVERT_ARG_CHECKED(JSFunction, function, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002051 CONVERT_SMI_ARG_CHECKED(num, 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002052 RUNTIME_ASSERT(num >= 0);
2053 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002054 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002055}
2056
2057
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002058MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2059 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002060 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002061 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002062 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002063 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002064 }
2065 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002066 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002067}
2068
2069
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002070RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002071 NoHandleAllocation ha;
2072 ASSERT(args.length() == 2);
2073
2074 CONVERT_CHECKED(String, subject, args[0]);
2075 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002076 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002077
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002078 uint32_t i = 0;
2079 if (index->IsSmi()) {
2080 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002081 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002082 i = value;
2083 } else {
2084 ASSERT(index->IsHeapNumber());
2085 double value = HeapNumber::cast(index)->value();
2086 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002087 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002088
2089 // Flatten the string. If someone wants to get a char at an index
2090 // in a cons string, it is likely that more indices will be
2091 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002092 Object* flat;
2093 { MaybeObject* maybe_flat = subject->TryFlatten();
2094 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2095 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002096 subject = String::cast(flat);
2097
2098 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002099 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002100 }
2101
2102 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002103}
2104
2105
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002106RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002107 NoHandleAllocation ha;
2108 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002109 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002110}
2111
lrn@chromium.org25156de2010-04-06 13:10:27 +00002112
2113class FixedArrayBuilder {
2114 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002115 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2116 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002117 length_(0) {
2118 // Require a non-zero initial size. Ensures that doubling the size to
2119 // extend the array will work.
2120 ASSERT(initial_capacity > 0);
2121 }
2122
2123 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2124 : array_(backing_store),
2125 length_(0) {
2126 // Require a non-zero initial size. Ensures that doubling the size to
2127 // extend the array will work.
2128 ASSERT(backing_store->length() > 0);
2129 }
2130
2131 bool HasCapacity(int elements) {
2132 int length = array_->length();
2133 int required_length = length_ + elements;
2134 return (length >= required_length);
2135 }
2136
2137 void EnsureCapacity(int elements) {
2138 int length = array_->length();
2139 int required_length = length_ + elements;
2140 if (length < required_length) {
2141 int new_length = length;
2142 do {
2143 new_length *= 2;
2144 } while (new_length < required_length);
2145 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002146 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002147 array_->CopyTo(0, *extended_array, 0, length_);
2148 array_ = extended_array;
2149 }
2150 }
2151
2152 void Add(Object* value) {
2153 ASSERT(length_ < capacity());
2154 array_->set(length_, value);
2155 length_++;
2156 }
2157
2158 void Add(Smi* value) {
2159 ASSERT(length_ < capacity());
2160 array_->set(length_, value);
2161 length_++;
2162 }
2163
2164 Handle<FixedArray> array() {
2165 return array_;
2166 }
2167
2168 int length() {
2169 return length_;
2170 }
2171
2172 int capacity() {
2173 return array_->length();
2174 }
2175
2176 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002177 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002178 result_array->set_length(Smi::FromInt(length_));
2179 return result_array;
2180 }
2181
2182 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
2183 target_array->set_elements(*array_);
2184 target_array->set_length(Smi::FromInt(length_));
2185 return target_array;
2186 }
2187
2188 private:
2189 Handle<FixedArray> array_;
2190 int length_;
2191};
2192
2193
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002194// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002195const int kStringBuilderConcatHelperLengthBits = 11;
2196const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002197
2198template <typename schar>
2199static inline void StringBuilderConcatHelper(String*,
2200 schar*,
2201 FixedArray*,
2202 int);
2203
lrn@chromium.org25156de2010-04-06 13:10:27 +00002204typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2205 StringBuilderSubstringLength;
2206typedef BitField<int,
2207 kStringBuilderConcatHelperLengthBits,
2208 kStringBuilderConcatHelperPositionBits>
2209 StringBuilderSubstringPosition;
2210
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002211
2212class ReplacementStringBuilder {
2213 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002214 ReplacementStringBuilder(Heap* heap,
2215 Handle<String> subject,
2216 int estimated_part_count)
2217 : heap_(heap),
2218 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002219 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002220 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002221 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002222 // Require a non-zero initial size. Ensures that doubling the size to
2223 // extend the array will work.
2224 ASSERT(estimated_part_count > 0);
2225 }
2226
lrn@chromium.org25156de2010-04-06 13:10:27 +00002227 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2228 int from,
2229 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002230 ASSERT(from >= 0);
2231 int length = to - from;
2232 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002233 if (StringBuilderSubstringLength::is_valid(length) &&
2234 StringBuilderSubstringPosition::is_valid(from)) {
2235 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2236 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002237 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002238 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002239 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002240 builder->Add(Smi::FromInt(-length));
2241 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002242 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002243 }
2244
2245
2246 void EnsureCapacity(int elements) {
2247 array_builder_.EnsureCapacity(elements);
2248 }
2249
2250
2251 void AddSubjectSlice(int from, int to) {
2252 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002253 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002254 }
2255
2256
2257 void AddString(Handle<String> string) {
2258 int length = string->length();
2259 ASSERT(length > 0);
2260 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002261 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002262 is_ascii_ = false;
2263 }
2264 IncrementCharacterCount(length);
2265 }
2266
2267
2268 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002269 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002270 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002271 }
2272
2273 Handle<String> joined_string;
2274 if (is_ascii_) {
ager@chromium.org04921a82011-06-27 13:21:41 +00002275 Handle<SeqAsciiString> seq = NewRawAsciiString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002276 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002277 char* char_buffer = seq->GetChars();
2278 StringBuilderConcatHelper(*subject_,
2279 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002280 *array_builder_.array(),
2281 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002282 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002283 } else {
2284 // Non-ASCII.
ager@chromium.org04921a82011-06-27 13:21:41 +00002285 Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002286 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002287 uc16* char_buffer = seq->GetChars();
2288 StringBuilderConcatHelper(*subject_,
2289 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002290 *array_builder_.array(),
2291 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002292 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002293 }
2294 return joined_string;
2295 }
2296
2297
2298 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002299 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002300 V8::FatalProcessOutOfMemory("String.replace result too large.");
2301 }
2302 character_count_ += by;
2303 }
2304
lrn@chromium.org25156de2010-04-06 13:10:27 +00002305 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002306 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002307 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002308
lrn@chromium.org25156de2010-04-06 13:10:27 +00002309 private:
ager@chromium.org04921a82011-06-27 13:21:41 +00002310 Handle<SeqAsciiString> NewRawAsciiString(int length) {
2311 return heap_->isolate()->factory()->NewRawAsciiString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002312 }
2313
2314
ager@chromium.org04921a82011-06-27 13:21:41 +00002315 Handle<SeqTwoByteString> NewRawTwoByteString(int length) {
2316 return heap_->isolate()->factory()->NewRawTwoByteString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002317 }
2318
2319
2320 void AddElement(Object* element) {
2321 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002322 ASSERT(array_builder_.capacity() > array_builder_.length());
2323 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002324 }
2325
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002326 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002327 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002328 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002329 int character_count_;
2330 bool is_ascii_;
2331};
2332
2333
2334class CompiledReplacement {
2335 public:
2336 CompiledReplacement()
2337 : parts_(1), replacement_substrings_(0) {}
2338
2339 void Compile(Handle<String> replacement,
2340 int capture_count,
2341 int subject_length);
2342
2343 void Apply(ReplacementStringBuilder* builder,
2344 int match_from,
2345 int match_to,
2346 Handle<JSArray> last_match_info);
2347
2348 // Number of distinct parts of the replacement pattern.
2349 int parts() {
2350 return parts_.length();
2351 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002352
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002353 private:
2354 enum PartType {
2355 SUBJECT_PREFIX = 1,
2356 SUBJECT_SUFFIX,
2357 SUBJECT_CAPTURE,
2358 REPLACEMENT_SUBSTRING,
2359 REPLACEMENT_STRING,
2360
2361 NUMBER_OF_PART_TYPES
2362 };
2363
2364 struct ReplacementPart {
2365 static inline ReplacementPart SubjectMatch() {
2366 return ReplacementPart(SUBJECT_CAPTURE, 0);
2367 }
2368 static inline ReplacementPart SubjectCapture(int capture_index) {
2369 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2370 }
2371 static inline ReplacementPart SubjectPrefix() {
2372 return ReplacementPart(SUBJECT_PREFIX, 0);
2373 }
2374 static inline ReplacementPart SubjectSuffix(int subject_length) {
2375 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2376 }
2377 static inline ReplacementPart ReplacementString() {
2378 return ReplacementPart(REPLACEMENT_STRING, 0);
2379 }
2380 static inline ReplacementPart ReplacementSubString(int from, int to) {
2381 ASSERT(from >= 0);
2382 ASSERT(to > from);
2383 return ReplacementPart(-from, to);
2384 }
2385
2386 // If tag <= 0 then it is the negation of a start index of a substring of
2387 // the replacement pattern, otherwise it's a value from PartType.
2388 ReplacementPart(int tag, int data)
2389 : tag(tag), data(data) {
2390 // Must be non-positive or a PartType value.
2391 ASSERT(tag < NUMBER_OF_PART_TYPES);
2392 }
2393 // Either a value of PartType or a non-positive number that is
2394 // the negation of an index into the replacement string.
2395 int tag;
2396 // The data value's interpretation depends on the value of tag:
2397 // tag == SUBJECT_PREFIX ||
2398 // tag == SUBJECT_SUFFIX: data is unused.
2399 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2400 // tag == REPLACEMENT_SUBSTRING ||
2401 // tag == REPLACEMENT_STRING: data is index into array of substrings
2402 // of the replacement string.
2403 // tag <= 0: Temporary representation of the substring of the replacement
2404 // string ranging over -tag .. data.
2405 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2406 // substring objects.
2407 int data;
2408 };
2409
2410 template<typename Char>
2411 static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
2412 Vector<Char> characters,
2413 int capture_count,
2414 int subject_length) {
2415 int length = characters.length();
2416 int last = 0;
2417 for (int i = 0; i < length; i++) {
2418 Char c = characters[i];
2419 if (c == '$') {
2420 int next_index = i + 1;
2421 if (next_index == length) { // No next character!
2422 break;
2423 }
2424 Char c2 = characters[next_index];
2425 switch (c2) {
2426 case '$':
2427 if (i > last) {
2428 // There is a substring before. Include the first "$".
2429 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2430 last = next_index + 1; // Continue after the second "$".
2431 } else {
2432 // Let the next substring start with the second "$".
2433 last = next_index;
2434 }
2435 i = next_index;
2436 break;
2437 case '`':
2438 if (i > last) {
2439 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2440 }
2441 parts->Add(ReplacementPart::SubjectPrefix());
2442 i = next_index;
2443 last = i + 1;
2444 break;
2445 case '\'':
2446 if (i > last) {
2447 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2448 }
2449 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2450 i = next_index;
2451 last = i + 1;
2452 break;
2453 case '&':
2454 if (i > last) {
2455 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2456 }
2457 parts->Add(ReplacementPart::SubjectMatch());
2458 i = next_index;
2459 last = i + 1;
2460 break;
2461 case '0':
2462 case '1':
2463 case '2':
2464 case '3':
2465 case '4':
2466 case '5':
2467 case '6':
2468 case '7':
2469 case '8':
2470 case '9': {
2471 int capture_ref = c2 - '0';
2472 if (capture_ref > capture_count) {
2473 i = next_index;
2474 continue;
2475 }
2476 int second_digit_index = next_index + 1;
2477 if (second_digit_index < length) {
2478 // Peek ahead to see if we have two digits.
2479 Char c3 = characters[second_digit_index];
2480 if ('0' <= c3 && c3 <= '9') { // Double digits.
2481 int double_digit_ref = capture_ref * 10 + c3 - '0';
2482 if (double_digit_ref <= capture_count) {
2483 next_index = second_digit_index;
2484 capture_ref = double_digit_ref;
2485 }
2486 }
2487 }
2488 if (capture_ref > 0) {
2489 if (i > last) {
2490 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2491 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002492 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002493 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2494 last = next_index + 1;
2495 }
2496 i = next_index;
2497 break;
2498 }
2499 default:
2500 i = next_index;
2501 break;
2502 }
2503 }
2504 }
2505 if (length > last) {
2506 if (last == 0) {
2507 parts->Add(ReplacementPart::ReplacementString());
2508 } else {
2509 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2510 }
2511 }
2512 }
2513
2514 ZoneList<ReplacementPart> parts_;
2515 ZoneList<Handle<String> > replacement_substrings_;
2516};
2517
2518
2519void CompiledReplacement::Compile(Handle<String> replacement,
2520 int capture_count,
2521 int subject_length) {
2522 ASSERT(replacement->IsFlat());
ager@chromium.org5ec48922009-05-05 07:25:34 +00002523 if (replacement->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002524 AssertNoAllocation no_alloc;
2525 ParseReplacementPattern(&parts_,
2526 replacement->ToAsciiVector(),
2527 capture_count,
2528 subject_length);
2529 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00002530 ASSERT(replacement->IsTwoByteRepresentation());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002531 AssertNoAllocation no_alloc;
2532
2533 ParseReplacementPattern(&parts_,
2534 replacement->ToUC16Vector(),
2535 capture_count,
2536 subject_length);
2537 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002538 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002539 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002540 int substring_index = 0;
2541 for (int i = 0, n = parts_.length(); i < n; i++) {
2542 int tag = parts_[i].tag;
2543 if (tag <= 0) { // A replacement string slice.
2544 int from = -tag;
2545 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002546 replacement_substrings_.Add(
2547 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002548 parts_[i].tag = REPLACEMENT_SUBSTRING;
2549 parts_[i].data = substring_index;
2550 substring_index++;
2551 } else if (tag == REPLACEMENT_STRING) {
2552 replacement_substrings_.Add(replacement);
2553 parts_[i].data = substring_index;
2554 substring_index++;
2555 }
2556 }
2557}
2558
2559
2560void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2561 int match_from,
2562 int match_to,
2563 Handle<JSArray> last_match_info) {
2564 for (int i = 0, n = parts_.length(); i < n; i++) {
2565 ReplacementPart part = parts_[i];
2566 switch (part.tag) {
2567 case SUBJECT_PREFIX:
2568 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2569 break;
2570 case SUBJECT_SUFFIX: {
2571 int subject_length = part.data;
2572 if (match_to < subject_length) {
2573 builder->AddSubjectSlice(match_to, subject_length);
2574 }
2575 break;
2576 }
2577 case SUBJECT_CAPTURE: {
2578 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002579 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002580 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2581 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2582 if (from >= 0 && to > from) {
2583 builder->AddSubjectSlice(from, to);
2584 }
2585 break;
2586 }
2587 case REPLACEMENT_SUBSTRING:
2588 case REPLACEMENT_STRING:
2589 builder->AddString(replacement_substrings_[part.data]);
2590 break;
2591 default:
2592 UNREACHABLE();
2593 }
2594 }
2595}
2596
2597
2598
lrn@chromium.org303ada72010-10-27 09:33:13 +00002599MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002600 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002601 String* subject,
2602 JSRegExp* regexp,
2603 String* replacement,
2604 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002605 ASSERT(subject->IsFlat());
2606 ASSERT(replacement->IsFlat());
2607
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002608 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002609
2610 int length = subject->length();
2611 Handle<String> subject_handle(subject);
2612 Handle<JSRegExp> regexp_handle(regexp);
2613 Handle<String> replacement_handle(replacement);
2614 Handle<JSArray> last_match_info_handle(last_match_info);
2615 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2616 subject_handle,
2617 0,
2618 last_match_info_handle);
2619 if (match.is_null()) {
2620 return Failure::Exception();
2621 }
2622 if (match->IsNull()) {
2623 return *subject_handle;
2624 }
2625
2626 int capture_count = regexp_handle->CaptureCount();
2627
2628 // CompiledReplacement uses zone allocation.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002629 ZoneScope zone(isolate, DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002630 CompiledReplacement compiled_replacement;
2631 compiled_replacement.Compile(replacement_handle,
2632 capture_count,
2633 length);
2634
2635 bool is_global = regexp_handle->GetFlags().is_global();
2636
2637 // Guessing the number of parts that the final result string is built
2638 // from. Global regexps can match any number of times, so we guess
2639 // conservatively.
2640 int expected_parts =
2641 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002642 ReplacementStringBuilder builder(isolate->heap(),
2643 subject_handle,
2644 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002645
2646 // Index of end of last match.
2647 int prev = 0;
2648
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002649 // Number of parts added by compiled replacement plus preceeding
2650 // string and possibly suffix after last match. It is possible for
2651 // all components to use two elements when encoded as two smis.
2652 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002653 bool matched = true;
2654 do {
2655 ASSERT(last_match_info_handle->HasFastElements());
2656 // Increase the capacity of the builder before entering local handle-scope,
2657 // so its internal buffer can safely allocate a new handle if it grows.
2658 builder.EnsureCapacity(parts_added_per_loop);
2659
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002660 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002661 int start, end;
2662 {
2663 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002664 FixedArray* match_info_array =
2665 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002666
2667 ASSERT_EQ(capture_count * 2 + 2,
2668 RegExpImpl::GetLastCaptureCount(match_info_array));
2669 start = RegExpImpl::GetCapture(match_info_array, 0);
2670 end = RegExpImpl::GetCapture(match_info_array, 1);
2671 }
2672
2673 if (prev < start) {
2674 builder.AddSubjectSlice(prev, start);
2675 }
2676 compiled_replacement.Apply(&builder,
2677 start,
2678 end,
2679 last_match_info_handle);
2680 prev = end;
2681
2682 // Only continue checking for global regexps.
2683 if (!is_global) break;
2684
2685 // Continue from where the match ended, unless it was an empty match.
2686 int next = end;
2687 if (start == end) {
2688 next = end + 1;
2689 if (next > length) break;
2690 }
2691
2692 match = RegExpImpl::Exec(regexp_handle,
2693 subject_handle,
2694 next,
2695 last_match_info_handle);
2696 if (match.is_null()) {
2697 return Failure::Exception();
2698 }
2699 matched = !match->IsNull();
2700 } while (matched);
2701
2702 if (prev < length) {
2703 builder.AddSubjectSlice(prev, length);
2704 }
2705
2706 return *(builder.ToString());
2707}
2708
2709
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002710template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00002711MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002712 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002713 String* subject,
2714 JSRegExp* regexp,
2715 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002716 ASSERT(subject->IsFlat());
2717
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002718 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002719
2720 Handle<String> subject_handle(subject);
2721 Handle<JSRegExp> regexp_handle(regexp);
2722 Handle<JSArray> last_match_info_handle(last_match_info);
2723 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2724 subject_handle,
2725 0,
2726 last_match_info_handle);
2727 if (match.is_null()) return Failure::Exception();
2728 if (match->IsNull()) return *subject_handle;
2729
2730 ASSERT(last_match_info_handle->HasFastElements());
2731
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002732 int start, end;
2733 {
2734 AssertNoAllocation match_info_array_is_not_in_a_handle;
2735 FixedArray* match_info_array =
2736 FixedArray::cast(last_match_info_handle->elements());
2737
2738 start = RegExpImpl::GetCapture(match_info_array, 0);
2739 end = RegExpImpl::GetCapture(match_info_array, 1);
2740 }
2741
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00002742 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002743 int new_length = length - (end - start);
2744 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002745 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002746 }
2747 Handle<ResultSeqString> answer;
2748 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002749 answer = Handle<ResultSeqString>::cast(
2750 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002751 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002752 answer = Handle<ResultSeqString>::cast(
2753 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002754 }
2755
2756 // If the regexp isn't global, only match once.
2757 if (!regexp_handle->GetFlags().is_global()) {
2758 if (start > 0) {
2759 String::WriteToFlat(*subject_handle,
2760 answer->GetChars(),
2761 0,
2762 start);
2763 }
2764 if (end < length) {
2765 String::WriteToFlat(*subject_handle,
2766 answer->GetChars() + start,
2767 end,
2768 length);
2769 }
2770 return *answer;
2771 }
2772
2773 int prev = 0; // Index of end of last match.
2774 int next = 0; // Start of next search (prev unless last match was empty).
2775 int position = 0;
2776
2777 do {
2778 if (prev < start) {
2779 // Add substring subject[prev;start] to answer string.
2780 String::WriteToFlat(*subject_handle,
2781 answer->GetChars() + position,
2782 prev,
2783 start);
2784 position += start - prev;
2785 }
2786 prev = end;
2787 next = end;
2788 // Continue from where the match ended, unless it was an empty match.
2789 if (start == end) {
2790 next++;
2791 if (next > length) break;
2792 }
2793 match = RegExpImpl::Exec(regexp_handle,
2794 subject_handle,
2795 next,
2796 last_match_info_handle);
2797 if (match.is_null()) return Failure::Exception();
2798 if (match->IsNull()) break;
2799
2800 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002801 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002802 {
2803 AssertNoAllocation match_info_array_is_not_in_a_handle;
2804 FixedArray* match_info_array =
2805 FixedArray::cast(last_match_info_handle->elements());
2806 start = RegExpImpl::GetCapture(match_info_array, 0);
2807 end = RegExpImpl::GetCapture(match_info_array, 1);
2808 }
2809 } while (true);
2810
2811 if (prev < length) {
2812 // Add substring subject[prev;length] to answer string.
2813 String::WriteToFlat(*subject_handle,
2814 answer->GetChars() + position,
2815 prev,
2816 length);
2817 position += length - prev;
2818 }
2819
2820 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002821 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002822 }
2823
2824 // Shorten string and fill
2825 int string_size = ResultSeqString::SizeFor(position);
2826 int allocated_string_size = ResultSeqString::SizeFor(new_length);
2827 int delta = allocated_string_size - string_size;
2828
2829 answer->set_length(position);
2830 if (delta == 0) return *answer;
2831
2832 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002833 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002834
2835 return *answer;
2836}
2837
2838
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002839RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002840 ASSERT(args.length() == 4);
2841
2842 CONVERT_CHECKED(String, subject, args[0]);
2843 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002844 Object* flat_subject;
2845 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
2846 if (!maybe_flat_subject->ToObject(&flat_subject)) {
2847 return maybe_flat_subject;
2848 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002849 }
2850 subject = String::cast(flat_subject);
2851 }
2852
2853 CONVERT_CHECKED(String, replacement, args[2]);
2854 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00002855 Object* flat_replacement;
2856 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
2857 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
2858 return maybe_flat_replacement;
2859 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002860 }
2861 replacement = String::cast(flat_replacement);
2862 }
2863
2864 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
2865 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
2866
2867 ASSERT(last_match_info->HasFastElements());
2868
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002869 if (replacement->length() == 0) {
2870 if (subject->HasOnlyAsciiChars()) {
2871 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002872 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002873 } else {
2874 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002875 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002876 }
2877 }
2878
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002879 return StringReplaceRegExpWithString(isolate,
2880 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002881 regexp,
2882 replacement,
2883 last_match_info);
2884}
2885
2886
ager@chromium.org7c537e22008-10-16 08:43:32 +00002887// Perform string match of pattern on subject, starting at start index.
2888// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002889// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002890int Runtime::StringMatch(Isolate* isolate,
2891 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00002892 Handle<String> pat,
2893 int start_index) {
2894 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002895 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002896
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00002897 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002898 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002899
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002900 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00002901 if (start_index + pattern_length > subject_length) return -1;
2902
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002903 if (!sub->IsFlat()) FlattenString(sub);
2904 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00002905
ager@chromium.org7c537e22008-10-16 08:43:32 +00002906 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002907 // Extract flattened substrings of cons strings before determining asciiness.
2908 String* seq_sub = *sub;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002909 if (seq_sub->IsConsString()) seq_sub = ConsString::cast(seq_sub)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002910 String* seq_pat = *pat;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002911 if (seq_pat->IsConsString()) seq_pat = ConsString::cast(seq_pat)->first();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002912
ager@chromium.org7c537e22008-10-16 08:43:32 +00002913 // dispatch on type of strings
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002914 if (seq_pat->IsAsciiRepresentation()) {
2915 Vector<const char> pat_vector = seq_pat->ToAsciiVector();
2916 if (seq_sub->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002917 return SearchString(isolate,
2918 seq_sub->ToAsciiVector(),
2919 pat_vector,
2920 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002921 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002922 return SearchString(isolate,
2923 seq_sub->ToUC16Vector(),
2924 pat_vector,
2925 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00002926 }
lrn@chromium.org32d961d2010-06-30 09:09:34 +00002927 Vector<const uc16> pat_vector = seq_pat->ToUC16Vector();
2928 if (seq_sub->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002929 return SearchString(isolate,
2930 seq_sub->ToAsciiVector(),
2931 pat_vector,
2932 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002933 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002934 return SearchString(isolate,
2935 seq_sub->ToUC16Vector(),
2936 pat_vector,
2937 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002938}
2939
2940
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002941RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002942 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002943 ASSERT(args.length() == 3);
2944
ager@chromium.org7c537e22008-10-16 08:43:32 +00002945 CONVERT_ARG_CHECKED(String, sub, 0);
2946 CONVERT_ARG_CHECKED(String, pat, 1);
2947
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002948 Object* index = args[2];
2949 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002950 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002951
ager@chromium.org870a0b62008-11-04 11:43:05 +00002952 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002953 int position =
2954 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002955 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002956}
2957
2958
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002959template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002960static int StringMatchBackwards(Vector<const schar> subject,
2961 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002962 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002963 int pattern_length = pattern.length();
2964 ASSERT(pattern_length >= 1);
2965 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002966
2967 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002968 for (int i = 0; i < pattern_length; i++) {
2969 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002970 if (c > String::kMaxAsciiCharCode) {
2971 return -1;
2972 }
2973 }
2974 }
2975
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002976 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002977 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002978 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002979 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002980 while (j < pattern_length) {
2981 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002982 break;
2983 }
2984 j++;
2985 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002986 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002987 return i;
2988 }
2989 }
2990 return -1;
2991}
2992
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002993RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002994 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002995 ASSERT(args.length() == 3);
2996
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00002997 CONVERT_ARG_CHECKED(String, sub, 0);
2998 CONVERT_ARG_CHECKED(String, pat, 1);
2999
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003000 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003001 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003002 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003003
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003004 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003005 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003006
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003007 if (start_index + pat_length > sub_length) {
3008 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00003009 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003010
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003011 if (pat_length == 0) {
3012 return Smi::FromInt(start_index);
3013 }
3014
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003015 if (!sub->IsFlat()) FlattenString(sub);
3016 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003017
3018 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3019
3020 int position = -1;
3021
3022 if (pat->IsAsciiRepresentation()) {
3023 Vector<const char> pat_vector = pat->ToAsciiVector();
3024 if (sub->IsAsciiRepresentation()) {
3025 position = StringMatchBackwards(sub->ToAsciiVector(),
3026 pat_vector,
3027 start_index);
3028 } else {
3029 position = StringMatchBackwards(sub->ToUC16Vector(),
3030 pat_vector,
3031 start_index);
3032 }
3033 } else {
3034 Vector<const uc16> pat_vector = pat->ToUC16Vector();
3035 if (sub->IsAsciiRepresentation()) {
3036 position = StringMatchBackwards(sub->ToAsciiVector(),
3037 pat_vector,
3038 start_index);
3039 } else {
3040 position = StringMatchBackwards(sub->ToUC16Vector(),
3041 pat_vector,
3042 start_index);
3043 }
3044 }
3045
3046 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003047}
3048
3049
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003050RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003051 NoHandleAllocation ha;
3052 ASSERT(args.length() == 2);
3053
3054 CONVERT_CHECKED(String, str1, args[0]);
3055 CONVERT_CHECKED(String, str2, args[1]);
3056
3057 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003058 int str1_length = str1->length();
3059 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003060
3061 // Decide trivial cases without flattening.
3062 if (str1_length == 0) {
3063 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3064 return Smi::FromInt(-str2_length);
3065 } else {
3066 if (str2_length == 0) return Smi::FromInt(str1_length);
3067 }
3068
3069 int end = str1_length < str2_length ? str1_length : str2_length;
3070
3071 // No need to flatten if we are going to find the answer on the first
3072 // character. At this point we know there is at least one character
3073 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003074 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003075 if (d != 0) return Smi::FromInt(d);
3076
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003077 str1->TryFlatten();
3078 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003079
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003080 StringInputBuffer& buf1 =
3081 *isolate->runtime_state()->string_locale_compare_buf1();
3082 StringInputBuffer& buf2 =
3083 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003084
3085 buf1.Reset(str1);
3086 buf2.Reset(str2);
3087
3088 for (int i = 0; i < end; i++) {
3089 uint16_t char1 = buf1.GetNext();
3090 uint16_t char2 = buf2.GetNext();
3091 if (char1 != char2) return Smi::FromInt(char1 - char2);
3092 }
3093
3094 return Smi::FromInt(str1_length - str2_length);
3095}
3096
3097
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003098RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003099 NoHandleAllocation ha;
3100 ASSERT(args.length() == 3);
3101
3102 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003103 int start, end;
3104 // We have a fast integer-only case here to avoid a conversion to double in
3105 // the common case where from and to are Smis.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003106 if (args[1]->IsSmi() && args[2]->IsSmi()) {
3107 CONVERT_SMI_ARG_CHECKED(from_number, 1);
3108 CONVERT_SMI_ARG_CHECKED(to_number, 2);
3109 start = from_number;
3110 end = to_number;
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003111 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003112 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
3113 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003114 start = FastD2I(from_number);
3115 end = FastD2I(to_number);
3116 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003117 RUNTIME_ASSERT(end >= start);
3118 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003119 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003120 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003121 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003122}
3123
3124
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003125RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003126 ASSERT_EQ(3, args.length());
3127
3128 CONVERT_ARG_CHECKED(String, subject, 0);
3129 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3130 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
3131 HandleScope handles;
3132
3133 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3134
3135 if (match.is_null()) {
3136 return Failure::Exception();
3137 }
3138 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003139 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003140 }
3141 int length = subject->length();
3142
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003143 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003144 ZoneList<int> offsets(8);
ager@chromium.org04921a82011-06-27 13:21:41 +00003145 int start;
3146 int end;
ager@chromium.org41826e72009-03-30 13:30:57 +00003147 do {
ager@chromium.org41826e72009-03-30 13:30:57 +00003148 {
3149 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003150 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003151 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3152 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3153 }
3154 offsets.Add(start);
3155 offsets.Add(end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003156 if (start == end) if (++end > length) break;
3157 match = RegExpImpl::Exec(regexp, subject, end, regexp_info);
ager@chromium.org41826e72009-03-30 13:30:57 +00003158 if (match.is_null()) {
3159 return Failure::Exception();
3160 }
3161 } while (!match->IsNull());
3162 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003163 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org04921a82011-06-27 13:21:41 +00003164 Handle<String> substring = isolate->factory()->
3165 NewSubString(subject, offsets.at(0), offsets.at(1));
3166 elements->set(0, *substring);
3167 for (int i = 1; i < matches ; i++) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003168 int from = offsets.at(i * 2);
3169 int to = offsets.at(i * 2 + 1);
ager@chromium.org04921a82011-06-27 13:21:41 +00003170 Handle<String> substring = isolate->factory()->
3171 NewProperSubString(subject, from, to);
3172 elements->set(i, *substring);
ager@chromium.org41826e72009-03-30 13:30:57 +00003173 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003174 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003175 result->set_length(Smi::FromInt(matches));
3176 return *result;
3177}
3178
3179
lrn@chromium.org25156de2010-04-06 13:10:27 +00003180// Two smis before and after the match, for very long strings.
3181const int kMaxBuilderEntriesPerRegExpMatch = 5;
3182
3183
3184static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3185 Handle<JSArray> last_match_info,
3186 int match_start,
3187 int match_end) {
3188 // Fill last_match_info with a single capture.
3189 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3190 AssertNoAllocation no_gc;
3191 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3192 RegExpImpl::SetLastCaptureCount(elements, 2);
3193 RegExpImpl::SetLastInput(elements, *subject);
3194 RegExpImpl::SetLastSubject(elements, *subject);
3195 RegExpImpl::SetCapture(elements, 0, match_start);
3196 RegExpImpl::SetCapture(elements, 1, match_end);
3197}
3198
3199
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003200template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003201static bool SearchStringMultiple(Isolate* isolate,
3202 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003203 Vector<const PatternChar> pattern,
3204 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003205 FixedArrayBuilder* builder,
3206 int* match_pos) {
3207 int pos = *match_pos;
3208 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003209 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003210 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003211 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003212 while (pos <= max_search_start) {
3213 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3214 *match_pos = pos;
3215 return false;
3216 }
3217 // Position of end of previous match.
3218 int match_end = pos + pattern_length;
3219 int new_pos = search.Search(subject, match_end);
3220 if (new_pos >= 0) {
3221 // A match.
3222 if (new_pos > match_end) {
3223 ReplacementStringBuilder::AddSubjectSlice(builder,
3224 match_end,
3225 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003226 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003227 pos = new_pos;
3228 builder->Add(pattern_string);
3229 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003230 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003231 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003232 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003233
lrn@chromium.org25156de2010-04-06 13:10:27 +00003234 if (pos < max_search_start) {
3235 ReplacementStringBuilder::AddSubjectSlice(builder,
3236 pos + pattern_length,
3237 subject_length);
3238 }
3239 *match_pos = pos;
3240 return true;
3241}
3242
3243
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003244static bool SearchStringMultiple(Isolate* isolate,
3245 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003246 Handle<String> pattern,
3247 Handle<JSArray> last_match_info,
3248 FixedArrayBuilder* builder) {
3249 ASSERT(subject->IsFlat());
3250 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003251
3252 // Treating as if a previous match was before first character.
3253 int match_pos = -pattern->length();
3254
3255 for (;;) { // Break when search complete.
3256 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3257 AssertNoAllocation no_gc;
3258 if (subject->IsAsciiRepresentation()) {
3259 Vector<const char> subject_vector = subject->ToAsciiVector();
3260 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003261 if (SearchStringMultiple(isolate,
3262 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003263 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003264 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003265 builder,
3266 &match_pos)) break;
3267 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003268 if (SearchStringMultiple(isolate,
3269 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003270 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003271 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003272 builder,
3273 &match_pos)) break;
3274 }
3275 } else {
3276 Vector<const uc16> subject_vector = subject->ToUC16Vector();
3277 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003278 if (SearchStringMultiple(isolate,
3279 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003280 pattern->ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003281 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003282 builder,
3283 &match_pos)) break;
3284 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003285 if (SearchStringMultiple(isolate,
3286 subject_vector,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003287 pattern->ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003288 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003289 builder,
3290 &match_pos)) break;
3291 }
3292 }
3293 }
3294
3295 if (match_pos >= 0) {
3296 SetLastMatchInfoNoCaptures(subject,
3297 last_match_info,
3298 match_pos,
3299 match_pos + pattern->length());
3300 return true;
3301 }
3302 return false; // No matches at all.
3303}
3304
3305
3306static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003307 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003308 Handle<String> subject,
3309 Handle<JSRegExp> regexp,
3310 Handle<JSArray> last_match_array,
3311 FixedArrayBuilder* builder) {
3312 ASSERT(subject->IsFlat());
3313 int match_start = -1;
3314 int match_end = 0;
3315 int pos = 0;
3316 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3317 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3318
3319 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003320 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003321 int subject_length = subject->length();
ager@chromium.org04921a82011-06-27 13:21:41 +00003322 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003323
3324 for (;;) { // Break on failure, return on exception.
3325 RegExpImpl::IrregexpResult result =
3326 RegExpImpl::IrregexpExecOnce(regexp,
3327 subject,
3328 pos,
3329 register_vector);
3330 if (result == RegExpImpl::RE_SUCCESS) {
3331 match_start = register_vector[0];
3332 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3333 if (match_end < match_start) {
3334 ReplacementStringBuilder::AddSubjectSlice(builder,
3335 match_end,
3336 match_start);
3337 }
3338 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003339 HandleScope loop_scope(isolate);
ager@chromium.org04921a82011-06-27 13:21:41 +00003340 if (!first) {
3341 builder->Add(*isolate->factory()->NewProperSubString(subject,
3342 match_start,
3343 match_end));
3344 } else {
3345 builder->Add(*isolate->factory()->NewSubString(subject,
3346 match_start,
3347 match_end));
3348 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003349 if (match_start != match_end) {
3350 pos = match_end;
3351 } else {
3352 pos = match_end + 1;
3353 if (pos > subject_length) break;
3354 }
3355 } else if (result == RegExpImpl::RE_FAILURE) {
3356 break;
3357 } else {
3358 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3359 return result;
3360 }
ager@chromium.org04921a82011-06-27 13:21:41 +00003361 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003362 }
3363
3364 if (match_start >= 0) {
3365 if (match_end < subject_length) {
3366 ReplacementStringBuilder::AddSubjectSlice(builder,
3367 match_end,
3368 subject_length);
3369 }
3370 SetLastMatchInfoNoCaptures(subject,
3371 last_match_array,
3372 match_start,
3373 match_end);
3374 return RegExpImpl::RE_SUCCESS;
3375 } else {
3376 return RegExpImpl::RE_FAILURE; // No matches at all.
3377 }
3378}
3379
3380
3381static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003382 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003383 Handle<String> subject,
3384 Handle<JSRegExp> regexp,
3385 Handle<JSArray> last_match_array,
3386 FixedArrayBuilder* builder) {
3387
3388 ASSERT(subject->IsFlat());
3389 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3390 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3391
3392 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003393 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003394
3395 RegExpImpl::IrregexpResult result =
3396 RegExpImpl::IrregexpExecOnce(regexp,
3397 subject,
3398 0,
3399 register_vector);
3400
3401 int capture_count = regexp->CaptureCount();
3402 int subject_length = subject->length();
3403
3404 // Position to search from.
3405 int pos = 0;
3406 // End of previous match. Differs from pos if match was empty.
3407 int match_end = 0;
3408 if (result == RegExpImpl::RE_SUCCESS) {
3409 // Need to keep a copy of the previous match for creating last_match_info
3410 // at the end, so we have two vectors that we swap between.
3411 OffsetsVector registers2(required_registers);
3412 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00003413 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003414 do {
3415 int match_start = register_vector[0];
3416 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3417 if (match_end < match_start) {
3418 ReplacementStringBuilder::AddSubjectSlice(builder,
3419 match_end,
3420 match_start);
3421 }
3422 match_end = register_vector[1];
3423
3424 {
3425 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003426 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003427 // Arguments array to replace function is match, captures, index and
3428 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003429 Handle<FixedArray> elements =
3430 isolate->factory()->NewFixedArray(3 + capture_count);
ager@chromium.org04921a82011-06-27 13:21:41 +00003431 Handle<String> match;
3432 if (!first) {
3433 match = isolate->factory()->NewProperSubString(subject,
3434 match_start,
3435 match_end);
3436 } else {
3437 match = isolate->factory()->NewSubString(subject,
3438 match_start,
3439 match_end);
3440 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003441 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003442 for (int i = 1; i <= capture_count; i++) {
3443 int start = register_vector[i * 2];
3444 if (start >= 0) {
3445 int end = register_vector[i * 2 + 1];
3446 ASSERT(start <= end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003447 Handle<String> substring;
3448 if (!first) {
3449 substring = isolate->factory()->NewProperSubString(subject,
3450 start,
3451 end);
3452 } else {
3453 substring = isolate->factory()->NewSubString(subject, start, end);
3454 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003455 elements->set(i, *substring);
3456 } else {
3457 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003458 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003459 }
3460 }
3461 elements->set(capture_count + 1, Smi::FromInt(match_start));
3462 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003463 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003464 }
3465 // Swap register vectors, so the last successful match is in
3466 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003467 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003468 prev_register_vector = register_vector;
3469 register_vector = tmp;
3470
3471 if (match_end > match_start) {
3472 pos = match_end;
3473 } else {
3474 pos = match_end + 1;
3475 if (pos > subject_length) {
3476 break;
3477 }
3478 }
3479
3480 result = RegExpImpl::IrregexpExecOnce(regexp,
3481 subject,
3482 pos,
3483 register_vector);
ager@chromium.org04921a82011-06-27 13:21:41 +00003484 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003485 } while (result == RegExpImpl::RE_SUCCESS);
3486
3487 if (result != RegExpImpl::RE_EXCEPTION) {
3488 // Finished matching, with at least one match.
3489 if (match_end < subject_length) {
3490 ReplacementStringBuilder::AddSubjectSlice(builder,
3491 match_end,
3492 subject_length);
3493 }
3494
3495 int last_match_capture_count = (capture_count + 1) * 2;
3496 int last_match_array_size =
3497 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3498 last_match_array->EnsureSize(last_match_array_size);
3499 AssertNoAllocation no_gc;
3500 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3501 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3502 RegExpImpl::SetLastSubject(elements, *subject);
3503 RegExpImpl::SetLastInput(elements, *subject);
3504 for (int i = 0; i < last_match_capture_count; i++) {
3505 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3506 }
3507 return RegExpImpl::RE_SUCCESS;
3508 }
3509 }
3510 // No matches at all, return failure or exception result directly.
3511 return result;
3512}
3513
3514
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003515RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003516 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003517 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003518
3519 CONVERT_ARG_CHECKED(String, subject, 1);
3520 if (!subject->IsFlat()) { FlattenString(subject); }
3521 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3522 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3523 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3524
3525 ASSERT(last_match_info->HasFastElements());
3526 ASSERT(regexp->GetFlags().is_global());
3527 Handle<FixedArray> result_elements;
3528 if (result_array->HasFastElements()) {
3529 result_elements =
3530 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
ager@chromium.org04921a82011-06-27 13:21:41 +00003531 }
3532 if (result_elements.is_null() || result_elements->length() < 16) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003533 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003534 }
3535 FixedArrayBuilder builder(result_elements);
3536
3537 if (regexp->TypeTag() == JSRegExp::ATOM) {
3538 Handle<String> pattern(
3539 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003540 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003541 if (SearchStringMultiple(isolate, subject, pattern,
3542 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003543 return *builder.ToJSArray(result_array);
3544 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003545 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003546 }
3547
3548 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3549
3550 RegExpImpl::IrregexpResult result;
3551 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003552 result = SearchRegExpNoCaptureMultiple(isolate,
3553 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003554 regexp,
3555 last_match_info,
3556 &builder);
3557 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003558 result = SearchRegExpMultiple(isolate,
3559 subject,
3560 regexp,
3561 last_match_info,
3562 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003563 }
3564 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003565 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003566 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3567 return Failure::Exception();
3568}
3569
3570
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003571RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003572 NoHandleAllocation ha;
3573 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003574 CONVERT_SMI_ARG_CHECKED(radix, 1);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003575 RUNTIME_ASSERT(2 <= radix && radix <= 36);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003576
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003577 // Fast case where the result is a one character string.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003578 if (args[0]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003579 int value = args.smi_at(0);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003580 if (value >= 0 && value < radix) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003581 // Character array used for conversion.
3582 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003583 return isolate->heap()->
3584 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003585 }
3586 }
3587
3588 // Slow case.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003589 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003590 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003591 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003592 }
3593 if (isinf(value)) {
3594 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003595 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003596 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003597 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003598 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003599 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003600 MaybeObject* result =
3601 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003602 DeleteArray(str);
3603 return result;
3604}
3605
3606
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003607RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003608 NoHandleAllocation ha;
3609 ASSERT(args.length() == 2);
3610
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003611 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003612 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003613 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003614 }
3615 if (isinf(value)) {
3616 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003617 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003618 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003619 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003620 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003621 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003622 int f = FastD2I(f_number);
3623 RUNTIME_ASSERT(f >= 0);
3624 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003625 MaybeObject* res =
3626 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003627 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003628 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003629}
3630
3631
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003632RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003633 NoHandleAllocation ha;
3634 ASSERT(args.length() == 2);
3635
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003636 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003637 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003638 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003639 }
3640 if (isinf(value)) {
3641 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003642 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003643 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003644 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003645 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003646 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003647 int f = FastD2I(f_number);
3648 RUNTIME_ASSERT(f >= -1 && f <= 20);
3649 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003650 MaybeObject* res =
3651 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003652 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003653 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003654}
3655
3656
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003657RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003658 NoHandleAllocation ha;
3659 ASSERT(args.length() == 2);
3660
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003661 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003662 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003663 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003664 }
3665 if (isinf(value)) {
3666 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003667 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003668 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003669 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003670 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003671 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003672 int f = FastD2I(f_number);
3673 RUNTIME_ASSERT(f >= 1 && f <= 21);
3674 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003675 MaybeObject* res =
3676 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003677 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003678 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003679}
3680
3681
3682// Returns a single character string where first character equals
3683// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003684static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003685 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003686 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003687 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003688 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003689 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003690 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003691}
3692
3693
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003694MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
3695 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003696 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003697 // Handle [] indexing on Strings
3698 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003699 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
3700 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003701 }
3702
3703 // Handle [] indexing on String objects
3704 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003705 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
3706 Handle<Object> result =
3707 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
3708 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003709 }
3710
3711 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003712 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003713 return prototype->GetElement(index);
3714 }
3715
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003716 return GetElement(object, index);
3717}
3718
3719
lrn@chromium.org303ada72010-10-27 09:33:13 +00003720MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003721 return object->GetElement(index);
3722}
3723
3724
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003725MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
3726 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003727 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003728 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003729
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003730 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003731 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003732 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003733 isolate->factory()->NewTypeError("non_object_property_load",
3734 HandleVector(args, 2));
3735 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003736 }
3737
3738 // Check if the given key is an array index.
3739 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003740 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003741 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003742 }
3743
3744 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003745 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003746 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003747 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003748 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003749 bool has_pending_exception = false;
3750 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003751 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003752 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003753 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003754 }
3755
ager@chromium.org32912102009-01-16 10:38:43 +00003756 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003757 // the element if so.
3758 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003759 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003760 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003761 return object->GetProperty(*name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003762 }
3763}
3764
3765
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003766RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003767 NoHandleAllocation ha;
3768 ASSERT(args.length() == 2);
3769
3770 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003771 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003772
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003773 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003774}
3775
3776
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003777// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003778RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00003779 NoHandleAllocation ha;
3780 ASSERT(args.length() == 2);
3781
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003782 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00003783 // itself.
3784 //
3785 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00003786 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00003787 // global proxy object never has properties. This is the case
3788 // because the global proxy object forwards everything to its hidden
3789 // prototype including local lookups.
3790 //
3791 // Additionally, we need to make sure that we do not cache results
3792 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003793 if (args[0]->IsJSObject() &&
3794 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00003795 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003796 args[1]->IsString()) {
3797 JSObject* receiver = JSObject::cast(args[0]);
3798 String* key = String::cast(args[1]);
3799 if (receiver->HasFastProperties()) {
3800 // Attempt to use lookup cache.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003801 Map* receiver_map = receiver->map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003802 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
3803 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003804 if (offset != -1) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003805 Object* value = receiver->FastPropertyAt(offset);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003806 return value->IsTheHole() ? isolate->heap()->undefined_value() : value;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003807 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003808 // Lookup cache miss. Perform lookup and update the cache if appropriate.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003809 LookupResult result;
3810 receiver->LocalLookup(key, &result);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00003811 if (result.IsProperty() && result.type() == FIELD) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003812 int offset = result.GetFieldIndex();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003813 keyed_lookup_cache->Update(receiver_map, key, offset);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003814 return receiver->FastPropertyAt(offset);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003815 }
3816 } else {
3817 // Attempt dictionary lookup.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00003818 StringDictionary* dictionary = receiver->property_dictionary();
3819 int entry = dictionary->FindEntry(key);
3820 if ((entry != StringDictionary::kNotFound) &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003821 (dictionary->DetailsAt(entry).type() == NORMAL)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003822 Object* value = dictionary->ValueAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003823 if (!receiver->IsGlobalObject()) return value;
3824 value = JSGlobalPropertyCell::cast(value)->value();
3825 if (!value->IsTheHole()) return value;
3826 // If value is the hole do the general lookup.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003827 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003828 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003829 } else if (args[0]->IsString() && args[1]->IsSmi()) {
3830 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003831 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003832 Handle<String> str = args.at<String>(0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003833 int index = args.smi_at(1);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003834 if (index >= 0 && index < str->length()) {
3835 Handle<Object> result = GetCharAt(str, index);
3836 return *result;
3837 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003838 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003839
3840 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003841 return Runtime::GetObjectProperty(isolate,
3842 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00003843 args.at<Object>(1));
3844}
3845
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003846// Implements part of 8.12.9 DefineOwnProperty.
3847// There are 3 cases that lead here:
3848// Step 4b - define a new accessor property.
3849// Steps 9c & 12 - replace an existing data property with an accessor property.
3850// Step 12 - update an existing accessor property with an accessor or generic
3851// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003852RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003853 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003854 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00003855 CONVERT_ARG_CHECKED(JSObject, obj, 0);
3856 CONVERT_CHECKED(String, name, args[1]);
3857 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003858 Object* fun = args[3];
3859 RUNTIME_ASSERT(fun->IsJSFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00003860 CONVERT_CHECKED(Smi, flag_attr, args[4]);
3861 int unchecked = flag_attr->value();
3862 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3863 RUNTIME_ASSERT(!obj->IsNull());
3864 LookupResult result;
3865 obj->LocalLookupRealNamedProperty(name, &result);
3866
3867 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3868 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
3869 // delete it to avoid running into trouble in DefineAccessor, which
3870 // handles this incorrectly if the property is readonly (does nothing)
3871 if (result.IsProperty() &&
3872 (result.type() == FIELD || result.type() == NORMAL
3873 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003874 Object* ok;
3875 { MaybeObject* maybe_ok =
3876 obj->DeleteProperty(name, JSObject::NORMAL_DELETION);
3877 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
3878 }
ager@chromium.org5c838252010-02-19 08:53:10 +00003879 }
3880 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
3881}
3882
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003883// Implements part of 8.12.9 DefineOwnProperty.
3884// There are 3 cases that lead here:
3885// Step 4a - define a new data property.
3886// Steps 9b & 12 - replace an existing accessor property with a data property.
3887// Step 12 - update an existing data property with a data or generic
3888// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003889RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003890 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003891 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00003892 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
3893 CONVERT_ARG_CHECKED(String, name, 1);
3894 Handle<Object> obj_value = args.at<Object>(2);
3895
3896 CONVERT_CHECKED(Smi, flag, args[3]);
3897 int unchecked = flag->value();
3898 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
3899
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003900 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
3901
3902 // Check if this is an element.
3903 uint32_t index;
3904 bool is_element = name->AsArrayIndex(&index);
3905
3906 // Special case for elements if any of the flags are true.
3907 // If elements are in fast case we always implicitly assume that:
3908 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
3909 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
3910 is_element) {
3911 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003912 if (js_object->IsJSGlobalProxy()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003913 // We do not need to do access checks here since these has already
3914 // been performed by the call to GetOwnProperty.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003915 Handle<Object> proto(js_object->GetPrototype());
3916 // If proxy is detached, ignore the assignment. Alternatively,
3917 // we could throw an exception.
3918 if (proto->IsNull()) return *obj_value;
3919 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003920 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003921 NormalizeElements(js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00003922 Handle<NumberDictionary> dictionary(js_object->element_dictionary());
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003923 // Make sure that we never go back to fast case.
3924 dictionary->set_requires_slow_elements();
3925 PropertyDetails details = PropertyDetails(attr, NORMAL);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003926 Handle<NumberDictionary> extended_dictionary =
3927 NumberDictionarySet(dictionary, index, obj_value, details);
3928 if (*extended_dictionary != *dictionary) {
3929 js_object->set_elements(*extended_dictionary);
3930 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003931 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003932 }
3933
ager@chromium.org5c838252010-02-19 08:53:10 +00003934 LookupResult result;
whesse@chromium.org7b260152011-06-20 15:33:18 +00003935 js_object->LocalLookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00003936
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00003937 // To be compatible with safari we do not change the value on API objects
3938 // in defineProperty. Firefox disagrees here, and actually changes the value.
3939 if (result.IsProperty() &&
3940 (result.type() == CALLBACKS) &&
3941 result.GetCallbackObject()->IsAccessorInfo()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003942 return isolate->heap()->undefined_value();
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00003943 }
3944
ager@chromium.org5c838252010-02-19 08:53:10 +00003945 // Take special care when attributes are different and there is already
3946 // a property. For simplicity we normalize the property which enables us
3947 // to not worry about changing the instance_descriptor and creating a new
3948 // map. The current version of SetObjectProperty does not handle attributes
3949 // correctly in the case where a property is a field and is reset with
3950 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003951 if (result.IsProperty() &&
3952 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00003953 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003954 if (js_object->IsJSGlobalProxy()) {
3955 // Since the result is a property, the prototype will exist so
3956 // we don't have to check for null.
3957 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00003958 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00003959 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00003960 // Use IgnoreAttributes version since a readonly property may be
3961 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00003962 return js_object->SetLocalPropertyIgnoreAttributes(*name,
3963 *obj_value,
3964 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003965 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00003966
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003967 return Runtime::ForceSetObjectProperty(isolate,
3968 js_object,
3969 name,
3970 obj_value,
3971 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00003972}
3973
3974
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003975// Special case for elements if any of the flags are true.
3976// If elements are in fast case we always implicitly assume that:
3977// DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
3978static MaybeObject* NormalizeObjectSetElement(Isolate* isolate,
3979 Handle<JSObject> js_object,
3980 uint32_t index,
3981 Handle<Object> value,
3982 PropertyAttributes attr) {
3983 // Normalize the elements to enable attributes on the property.
3984 NormalizeElements(js_object);
3985 Handle<NumberDictionary> dictionary(js_object->element_dictionary());
3986 // Make sure that we never go back to fast case.
3987 dictionary->set_requires_slow_elements();
3988 PropertyDetails details = PropertyDetails(attr, NORMAL);
3989 Handle<NumberDictionary> extended_dictionary =
3990 NumberDictionarySet(dictionary, index, value, details);
3991 if (*extended_dictionary != *dictionary) {
3992 js_object->set_elements(*extended_dictionary);
3993 }
3994 return *value;
3995}
3996
3997
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003998MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
3999 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004000 Handle<Object> key,
4001 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004002 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004003 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004004 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004005
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004006 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004007 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004008 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004009 isolate->factory()->NewTypeError("non_object_property_store",
4010 HandleVector(args, 2));
4011 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004012 }
4013
4014 // If the object isn't a JavaScript object, we ignore the store.
4015 if (!object->IsJSObject()) return *value;
4016
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004017 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
4018
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004019 // Check if the given key is an array index.
4020 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004021 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004022 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4023 // of a string using [] notation. We need to support this too in
4024 // JavaScript.
4025 // In the case of a String object we just need to redirect the assignment to
4026 // the underlying string if the index is in range. Since the underlying
4027 // string does nothing with the assignment then we can ignore such
4028 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004029 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004030 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004031 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004032
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004033 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4034 return NormalizeObjectSetElement(isolate, js_object, index, value, attr);
4035 }
4036
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004037 Handle<Object> result = SetElement(js_object, index, value, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004038 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004039 return *value;
4040 }
4041
4042 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004043 Handle<Object> result;
4044 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004045 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4046 return NormalizeObjectSetElement(isolate,
4047 js_object,
4048 index,
4049 value,
4050 attr);
4051 }
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004052 result = SetElement(js_object, index, value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004053 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004054 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004055 key_string->TryFlatten();
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004056 result = SetProperty(js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004057 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004058 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004059 return *value;
4060 }
4061
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004062 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004063 bool has_pending_exception = false;
4064 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4065 if (has_pending_exception) return Failure::Exception();
4066 Handle<String> name = Handle<String>::cast(converted);
4067
4068 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004069 return js_object->SetElement(index, *value, strict_mode, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004070 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004071 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004072 }
4073}
4074
4075
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004076MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4077 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004078 Handle<Object> key,
4079 Handle<Object> value,
4080 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004081 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004082
4083 // Check if the given key is an array index.
4084 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004085 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004086 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4087 // of a string using [] notation. We need to support this too in
4088 // JavaScript.
4089 // In the case of a String object we just need to redirect the assignment to
4090 // the underlying string if the index is in range. Since the underlying
4091 // string does nothing with the assignment then we can ignore such
4092 // assignments.
4093 if (js_object->IsStringObjectWithCharacterAt(index)) {
4094 return *value;
4095 }
4096
whesse@chromium.org7b260152011-06-20 15:33:18 +00004097 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004098 }
4099
4100 if (key->IsString()) {
4101 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004102 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004103 } else {
4104 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004105 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004106 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4107 *value,
4108 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004109 }
4110 }
4111
4112 // Call-back into JavaScript to convert the key to a string.
4113 bool has_pending_exception = false;
4114 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4115 if (has_pending_exception) return Failure::Exception();
4116 Handle<String> name = Handle<String>::cast(converted);
4117
4118 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004119 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004120 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004121 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004122 }
4123}
4124
4125
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004126MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
4127 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004128 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004129 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004130
4131 // Check if the given key is an array index.
4132 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004133 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004134 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4135 // characters of a string using [] notation. In the case of a
4136 // String object we just need to redirect the deletion to the
4137 // underlying string if the index is in range. Since the
4138 // underlying string does nothing with the deletion, we can ignore
4139 // such deletions.
4140 if (js_object->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004141 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004142 }
4143
4144 return js_object->DeleteElement(index, JSObject::FORCE_DELETION);
4145 }
4146
4147 Handle<String> key_string;
4148 if (key->IsString()) {
4149 key_string = Handle<String>::cast(key);
4150 } else {
4151 // Call-back into JavaScript to convert the key to a string.
4152 bool has_pending_exception = false;
4153 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4154 if (has_pending_exception) return Failure::Exception();
4155 key_string = Handle<String>::cast(converted);
4156 }
4157
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004158 key_string->TryFlatten();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004159 return js_object->DeleteProperty(*key_string, JSObject::FORCE_DELETION);
4160}
4161
4162
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004163RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004164 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004165 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004166
4167 Handle<Object> object = args.at<Object>(0);
4168 Handle<Object> key = args.at<Object>(1);
4169 Handle<Object> value = args.at<Object>(2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004170 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004171 RUNTIME_ASSERT(
4172 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004173 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004174 PropertyAttributes attributes =
4175 static_cast<PropertyAttributes>(unchecked_attributes);
4176
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004177 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004178 if (args.length() == 5) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004179 CONVERT_SMI_ARG_CHECKED(strict_unchecked, 4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004180 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
4181 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004182 strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004183 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004184
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004185 return Runtime::SetObjectProperty(isolate,
4186 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004187 key,
4188 value,
4189 attributes,
4190 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004191}
4192
4193
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004194// Set the native flag on the function.
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004195// This is used to decide if we should transform null and undefined
4196// into the global object when doing call and apply.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004197RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004198 NoHandleAllocation ha;
4199 RUNTIME_ASSERT(args.length() == 1);
4200
4201 Handle<Object> object = args.at<Object>(0);
4202
4203 if (object->IsJSFunction()) {
4204 JSFunction* func = JSFunction::cast(*object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004205 func->shared()->set_native(true);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004206 }
4207 return isolate->heap()->undefined_value();
4208}
4209
4210
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004211// Set a local property, even if it is READ_ONLY. If the property does not
4212// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004213RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004214 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004215 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004216 CONVERT_CHECKED(JSObject, object, args[0]);
4217 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004218 // Compute attributes.
4219 PropertyAttributes attributes = NONE;
4220 if (args.length() == 4) {
4221 CONVERT_CHECKED(Smi, value_obj, args[3]);
4222 int unchecked_value = value_obj->value();
4223 // Only attribute bits should be set.
4224 RUNTIME_ASSERT(
4225 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4226 attributes = static_cast<PropertyAttributes>(unchecked_value);
4227 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004228
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004229 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004230 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004231}
4232
4233
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004234RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004235 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004236 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004237
4238 CONVERT_CHECKED(JSObject, object, args[0]);
4239 CONVERT_CHECKED(String, key, args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004240 CONVERT_SMI_ARG_CHECKED(strict, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004241 return object->DeleteProperty(key, (strict == kStrictMode)
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004242 ? JSObject::STRICT_DELETION
4243 : JSObject::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004244}
4245
4246
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004247static Object* HasLocalPropertyImplementation(Isolate* isolate,
4248 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004249 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004250 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004251 // Handle hidden prototypes. If there's a hidden prototype above this thing
4252 // then we have to check it for properties, because they are supposed to
4253 // look like they are on this object.
4254 Handle<Object> proto(object->GetPrototype());
4255 if (proto->IsJSObject() &&
4256 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004257 return HasLocalPropertyImplementation(isolate,
4258 Handle<JSObject>::cast(proto),
4259 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004260 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004261 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004262}
4263
4264
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004265RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004266 NoHandleAllocation ha;
4267 ASSERT(args.length() == 2);
4268 CONVERT_CHECKED(String, key, args[1]);
4269
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004270 uint32_t index;
4271 const bool key_is_array_index = key->AsArrayIndex(&index);
4272
ager@chromium.org9085a012009-05-11 19:22:57 +00004273 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004274 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004275 if (obj->IsJSObject()) {
4276 JSObject* object = JSObject::cast(obj);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004277 // Fast case: either the key is a real named property or it is not
4278 // an array index and there are no interceptors or hidden
4279 // prototypes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004280 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004281 Map* map = object->map();
4282 if (!key_is_array_index &&
4283 !map->has_named_interceptor() &&
4284 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4285 return isolate->heap()->false_value();
4286 }
4287 // Slow case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004288 HandleScope scope(isolate);
4289 return HasLocalPropertyImplementation(isolate,
4290 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004291 Handle<String>(key));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004292 } else if (obj->IsString() && key_is_array_index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004293 // Well, there is one exception: Handle [] on strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004294 String* string = String::cast(obj);
4295 if (index < static_cast<uint32_t>(string->length())) {
4296 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004297 }
4298 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004299 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004300}
4301
4302
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004303RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004304 NoHandleAllocation na;
4305 ASSERT(args.length() == 2);
4306
4307 // Only JS objects can have properties.
4308 if (args[0]->IsJSObject()) {
4309 JSObject* object = JSObject::cast(args[0]);
4310 CONVERT_CHECKED(String, key, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004311 if (object->HasProperty(key)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004312 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004313 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004314}
4315
4316
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004317RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004318 NoHandleAllocation na;
4319 ASSERT(args.length() == 2);
4320
4321 // Only JS objects can have elements.
4322 if (args[0]->IsJSObject()) {
4323 JSObject* object = JSObject::cast(args[0]);
4324 CONVERT_CHECKED(Smi, index_obj, args[1]);
4325 uint32_t index = index_obj->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004326 if (object->HasElement(index)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004327 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004328 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004329}
4330
4331
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004332RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004333 NoHandleAllocation ha;
4334 ASSERT(args.length() == 2);
4335
4336 CONVERT_CHECKED(JSObject, object, args[0]);
4337 CONVERT_CHECKED(String, key, args[1]);
4338
4339 uint32_t index;
4340 if (key->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004341 return isolate->heap()->ToBoolean(object->HasElement(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004342 }
4343
ager@chromium.org870a0b62008-11-04 11:43:05 +00004344 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004345 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004346}
4347
4348
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004349RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004350 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004351 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004352 CONVERT_ARG_CHECKED(JSObject, object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004353 return *GetKeysFor(object);
4354}
4355
4356
4357// Returns either a FixedArray as Runtime_GetPropertyNames,
4358// or, if the given object has an enum cache that contains
4359// all enumerable properties of the object and its prototypes
4360// have none, the map of the object. This is used to speed up
4361// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004362RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004363 ASSERT(args.length() == 1);
4364
4365 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4366
4367 if (raw_object->IsSimpleEnum()) return raw_object->map();
4368
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004369 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004370 Handle<JSObject> object(raw_object);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004371 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
4372 INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004373
4374 // Test again, since cache may have been built by preceding call.
4375 if (object->IsSimpleEnum()) return object->map();
4376
4377 return *content;
4378}
4379
4380
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004381// Find the length of the prototype chain that is to to handled as one. If a
4382// prototype object is hidden it is to be viewed as part of the the object it
4383// is prototype for.
4384static int LocalPrototypeChainLength(JSObject* obj) {
4385 int count = 1;
4386 Object* proto = obj->GetPrototype();
4387 while (proto->IsJSObject() &&
4388 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4389 count++;
4390 proto = JSObject::cast(proto)->GetPrototype();
4391 }
4392 return count;
4393}
4394
4395
4396// Return the names of the local named properties.
4397// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004398RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004399 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004400 ASSERT(args.length() == 1);
4401 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004402 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004403 }
4404 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4405
4406 // Skip the global proxy as it has no properties and always delegates to the
4407 // real global object.
4408 if (obj->IsJSGlobalProxy()) {
4409 // Only collect names if access is permitted.
4410 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004411 !isolate->MayNamedAccess(*obj,
4412 isolate->heap()->undefined_value(),
4413 v8::ACCESS_KEYS)) {
4414 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4415 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004416 }
4417 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4418 }
4419
4420 // Find the number of objects making up this.
4421 int length = LocalPrototypeChainLength(*obj);
4422
4423 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004424 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004425 int total_property_count = 0;
4426 Handle<JSObject> jsproto = obj;
4427 for (int i = 0; i < length; i++) {
4428 // Only collect names if access is permitted.
4429 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004430 !isolate->MayNamedAccess(*jsproto,
4431 isolate->heap()->undefined_value(),
4432 v8::ACCESS_KEYS)) {
4433 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4434 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004435 }
4436 int n;
4437 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4438 local_property_count[i] = n;
4439 total_property_count += n;
4440 if (i < length - 1) {
4441 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4442 }
4443 }
4444
4445 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004446 Handle<FixedArray> names =
4447 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004448
4449 // Get the property names.
4450 jsproto = obj;
4451 int proto_with_hidden_properties = 0;
4452 for (int i = 0; i < length; i++) {
4453 jsproto->GetLocalPropertyNames(*names,
4454 i == 0 ? 0 : local_property_count[i - 1]);
4455 if (!GetHiddenProperties(jsproto, false)->IsUndefined()) {
4456 proto_with_hidden_properties++;
4457 }
4458 if (i < length - 1) {
4459 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4460 }
4461 }
4462
4463 // Filter out name of hidden propeties object.
4464 if (proto_with_hidden_properties > 0) {
4465 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004466 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004467 names->length() - proto_with_hidden_properties);
4468 int dest_pos = 0;
4469 for (int i = 0; i < total_property_count; i++) {
4470 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004471 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004472 continue;
4473 }
4474 names->set(dest_pos++, name);
4475 }
4476 }
4477
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004478 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004479}
4480
4481
4482// Return the names of the local indexed properties.
4483// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004484RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004485 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004486 ASSERT(args.length() == 1);
4487 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004488 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004489 }
4490 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4491
4492 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004493 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004494 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004495 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004496}
4497
4498
4499// Return information on whether an object has a named or indexed interceptor.
4500// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004501RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004502 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004503 ASSERT(args.length() == 1);
4504 if (!args[0]->IsJSObject()) {
4505 return Smi::FromInt(0);
4506 }
4507 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4508
4509 int result = 0;
4510 if (obj->HasNamedInterceptor()) result |= 2;
4511 if (obj->HasIndexedInterceptor()) result |= 1;
4512
4513 return Smi::FromInt(result);
4514}
4515
4516
4517// Return property names from named interceptor.
4518// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004519RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004520 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004521 ASSERT(args.length() == 1);
4522 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4523
4524 if (obj->HasNamedInterceptor()) {
4525 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4526 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4527 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004528 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004529}
4530
4531
4532// Return element names from indexed interceptor.
4533// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004534RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004535 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004536 ASSERT(args.length() == 1);
4537 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4538
4539 if (obj->HasIndexedInterceptor()) {
4540 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4541 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4542 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004543 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004544}
4545
4546
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004547RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004548 ASSERT_EQ(args.length(), 1);
4549 CONVERT_CHECKED(JSObject, raw_object, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004550 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004551 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004552
4553 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00004554 // Do access checks before going to the global object.
4555 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004556 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00004557 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004558 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
4559 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00004560 }
4561
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004562 Handle<Object> proto(object->GetPrototype());
4563 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004564 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004565 object = Handle<JSObject>::cast(proto);
4566 }
4567
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004568 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4569 LOCAL_ONLY);
4570 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4571 // property array and since the result is mutable we have to create
4572 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004573 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004574 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004575 for (int i = 0; i < length; i++) {
4576 Object* entry = contents->get(i);
4577 if (entry->IsString()) {
4578 copy->set(i, entry);
4579 } else {
4580 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004581 HandleScope scope(isolate);
4582 Handle<Object> entry_handle(entry, isolate);
4583 Handle<Object> entry_str =
4584 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004585 copy->set(i, *entry_str);
4586 }
4587 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004588 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004589}
4590
4591
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004592RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004593 NoHandleAllocation ha;
4594 ASSERT(args.length() == 1);
4595
4596 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00004597 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004598 it.AdvanceToArgumentsFrame();
4599 JavaScriptFrame* frame = it.frame();
4600
4601 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00004602 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004603
4604 // Try to convert the key to an index. If successful and within
4605 // index return the the argument from the frame.
4606 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004607 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004608 return frame->GetParameter(index);
4609 }
4610
4611 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004612 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004613 bool exception = false;
4614 Handle<Object> converted =
4615 Execution::ToString(args.at<Object>(0), &exception);
4616 if (exception) return Failure::Exception();
4617 Handle<String> key = Handle<String>::cast(converted);
4618
4619 // Try to convert the string key into an array index.
4620 if (key->AsArrayIndex(&index)) {
4621 if (index < n) {
4622 return frame->GetParameter(index);
4623 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004624 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004625 }
4626 }
4627
4628 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004629 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
4630 if (key->Equals(isolate->heap()->callee_symbol())) {
4631 Object* function = frame->function();
4632 if (function->IsJSFunction() &&
4633 JSFunction::cast(function)->shared()->strict_mode()) {
4634 return isolate->Throw(*isolate->factory()->NewTypeError(
4635 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
4636 }
4637 return function;
4638 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004639
4640 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004641 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004642}
4643
4644
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004645RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004646 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004647
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004648 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004649 Handle<Object> object = args.at<Object>(0);
4650 if (object->IsJSObject()) {
4651 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00004652 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004653 MaybeObject* ok = js_object->TransformToFastProperties(0);
4654 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00004655 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004656 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004657 return *object;
4658}
4659
4660
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004661RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004662 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004663
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004664 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004665 Handle<Object> object = args.at<Object>(0);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004666 if (object->IsJSObject() && !object->IsJSGlobalProxy()) {
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004667 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004668 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004669 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004670 return *object;
4671}
4672
4673
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004674RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004675 NoHandleAllocation ha;
4676 ASSERT(args.length() == 1);
4677
4678 return args[0]->ToBoolean();
4679}
4680
4681
4682// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
4683// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004684RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004685 NoHandleAllocation ha;
4686
4687 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004688 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004689 HeapObject* heap_obj = HeapObject::cast(obj);
4690
4691 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004692 if (heap_obj->map()->is_undetectable()) {
4693 return isolate->heap()->undefined_symbol();
4694 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004695
4696 InstanceType instance_type = heap_obj->map()->instance_type();
4697 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004698 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004699 }
4700
4701 switch (instance_type) {
4702 case ODDBALL_TYPE:
4703 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004704 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004705 }
4706 if (heap_obj->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004707 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004708 }
4709 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004710 return isolate->heap()->undefined_symbol();
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00004711 case JS_FUNCTION_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004712 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004713 default:
4714 // For any kind of object not handled above, the spec rule for
4715 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004716 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004717 }
4718}
4719
4720
lrn@chromium.org25156de2010-04-06 13:10:27 +00004721static bool AreDigits(const char*s, int from, int to) {
4722 for (int i = from; i < to; i++) {
4723 if (s[i] < '0' || s[i] > '9') return false;
4724 }
4725
4726 return true;
4727}
4728
4729
4730static int ParseDecimalInteger(const char*s, int from, int to) {
4731 ASSERT(to - from < 10); // Overflow is not possible.
4732 ASSERT(from < to);
4733 int d = s[from] - '0';
4734
4735 for (int i = from + 1; i < to; i++) {
4736 d = 10 * d + (s[i] - '0');
4737 }
4738
4739 return d;
4740}
4741
4742
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004743RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004744 NoHandleAllocation ha;
4745 ASSERT(args.length() == 1);
4746 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004747 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004748
4749 // Fast case: short integer or some sorts of junk values.
4750 int len = subject->length();
4751 if (subject->IsSeqAsciiString()) {
4752 if (len == 0) return Smi::FromInt(0);
4753
4754 char const* data = SeqAsciiString::cast(subject)->GetChars();
4755 bool minus = (data[0] == '-');
4756 int start_pos = (minus ? 1 : 0);
4757
4758 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004759 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004760 } else if (data[start_pos] > '9') {
4761 // Fast check for a junk value. A valid string may start from a
4762 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
4763 // the 'I' character ('Infinity'). All of that have codes not greater than
4764 // '9' except 'I'.
4765 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004766 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004767 }
4768 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
4769 // The maximal/minimal smi has 10 digits. If the string has less digits we
4770 // know it will fit into the smi-data type.
4771 int d = ParseDecimalInteger(data, start_pos, len);
4772 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004773 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004774 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004775 } else if (!subject->HasHashCode() &&
4776 len <= String::kMaxArrayIndexSize &&
4777 (len == 1 || data[0] != '0')) {
4778 // String hash is not calculated yet but all the data are present.
4779 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004780 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004781#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004782 subject->Hash(); // Force hash calculation.
4783 ASSERT_EQ(static_cast<int>(subject->hash_field()),
4784 static_cast<int>(hash));
4785#endif
4786 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004787 }
4788 return Smi::FromInt(d);
4789 }
4790 }
4791
4792 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00004793 return isolate->heap()->NumberFromDouble(
4794 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004795}
4796
4797
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004798RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004799 NoHandleAllocation ha;
4800 ASSERT(args.length() == 1);
4801
4802 CONVERT_CHECKED(JSArray, codes, args[0]);
4803 int length = Smi::cast(codes->length())->value();
4804
4805 // Check if the string can be ASCII.
4806 int i;
4807 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004808 Object* element;
4809 { MaybeObject* maybe_element = codes->GetElement(i);
4810 // We probably can't get an exception here, but just in order to enforce
4811 // the checking of inputs in the runtime calls we check here.
4812 if (!maybe_element->ToObject(&element)) return maybe_element;
4813 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004814 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
4815 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
4816 break;
4817 }
4818
lrn@chromium.org303ada72010-10-27 09:33:13 +00004819 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004820 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004821 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004822 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004823 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004824 }
4825
lrn@chromium.org303ada72010-10-27 09:33:13 +00004826 Object* object = NULL;
4827 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004828 String* result = String::cast(object);
4829 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004830 Object* element;
4831 { MaybeObject* maybe_element = codes->GetElement(i);
4832 if (!maybe_element->ToObject(&element)) return maybe_element;
4833 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004834 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004835 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004836 }
4837 return result;
4838}
4839
4840
4841// kNotEscaped is generated by the following:
4842//
4843// #!/bin/perl
4844// for (my $i = 0; $i < 256; $i++) {
4845// print "\n" if $i % 16 == 0;
4846// my $c = chr($i);
4847// my $escaped = 1;
4848// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
4849// print $escaped ? "0, " : "1, ";
4850// }
4851
4852
4853static bool IsNotEscaped(uint16_t character) {
4854 // Only for 8 bit characters, the rest are always escaped (in a different way)
4855 ASSERT(character < 256);
4856 static const char kNotEscaped[256] = {
4857 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4858 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4859 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
4860 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
4861 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
4862 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
4863 0, 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, 0,
4865 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
4866 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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 };
4874 return kNotEscaped[character] != 0;
4875}
4876
4877
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004878RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004879 const char hex_chars[] = "0123456789ABCDEF";
4880 NoHandleAllocation ha;
4881 ASSERT(args.length() == 1);
4882 CONVERT_CHECKED(String, source, args[0]);
4883
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004884 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004885
4886 int escaped_length = 0;
4887 int length = source->length();
4888 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004889 Access<StringInputBuffer> buffer(
4890 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004891 buffer->Reset(source);
4892 while (buffer->has_more()) {
4893 uint16_t character = buffer->GetNext();
4894 if (character >= 256) {
4895 escaped_length += 6;
4896 } else if (IsNotEscaped(character)) {
4897 escaped_length++;
4898 } else {
4899 escaped_length += 3;
4900 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004901 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004902 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00004903 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004904 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004905 return Failure::OutOfMemoryException();
4906 }
4907 }
4908 }
4909 // No length change implies no change. Return original string if no change.
4910 if (escaped_length == length) {
4911 return source;
4912 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00004913 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004914 { MaybeObject* maybe_o =
4915 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004916 if (!maybe_o->ToObject(&o)) return maybe_o;
4917 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004918 String* destination = String::cast(o);
4919 int dest_position = 0;
4920
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004921 Access<StringInputBuffer> buffer(
4922 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004923 buffer->Rewind();
4924 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00004925 uint16_t chr = buffer->GetNext();
4926 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004927 destination->Set(dest_position, '%');
4928 destination->Set(dest_position+1, 'u');
4929 destination->Set(dest_position+2, hex_chars[chr >> 12]);
4930 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
4931 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
4932 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004933 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00004934 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004935 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004936 dest_position++;
4937 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004938 destination->Set(dest_position, '%');
4939 destination->Set(dest_position+1, hex_chars[chr >> 4]);
4940 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004941 dest_position += 3;
4942 }
4943 }
4944 return destination;
4945}
4946
4947
4948static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
4949 static const signed char kHexValue['g'] = {
4950 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4951 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4952 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4953 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
4954 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4955 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
4956 -1, 10, 11, 12, 13, 14, 15 };
4957
4958 if (character1 > 'f') return -1;
4959 int hi = kHexValue[character1];
4960 if (hi == -1) return -1;
4961 if (character2 > 'f') return -1;
4962 int lo = kHexValue[character2];
4963 if (lo == -1) return -1;
4964 return (hi << 4) + lo;
4965}
4966
4967
ager@chromium.org870a0b62008-11-04 11:43:05 +00004968static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00004969 int i,
4970 int length,
4971 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004972 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00004973 int32_t hi = 0;
4974 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004975 if (character == '%' &&
4976 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004977 source->Get(i + 1) == 'u' &&
4978 (hi = TwoDigitHex(source->Get(i + 2),
4979 source->Get(i + 3))) != -1 &&
4980 (lo = TwoDigitHex(source->Get(i + 4),
4981 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004982 *step = 6;
4983 return (hi << 8) + lo;
4984 } else if (character == '%' &&
4985 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004986 (lo = TwoDigitHex(source->Get(i + 1),
4987 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004988 *step = 3;
4989 return lo;
4990 } else {
4991 *step = 1;
4992 return character;
4993 }
4994}
4995
4996
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004997RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004998 NoHandleAllocation ha;
4999 ASSERT(args.length() == 1);
5000 CONVERT_CHECKED(String, source, args[0]);
5001
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005002 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005003
5004 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005005 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005006
5007 int unescaped_length = 0;
5008 for (int i = 0; i < length; unescaped_length++) {
5009 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005010 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005011 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005012 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005013 i += step;
5014 }
5015
5016 // No length change implies no change. Return original string if no change.
5017 if (unescaped_length == length)
5018 return source;
5019
lrn@chromium.org303ada72010-10-27 09:33:13 +00005020 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005021 { MaybeObject* maybe_o =
5022 ascii ?
5023 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
5024 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005025 if (!maybe_o->ToObject(&o)) return maybe_o;
5026 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005027 String* destination = String::cast(o);
5028
5029 int dest_position = 0;
5030 for (int i = 0; i < length; dest_position++) {
5031 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005032 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005033 i += step;
5034 }
5035 return destination;
5036}
5037
5038
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005039static const unsigned int kQuoteTableLength = 128u;
5040
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005041static const int kJsonQuotesCharactersPerEntry = 8;
5042static const char* const JsonQuotes =
5043 "\\u0000 \\u0001 \\u0002 \\u0003 "
5044 "\\u0004 \\u0005 \\u0006 \\u0007 "
5045 "\\b \\t \\n \\u000b "
5046 "\\f \\r \\u000e \\u000f "
5047 "\\u0010 \\u0011 \\u0012 \\u0013 "
5048 "\\u0014 \\u0015 \\u0016 \\u0017 "
5049 "\\u0018 \\u0019 \\u001a \\u001b "
5050 "\\u001c \\u001d \\u001e \\u001f "
5051 " ! \\\" # "
5052 "$ % & ' "
5053 "( ) * + "
5054 ", - . / "
5055 "0 1 2 3 "
5056 "4 5 6 7 "
5057 "8 9 : ; "
5058 "< = > ? "
5059 "@ A B C "
5060 "D E F G "
5061 "H I J K "
5062 "L M N O "
5063 "P Q R S "
5064 "T U V W "
5065 "X Y Z [ "
5066 "\\\\ ] ^ _ "
5067 "` a b c "
5068 "d e f g "
5069 "h i j k "
5070 "l m n o "
5071 "p q r s "
5072 "t u v w "
5073 "x y z { "
5074 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005075
5076
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005077// For a string that is less than 32k characters it should always be
5078// possible to allocate it in new space.
5079static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5080
5081
5082// Doing JSON quoting cannot make the string more than this many times larger.
5083static const int kJsonQuoteWorstCaseBlowup = 6;
5084
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005085static const int kSpaceForQuotesAndComma = 3;
5086static const int kSpaceForBrackets = 2;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005087
5088// Covers the entire ASCII range (all other characters are unchanged by JSON
5089// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005090static const byte JsonQuoteLengths[kQuoteTableLength] = {
5091 6, 6, 6, 6, 6, 6, 6, 6,
5092 2, 2, 2, 6, 2, 2, 6, 6,
5093 6, 6, 6, 6, 6, 6, 6, 6,
5094 6, 6, 6, 6, 6, 6, 6, 6,
5095 1, 1, 2, 1, 1, 1, 1, 1,
5096 1, 1, 1, 1, 1, 1, 1, 1,
5097 1, 1, 1, 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, 2, 1, 1, 1,
5103 1, 1, 1, 1, 1, 1, 1, 1,
5104 1, 1, 1, 1, 1, 1, 1, 1,
5105 1, 1, 1, 1, 1, 1, 1, 1,
5106 1, 1, 1, 1, 1, 1, 1, 1,
5107};
5108
5109
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005110template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005111MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005112
5113
5114template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005115MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5116 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005117}
5118
5119
5120template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005121MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5122 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005123}
5124
5125
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005126template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005127static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5128 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005129 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005130 const Char* read_cursor = characters.start();
5131 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005132 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005133 int quoted_length = kSpaceForQuotes;
5134 while (read_cursor < end) {
5135 Char c = *(read_cursor++);
5136 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5137 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005138 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005139 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005140 }
5141 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005142 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5143 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005144 Object* new_object;
5145 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005146 return new_alloc;
5147 }
5148 StringType* new_string = StringType::cast(new_object);
5149
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005150 Char* write_cursor = reinterpret_cast<Char*>(
5151 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005152 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005153 *(write_cursor++) = '"';
5154
5155 read_cursor = characters.start();
5156 while (read_cursor < end) {
5157 Char c = *(read_cursor++);
5158 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5159 *(write_cursor++) = c;
5160 } else {
5161 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5162 const char* replacement = JsonQuotes +
5163 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5164 for (int i = 0; i < len; i++) {
5165 *write_cursor++ = *replacement++;
5166 }
5167 }
5168 }
5169 *(write_cursor++) = '"';
5170 return new_string;
5171}
5172
5173
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005174template <typename SinkChar, typename SourceChar>
5175static inline SinkChar* WriteQuoteJsonString(
5176 Isolate* isolate,
5177 SinkChar* write_cursor,
5178 Vector<const SourceChar> characters) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005179 // SinkChar is only char if SourceChar is guaranteed to be char.
5180 ASSERT(sizeof(SinkChar) >= sizeof(SourceChar));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005181 const SourceChar* read_cursor = characters.start();
5182 const SourceChar* end = read_cursor + characters.length();
5183 *(write_cursor++) = '"';
5184 while (read_cursor < end) {
5185 SourceChar c = *(read_cursor++);
5186 if (sizeof(SourceChar) > 1u &&
5187 static_cast<unsigned>(c) >= kQuoteTableLength) {
5188 *(write_cursor++) = static_cast<SinkChar>(c);
5189 } else {
5190 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5191 const char* replacement = JsonQuotes +
5192 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5193 write_cursor[0] = replacement[0];
5194 if (len > 1) {
5195 write_cursor[1] = replacement[1];
5196 if (len > 2) {
5197 ASSERT(len == 6);
5198 write_cursor[2] = replacement[2];
5199 write_cursor[3] = replacement[3];
5200 write_cursor[4] = replacement[4];
5201 write_cursor[5] = replacement[5];
5202 }
5203 }
5204 write_cursor += len;
5205 }
5206 }
5207 *(write_cursor++) = '"';
5208 return write_cursor;
5209}
5210
5211
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005212template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005213static MaybeObject* QuoteJsonString(Isolate* isolate,
5214 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005215 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005216 isolate->counters()->quote_json_char_count()->Increment(length);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005217 int worst_case_length =
5218 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005219 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005220 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005221 }
5222
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005223 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5224 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005225 Object* new_object;
5226 if (!new_alloc->ToObject(&new_object)) {
5227 return new_alloc;
5228 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005229 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005230 // Even if our string is small enough to fit in new space we still have to
5231 // handle it being allocated in old space as may happen in the third
5232 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5233 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005234 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005235 }
5236 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005237 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005238
5239 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5240 Char* write_cursor = reinterpret_cast<Char*>(
5241 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005242 if (comma) *(write_cursor++) = ',';
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005243 write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
5244 write_cursor,
5245 characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005246 int final_length = static_cast<int>(
5247 write_cursor - reinterpret_cast<Char*>(
5248 new_string->address() + SeqAsciiString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005249 isolate->heap()->new_space()->
5250 template ShrinkStringAtAllocationBoundary<StringType>(
5251 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005252 return new_string;
5253}
5254
5255
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005256RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005257 NoHandleAllocation ha;
5258 CONVERT_CHECKED(String, str, args[0]);
5259 if (!str->IsFlat()) {
5260 MaybeObject* try_flatten = str->TryFlatten();
5261 Object* flat;
5262 if (!try_flatten->ToObject(&flat)) {
5263 return try_flatten;
5264 }
5265 str = String::cast(flat);
5266 ASSERT(str->IsFlat());
5267 }
5268 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005269 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
5270 str->ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005271 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005272 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
5273 str->ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005274 }
5275}
5276
5277
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005278RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005279 NoHandleAllocation ha;
5280 CONVERT_CHECKED(String, str, args[0]);
5281 if (!str->IsFlat()) {
5282 MaybeObject* try_flatten = str->TryFlatten();
5283 Object* flat;
5284 if (!try_flatten->ToObject(&flat)) {
5285 return try_flatten;
5286 }
5287 str = String::cast(flat);
5288 ASSERT(str->IsFlat());
5289 }
5290 if (str->IsTwoByteRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005291 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
5292 str->ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005293 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005294 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
5295 str->ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005296 }
5297}
5298
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005299
5300template <typename Char, typename StringType>
5301static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
5302 FixedArray* array,
5303 int worst_case_length) {
5304 int length = array->length();
5305
5306 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5307 worst_case_length);
5308 Object* new_object;
5309 if (!new_alloc->ToObject(&new_object)) {
5310 return new_alloc;
5311 }
5312 if (!isolate->heap()->new_space()->Contains(new_object)) {
5313 // Even if our string is small enough to fit in new space we still have to
5314 // handle it being allocated in old space as may happen in the third
5315 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5316 // CEntryStub::GenerateCore.
5317 return isolate->heap()->undefined_value();
5318 }
5319 AssertNoAllocation no_gc;
5320 StringType* new_string = StringType::cast(new_object);
5321 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5322
5323 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5324 Char* write_cursor = reinterpret_cast<Char*>(
5325 new_string->address() + SeqAsciiString::kHeaderSize);
5326 *(write_cursor++) = '[';
5327 for (int i = 0; i < length; i++) {
5328 if (i != 0) *(write_cursor++) = ',';
5329 String* str = String::cast(array->get(i));
5330 if (str->IsTwoByteRepresentation()) {
5331 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
5332 write_cursor,
5333 str->ToUC16Vector());
5334 } else {
5335 write_cursor = WriteQuoteJsonString<Char, char>(isolate,
5336 write_cursor,
5337 str->ToAsciiVector());
5338 }
5339 }
5340 *(write_cursor++) = ']';
5341
5342 int final_length = static_cast<int>(
5343 write_cursor - reinterpret_cast<Char*>(
5344 new_string->address() + SeqAsciiString::kHeaderSize));
5345 isolate->heap()->new_space()->
5346 template ShrinkStringAtAllocationBoundary<StringType>(
5347 new_string, final_length);
5348 return new_string;
5349}
5350
5351
5352RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
5353 NoHandleAllocation ha;
5354 ASSERT(args.length() == 1);
5355 CONVERT_CHECKED(JSArray, array, args[0]);
5356
5357 if (!array->HasFastElements()) return isolate->heap()->undefined_value();
5358 FixedArray* elements = FixedArray::cast(array->elements());
5359 int n = elements->length();
5360 bool ascii = true;
5361 int total_length = 0;
5362
5363 for (int i = 0; i < n; i++) {
5364 Object* elt = elements->get(i);
5365 if (!elt->IsString()) return isolate->heap()->undefined_value();
5366 String* element = String::cast(elt);
5367 if (!element->IsFlat()) return isolate->heap()->undefined_value();
5368 total_length += element->length();
5369 if (ascii && element->IsTwoByteRepresentation()) {
5370 ascii = false;
5371 }
5372 }
5373
5374 int worst_case_length =
5375 kSpaceForBrackets + n * kSpaceForQuotesAndComma
5376 + total_length * kJsonQuoteWorstCaseBlowup;
5377
5378 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5379 return isolate->heap()->undefined_value();
5380 }
5381
5382 if (ascii) {
5383 return QuoteJsonStringArray<char, SeqAsciiString>(isolate,
5384 elements,
5385 worst_case_length);
5386 } else {
5387 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
5388 elements,
5389 worst_case_length);
5390 }
5391}
5392
5393
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005394RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005395 NoHandleAllocation ha;
5396
5397 CONVERT_CHECKED(String, s, args[0]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005398 CONVERT_SMI_ARG_CHECKED(radix, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005399
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005400 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005401
lrn@chromium.org25156de2010-04-06 13:10:27 +00005402 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005403 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005404 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005405}
5406
5407
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005408RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005409 NoHandleAllocation ha;
5410 CONVERT_CHECKED(String, str, args[0]);
5411
5412 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005413 double value = StringToDouble(isolate->unicode_cache(),
5414 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005415
5416 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005417 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005418}
5419
5420
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005421template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005422MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005423 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005424 String* s,
5425 int length,
5426 int input_string_length,
5427 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005428 // We try this twice, once with the assumption that the result is no longer
5429 // than the input and, if that assumption breaks, again with the exact
5430 // length. This may not be pretty, but it is nicer than what was here before
5431 // and I hereby claim my vaffel-is.
5432 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005433 // Allocate the resulting string.
5434 //
5435 // NOTE: This assumes that the upper/lower case of an ascii
5436 // character is also ascii. This is currently the case, but it
5437 // might break in the future if we implement more context and locale
5438 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005439 Object* o;
5440 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005441 ? isolate->heap()->AllocateRawAsciiString(length)
5442 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005443 if (!maybe_o->ToObject(&o)) return maybe_o;
5444 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005445 String* result = String::cast(o);
5446 bool has_changed_character = false;
5447
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005448 // Convert all characters to upper case, assuming that they will fit
5449 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005450 Access<StringInputBuffer> buffer(
5451 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005452 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005453 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005454 // We can assume that the string is not empty
5455 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005456 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005457 bool has_next = buffer->has_more();
5458 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005459 int char_length = mapping->get(current, next, chars);
5460 if (char_length == 0) {
5461 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005462 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005463 i++;
5464 } else if (char_length == 1) {
5465 // Common case: converting the letter resulted in one character.
5466 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005467 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005468 has_changed_character = true;
5469 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005470 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005471 // We've assumed that the result would be as long as the
5472 // input but here is a character that converts to several
5473 // characters. No matter, we calculate the exact length
5474 // of the result and try the whole thing again.
5475 //
5476 // Note that this leaves room for optimization. We could just
5477 // memcpy what we already have to the result string. Also,
5478 // the result string is the last object allocated we could
5479 // "realloc" it and probably, in the vast majority of cases,
5480 // extend the existing string to be able to hold the full
5481 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00005482 int next_length = 0;
5483 if (has_next) {
5484 next_length = mapping->get(next, 0, chars);
5485 if (next_length == 0) next_length = 1;
5486 }
5487 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005488 while (buffer->has_more()) {
5489 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005490 // NOTE: we use 0 as the next character here because, while
5491 // the next character may affect what a character converts to,
5492 // it does not in any case affect the length of what it convert
5493 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005494 int char_length = mapping->get(current, 0, chars);
5495 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00005496 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005497 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005498 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005499 return Failure::OutOfMemoryException();
5500 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005501 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005502 // Try again with the real length.
5503 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005504 } else {
5505 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005506 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005507 i++;
5508 }
5509 has_changed_character = true;
5510 }
5511 current = next;
5512 }
5513 if (has_changed_character) {
5514 return result;
5515 } else {
5516 // If we didn't actually change anything in doing the conversion
5517 // we simple return the result and let the converted string
5518 // become garbage; there is no reason to keep two identical strings
5519 // alive.
5520 return s;
5521 }
5522}
5523
5524
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005525namespace {
5526
lrn@chromium.org303ada72010-10-27 09:33:13 +00005527static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
5528
5529
5530// Given a word and two range boundaries returns a word with high bit
5531// set in every byte iff the corresponding input byte was strictly in
5532// the range (m, n). All the other bits in the result are cleared.
5533// This function is only useful when it can be inlined and the
5534// boundaries are statically known.
5535// Requires: all bytes in the input word and the boundaries must be
5536// ascii (less than 0x7F).
5537static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
5538 // Every byte in an ascii string is less than or equal to 0x7F.
5539 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
5540 // Use strict inequalities since in edge cases the function could be
5541 // further simplified.
5542 ASSERT(0 < m && m < n && n < 0x7F);
5543 // Has high bit set in every w byte less than n.
5544 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
5545 // Has high bit set in every w byte greater than m.
5546 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
5547 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
5548}
5549
5550
5551enum AsciiCaseConversion {
5552 ASCII_TO_LOWER,
5553 ASCII_TO_UPPER
5554};
5555
5556
5557template <AsciiCaseConversion dir>
5558struct FastAsciiConverter {
5559 static bool Convert(char* dst, char* src, int length) {
5560#ifdef DEBUG
5561 char* saved_dst = dst;
5562 char* saved_src = src;
5563#endif
5564 // We rely on the distance between upper and lower case letters
5565 // being a known power of 2.
5566 ASSERT('a' - 'A' == (1 << 5));
5567 // Boundaries for the range of input characters than require conversion.
5568 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
5569 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
5570 bool changed = false;
5571 char* const limit = src + length;
5572#ifdef V8_HOST_CAN_READ_UNALIGNED
5573 // Process the prefix of the input that requires no conversion one
5574 // (machine) word at a time.
5575 while (src <= limit - sizeof(uintptr_t)) {
5576 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5577 if (AsciiRangeMask(w, lo, hi) != 0) {
5578 changed = true;
5579 break;
5580 }
5581 *reinterpret_cast<uintptr_t*>(dst) = w;
5582 src += sizeof(uintptr_t);
5583 dst += sizeof(uintptr_t);
5584 }
5585 // Process the remainder of the input performing conversion when
5586 // required one word at a time.
5587 while (src <= limit - sizeof(uintptr_t)) {
5588 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5589 uintptr_t m = AsciiRangeMask(w, lo, hi);
5590 // The mask has high (7th) bit set in every byte that needs
5591 // conversion and we know that the distance between cases is
5592 // 1 << 5.
5593 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
5594 src += sizeof(uintptr_t);
5595 dst += sizeof(uintptr_t);
5596 }
5597#endif
5598 // Process the last few bytes of the input (or the whole input if
5599 // unaligned access is not supported).
5600 while (src < limit) {
5601 char c = *src;
5602 if (lo < c && c < hi) {
5603 c ^= (1 << 5);
5604 changed = true;
5605 }
5606 *dst = c;
5607 ++src;
5608 ++dst;
5609 }
5610#ifdef DEBUG
5611 CheckConvert(saved_dst, saved_src, length, changed);
5612#endif
5613 return changed;
5614 }
5615
5616#ifdef DEBUG
5617 static void CheckConvert(char* dst, char* src, int length, bool changed) {
5618 bool expected_changed = false;
5619 for (int i = 0; i < length; i++) {
5620 if (dst[i] == src[i]) continue;
5621 expected_changed = true;
5622 if (dir == ASCII_TO_LOWER) {
5623 ASSERT('A' <= src[i] && src[i] <= 'Z');
5624 ASSERT(dst[i] == src[i] + ('a' - 'A'));
5625 } else {
5626 ASSERT(dir == ASCII_TO_UPPER);
5627 ASSERT('a' <= src[i] && src[i] <= 'z');
5628 ASSERT(dst[i] == src[i] - ('a' - 'A'));
5629 }
5630 }
5631 ASSERT(expected_changed == changed);
5632 }
5633#endif
5634};
5635
5636
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005637struct ToLowerTraits {
5638 typedef unibrow::ToLowercase UnibrowConverter;
5639
lrn@chromium.org303ada72010-10-27 09:33:13 +00005640 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005641};
5642
5643
5644struct ToUpperTraits {
5645 typedef unibrow::ToUppercase UnibrowConverter;
5646
lrn@chromium.org303ada72010-10-27 09:33:13 +00005647 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005648};
5649
5650} // namespace
5651
5652
5653template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005654MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005655 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005656 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005657 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005658 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005659 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005660 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005661
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005662 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005663 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005664 if (length == 0) return s;
5665
5666 // Simpler handling of ascii strings.
5667 //
5668 // NOTE: This assumes that the upper/lower case of an ascii
5669 // character is also ascii. This is currently the case, but it
5670 // might break in the future if we implement more context and locale
5671 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005672 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005673 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005674 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005675 if (!maybe_o->ToObject(&o)) return maybe_o;
5676 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005677 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005678 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005679 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005680 return has_changed_character ? result : s;
5681 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005682
lrn@chromium.org303ada72010-10-27 09:33:13 +00005683 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005684 { MaybeObject* maybe_answer =
5685 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005686 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5687 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005688 if (answer->IsSmi()) {
5689 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005690 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005691 ConvertCaseHelper(isolate,
5692 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005693 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5694 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005695 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005696 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005697}
5698
5699
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005700RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005701 return ConvertCase<ToLowerTraits>(
5702 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005703}
5704
5705
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005706RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005707 return ConvertCase<ToUpperTraits>(
5708 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005709}
5710
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005711
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005712static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
5713 return unibrow::WhiteSpace::Is(c) || c == 0x200b;
5714}
5715
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005716
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005717RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005718 NoHandleAllocation ha;
5719 ASSERT(args.length() == 3);
5720
5721 CONVERT_CHECKED(String, s, args[0]);
5722 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
5723 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
5724
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005725 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005726 int length = s->length();
5727
5728 int left = 0;
5729 if (trimLeft) {
5730 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
5731 left++;
5732 }
5733 }
5734
5735 int right = length;
5736 if (trimRight) {
5737 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
5738 right--;
5739 }
5740 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005741 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005742}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005743
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005744
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005745template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005746void FindStringIndices(Isolate* isolate,
5747 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005748 Vector<const PatternChar> pattern,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005749 ZoneList<int>* indices,
5750 unsigned int limit) {
5751 ASSERT(limit > 0);
5752 // Collect indices of pattern in subject, and the end-of-string index.
5753 // Stop after finding at most limit values.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005754 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005755 int pattern_length = pattern.length();
5756 int index = 0;
5757 while (limit > 0) {
5758 index = search.Search(subject, index);
5759 if (index < 0) return;
5760 indices->Add(index);
5761 index += pattern_length;
5762 limit--;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005763 }
5764}
5765
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005766
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005767RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005768 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005769 HandleScope handle_scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005770 CONVERT_ARG_CHECKED(String, subject, 0);
5771 CONVERT_ARG_CHECKED(String, pattern, 1);
5772 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
5773
5774 int subject_length = subject->length();
5775 int pattern_length = pattern->length();
5776 RUNTIME_ASSERT(pattern_length > 0);
5777
5778 // The limit can be very large (0xffffffffu), but since the pattern
5779 // isn't empty, we can never create more parts than ~half the length
5780 // of the subject.
5781
5782 if (!subject->IsFlat()) FlattenString(subject);
5783
5784 static const int kMaxInitialListCapacity = 16;
5785
danno@chromium.org40cb8782011-05-25 07:58:50 +00005786 ZoneScope scope(isolate, DELETE_ON_EXIT);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005787
5788 // Find (up to limit) indices of separator and end-of-string in subject
5789 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
5790 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005791 if (!pattern->IsFlat()) FlattenString(pattern);
5792
5793 // No allocation block.
5794 {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005795 AssertNoAllocation nogc;
5796 if (subject->IsAsciiRepresentation()) {
5797 Vector<const char> subject_vector = subject->ToAsciiVector();
5798 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005799 FindStringIndices(isolate,
5800 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005801 pattern->ToAsciiVector(),
5802 &indices,
5803 limit);
5804 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005805 FindStringIndices(isolate,
5806 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005807 pattern->ToUC16Vector(),
5808 &indices,
5809 limit);
5810 }
5811 } else {
5812 Vector<const uc16> subject_vector = subject->ToUC16Vector();
5813 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005814 FindStringIndices(isolate,
5815 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005816 pattern->ToAsciiVector(),
5817 &indices,
5818 limit);
5819 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005820 FindStringIndices(isolate,
5821 subject_vector,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005822 pattern->ToUC16Vector(),
5823 &indices,
5824 limit);
5825 }
5826 }
5827 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005828
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005829 if (static_cast<uint32_t>(indices.length()) < limit) {
5830 indices.Add(subject_length);
5831 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005832
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005833 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005834
5835 // Create JSArray of substrings separated by separator.
5836 int part_count = indices.length();
5837
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005838 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005839 result->set_length(Smi::FromInt(part_count));
5840
5841 ASSERT(result->HasFastElements());
5842
5843 if (part_count == 1 && indices.at(0) == subject_length) {
5844 FixedArray::cast(result->elements())->set(0, *subject);
5845 return *result;
5846 }
5847
5848 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
5849 int part_start = 0;
5850 for (int i = 0; i < part_count; i++) {
5851 HandleScope local_loop_handle;
5852 int part_end = indices.at(i);
5853 Handle<String> substring =
ager@chromium.org04921a82011-06-27 13:21:41 +00005854 isolate->factory()->NewProperSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005855 elements->set(i, *substring);
5856 part_start = part_end + pattern_length;
5857 }
5858
5859 return *result;
5860}
5861
5862
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005863// Copies ascii characters to the given fixed array looking up
5864// one-char strings in the cache. Gives up on the first char that is
5865// not in the cache and fills the remainder with smi zeros. Returns
5866// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005867static int CopyCachedAsciiCharsToArray(Heap* heap,
5868 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005869 FixedArray* elements,
5870 int length) {
5871 AssertNoAllocation nogc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005872 FixedArray* ascii_cache = heap->single_character_string_cache();
5873 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005874 int i;
5875 for (i = 0; i < length; ++i) {
5876 Object* value = ascii_cache->get(chars[i]);
5877 if (value == undefined) break;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005878 ASSERT(!heap->InNewSpace(value));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005879 elements->set(i, value, SKIP_WRITE_BARRIER);
5880 }
5881 if (i < length) {
5882 ASSERT(Smi::FromInt(0) == 0);
5883 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
5884 }
5885#ifdef DEBUG
5886 for (int j = 0; j < length; ++j) {
5887 Object* element = elements->get(j);
5888 ASSERT(element == Smi::FromInt(0) ||
5889 (element->IsString() && String::cast(element)->LooksValid()));
5890 }
5891#endif
5892 return i;
5893}
5894
5895
5896// Converts a String to JSArray.
5897// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005898RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005899 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005900 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005901 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005902 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005903
5904 s->TryFlatten();
ager@chromium.orgbeb25712010-11-29 08:02:25 +00005905 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005906
5907 Handle<FixedArray> elements;
5908 if (s->IsFlat() && s->IsAsciiRepresentation()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005909 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005910 { MaybeObject* maybe_obj =
5911 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005912 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
5913 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005914 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005915
5916 Vector<const char> chars = s->ToAsciiVector();
5917 // Note, this will initialize all elements (not only the prefix)
5918 // to prevent GC from seeing partially initialized array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005919 int num_copied_from_cache = CopyCachedAsciiCharsToArray(isolate->heap(),
5920 chars.start(),
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005921 *elements,
5922 length);
5923
5924 for (int i = num_copied_from_cache; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005925 Handle<Object> str = LookupSingleCharacterStringFromCode(chars[i]);
5926 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005927 }
5928 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005929 elements = isolate->factory()->NewFixedArray(length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005930 for (int i = 0; i < length; ++i) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00005931 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
5932 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005933 }
5934 }
5935
5936#ifdef DEBUG
5937 for (int i = 0; i < length; ++i) {
5938 ASSERT(String::cast(elements->get(i))->length() == 1);
5939 }
5940#endif
5941
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005942 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005943}
5944
5945
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005946RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005947 NoHandleAllocation ha;
5948 ASSERT(args.length() == 1);
5949 CONVERT_CHECKED(String, value, args[0]);
5950 return value->ToObject();
5951}
5952
5953
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005954bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005955 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005956 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00005957 return char_length == 0;
5958}
5959
5960
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005961RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005962 NoHandleAllocation ha;
5963 ASSERT(args.length() == 1);
5964
5965 Object* number = args[0];
5966 RUNTIME_ASSERT(number->IsNumber());
5967
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005968 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005969}
5970
5971
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005972RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00005973 NoHandleAllocation ha;
5974 ASSERT(args.length() == 1);
5975
5976 Object* number = args[0];
5977 RUNTIME_ASSERT(number->IsNumber());
5978
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005979 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00005980}
5981
5982
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005983RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005984 NoHandleAllocation ha;
5985 ASSERT(args.length() == 1);
5986
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005987 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005988
5989 // We do not include 0 so that we don't have to treat +0 / -0 cases.
5990 if (number > 0 && number <= Smi::kMaxValue) {
5991 return Smi::FromInt(static_cast<int>(number));
5992 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005993 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005994}
5995
5996
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005997RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005998 NoHandleAllocation ha;
5999 ASSERT(args.length() == 1);
6000
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006001 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006002
6003 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6004 if (number > 0 && number <= Smi::kMaxValue) {
6005 return Smi::FromInt(static_cast<int>(number));
6006 }
6007
6008 double double_value = DoubleToInteger(number);
6009 // Map both -0 and +0 to +0.
6010 if (double_value == 0) double_value = 0;
6011
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006012 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006013}
6014
6015
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006016RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006017 NoHandleAllocation ha;
6018 ASSERT(args.length() == 1);
6019
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006020 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006021 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006022}
6023
6024
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006025RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006026 NoHandleAllocation ha;
6027 ASSERT(args.length() == 1);
6028
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006029 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006030
6031 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6032 if (number > 0 && number <= Smi::kMaxValue) {
6033 return Smi::FromInt(static_cast<int>(number));
6034 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006035 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006036}
6037
6038
ager@chromium.org870a0b62008-11-04 11:43:05 +00006039// Converts a Number to a Smi, if possible. Returns NaN if the number is not
6040// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006041RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00006042 NoHandleAllocation ha;
6043 ASSERT(args.length() == 1);
6044
6045 Object* obj = args[0];
6046 if (obj->IsSmi()) {
6047 return obj;
6048 }
6049 if (obj->IsHeapNumber()) {
6050 double value = HeapNumber::cast(obj)->value();
6051 int int_value = FastD2I(value);
6052 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
6053 return Smi::FromInt(int_value);
6054 }
6055 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006056 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006057}
6058
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006059
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006060RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006061 NoHandleAllocation ha;
6062 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006063 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006064}
6065
6066
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006067RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006068 NoHandleAllocation ha;
6069 ASSERT(args.length() == 2);
6070
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006071 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6072 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006073 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006074}
6075
6076
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006077RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006078 NoHandleAllocation ha;
6079 ASSERT(args.length() == 2);
6080
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006081 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6082 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006083 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006084}
6085
6086
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006087RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006088 NoHandleAllocation ha;
6089 ASSERT(args.length() == 2);
6090
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006091 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6092 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006093 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006094}
6095
6096
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006097RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006098 NoHandleAllocation ha;
6099 ASSERT(args.length() == 1);
6100
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006101 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006102 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006103}
6104
6105
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006106RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006107 NoHandleAllocation ha;
6108 ASSERT(args.length() == 0);
6109
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006110 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006111}
6112
6113
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006114RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006115 NoHandleAllocation ha;
6116 ASSERT(args.length() == 2);
6117
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006118 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6119 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006120 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006121}
6122
6123
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006124RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006125 NoHandleAllocation ha;
6126 ASSERT(args.length() == 2);
6127
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006128 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6129 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006130
ager@chromium.org3811b432009-10-28 14:53:37 +00006131 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006132 // NumberFromDouble may return a Smi instead of a Number object
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_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006138 NoHandleAllocation ha;
6139 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006140 CONVERT_CHECKED(String, str1, args[0]);
6141 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006142 isolate->counters()->string_add_runtime()->Increment();
6143 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006144}
6145
6146
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006147template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006148static inline void StringBuilderConcatHelper(String* special,
6149 sinkchar* sink,
6150 FixedArray* fixed_array,
6151 int array_length) {
6152 int position = 0;
6153 for (int i = 0; i < array_length; i++) {
6154 Object* element = fixed_array->get(i);
6155 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006156 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006157 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006158 int pos;
6159 int len;
6160 if (encoded_slice > 0) {
6161 // Position and length encoded in one smi.
6162 pos = StringBuilderSubstringPosition::decode(encoded_slice);
6163 len = StringBuilderSubstringLength::decode(encoded_slice);
6164 } else {
6165 // Position and length encoded in two smis.
6166 Object* obj = fixed_array->get(++i);
6167 ASSERT(obj->IsSmi());
6168 pos = Smi::cast(obj)->value();
6169 len = -encoded_slice;
6170 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00006171 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00006172 sink + position,
6173 pos,
6174 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006175 position += len;
6176 } else {
6177 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006178 int element_length = string->length();
6179 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006180 position += element_length;
6181 }
6182 }
6183}
6184
6185
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006186RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006187 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006188 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006189 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006190 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006191 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006192 return Failure::OutOfMemoryException();
6193 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006194 int array_length = args.smi_at(1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006195 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006196
6197 // This assumption is used by the slice encoding in one or two smis.
6198 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6199
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006200 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006201 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006202 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006203 }
6204 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006205 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006206 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006207 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006208
6209 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006210 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006211 } else if (array_length == 1) {
6212 Object* first = fixed_array->get(0);
6213 if (first->IsString()) return first;
6214 }
6215
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006216 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006217 int position = 0;
6218 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006219 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006220 Object* elt = fixed_array->get(i);
6221 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006222 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006223 int smi_value = Smi::cast(elt)->value();
6224 int pos;
6225 int len;
6226 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006227 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006228 pos = StringBuilderSubstringPosition::decode(smi_value);
6229 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006230 } else {
6231 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006232 len = -smi_value;
6233 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006234 i++;
6235 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006236 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006237 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006238 Object* next_smi = fixed_array->get(i);
6239 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006240 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006241 }
6242 pos = Smi::cast(next_smi)->value();
6243 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006244 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006245 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006246 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006247 ASSERT(pos >= 0);
6248 ASSERT(len >= 0);
6249 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006250 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006251 }
6252 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006253 } else if (elt->IsString()) {
6254 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006255 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006256 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006257 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006258 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006259 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006260 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006261 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006262 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006263 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006264 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006265 return Failure::OutOfMemoryException();
6266 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006267 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006268 }
6269
6270 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006271 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006272
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006273 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006274 { MaybeObject* maybe_object =
6275 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006276 if (!maybe_object->ToObject(&object)) return maybe_object;
6277 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006278 SeqAsciiString* answer = SeqAsciiString::cast(object);
6279 StringBuilderConcatHelper(special,
6280 answer->GetChars(),
6281 fixed_array,
6282 array_length);
6283 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006284 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006285 { MaybeObject* maybe_object =
6286 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006287 if (!maybe_object->ToObject(&object)) return maybe_object;
6288 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006289 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6290 StringBuilderConcatHelper(special,
6291 answer->GetChars(),
6292 fixed_array,
6293 array_length);
6294 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006295 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006296}
6297
6298
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006299RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006300 NoHandleAllocation ha;
6301 ASSERT(args.length() == 3);
6302 CONVERT_CHECKED(JSArray, array, args[0]);
6303 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006304 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006305 return Failure::OutOfMemoryException();
6306 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006307 int array_length = args.smi_at(1);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006308 CONVERT_CHECKED(String, separator, args[2]);
6309
6310 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006311 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006312 }
6313 FixedArray* fixed_array = FixedArray::cast(array->elements());
6314 if (fixed_array->length() < array_length) {
6315 array_length = fixed_array->length();
6316 }
6317
6318 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006319 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006320 } else if (array_length == 1) {
6321 Object* first = fixed_array->get(0);
6322 if (first->IsString()) return first;
6323 }
6324
6325 int separator_length = separator->length();
6326 int max_nof_separators =
6327 (String::kMaxLength + separator_length - 1) / separator_length;
6328 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006329 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006330 return Failure::OutOfMemoryException();
6331 }
6332 int length = (array_length - 1) * separator_length;
6333 for (int i = 0; i < array_length; i++) {
6334 Object* element_obj = fixed_array->get(i);
6335 if (!element_obj->IsString()) {
6336 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006337 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006338 }
6339 String* element = String::cast(element_obj);
6340 int increment = element->length();
6341 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006342 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006343 return Failure::OutOfMemoryException();
6344 }
6345 length += increment;
6346 }
6347
6348 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006349 { MaybeObject* maybe_object =
6350 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006351 if (!maybe_object->ToObject(&object)) return maybe_object;
6352 }
6353 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6354
6355 uc16* sink = answer->GetChars();
6356#ifdef DEBUG
6357 uc16* end = sink + length;
6358#endif
6359
6360 String* first = String::cast(fixed_array->get(0));
6361 int first_length = first->length();
6362 String::WriteToFlat(first, sink, 0, first_length);
6363 sink += first_length;
6364
6365 for (int i = 1; i < array_length; i++) {
6366 ASSERT(sink + separator_length <= end);
6367 String::WriteToFlat(separator, sink, 0, separator_length);
6368 sink += separator_length;
6369
6370 String* element = String::cast(fixed_array->get(i));
6371 int element_length = element->length();
6372 ASSERT(sink + element_length <= end);
6373 String::WriteToFlat(element, sink, 0, element_length);
6374 sink += element_length;
6375 }
6376 ASSERT(sink == end);
6377
6378 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6379 return answer;
6380}
6381
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006382template <typename Char>
6383static void JoinSparseArrayWithSeparator(FixedArray* elements,
6384 int elements_length,
6385 uint32_t array_length,
6386 String* separator,
6387 Vector<Char> buffer) {
6388 int previous_separator_position = 0;
6389 int separator_length = separator->length();
6390 int cursor = 0;
6391 for (int i = 0; i < elements_length; i += 2) {
6392 int position = NumberToInt32(elements->get(i));
6393 String* string = String::cast(elements->get(i + 1));
6394 int string_length = string->length();
6395 if (string->length() > 0) {
6396 while (previous_separator_position < position) {
6397 String::WriteToFlat<Char>(separator, &buffer[cursor],
6398 0, separator_length);
6399 cursor += separator_length;
6400 previous_separator_position++;
6401 }
6402 String::WriteToFlat<Char>(string, &buffer[cursor],
6403 0, string_length);
6404 cursor += string->length();
6405 }
6406 }
6407 if (separator_length > 0) {
6408 // Array length must be representable as a signed 32-bit number,
6409 // otherwise the total string length would have been too large.
6410 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6411 int last_array_index = static_cast<int>(array_length - 1);
6412 while (previous_separator_position < last_array_index) {
6413 String::WriteToFlat<Char>(separator, &buffer[cursor],
6414 0, separator_length);
6415 cursor += separator_length;
6416 previous_separator_position++;
6417 }
6418 }
6419 ASSERT(cursor <= buffer.length());
6420}
6421
6422
6423RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6424 NoHandleAllocation ha;
6425 ASSERT(args.length() == 3);
6426 CONVERT_CHECKED(JSArray, elements_array, args[0]);
6427 RUNTIME_ASSERT(elements_array->HasFastElements());
6428 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
6429 CONVERT_CHECKED(String, separator, args[2]);
6430 // elements_array is fast-mode JSarray of alternating positions
6431 // (increasing order) and strings.
6432 // array_length is length of original array (used to add separators);
6433 // separator is string to put between elements. Assumed to be non-empty.
6434
6435 // Find total length of join result.
6436 int string_length = 0;
6437 bool is_ascii = true;
6438 int max_string_length = SeqAsciiString::kMaxLength;
6439 bool overflow = false;
6440 CONVERT_NUMBER_CHECKED(int, elements_length,
6441 Int32, elements_array->length());
6442 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
6443 FixedArray* elements = FixedArray::cast(elements_array->elements());
6444 for (int i = 0; i < elements_length; i += 2) {
6445 RUNTIME_ASSERT(elements->get(i)->IsNumber());
6446 CONVERT_CHECKED(String, string, elements->get(i + 1));
6447 int length = string->length();
6448 if (is_ascii && !string->IsAsciiRepresentation()) {
6449 is_ascii = false;
6450 max_string_length = SeqTwoByteString::kMaxLength;
6451 }
6452 if (length > max_string_length ||
6453 max_string_length - length < string_length) {
6454 overflow = true;
6455 break;
6456 }
6457 string_length += length;
6458 }
6459 int separator_length = separator->length();
6460 if (!overflow && separator_length > 0) {
6461 if (array_length <= 0x7fffffffu) {
6462 int separator_count = static_cast<int>(array_length) - 1;
6463 int remaining_length = max_string_length - string_length;
6464 if ((remaining_length / separator_length) >= separator_count) {
6465 string_length += separator_length * (array_length - 1);
6466 } else {
6467 // Not room for the separators within the maximal string length.
6468 overflow = true;
6469 }
6470 } else {
6471 // Nonempty separator and at least 2^31-1 separators necessary
6472 // means that the string is too large to create.
6473 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
6474 overflow = true;
6475 }
6476 }
6477 if (overflow) {
6478 // Throw OutOfMemory exception for creating too large a string.
6479 V8::FatalProcessOutOfMemory("Array join result too large.");
6480 }
6481
6482 if (is_ascii) {
6483 MaybeObject* result_allocation =
6484 isolate->heap()->AllocateRawAsciiString(string_length);
6485 if (result_allocation->IsFailure()) return result_allocation;
6486 SeqAsciiString* result_string =
6487 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
6488 JoinSparseArrayWithSeparator<char>(elements,
6489 elements_length,
6490 array_length,
6491 separator,
6492 Vector<char>(result_string->GetChars(),
6493 string_length));
6494 return result_string;
6495 } else {
6496 MaybeObject* result_allocation =
6497 isolate->heap()->AllocateRawTwoByteString(string_length);
6498 if (result_allocation->IsFailure()) return result_allocation;
6499 SeqTwoByteString* result_string =
6500 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
6501 JoinSparseArrayWithSeparator<uc16>(elements,
6502 elements_length,
6503 array_length,
6504 separator,
6505 Vector<uc16>(result_string->GetChars(),
6506 string_length));
6507 return result_string;
6508 }
6509}
6510
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006511
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006512RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006513 NoHandleAllocation ha;
6514 ASSERT(args.length() == 2);
6515
6516 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6517 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006518 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006519}
6520
6521
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006522RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006523 NoHandleAllocation ha;
6524 ASSERT(args.length() == 2);
6525
6526 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6527 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006528 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006529}
6530
6531
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006532RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006533 NoHandleAllocation ha;
6534 ASSERT(args.length() == 2);
6535
6536 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6537 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006538 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006539}
6540
6541
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006542RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006543 NoHandleAllocation ha;
6544 ASSERT(args.length() == 1);
6545
6546 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006547 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006548}
6549
6550
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006551RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006552 NoHandleAllocation ha;
6553 ASSERT(args.length() == 2);
6554
6555 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6556 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006557 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006558}
6559
6560
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006561RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006562 NoHandleAllocation ha;
6563 ASSERT(args.length() == 2);
6564
6565 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
6566 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006567 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006568}
6569
6570
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006571RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006572 NoHandleAllocation ha;
6573 ASSERT(args.length() == 2);
6574
6575 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6576 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006577 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006578}
6579
6580
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006581RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006582 NoHandleAllocation ha;
6583 ASSERT(args.length() == 2);
6584
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006585 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6586 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006587 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
6588 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
6589 if (x == y) return Smi::FromInt(EQUAL);
6590 Object* result;
6591 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
6592 result = Smi::FromInt(EQUAL);
6593 } else {
6594 result = Smi::FromInt(NOT_EQUAL);
6595 }
6596 return result;
6597}
6598
6599
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006600RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006601 NoHandleAllocation ha;
6602 ASSERT(args.length() == 2);
6603
6604 CONVERT_CHECKED(String, x, args[0]);
6605 CONVERT_CHECKED(String, y, args[1]);
6606
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006607 bool not_equal = !x->Equals(y);
6608 // This is slightly convoluted because the value that signifies
6609 // equality is 0 and inequality is 1 so we have to negate the result
6610 // from String::Equals.
6611 ASSERT(not_equal == 0 || not_equal == 1);
6612 STATIC_CHECK(EQUAL == 0);
6613 STATIC_CHECK(NOT_EQUAL == 1);
6614 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006615}
6616
6617
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006618RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006619 NoHandleAllocation ha;
6620 ASSERT(args.length() == 3);
6621
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006622 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6623 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006624 if (isnan(x) || isnan(y)) return args[2];
6625 if (x == y) return Smi::FromInt(EQUAL);
6626 if (isless(x, y)) return Smi::FromInt(LESS);
6627 return Smi::FromInt(GREATER);
6628}
6629
6630
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006631// Compare two Smis as if they were converted to strings and then
6632// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006633RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006634 NoHandleAllocation ha;
6635 ASSERT(args.length() == 2);
6636
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006637 // Extract the integer values from the Smis.
6638 CONVERT_CHECKED(Smi, x, args[0]);
6639 CONVERT_CHECKED(Smi, y, args[1]);
6640 int x_value = x->value();
6641 int y_value = y->value();
6642
6643 // If the integers are equal so are the string representations.
6644 if (x_value == y_value) return Smi::FromInt(EQUAL);
6645
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006646 // If one of the integers is zero the normal integer order is the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006647 // same as the lexicographic order of the string representations.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006648 if (x_value == 0 || y_value == 0)
6649 return Smi::FromInt(x_value < y_value ? LESS : GREATER);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006650
ager@chromium.org32912102009-01-16 10:38:43 +00006651 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006652 // smallest because the char code of '-' is less than the char code
6653 // of any digit. Otherwise, we make both values positive.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006654
6655 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
6656 // architectures using 32-bit Smis.
6657 uint32_t x_scaled = x_value;
6658 uint32_t y_scaled = y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006659 if (x_value < 0 || y_value < 0) {
6660 if (y_value >= 0) return Smi::FromInt(LESS);
6661 if (x_value >= 0) return Smi::FromInt(GREATER);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006662 x_scaled = -x_value;
6663 y_scaled = -y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006664 }
6665
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006666 static const uint32_t kPowersOf10[] = {
6667 1, 10, 100, 1000, 10*1000, 100*1000,
6668 1000*1000, 10*1000*1000, 100*1000*1000,
6669 1000*1000*1000
6670 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006671
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006672 // If the integers have the same number of decimal digits they can be
6673 // compared directly as the numeric order is the same as the
6674 // lexicographic order. If one integer has fewer digits, it is scaled
6675 // by some power of 10 to have the same number of digits as the longer
6676 // integer. If the scaled integers are equal it means the shorter
6677 // integer comes first in the lexicographic order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006678
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006679 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
6680 int x_log2 = IntegerLog2(x_scaled);
6681 int x_log10 = ((x_log2 + 1) * 1233) >> 12;
6682 x_log10 -= x_scaled < kPowersOf10[x_log10];
6683
6684 int y_log2 = IntegerLog2(y_scaled);
6685 int y_log10 = ((y_log2 + 1) * 1233) >> 12;
6686 y_log10 -= y_scaled < kPowersOf10[y_log10];
6687
6688 int tie = EQUAL;
6689
6690 if (x_log10 < y_log10) {
6691 // X has fewer digits. We would like to simply scale up X but that
6692 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
6693 // be scaled up to 9_000_000_000. So we scale up by the next
6694 // smallest power and scale down Y to drop one digit. It is OK to
6695 // drop one digit from the longer integer since the final digit is
6696 // past the length of the shorter integer.
6697 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
6698 y_scaled /= 10;
6699 tie = LESS;
6700 } else if (y_log10 < x_log10) {
6701 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
6702 x_scaled /= 10;
6703 tie = GREATER;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006704 }
6705
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006706 if (x_scaled < y_scaled) return Smi::FromInt(LESS);
6707 if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
6708 return Smi::FromInt(tie);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006709}
6710
6711
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006712static Object* StringInputBufferCompare(RuntimeState* state,
6713 String* x,
6714 String* y) {
6715 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
6716 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006717 bufx.Reset(x);
6718 bufy.Reset(y);
6719 while (bufx.has_more() && bufy.has_more()) {
6720 int d = bufx.GetNext() - bufy.GetNext();
6721 if (d < 0) return Smi::FromInt(LESS);
6722 else if (d > 0) return Smi::FromInt(GREATER);
6723 }
6724
6725 // x is (non-trivial) prefix of y:
6726 if (bufy.has_more()) return Smi::FromInt(LESS);
6727 // y is prefix of x:
6728 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
6729}
6730
6731
6732static Object* FlatStringCompare(String* x, String* y) {
6733 ASSERT(x->IsFlat());
6734 ASSERT(y->IsFlat());
6735 Object* equal_prefix_result = Smi::FromInt(EQUAL);
6736 int prefix_length = x->length();
6737 if (y->length() < prefix_length) {
6738 prefix_length = y->length();
6739 equal_prefix_result = Smi::FromInt(GREATER);
6740 } else if (y->length() > prefix_length) {
6741 equal_prefix_result = Smi::FromInt(LESS);
6742 }
6743 int r;
6744 if (x->IsAsciiRepresentation()) {
6745 Vector<const char> x_chars = x->ToAsciiVector();
6746 if (y->IsAsciiRepresentation()) {
6747 Vector<const char> y_chars = y->ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006748 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006749 } else {
6750 Vector<const uc16> y_chars = y->ToUC16Vector();
6751 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6752 }
6753 } else {
6754 Vector<const uc16> x_chars = x->ToUC16Vector();
6755 if (y->IsAsciiRepresentation()) {
6756 Vector<const char> y_chars = y->ToAsciiVector();
6757 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6758 } else {
6759 Vector<const uc16> y_chars = y->ToUC16Vector();
6760 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6761 }
6762 }
6763 Object* result;
6764 if (r == 0) {
6765 result = equal_prefix_result;
6766 } else {
6767 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
6768 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006769 ASSERT(result ==
6770 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006771 return result;
6772}
6773
6774
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006775RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006776 NoHandleAllocation ha;
6777 ASSERT(args.length() == 2);
6778
6779 CONVERT_CHECKED(String, x, args[0]);
6780 CONVERT_CHECKED(String, y, args[1]);
6781
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006782 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006783
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006784 // A few fast case tests before we flatten.
6785 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006786 if (y->length() == 0) {
6787 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006788 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006789 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006790 return Smi::FromInt(LESS);
6791 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006792
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006793 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006794 if (d < 0) return Smi::FromInt(LESS);
6795 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006796
lrn@chromium.org303ada72010-10-27 09:33:13 +00006797 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006798 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006799 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6800 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006801 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006802 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6803 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006804
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006805 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006806 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006807}
6808
6809
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006810RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006811 NoHandleAllocation ha;
6812 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006813 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006814
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006815 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006816 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006817}
6818
6819
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006820RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006821 NoHandleAllocation ha;
6822 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006823 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006824
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006825 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006826 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006827}
6828
6829
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006830RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006831 NoHandleAllocation ha;
6832 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006833 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006834
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006835 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006836 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006837}
6838
6839
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006840static const double kPiDividedBy4 = 0.78539816339744830962;
6841
6842
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006843RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006844 NoHandleAllocation ha;
6845 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006846 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006847
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006848 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6849 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006850 double result;
6851 if (isinf(x) && isinf(y)) {
6852 // Make sure that the result in case of two infinite arguments
6853 // is a multiple of Pi / 4. The sign of the result is determined
6854 // by the first argument (x) and the sign of the second argument
6855 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006856 int multiplier = (x < 0) ? -1 : 1;
6857 if (y < 0) multiplier *= 3;
6858 result = multiplier * kPiDividedBy4;
6859 } else {
6860 result = atan2(x, y);
6861 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006862 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006863}
6864
6865
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006866RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006867 NoHandleAllocation ha;
6868 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006869 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006870
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006871 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006872 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006873}
6874
6875
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006876RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006877 NoHandleAllocation ha;
6878 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006879 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006880
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006881 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006882 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006883}
6884
6885
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006886RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006887 NoHandleAllocation ha;
6888 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006889 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006890
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006891 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006892 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006893}
6894
6895
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006896RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006897 NoHandleAllocation ha;
6898 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006899 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006900
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006901 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006902 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006903}
6904
6905
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006906RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006907 NoHandleAllocation ha;
6908 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006909 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006910
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006911 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006912 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006913}
6914
6915
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006916RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006917 NoHandleAllocation ha;
6918 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006919 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006920
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006921 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006922
6923 // If the second argument is a smi, it is much faster to call the
6924 // custom powi() function than the generic pow().
6925 if (args[1]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006926 int y = args.smi_at(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006927 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00006928 }
6929
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006930 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006931 return isolate->heap()->AllocateHeapNumber(power_double_double(x, y));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006932}
6933
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006934// Fast version of Math.pow if we know that y is not an integer and
6935// y is not -0.5 or 0.5. Used as slowcase from codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006936RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006937 NoHandleAllocation ha;
6938 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006939 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6940 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006941 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00006942 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006943 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006944 return isolate->heap()->nan_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006945 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006946 return isolate->heap()->AllocateHeapNumber(pow(x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006947 }
6948}
6949
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006950
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006951RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006952 NoHandleAllocation ha;
6953 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006954 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006955
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006956 if (!args[0]->IsHeapNumber()) {
6957 // Must be smi. Return the argument unchanged for all the other types
6958 // to make fuzz-natives test happy.
6959 return args[0];
6960 }
6961
6962 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
6963
6964 double value = number->value();
6965 int exponent = number->get_exponent();
6966 int sign = number->get_sign();
6967
danno@chromium.org160a7b02011-04-18 15:51:38 +00006968 if (exponent < -1) {
6969 // Number in range ]-0.5..0.5[. These always round to +/-zero.
6970 if (sign) return isolate->heap()->minus_zero_value();
6971 return Smi::FromInt(0);
6972 }
6973
6974 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
6975 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
6976 // agument holds for 32-bit smis).
6977 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006978 return Smi::FromInt(static_cast<int>(value + 0.5));
6979 }
6980
6981 // If the magnitude is big enough, there's no place for fraction part. If we
6982 // try to add 0.5 to this number, 1.0 will be added instead.
6983 if (exponent >= 52) {
6984 return number;
6985 }
6986
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006987 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00006988
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006989 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006990 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006991}
6992
6993
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006994RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006995 NoHandleAllocation ha;
6996 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006997 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006998
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006999 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007000 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007001}
7002
7003
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007004RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007005 NoHandleAllocation ha;
7006 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007007 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007008
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007009 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007010 return isolate->heap()->AllocateHeapNumber(sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007011}
7012
7013
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007014RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007015 NoHandleAllocation ha;
7016 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007017 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007018
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007019 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007020 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007021}
7022
7023
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007024static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007025 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
7026 181, 212, 243, 273, 304, 334};
7027 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
7028 182, 213, 244, 274, 305, 335};
7029
7030 year += month / 12;
7031 month %= 12;
7032 if (month < 0) {
7033 year--;
7034 month += 12;
7035 }
7036
7037 ASSERT(month >= 0);
7038 ASSERT(month < 12);
7039
7040 // year_delta is an arbitrary number such that:
7041 // a) year_delta = -1 (mod 400)
7042 // b) year + year_delta > 0 for years in the range defined by
7043 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
7044 // Jan 1 1970. This is required so that we don't run into integer
7045 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007046 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007047 // operations.
7048 static const int year_delta = 399999;
7049 static const int base_day = 365 * (1970 + year_delta) +
7050 (1970 + year_delta) / 4 -
7051 (1970 + year_delta) / 100 +
7052 (1970 + year_delta) / 400;
7053
7054 int year1 = year + year_delta;
7055 int day_from_year = 365 * year1 +
7056 year1 / 4 -
7057 year1 / 100 +
7058 year1 / 400 -
7059 base_day;
7060
7061 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007062 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007063 }
7064
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007065 return day_from_year + day_from_month_leap[month] + day - 1;
7066}
7067
7068
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007069RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007070 NoHandleAllocation ha;
7071 ASSERT(args.length() == 3);
7072
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007073 CONVERT_SMI_ARG_CHECKED(year, 0);
7074 CONVERT_SMI_ARG_CHECKED(month, 1);
7075 CONVERT_SMI_ARG_CHECKED(date, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007076
7077 return Smi::FromInt(MakeDay(year, month, date));
7078}
7079
7080
7081static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
7082static const int kDaysIn4Years = 4 * 365 + 1;
7083static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
7084static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
7085static const int kDays1970to2000 = 30 * 365 + 7;
7086static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
7087 kDays1970to2000;
7088static const int kYearsOffset = 400000;
7089
7090static const char kDayInYear[] = {
7091 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7092 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7093 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7094 22, 23, 24, 25, 26, 27, 28,
7095 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7096 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7097 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7098 22, 23, 24, 25, 26, 27, 28, 29, 30,
7099 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7100 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7101 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7102 22, 23, 24, 25, 26, 27, 28, 29, 30,
7103 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7104 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7105 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7106 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7107 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7108 22, 23, 24, 25, 26, 27, 28, 29, 30,
7109 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7110 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7111 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7112 22, 23, 24, 25, 26, 27, 28, 29, 30,
7113 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7114 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7115
7116 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7117 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7118 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7119 22, 23, 24, 25, 26, 27, 28,
7120 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7121 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
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,
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, 29, 30, 31,
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,
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, 31,
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,
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, 31,
7140
7141 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7142 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7143 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7144 22, 23, 24, 25, 26, 27, 28, 29,
7145 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7146 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
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,
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, 29, 30, 31,
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,
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, 31,
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,
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, 31,
7165
7166 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7167 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7168 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7169 22, 23, 24, 25, 26, 27, 28,
7170 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7171 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
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,
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, 30, 31,
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,
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, 31,
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,
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, 31};
7190
7191static const char kMonthInYear[] = {
7192 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,
7193 0, 0, 0, 0, 0, 0,
7194 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,
7195 1, 1, 1,
7196 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,
7197 2, 2, 2, 2, 2, 2,
7198 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,
7199 3, 3, 3, 3, 3,
7200 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,
7201 4, 4, 4, 4, 4, 4,
7202 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,
7203 5, 5, 5, 5, 5,
7204 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,
7205 6, 6, 6, 6, 6, 6,
7206 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,
7207 7, 7, 7, 7, 7, 7,
7208 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,
7209 8, 8, 8, 8, 8,
7210 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,
7211 9, 9, 9, 9, 9, 9,
7212 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7213 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7214 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7215 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7216
7217 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,
7218 0, 0, 0, 0, 0, 0,
7219 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,
7220 1, 1, 1,
7221 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,
7222 2, 2, 2, 2, 2, 2,
7223 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,
7224 3, 3, 3, 3, 3,
7225 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,
7226 4, 4, 4, 4, 4, 4,
7227 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,
7228 5, 5, 5, 5, 5,
7229 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,
7230 6, 6, 6, 6, 6, 6,
7231 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,
7232 7, 7, 7, 7, 7, 7,
7233 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,
7234 8, 8, 8, 8, 8,
7235 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,
7236 9, 9, 9, 9, 9, 9,
7237 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7238 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7239 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7240 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7241
7242 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,
7243 0, 0, 0, 0, 0, 0,
7244 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,
7245 1, 1, 1, 1,
7246 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,
7247 2, 2, 2, 2, 2, 2,
7248 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,
7249 3, 3, 3, 3, 3,
7250 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,
7251 4, 4, 4, 4, 4, 4,
7252 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,
7253 5, 5, 5, 5, 5,
7254 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,
7255 6, 6, 6, 6, 6, 6,
7256 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,
7257 7, 7, 7, 7, 7, 7,
7258 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,
7259 8, 8, 8, 8, 8,
7260 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,
7261 9, 9, 9, 9, 9, 9,
7262 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7263 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7264 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7265 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7266
7267 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,
7268 0, 0, 0, 0, 0, 0,
7269 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,
7270 1, 1, 1,
7271 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,
7272 2, 2, 2, 2, 2, 2,
7273 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,
7274 3, 3, 3, 3, 3,
7275 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,
7276 4, 4, 4, 4, 4, 4,
7277 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,
7278 5, 5, 5, 5, 5,
7279 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,
7280 6, 6, 6, 6, 6, 6,
7281 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,
7282 7, 7, 7, 7, 7, 7,
7283 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,
7284 8, 8, 8, 8, 8,
7285 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,
7286 9, 9, 9, 9, 9, 9,
7287 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7288 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7289 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7290 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
7291
7292
7293// This function works for dates from 1970 to 2099.
7294static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007295 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007296#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007297 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007298#endif
7299
7300 year = 1970 + (4 * date + 2) / kDaysIn4Years;
7301 date %= kDaysIn4Years;
7302
7303 month = kMonthInYear[date];
7304 day = kDayInYear[date];
7305
7306 ASSERT(MakeDay(year, month, day) == save_date);
7307}
7308
7309
7310static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007311 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007312#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007313 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007314#endif
7315
7316 date += kDaysOffset;
7317 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
7318 date %= kDaysIn400Years;
7319
7320 ASSERT(MakeDay(year, 0, 1) + date == save_date);
7321
7322 date--;
7323 int yd1 = date / kDaysIn100Years;
7324 date %= kDaysIn100Years;
7325 year += 100 * yd1;
7326
7327 date++;
7328 int yd2 = date / kDaysIn4Years;
7329 date %= kDaysIn4Years;
7330 year += 4 * yd2;
7331
7332 date--;
7333 int yd3 = date / 365;
7334 date %= 365;
7335 year += yd3;
7336
7337 bool is_leap = (!yd1 || yd2) && !yd3;
7338
7339 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007340 ASSERT(is_leap || (date >= 0));
7341 ASSERT((date < 365) || (is_leap && (date < 366)));
7342 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
7343 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
7344 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007345
7346 if (is_leap) {
7347 day = kDayInYear[2*365 + 1 + date];
7348 month = kMonthInYear[2*365 + 1 + date];
7349 } else {
7350 day = kDayInYear[date];
7351 month = kMonthInYear[date];
7352 }
7353
7354 ASSERT(MakeDay(year, month, day) == save_date);
7355}
7356
7357
7358static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007359 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007360 if (date >= 0 && date < 32 * kDaysIn4Years) {
7361 DateYMDFromTimeAfter1970(date, year, month, day);
7362 } else {
7363 DateYMDFromTimeSlow(date, year, month, day);
7364 }
7365}
7366
7367
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007368RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007369 NoHandleAllocation ha;
7370 ASSERT(args.length() == 2);
7371
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007372 CONVERT_DOUBLE_ARG_CHECKED(t, 0);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007373 CONVERT_CHECKED(JSArray, res_array, args[1]);
7374
7375 int year, month, day;
7376 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7377
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007378 RUNTIME_ASSERT(res_array->elements()->map() ==
7379 isolate->heap()->fixed_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007380 FixedArray* elms = FixedArray::cast(res_array->elements());
7381 RUNTIME_ASSERT(elms->length() == 3);
7382
7383 elms->set(0, Smi::FromInt(year));
7384 elms->set(1, Smi::FromInt(month));
7385 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007386
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007387 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007388}
7389
7390
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007391RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007392 HandleScope scope(isolate);
7393 ASSERT(args.length() == 3);
7394
7395 Handle<JSFunction> callee = args.at<JSFunction>(0);
7396 Object** parameters = reinterpret_cast<Object**>(args[1]);
7397 const int argument_count = Smi::cast(args[2])->value();
7398
7399 Handle<JSObject> result =
7400 isolate->factory()->NewArgumentsObject(callee, argument_count);
7401 // Allocate the elements if needed.
7402 int parameter_count = callee->shared()->formal_parameter_count();
7403 if (argument_count > 0) {
7404 if (parameter_count > 0) {
7405 int mapped_count = Min(argument_count, parameter_count);
7406 Handle<FixedArray> parameter_map =
7407 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
7408 parameter_map->set_map(
7409 isolate->heap()->non_strict_arguments_elements_map());
7410
7411 Handle<Map> old_map(result->map());
7412 Handle<Map> new_map =
7413 isolate->factory()->CopyMapDropTransitions(old_map);
7414 new_map->set_elements_kind(JSObject::NON_STRICT_ARGUMENTS_ELEMENTS);
7415
7416 result->set_map(*new_map);
7417 result->set_elements(*parameter_map);
7418
7419 // Store the context and the arguments array at the beginning of the
7420 // parameter map.
7421 Handle<Context> context(isolate->context());
7422 Handle<FixedArray> arguments =
7423 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7424 parameter_map->set(0, *context);
7425 parameter_map->set(1, *arguments);
7426
7427 // Loop over the actual parameters backwards.
7428 int index = argument_count - 1;
7429 while (index >= mapped_count) {
7430 // These go directly in the arguments array and have no
7431 // corresponding slot in the parameter map.
7432 arguments->set(index, *(parameters - index - 1));
7433 --index;
7434 }
7435
7436 ScopeInfo<> scope_info(callee->shared()->scope_info());
7437 while (index >= 0) {
7438 // Detect duplicate names to the right in the parameter list.
7439 Handle<String> name = scope_info.parameter_name(index);
7440 int context_slot_count = scope_info.number_of_context_slots();
7441 bool duplicate = false;
7442 for (int j = index + 1; j < parameter_count; ++j) {
7443 if (scope_info.parameter_name(j).is_identical_to(name)) {
7444 duplicate = true;
7445 break;
7446 }
7447 }
7448
7449 if (duplicate) {
7450 // This goes directly in the arguments array with a hole in the
7451 // parameter map.
7452 arguments->set(index, *(parameters - index - 1));
7453 parameter_map->set_the_hole(index + 2);
7454 } else {
7455 // The context index goes in the parameter map with a hole in the
7456 // arguments array.
7457 int context_index = -1;
7458 for (int j = Context::MIN_CONTEXT_SLOTS;
7459 j < context_slot_count;
7460 ++j) {
7461 if (scope_info.context_slot_name(j).is_identical_to(name)) {
7462 context_index = j;
7463 break;
7464 }
7465 }
7466 ASSERT(context_index >= 0);
7467 arguments->set_the_hole(index);
7468 parameter_map->set(index + 2, Smi::FromInt(context_index));
7469 }
7470
7471 --index;
7472 }
7473 } else {
7474 // If there is no aliasing, the arguments object elements are not
7475 // special in any way.
7476 Handle<FixedArray> elements =
7477 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7478 result->set_elements(*elements);
7479 for (int i = 0; i < argument_count; ++i) {
7480 elements->set(i, *(parameters - i - 1));
7481 }
7482 }
7483 }
7484 return *result;
7485}
7486
7487
7488RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007489 NoHandleAllocation ha;
7490 ASSERT(args.length() == 3);
7491
7492 JSFunction* callee = JSFunction::cast(args[0]);
7493 Object** parameters = reinterpret_cast<Object**>(args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007494 const int length = args.smi_at(2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007495
lrn@chromium.org303ada72010-10-27 09:33:13 +00007496 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007497 { MaybeObject* maybe_result =
7498 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007499 if (!maybe_result->ToObject(&result)) return maybe_result;
7500 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007501 // Allocate the elements if needed.
7502 if (length > 0) {
7503 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007504 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007505 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007506 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7507 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007508
7509 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007510 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007511 array->set_map(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007512 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007513
7514 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007515 for (int i = 0; i < length; i++) {
7516 array->set(i, *--parameters, mode);
7517 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007518 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007519 }
7520 return result;
7521}
7522
7523
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007524RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007525 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007526 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00007527 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007528 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007529 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007530
whesse@chromium.org7b260152011-06-20 15:33:18 +00007531 // The caller ensures that we pretenure closures that are assigned
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007532 // directly to properties.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007533 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007534 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007535 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
7536 context,
7537 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007538 return *result;
7539}
7540
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007541
7542static SmartPointer<Object**> GetNonBoundArguments(int bound_argc,
7543 int* total_argc) {
7544 // Find frame containing arguments passed to the caller.
7545 JavaScriptFrameIterator it;
7546 JavaScriptFrame* frame = it.frame();
7547 List<JSFunction*> functions(2);
7548 frame->GetFunctions(&functions);
7549 if (functions.length() > 1) {
7550 int inlined_frame_index = functions.length() - 1;
7551 JSFunction* inlined_function = functions[inlined_frame_index];
7552 int args_count = inlined_function->shared()->formal_parameter_count();
7553 ScopedVector<SlotRef> args_slots(args_count);
7554 SlotRef::ComputeSlotMappingForArguments(frame,
7555 inlined_frame_index,
7556 &args_slots);
7557
7558 *total_argc = bound_argc + args_count;
7559 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7560 for (int i = 0; i < args_count; i++) {
7561 Handle<Object> val = args_slots[i].GetValue();
7562 param_data[bound_argc + i] = val.location();
7563 }
7564 return param_data;
7565 } else {
7566 it.AdvanceToArgumentsFrame();
7567 frame = it.frame();
7568 int args_count = frame->ComputeParametersCount();
7569
7570 *total_argc = bound_argc + args_count;
7571 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7572 for (int i = 0; i < args_count; i++) {
7573 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
7574 param_data[bound_argc + i] = val.location();
7575 }
7576 return param_data;
7577 }
7578}
7579
7580
7581RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007582 HandleScope scope(isolate);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007583 ASSERT(args.length() == 2);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007584 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007585 CONVERT_ARG_CHECKED(JSFunction, function, 0);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007586
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007587 // Second argument is either null or an array of bound arguments.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007588 Handle<FixedArray> bound_args;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007589 int bound_argc = 0;
7590 if (!args[1]->IsNull()) {
7591 CONVERT_ARG_CHECKED(JSArray, params, 1);
7592 RUNTIME_ASSERT(params->HasFastElements());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007593 bound_args = Handle<FixedArray>(FixedArray::cast(params->elements()));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007594 bound_argc = Smi::cast(params->length())->value();
7595 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007596
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007597 int total_argc = 0;
7598 SmartPointer<Object**> param_data =
7599 GetNonBoundArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007600 for (int i = 0; i < bound_argc; i++) {
7601 Handle<Object> val = Handle<Object>(bound_args->get(i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007602 param_data[i] = val.location();
7603 }
7604
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007605 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007606 Handle<Object> result =
7607 Execution::New(function, total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007608 if (exception) {
7609 return Failure::Exception();
7610 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007611
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007612 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007613 return *result;
7614}
7615
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007616
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007617static void TrySettingInlineConstructStub(Isolate* isolate,
7618 Handle<JSFunction> function) {
7619 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00007620 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007621 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00007622 }
7623 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007624 ConstructStubCompiler compiler;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00007625 MaybeObject* code = compiler.CompileConstructStub(*function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007626 if (!code->IsFailure()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007627 function->shared()->set_construct_stub(
7628 Code::cast(code->ToObjectUnchecked()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007629 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007630 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007631}
7632
7633
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007634RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007635 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007636 ASSERT(args.length() == 1);
7637
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007638 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007639
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007640 // If the constructor isn't a proper function we throw a type error.
7641 if (!constructor->IsJSFunction()) {
7642 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7643 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007644 isolate->factory()->NewTypeError("not_constructor", arguments);
7645 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007646 }
7647
7648 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007649
7650 // If function should not have prototype, construction is not allowed. In this
7651 // case generated code bailouts here, since function has no initial_map.
whesse@chromium.org7b260152011-06-20 15:33:18 +00007652 if (!function->should_have_prototype() && !function->shared()->bound()) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007653 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7654 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007655 isolate->factory()->NewTypeError("not_constructor", arguments);
7656 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007657 }
7658
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007659#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007660 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007661 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007662 if (debug->StepInActive()) {
7663 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007664 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007665#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007666
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007667 if (function->has_initial_map()) {
7668 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007669 // The 'Function' function ignores the receiver object when
7670 // called using 'new' and creates a new JSFunction object that
7671 // is returned. The receiver object is only used for error
7672 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007673 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007674 // allocate JSFunctions since it does not properly initialize
7675 // the shared part of the function. Since the receiver is
7676 // ignored anyway, we use the global object as the receiver
7677 // instead of a new JSFunction object. This way, errors are
7678 // reported the same way whether or not 'Function' is called
7679 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007680 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007681 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007682 }
7683
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007684 // The function should be compiled for the optimization hints to be
7685 // available. We cannot use EnsureCompiled because that forces a
7686 // compilation through the shared function info which makes it
7687 // impossible for us to optimize.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007688 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007689 if (!function->is_compiled()) CompileLazy(function, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007690
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007691 if (!function->has_initial_map() &&
7692 shared->IsInobjectSlackTrackingInProgress()) {
7693 // The tracking is already in progress for another function. We can only
7694 // track one initial_map at a time, so we force the completion before the
7695 // function is called as a constructor for the first time.
7696 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007697 }
7698
7699 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007700 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
7701 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007702 // Delay setting the stub if inobject slack tracking is in progress.
7703 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007704 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007705 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007706
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007707 isolate->counters()->constructed_objects()->Increment();
7708 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007709
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007710 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007711}
7712
7713
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007714RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007715 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007716 ASSERT(args.length() == 1);
7717
7718 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7719 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007720 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007721
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007722 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007723}
7724
7725
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007726RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007727 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007728 ASSERT(args.length() == 1);
7729
7730 Handle<JSFunction> function = args.at<JSFunction>(0);
7731#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00007732 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007733 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007734 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007735 PrintF("]\n");
7736 }
7737#endif
7738
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007739 // Compile the target function. Here we compile using CompileLazyInLoop in
7740 // order to get the optimized version. This helps code like delta-blue
7741 // that calls performance-critical routines through constructors. A
7742 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
7743 // direct call. Since the in-loop tracking takes place through CallICs
7744 // this means that things called through constructors are never known to
7745 // be in loops. We compile them as if they are in loops here just in case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007746 ASSERT(!function->is_compiled());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007747 if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007748 return Failure::Exception();
7749 }
7750
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007751 // All done. Return the compiled code.
7752 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007753 return function->code();
7754}
7755
7756
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007757RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007758 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007759 ASSERT(args.length() == 1);
7760 Handle<JSFunction> function = args.at<JSFunction>(0);
7761 // If the function is not optimizable or debugger is active continue using the
7762 // code from the full compiler.
7763 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007764 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007765 if (FLAG_trace_opt) {
7766 PrintF("[failed to optimize ");
7767 function->PrintName();
7768 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
7769 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007770 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007771 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007772 function->ReplaceCode(function->shared()->code());
7773 return function->code();
7774 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007775 if (CompileOptimized(function, AstNode::kNoNumber, CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007776 return function->code();
7777 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007778 if (FLAG_trace_opt) {
7779 PrintF("[failed to optimize ");
7780 function->PrintName();
7781 PrintF(": optimized compilation failed]\n");
7782 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007783 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007784 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007785}
7786
7787
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007788RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
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 RUNTIME_ASSERT(args[0]->IsSmi());
7792 Deoptimizer::BailoutType type =
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007793 static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007794 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
7795 ASSERT(isolate->heap()->IsAllocationAllowed());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007796 int frames = deoptimizer->output_count();
7797
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007798 deoptimizer->MaterializeHeapNumbers();
7799 delete deoptimizer;
7800
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007801 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007802 JavaScriptFrame* frame = NULL;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00007803 for (int i = 0; i < frames - 1; i++) it.Advance();
7804 frame = it.frame();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007805
7806 RUNTIME_ASSERT(frame->function()->IsJSFunction());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007807 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007808 Handle<Object> arguments;
7809 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007810 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007811 if (arguments.is_null()) {
7812 // FunctionGetArguments can't throw an exception, so cast away the
7813 // doubt with an assert.
7814 arguments = Handle<Object>(
7815 Accessors::FunctionGetArguments(*function,
7816 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007817 ASSERT(*arguments != isolate->heap()->null_value());
7818 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007819 }
7820 frame->SetExpression(i, *arguments);
7821 }
7822 }
7823
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007824 isolate->compilation_cache()->MarkForLazyOptimizing(function);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007825 if (type == Deoptimizer::EAGER) {
7826 RUNTIME_ASSERT(function->IsOptimized());
7827 } else {
7828 RUNTIME_ASSERT(!function->IsOptimized());
7829 }
7830
7831 // Avoid doing too much work when running with --always-opt and keep
7832 // the optimized code around.
7833 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007834 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007835 }
7836
7837 // Count the number of optimized activations of the function.
7838 int activations = 0;
7839 while (!it.done()) {
7840 JavaScriptFrame* frame = it.frame();
7841 if (frame->is_optimized() && frame->function() == *function) {
7842 activations++;
7843 }
7844 it.Advance();
7845 }
7846
7847 // TODO(kasperl): For now, we cannot support removing the optimized
7848 // code when we have recursive invocations of the same function.
7849 if (activations == 0) {
7850 if (FLAG_trace_deopt) {
7851 PrintF("[removing optimized code for: ");
7852 function->PrintName();
7853 PrintF("]\n");
7854 }
7855 function->ReplaceCode(function->shared()->code());
7856 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007857 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007858}
7859
7860
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007861RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007862 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007863 delete deoptimizer;
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
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007868RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007869 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007870 ASSERT(args.length() == 1);
7871 CONVERT_ARG_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007872 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007873
7874 Deoptimizer::DeoptimizeFunction(*function);
7875
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007876 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007877}
7878
7879
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007880RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
7881#if defined(USE_SIMULATOR)
7882 return isolate->heap()->true_value();
7883#else
7884 return isolate->heap()->false_value();
7885#endif
7886}
7887
7888
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00007889RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
7890 HandleScope scope(isolate);
7891 ASSERT(args.length() == 1);
7892 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7893 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
7894 function->MarkForLazyRecompilation();
7895 return isolate->heap()->undefined_value();
7896}
7897
7898
lrn@chromium.org1c092762011-05-09 09:42:16 +00007899RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
7900 HandleScope scope(isolate);
7901 ASSERT(args.length() == 1);
7902 if (!V8::UseCrankshaft()) {
7903 return Smi::FromInt(4); // 4 == "never".
7904 }
7905 if (FLAG_always_opt) {
7906 return Smi::FromInt(3); // 3 == "always".
7907 }
7908 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7909 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
7910 : Smi::FromInt(2); // 2 == "no".
7911}
7912
7913
7914RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
7915 HandleScope scope(isolate);
7916 ASSERT(args.length() == 1);
7917 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7918 return Smi::FromInt(function->shared()->opt_count());
7919}
7920
7921
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007922RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007923 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007924 ASSERT(args.length() == 1);
7925 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7926
7927 // We're not prepared to handle a function with arguments object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00007928 ASSERT(!function->shared()->uses_arguments());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007929
7930 // We have hit a back edge in an unoptimized frame for a function that was
7931 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007932 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007933 // Keep track of whether we've succeeded in optimizing.
7934 bool succeeded = unoptimized->optimizable();
7935 if (succeeded) {
7936 // If we are trying to do OSR when there are already optimized
7937 // activations of the function, it means (a) the function is directly or
7938 // indirectly recursive and (b) an optimized invocation has been
7939 // deoptimized so that we are currently in an unoptimized activation.
7940 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007941 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007942 while (succeeded && !it.done()) {
7943 JavaScriptFrame* frame = it.frame();
7944 succeeded = !frame->is_optimized() || frame->function() != *function;
7945 it.Advance();
7946 }
7947 }
7948
7949 int ast_id = AstNode::kNoNumber;
7950 if (succeeded) {
7951 // The top JS function is this one, the PC is somewhere in the
7952 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007953 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007954 JavaScriptFrame* frame = it.frame();
7955 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00007956 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007957 ASSERT(unoptimized->contains(frame->pc()));
7958
7959 // Use linear search of the unoptimized code's stack check table to find
7960 // the AST id matching the PC.
7961 Address start = unoptimized->instruction_start();
7962 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00007963 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007964 uint32_t table_length = Memory::uint32_at(table_cursor);
7965 table_cursor += kIntSize;
7966 for (unsigned i = 0; i < table_length; ++i) {
7967 // Table entries are (AST id, pc offset) pairs.
7968 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
7969 if (pc_offset == target_pc_offset) {
7970 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
7971 break;
7972 }
7973 table_cursor += 2 * kIntSize;
7974 }
7975 ASSERT(ast_id != AstNode::kNoNumber);
7976 if (FLAG_trace_osr) {
7977 PrintF("[replacing on-stack at AST id %d in ", ast_id);
7978 function->PrintName();
7979 PrintF("]\n");
7980 }
7981
7982 // Try to compile the optimized code. A true return value from
7983 // CompileOptimized means that compilation succeeded, not necessarily
7984 // that optimization succeeded.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007985 if (CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
7986 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007987 DeoptimizationInputData* data = DeoptimizationInputData::cast(
7988 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007989 if (data->OsrPcOffset()->value() >= 0) {
7990 if (FLAG_trace_osr) {
7991 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007992 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007993 }
7994 ASSERT(data->OsrAstId()->value() == ast_id);
7995 } else {
7996 // We may never generate the desired OSR entry if we emit an
7997 // early deoptimize.
7998 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007999 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008000 } else {
8001 succeeded = false;
8002 }
8003 }
8004
8005 // Revert to the original stack checks in the original unoptimized code.
8006 if (FLAG_trace_osr) {
8007 PrintF("[restoring original stack checks in ");
8008 function->PrintName();
8009 PrintF("]\n");
8010 }
8011 StackCheckStub check_stub;
8012 Handle<Code> check_code = check_stub.GetCode();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00008013 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008014 Deoptimizer::RevertStackCheckCode(*unoptimized,
8015 *check_code,
8016 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008017
8018 // Allow OSR only at nesting level zero again.
8019 unoptimized->set_allow_osr_at_loop_nesting_level(0);
8020
8021 // If the optimization attempt succeeded, return the AST id tagged as a
8022 // smi. This tells the builtin that we need to translate the unoptimized
8023 // frame to an optimized one.
8024 if (succeeded) {
8025 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
8026 return Smi::FromInt(ast_id);
8027 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008028 if (function->IsMarkedForLazyRecompilation()) {
8029 function->ReplaceCode(function->shared()->code());
8030 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008031 return Smi::FromInt(-1);
8032 }
8033}
8034
8035
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008036RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008037 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008038 ASSERT(args.length() == 1);
8039 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8040 return *Execution::GetFunctionDelegate(args.at<Object>(0));
8041}
8042
8043
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008044RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008045 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008046 ASSERT(args.length() == 1);
8047 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8048 return *Execution::GetConstructorDelegate(args.at<Object>(0));
8049}
8050
8051
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008052RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008053 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00008054 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008055
kasper.lund7276f142008-07-30 08:49:36 +00008056 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00008057 int length = function->shared()->scope_info()->NumberOfContextSlots();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008058 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008059 { MaybeObject* maybe_result =
8060 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008061 if (!maybe_result->ToObject(&result)) return maybe_result;
8062 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008063
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008064 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008065
kasper.lund7276f142008-07-30 08:49:36 +00008066 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008067}
8068
lrn@chromium.org303ada72010-10-27 09:33:13 +00008069
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008070RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
8071 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008072 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008073 JSObject* extension_object;
8074 if (args[0]->IsJSObject()) {
8075 extension_object = JSObject::cast(args[0]);
8076 } else {
8077 // Convert the object to a proper JavaScript object.
8078 MaybeObject* maybe_js_object = args[0]->ToObject();
8079 if (!maybe_js_object->To(&extension_object)) {
8080 if (Failure::cast(maybe_js_object)->IsInternalError()) {
8081 HandleScope scope(isolate);
8082 Handle<Object> handle = args.at<Object>(0);
8083 Handle<Object> result =
8084 isolate->factory()->NewTypeError("with_expression",
8085 HandleVector(&handle, 1));
8086 return isolate->Throw(*result);
8087 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008088 return maybe_js_object;
8089 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008090 }
8091 }
8092
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008093 JSFunction* function;
8094 if (args[1]->IsSmi()) {
8095 // A smi sentinel indicates a context nested inside global code rather
8096 // than some function. There is a canonical empty function that can be
8097 // gotten from the global context.
8098 function = isolate->context()->global_context()->closure();
8099 } else {
8100 function = JSFunction::cast(args[1]);
8101 }
8102
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008103 Context* context;
8104 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008105 isolate->heap()->AllocateWithContext(function,
8106 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008107 extension_object);
8108 if (!maybe_context->To(&context)) return maybe_context;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008109 isolate->set_context(context);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008110 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008111}
8112
8113
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008114RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008115 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008116 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008117 String* name = String::cast(args[0]);
8118 Object* thrown_object = args[1];
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008119 JSFunction* function;
8120 if (args[2]->IsSmi()) {
8121 // A smi sentinel indicates a context nested inside global code rather
8122 // than some function. There is a canonical empty function that can be
8123 // gotten from the global context.
8124 function = isolate->context()->global_context()->closure();
8125 } else {
8126 function = JSFunction::cast(args[2]);
8127 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008128 Context* context;
8129 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008130 isolate->heap()->AllocateCatchContext(function,
8131 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008132 name,
8133 thrown_object);
8134 if (!maybe_context->To(&context)) return maybe_context;
8135 isolate->set_context(context);
8136 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008137}
8138
8139
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008140RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008141 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008142 ASSERT(args.length() == 2);
8143
8144 CONVERT_ARG_CHECKED(Context, context, 0);
8145 CONVERT_ARG_CHECKED(String, name, 1);
8146
8147 int index;
8148 PropertyAttributes attributes;
8149 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008150 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008151
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008152 // If the slot was not found the result is true.
8153 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008154 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008155 }
8156
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008157 // If the slot was found in a context, it should be DONT_DELETE.
8158 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008159 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008160 }
8161
8162 // The slot was found in a JSObject, either a context extension object,
8163 // the global object, or an arguments object. Try to delete it
8164 // (respecting DONT_DELETE). For consistency with V8's usual behavior,
8165 // which allows deleting all parameters in functions that mention
8166 // 'arguments', we do this even for the case of slots found on an
8167 // arguments object. The slot was found on an arguments object if the
8168 // index is non-negative.
8169 Handle<JSObject> object = Handle<JSObject>::cast(holder);
8170 if (index >= 0) {
8171 return object->DeleteElement(index, JSObject::NORMAL_DELETION);
8172 } else {
8173 return object->DeleteProperty(*name, JSObject::NORMAL_DELETION);
8174 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008175}
8176
8177
ager@chromium.orga1645e22009-09-09 19:27:10 +00008178// A mechanism to return a pair of Object pointers in registers (if possible).
8179// How this is achieved is calling convention-dependent.
8180// All currently supported x86 compiles uses calling conventions that are cdecl
8181// variants where a 64-bit value is returned in two 32-bit registers
8182// (edx:eax on ia32, r1:r0 on ARM).
8183// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
8184// In Win64 calling convention, a struct of two pointers is returned in memory,
8185// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008186#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008187struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008188 MaybeObject* x;
8189 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008190};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008191
lrn@chromium.org303ada72010-10-27 09:33:13 +00008192static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008193 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008194 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
8195 // In Win64 they are assigned to a hidden first argument.
8196 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008197}
8198#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008199typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008200static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008201 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008202 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008203}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008204#endif
8205
8206
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008207static inline MaybeObject* Unhole(Heap* heap,
8208 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00008209 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008210 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
8211 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008212 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008213}
8214
8215
danno@chromium.org40cb8782011-05-25 07:58:50 +00008216static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
8217 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008218 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008219 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008220 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008221 JSFunction* context_extension_function =
8222 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008223 // If the holder isn't a context extension object, we just return it
8224 // as the receiver. This allows arguments objects to be used as
8225 // receivers, but only if they are put in the context scope chain
8226 // explicitly via a with-statement.
8227 Object* constructor = holder->map()->constructor();
8228 if (constructor != context_extension_function) return holder;
danno@chromium.org40cb8782011-05-25 07:58:50 +00008229 // Fall back to using the global object as the implicit receiver if
8230 // the property turns out to be a local variable allocated in a
8231 // context extension object - introduced via eval. Implicit global
8232 // receivers are indicated with the hole value.
8233 return isolate->heap()->the_hole_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008234}
8235
8236
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008237static ObjectPair LoadContextSlotHelper(Arguments args,
8238 Isolate* isolate,
8239 bool throw_error) {
8240 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00008241 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008242
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008243 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008244 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008245 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008246 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008247 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008248
8249 int index;
8250 PropertyAttributes attributes;
8251 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008252 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008253
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008254 // If the index is non-negative, the slot has been found in a local
8255 // variable or a parameter. Read it from the context object or the
8256 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008257 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008258 // If the "property" we were looking for is a local variable or an
8259 // argument in a context, the receiver is the global object; see
8260 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008261 //
8262 // Use the hole as the receiver to signal that the receiver is
8263 // implicit and that the global receiver should be used.
8264 Handle<Object> receiver = isolate->factory()->the_hole_value();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008265 MaybeObject* value = (holder->IsContext())
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008266 ? Context::cast(*holder)->get(index)
8267 : JSObject::cast(*holder)->GetElement(index);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008268 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008269 }
8270
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008271 // If the holder is found, we read the property from it.
8272 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008273 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008274 JSObject* object = JSObject::cast(*holder);
danno@chromium.org40cb8782011-05-25 07:58:50 +00008275 Object* receiver;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008276 if (object->IsGlobalObject()) {
8277 receiver = GlobalObject::cast(object)->global_receiver();
8278 } else if (context->is_exception_holder(*holder)) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008279 // Use the hole as the receiver to signal that the receiver is
8280 // implicit and that the global receiver should be used.
8281 receiver = isolate->heap()->the_hole_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008282 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008283 receiver = ComputeReceiverForNonGlobal(isolate, object);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008284 }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008285
8286 // GetProperty below can cause GC.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008287 Handle<Object> receiver_handle(receiver);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008288
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008289 // No need to unhole the value here. This is taken care of by the
8290 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008291 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008292 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008293 }
8294
8295 if (throw_error) {
8296 // The property doesn't exist - throw exception.
8297 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008298 isolate->factory()->NewReferenceError("not_defined",
8299 HandleVector(&name, 1));
8300 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008301 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008302 // The property doesn't exist - return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008303 return MakePair(isolate->heap()->undefined_value(),
8304 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008305 }
8306}
8307
8308
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008309RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008310 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008311}
8312
8313
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008314RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008315 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008316}
8317
8318
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008319RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008320 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008321 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008322
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008323 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008324 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008325 CONVERT_ARG_CHECKED(String, name, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008326 CONVERT_SMI_ARG_CHECKED(strict_unchecked, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008327 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
8328 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008329 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008330
8331 int index;
8332 PropertyAttributes attributes;
8333 ContextLookupFlags flags = FOLLOW_CHAINS;
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008334 Handle<Object> holder = context->Lookup(name, flags, &index, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008335
8336 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008337 if (holder->IsContext()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008338 // Ignore if read_only variable.
8339 if ((attributes & READ_ONLY) == 0) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008340 // Context is a fixed array and set cannot fail.
8341 Context::cast(*holder)->set(index, *value);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008342 } else if (strict_mode == kStrictMode) {
8343 // Setting read only property in strict mode.
8344 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008345 isolate->factory()->NewTypeError("strict_cannot_assign",
8346 HandleVector(&name, 1));
8347 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008348 }
8349 } else {
8350 ASSERT((attributes & READ_ONLY) == 0);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008351 Handle<Object> result =
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008352 SetElement(Handle<JSObject>::cast(holder), index, value, strict_mode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008353 if (result.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008354 ASSERT(isolate->has_pending_exception());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008355 return Failure::Exception();
8356 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008357 }
8358 return *value;
8359 }
8360
8361 // Slow case: The property is not in a FixedArray context.
8362 // It is either in an JSObject extension context or it was not found.
8363 Handle<JSObject> context_ext;
8364
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008365 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008366 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008367 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008368 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008369 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008370 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008371
8372 if (strict_mode == kStrictMode) {
8373 // Throw in strict mode (assignment to undefined variable).
8374 Handle<Object> error =
8375 isolate->factory()->NewReferenceError(
8376 "not_defined", HandleVector(&name, 1));
8377 return isolate->Throw(*error);
8378 }
8379 // In non-strict mode, the property is stored in the global context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008380 attributes = NONE;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008381 context_ext = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008382 }
8383
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008384 // Set the property, but ignore if read_only variable on the context
8385 // extension object itself.
8386 if ((attributes & READ_ONLY) == 0 ||
8387 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008388 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008389 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008390 SetProperty(context_ext, name, value, NONE, strict_mode));
8391 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008392 // Setting read only property in strict mode.
8393 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008394 isolate->factory()->NewTypeError(
8395 "strict_cannot_assign", HandleVector(&name, 1));
8396 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008397 }
8398 return *value;
8399}
8400
8401
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008402RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008403 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008404 ASSERT(args.length() == 1);
8405
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008406 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008407}
8408
8409
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008410RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008411 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008412 ASSERT(args.length() == 1);
8413
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008414 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008415}
8416
8417
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008418RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008419 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008420 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008421}
8422
8423
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008424RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008425 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008426 ASSERT(args.length() == 1);
8427
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008428 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008429 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008430 isolate->factory()->NewReferenceError("not_defined",
8431 HandleVector(&name, 1));
8432 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008433}
8434
8435
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008436RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00008437 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008438
8439 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008440 if (isolate->stack_guard()->IsStackOverflow()) {
8441 NoHandleAllocation na;
8442 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008443 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008444
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008445 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008446}
8447
8448
8449// NOTE: These PrintXXX functions are defined for all builds (not just
8450// DEBUG builds) because we may want to be able to trace function
8451// calls in all modes.
8452static void PrintString(String* str) {
8453 // not uncommon to have empty strings
8454 if (str->length() > 0) {
8455 SmartPointer<char> s =
8456 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
8457 PrintF("%s", *s);
8458 }
8459}
8460
8461
8462static void PrintObject(Object* obj) {
8463 if (obj->IsSmi()) {
8464 PrintF("%d", Smi::cast(obj)->value());
8465 } else if (obj->IsString() || obj->IsSymbol()) {
8466 PrintString(String::cast(obj));
8467 } else if (obj->IsNumber()) {
8468 PrintF("%g", obj->Number());
8469 } else if (obj->IsFailure()) {
8470 PrintF("<failure>");
8471 } else if (obj->IsUndefined()) {
8472 PrintF("<undefined>");
8473 } else if (obj->IsNull()) {
8474 PrintF("<null>");
8475 } else if (obj->IsTrue()) {
8476 PrintF("<true>");
8477 } else if (obj->IsFalse()) {
8478 PrintF("<false>");
8479 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00008480 PrintF("%p", reinterpret_cast<void*>(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008481 }
8482}
8483
8484
8485static int StackSize() {
8486 int n = 0;
8487 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
8488 return n;
8489}
8490
8491
8492static void PrintTransition(Object* result) {
8493 // indentation
8494 { const int nmax = 80;
8495 int n = StackSize();
8496 if (n <= nmax)
8497 PrintF("%4d:%*s", n, n, "");
8498 else
8499 PrintF("%4d:%*s", n, nmax, "...");
8500 }
8501
8502 if (result == NULL) {
8503 // constructor calls
8504 JavaScriptFrameIterator it;
8505 JavaScriptFrame* frame = it.frame();
8506 if (frame->IsConstructor()) PrintF("new ");
8507 // function name
8508 Object* fun = frame->function();
8509 if (fun->IsJSFunction()) {
8510 PrintObject(JSFunction::cast(fun)->shared()->name());
8511 } else {
8512 PrintObject(fun);
8513 }
8514 // function arguments
8515 // (we are intentionally only printing the actually
8516 // supplied parameters, not all parameters required)
8517 PrintF("(this=");
8518 PrintObject(frame->receiver());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008519 const int length = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008520 for (int i = 0; i < length; i++) {
8521 PrintF(", ");
8522 PrintObject(frame->GetParameter(i));
8523 }
8524 PrintF(") {\n");
8525
8526 } else {
8527 // function result
8528 PrintF("} -> ");
8529 PrintObject(result);
8530 PrintF("\n");
8531 }
8532}
8533
8534
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008535RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008536 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008537 NoHandleAllocation ha;
8538 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008539 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008540}
8541
8542
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008543RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008544 NoHandleAllocation ha;
8545 PrintTransition(args[0]);
8546 return args[0]; // return TOS
8547}
8548
8549
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008550RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008551 NoHandleAllocation ha;
8552 ASSERT(args.length() == 1);
8553
8554#ifdef DEBUG
8555 if (args[0]->IsString()) {
8556 // If we have a string, assume it's a code "marker"
8557 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008558 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008559 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008560 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
8561 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008562 } else {
8563 PrintF("DebugPrint: ");
8564 }
8565 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008566 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008567 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008568 HeapObject::cast(args[0])->map()->Print();
8569 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008570#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008571 // ShortPrint is available in release mode. Print is not.
8572 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008573#endif
8574 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00008575 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008576
8577 return args[0]; // return TOS
8578}
8579
8580
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008581RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008582 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008583 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008584 isolate->PrintStack();
8585 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008586}
8587
8588
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008589RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008590 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008591 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008592
8593 // According to ECMA-262, section 15.9.1, page 117, the precision of
8594 // the number in a Date object representing a particular instant in
8595 // time is milliseconds. Therefore, we floor the result of getting
8596 // the OS time.
8597 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008598 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008599}
8600
8601
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008602RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008603 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008604 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008605
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008606 CONVERT_ARG_CHECKED(String, str, 0);
8607 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008608
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008609 CONVERT_ARG_CHECKED(JSArray, output, 1);
8610 RUNTIME_ASSERT(output->HasFastElements());
8611
8612 AssertNoAllocation no_allocation;
8613
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008614 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008615 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
8616 bool result;
ager@chromium.org5ec48922009-05-05 07:25:34 +00008617 if (str->IsAsciiRepresentation()) {
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008618 result = DateParser::Parse(str->ToAsciiVector(),
8619 output_array,
8620 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008621 } else {
ager@chromium.org5ec48922009-05-05 07:25:34 +00008622 ASSERT(str->IsTwoByteRepresentation());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008623 result = DateParser::Parse(str->ToUC16Vector(),
8624 output_array,
8625 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008626 }
8627
8628 if (result) {
8629 return *output;
8630 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008631 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008632 }
8633}
8634
8635
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008636RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008637 NoHandleAllocation ha;
8638 ASSERT(args.length() == 1);
8639
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008640 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00008641 const char* zone = OS::LocalTimezone(x);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008642 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008643}
8644
8645
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008646RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008647 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008648 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008649
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008650 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008651}
8652
8653
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008654RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008655 NoHandleAllocation ha;
8656 ASSERT(args.length() == 1);
8657
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008658 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008659 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008660}
8661
8662
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008663RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008664 ASSERT(args.length() == 1);
8665 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008666 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008667 return JSGlobalObject::cast(global)->global_receiver();
8668}
8669
8670
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008671RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008672 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008673 ASSERT_EQ(1, args.length());
8674 CONVERT_ARG_CHECKED(String, source, 0);
8675
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00008676 source = Handle<String>(source->TryFlattenGetString());
8677 // Optimized fast case where we only have ascii characters.
8678 Handle<Object> result;
8679 if (source->IsSeqAsciiString()) {
8680 result = JsonParser<true>::Parse(source);
8681 } else {
8682 result = JsonParser<false>::Parse(source);
8683 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008684 if (result.is_null()) {
8685 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008686 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008687 return Failure::Exception();
8688 }
8689 return *result;
8690}
8691
8692
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008693bool CodeGenerationFromStringsAllowed(Isolate* isolate,
8694 Handle<Context> context) {
8695 if (context->allow_code_gen_from_strings()->IsFalse()) {
8696 // Check with callback if set.
8697 AllowCodeGenerationFromStringsCallback callback =
8698 isolate->allow_code_gen_callback();
8699 if (callback == NULL) {
8700 // No callback set and code generation disallowed.
8701 return false;
8702 } else {
8703 // Callback set. Let it decide if code generation is allowed.
8704 VMState state(isolate, EXTERNAL);
8705 return callback(v8::Utils::ToLocal(context));
8706 }
8707 }
8708 return true;
8709}
8710
8711
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008712RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008713 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008714 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00008715 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008716
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008717 // Extract global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008718 Handle<Context> context(isolate->context()->global_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008719
8720 // Check if global context allows code generation from
8721 // strings. Throw an exception if it doesn't.
8722 if (!CodeGenerationFromStringsAllowed(isolate, context)) {
8723 return isolate->Throw(*isolate->factory()->NewError(
8724 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
8725 }
8726
8727 // Compile source string in the global context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008728 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
8729 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008730 true,
8731 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008732 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008733 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008734 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8735 context,
8736 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008737 return *fun;
8738}
8739
8740
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008741static ObjectPair CompileGlobalEval(Isolate* isolate,
8742 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008743 Handle<Object> receiver,
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00008744 StrictModeFlag strict_mode) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008745 Handle<Context> context = Handle<Context>(isolate->context());
8746 Handle<Context> global_context = Handle<Context>(context->global_context());
8747
8748 // Check if global context allows code generation from
8749 // strings. Throw an exception if it doesn't.
8750 if (!CodeGenerationFromStringsAllowed(isolate, global_context)) {
8751 isolate->Throw(*isolate->factory()->NewError(
8752 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
8753 return MakePair(Failure::Exception(), NULL);
8754 }
8755
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008756 // Deal with a normal eval call with a string argument. Compile it
8757 // and return the compiled function bound in the local context.
8758 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
8759 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008760 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008761 context->IsGlobalContext(),
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00008762 strict_mode);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008763 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008764 Handle<JSFunction> compiled =
8765 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008766 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008767 return MakePair(*compiled, *receiver);
8768}
8769
8770
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008771RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008772 ASSERT(args.length() == 4);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008773
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008774 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008775 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008776 Handle<Object> receiver; // Will be overwritten.
8777
8778 // Compute the calling context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008779 Handle<Context> context = Handle<Context>(isolate->context(), isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008780#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008781 // Make sure Isolate::context() agrees with the old code that traversed
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008782 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008783 StackFrameLocator locator;
8784 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008785 ASSERT(Context::cast(frame->context()) == *context);
8786#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008787
8788 // Find where the 'eval' symbol is bound. It is unaliased only if
8789 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008790 int index = -1;
8791 PropertyAttributes attributes = ABSENT;
8792 while (true) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008793 receiver = context->Lookup(isolate->factory()->eval_symbol(),
8794 FOLLOW_PROTOTYPE_CHAIN,
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008795 &index, &attributes);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008796 // Stop search when eval is found or when the global context is
8797 // reached.
8798 if (attributes != ABSENT || context->IsGlobalContext()) break;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008799 context = Handle<Context>(context->previous(), isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008800 }
8801
iposva@chromium.org245aa852009-02-10 00:49:54 +00008802 // If eval could not be resolved, it has been deleted and we need to
8803 // throw a reference error.
8804 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008805 Handle<Object> name = isolate->factory()->eval_symbol();
iposva@chromium.org245aa852009-02-10 00:49:54 +00008806 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008807 isolate->factory()->NewReferenceError("not_defined",
8808 HandleVector(&name, 1));
8809 return MakePair(isolate->Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00008810 }
8811
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008812 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008813 // 'eval' is not bound in the global context. Just call the function
8814 // with the given arguments. This is not necessarily the global eval.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00008815 if (receiver->IsContext() || receiver->IsJSContextExtensionObject()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008816 receiver = isolate->factory()->the_hole_value();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008817 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008818 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008819 }
8820
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008821 // 'eval' is bound in the global context, but it may have been overwritten.
8822 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008823 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008824 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008825 return MakePair(*callee, isolate->heap()->the_hole_value());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008826 }
8827
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008828 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008829 return CompileGlobalEval(isolate,
8830 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008831 args.at<Object>(2),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008832 static_cast<StrictModeFlag>(args.smi_at(3)));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008833}
8834
8835
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008836RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEvalNoLookup) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008837 ASSERT(args.length() == 4);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008838
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008839 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008840 Handle<Object> callee = args.at<Object>(0);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008841
8842 // 'eval' is bound in the global context, but it may have been overwritten.
8843 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008844 if (*callee != isolate->global_context()->global_eval_fun() ||
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008845 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008846 return MakePair(*callee, isolate->heap()->the_hole_value());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00008847 }
8848
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008849 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008850 return CompileGlobalEval(isolate,
8851 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008852 args.at<Object>(2),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008853 static_cast<StrictModeFlag>(args.smi_at(3)));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00008854}
8855
8856
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008857RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008858 // This utility adjusts the property attributes for newly created Function
8859 // object ("new Function(...)") by changing the map.
8860 // All it does is changing the prototype property to enumerable
8861 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008862 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008863 ASSERT(args.length() == 1);
8864 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008865
8866 Handle<Map> map = func->shared()->strict_mode()
8867 ? isolate->strict_mode_function_instance_map()
8868 : isolate->function_instance_map();
8869
8870 ASSERT(func->map()->instance_type() == map->instance_type());
8871 ASSERT(func->map()->instance_size() == map->instance_size());
8872 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008873 return *func;
8874}
8875
8876
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008877RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008878 // Allocate a block of memory in NewSpace (filled with a filler).
8879 // Use as fallback for allocation in generated code when NewSpace
8880 // is full.
8881 ASSERT(args.length() == 1);
8882 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
8883 int size = size_smi->value();
8884 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
8885 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008886 Heap* heap = isolate->heap();
8887 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008888 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008889 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008890 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008891 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008892 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008893 }
8894 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008895 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00008896}
8897
8898
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008899// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008900// array. Returns true if the element was pushed on the stack and
8901// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008902RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008903 ASSERT(args.length() == 2);
8904 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008905 CONVERT_CHECKED(JSObject, element, args[1]);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008906 RUNTIME_ASSERT(array->HasFastElements());
8907 int length = Smi::cast(array->length())->value();
8908 FixedArray* elements = FixedArray::cast(array->elements());
8909 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008910 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008911 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00008912 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008913 // Strict not needed. Used for cycle detection in Array join implementation.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008914 { MaybeObject* maybe_obj =
8915 array->SetFastElement(length, element, kNonStrictMode, true);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008916 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8917 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008918 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008919}
8920
8921
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008922/**
8923 * A simple visitor visits every element of Array's.
8924 * The backend storage can be a fixed array for fast elements case,
8925 * or a dictionary for sparse array. Since Dictionary is a subtype
8926 * of FixedArray, the class can be used by both fast and slow cases.
8927 * The second parameter of the constructor, fast_elements, specifies
8928 * whether the storage is a FixedArray or Dictionary.
8929 *
8930 * An index limit is used to deal with the situation that a result array
8931 * length overflows 32-bit non-negative integer.
8932 */
8933class ArrayConcatVisitor {
8934 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008935 ArrayConcatVisitor(Isolate* isolate,
8936 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008937 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008938 isolate_(isolate),
8939 storage_(Handle<FixedArray>::cast(
8940 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008941 index_offset_(0u),
8942 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008943
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008944 ~ArrayConcatVisitor() {
8945 clear_storage();
8946 }
8947
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008948 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008949 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008950 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008951
8952 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008953 if (index < static_cast<uint32_t>(storage_->length())) {
8954 storage_->set(index, *elm);
8955 return;
8956 }
8957 // Our initial estimate of length was foiled, possibly by
8958 // getters on the arrays increasing the length of later arrays
8959 // during iteration.
8960 // This shouldn't happen in anything but pathological cases.
8961 SetDictionaryMode(index);
8962 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008963 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008964 ASSERT(!fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008965 Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008966 Handle<NumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008967 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008968 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008969 // Dictionary needed to grow.
8970 clear_storage();
8971 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008972 }
8973}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008974
8975 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008976 if (JSObject::kMaxElementCount - index_offset_ < delta) {
8977 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00008978 } else {
8979 index_offset_ += delta;
8980 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008981 }
8982
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008983 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008984 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008985 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008986 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008987 Handle<Map> map;
8988 if (fast_elements_) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008989 map = isolate_->factory()->GetFastElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008990 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008991 map = isolate_->factory()->GetSlowElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008992 }
8993 array->set_map(*map);
8994 array->set_length(*length);
8995 array->set_elements(*storage_);
8996 return array;
8997 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00008998
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008999 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009000 // Convert storage to dictionary mode.
9001 void SetDictionaryMode(uint32_t index) {
9002 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009003 Handle<FixedArray> current_storage(*storage_);
9004 Handle<NumberDictionary> slow_storage(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009005 isolate_->factory()->NewNumberDictionary(current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009006 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
9007 for (uint32_t i = 0; i < current_length; i++) {
9008 HandleScope loop_scope;
9009 Handle<Object> element(current_storage->get(i));
9010 if (!element->IsTheHole()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009011 Handle<NumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009012 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009013 if (!new_storage.is_identical_to(slow_storage)) {
9014 slow_storage = loop_scope.CloseAndEscape(new_storage);
9015 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009016 }
9017 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009018 clear_storage();
9019 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009020 fast_elements_ = false;
9021 }
9022
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009023 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009024 isolate_->global_handles()->Destroy(
9025 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009026 }
9027
9028 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009029 storage_ = Handle<FixedArray>::cast(
9030 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009031 }
9032
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009033 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009034 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009035 // Index after last seen index. Always less than or equal to
9036 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009037 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009038 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009039};
9040
9041
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009042static uint32_t EstimateElementCount(Handle<JSArray> array) {
9043 uint32_t length = static_cast<uint32_t>(array->length()->Number());
9044 int element_count = 0;
9045 switch (array->GetElementsKind()) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009046 case JSObject::FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009047 // Fast elements can't have lengths that are not representable by
9048 // a 32-bit signed integer.
9049 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
9050 int fast_length = static_cast<int>(length);
9051 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
9052 for (int i = 0; i < fast_length; i++) {
9053 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009054 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009055 break;
9056 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009057 case JSObject::DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009058 Handle<NumberDictionary> dictionary(
9059 NumberDictionary::cast(array->elements()));
9060 int capacity = dictionary->Capacity();
9061 for (int i = 0; i < capacity; i++) {
9062 Handle<Object> key(dictionary->KeyAt(i));
9063 if (dictionary->IsKey(*key)) {
9064 element_count++;
9065 }
9066 }
9067 break;
9068 }
9069 default:
9070 // External arrays are always dense.
9071 return length;
9072 }
9073 // As an estimate, we assume that the prototype doesn't contain any
9074 // inherited elements.
9075 return element_count;
9076}
9077
9078
9079
9080template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009081static void IterateExternalArrayElements(Isolate* isolate,
9082 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009083 bool elements_are_ints,
9084 bool elements_are_guaranteed_smis,
9085 ArrayConcatVisitor* visitor) {
9086 Handle<ExternalArrayClass> array(
9087 ExternalArrayClass::cast(receiver->elements()));
9088 uint32_t len = static_cast<uint32_t>(array->length());
9089
9090 ASSERT(visitor != NULL);
9091 if (elements_are_ints) {
9092 if (elements_are_guaranteed_smis) {
9093 for (uint32_t j = 0; j < len; j++) {
9094 HandleScope loop_scope;
9095 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get(j))));
9096 visitor->visit(j, e);
9097 }
9098 } else {
9099 for (uint32_t j = 0; j < len; j++) {
9100 HandleScope loop_scope;
9101 int64_t val = static_cast<int64_t>(array->get(j));
9102 if (Smi::IsValid(static_cast<intptr_t>(val))) {
9103 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
9104 visitor->visit(j, e);
9105 } else {
9106 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009107 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009108 visitor->visit(j, e);
9109 }
9110 }
9111 }
9112 } else {
9113 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009114 HandleScope loop_scope(isolate);
9115 Handle<Object> e = isolate->factory()->NewNumber(array->get(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009116 visitor->visit(j, e);
9117 }
9118 }
9119}
9120
9121
9122// Used for sorting indices in a List<uint32_t>.
9123static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
9124 uint32_t a = *ap;
9125 uint32_t b = *bp;
9126 return (a == b) ? 0 : (a < b) ? -1 : 1;
9127}
9128
9129
9130static void CollectElementIndices(Handle<JSObject> object,
9131 uint32_t range,
9132 List<uint32_t>* indices) {
9133 JSObject::ElementsKind kind = object->GetElementsKind();
9134 switch (kind) {
9135 case JSObject::FAST_ELEMENTS: {
9136 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
9137 uint32_t length = static_cast<uint32_t>(elements->length());
9138 if (range < length) length = range;
9139 for (uint32_t i = 0; i < length; i++) {
9140 if (!elements->get(i)->IsTheHole()) {
9141 indices->Add(i);
9142 }
9143 }
9144 break;
9145 }
9146 case JSObject::DICTIONARY_ELEMENTS: {
9147 Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009148 uint32_t capacity = dict->Capacity();
9149 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009150 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009151 Handle<Object> k(dict->KeyAt(j));
9152 if (dict->IsKey(*k)) {
9153 ASSERT(k->IsNumber());
9154 uint32_t index = static_cast<uint32_t>(k->Number());
9155 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009156 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009157 }
9158 }
9159 }
9160 break;
9161 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009162 default: {
9163 int dense_elements_length;
9164 switch (kind) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009165 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009166 dense_elements_length =
9167 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009168 break;
9169 }
9170 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009171 dense_elements_length =
9172 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009173 break;
9174 }
9175 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009176 dense_elements_length =
9177 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009178 break;
9179 }
9180 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009181 dense_elements_length =
9182 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009183 break;
9184 }
9185 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009186 dense_elements_length =
9187 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009188 break;
9189 }
9190 case JSObject::EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009191 dense_elements_length =
9192 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009193 break;
9194 }
9195 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009196 dense_elements_length =
9197 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009198 break;
9199 }
9200 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009201 dense_elements_length =
9202 ExternalFloatArray::cast(object->elements())->length();
9203 break;
9204 }
9205 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
9206 dense_elements_length =
9207 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009208 break;
9209 }
9210 default:
9211 UNREACHABLE();
9212 dense_elements_length = 0;
9213 break;
9214 }
9215 uint32_t length = static_cast<uint32_t>(dense_elements_length);
9216 if (range <= length) {
9217 length = range;
9218 // We will add all indices, so we might as well clear it first
9219 // and avoid duplicates.
9220 indices->Clear();
9221 }
9222 for (uint32_t i = 0; i < length; i++) {
9223 indices->Add(i);
9224 }
9225 if (length == range) return; // All indices accounted for already.
9226 break;
9227 }
9228 }
9229
9230 Handle<Object> prototype(object->GetPrototype());
9231 if (prototype->IsJSObject()) {
9232 // The prototype will usually have no inherited element indices,
9233 // but we have to check.
9234 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
9235 }
9236}
9237
9238
9239/**
9240 * A helper function that visits elements of a JSArray in numerical
9241 * order.
9242 *
9243 * The visitor argument called for each existing element in the array
9244 * with the element index and the element's value.
9245 * Afterwards it increments the base-index of the visitor by the array
9246 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009247 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009248 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009249static bool IterateElements(Isolate* isolate,
9250 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009251 ArrayConcatVisitor* visitor) {
9252 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
9253 switch (receiver->GetElementsKind()) {
9254 case JSObject::FAST_ELEMENTS: {
9255 // Run through the elements FixedArray and use HasElement and GetElement
9256 // to check the prototype for missing elements.
9257 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
9258 int fast_length = static_cast<int>(length);
9259 ASSERT(fast_length <= elements->length());
9260 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009261 HandleScope loop_scope(isolate);
9262 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009263 if (!element_value->IsTheHole()) {
9264 visitor->visit(j, element_value);
9265 } else if (receiver->HasElement(j)) {
9266 // Call GetElement on receiver, not its prototype, or getters won't
9267 // have the correct receiver.
9268 element_value = GetElement(receiver, j);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009269 if (element_value.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009270 visitor->visit(j, element_value);
9271 }
9272 }
9273 break;
9274 }
9275 case JSObject::DICTIONARY_ELEMENTS: {
9276 Handle<NumberDictionary> dict(receiver->element_dictionary());
9277 List<uint32_t> indices(dict->Capacity() / 2);
9278 // Collect all indices in the object and the prototypes less
9279 // than length. This might introduce duplicates in the indices list.
9280 CollectElementIndices(receiver, length, &indices);
9281 indices.Sort(&compareUInt32);
9282 int j = 0;
9283 int n = indices.length();
9284 while (j < n) {
9285 HandleScope loop_scope;
9286 uint32_t index = indices[j];
9287 Handle<Object> element = GetElement(receiver, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009288 if (element.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009289 visitor->visit(index, element);
9290 // Skip to next different index (i.e., omit duplicates).
9291 do {
9292 j++;
9293 } while (j < n && indices[j] == index);
9294 }
9295 break;
9296 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009297 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
9298 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
9299 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009300 for (uint32_t j = 0; j < length; j++) {
9301 Handle<Smi> e(Smi::FromInt(pixels->get(j)));
9302 visitor->visit(j, e);
9303 }
9304 break;
9305 }
9306 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
9307 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009308 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009309 break;
9310 }
9311 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
9312 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009313 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009314 break;
9315 }
9316 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
9317 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009318 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009319 break;
9320 }
9321 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
9322 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009323 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009324 break;
9325 }
9326 case JSObject::EXTERNAL_INT_ELEMENTS: {
9327 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009328 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009329 break;
9330 }
9331 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
9332 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009333 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009334 break;
9335 }
9336 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
9337 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009338 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009339 break;
9340 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009341 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
9342 IterateExternalArrayElements<ExternalDoubleArray, double>(
9343 isolate, receiver, false, false, visitor);
9344 break;
9345 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009346 default:
9347 UNREACHABLE();
9348 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009349 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009350 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009351 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009352}
9353
9354
9355/**
9356 * Array::concat implementation.
9357 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009358 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009359 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009360 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009361RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009362 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009363 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009364
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009365 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
9366 int argument_count = static_cast<int>(arguments->length()->Number());
9367 RUNTIME_ASSERT(arguments->HasFastElements());
9368 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009369
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009370 // Pass 1: estimate the length and number of elements of the result.
9371 // The actual length can be larger if any of the arguments have getters
9372 // that mutate other arguments (but will otherwise be precise).
9373 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009374
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009375 uint32_t estimate_result_length = 0;
9376 uint32_t estimate_nof_elements = 0;
9377 {
9378 for (int i = 0; i < argument_count; i++) {
9379 HandleScope loop_scope;
9380 Handle<Object> obj(elements->get(i));
9381 uint32_t length_estimate;
9382 uint32_t element_estimate;
9383 if (obj->IsJSArray()) {
9384 Handle<JSArray> array(Handle<JSArray>::cast(obj));
9385 length_estimate =
9386 static_cast<uint32_t>(array->length()->Number());
9387 element_estimate =
9388 EstimateElementCount(array);
9389 } else {
9390 length_estimate = 1;
9391 element_estimate = 1;
9392 }
9393 // Avoid overflows by capping at kMaxElementCount.
9394 if (JSObject::kMaxElementCount - estimate_result_length <
9395 length_estimate) {
9396 estimate_result_length = JSObject::kMaxElementCount;
9397 } else {
9398 estimate_result_length += length_estimate;
9399 }
9400 if (JSObject::kMaxElementCount - estimate_nof_elements <
9401 element_estimate) {
9402 estimate_nof_elements = JSObject::kMaxElementCount;
9403 } else {
9404 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009405 }
9406 }
9407 }
9408
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009409 // If estimated number of elements is more than half of length, a
9410 // fixed array (fast case) is more time and space-efficient than a
9411 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009412 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009413
9414 Handle<FixedArray> storage;
9415 if (fast_case) {
9416 // The backing storage array must have non-existing elements to
9417 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009418 storage = isolate->factory()->NewFixedArrayWithHoles(
9419 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009420 } else {
9421 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
9422 uint32_t at_least_space_for = estimate_nof_elements +
9423 (estimate_nof_elements >> 2);
9424 storage = Handle<FixedArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009425 isolate->factory()->NewNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009426 }
9427
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009428 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009429
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009430 for (int i = 0; i < argument_count; i++) {
9431 Handle<Object> obj(elements->get(i));
9432 if (obj->IsJSArray()) {
9433 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009434 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009435 return Failure::Exception();
9436 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009437 } else {
9438 visitor.visit(0, obj);
9439 visitor.increase_index_offset(1);
9440 }
9441 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009442
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009443 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009444}
9445
9446
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009447// This will not allocate (flatten the string), but it may run
9448// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009449RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009450 NoHandleAllocation ha;
9451 ASSERT(args.length() == 1);
9452
9453 CONVERT_CHECKED(String, string, args[0]);
9454 StringInputBuffer buffer(string);
9455 while (buffer.has_more()) {
9456 uint16_t character = buffer.GetNext();
9457 PrintF("%c", character);
9458 }
9459 return string;
9460}
9461
ager@chromium.org5ec48922009-05-05 07:25:34 +00009462// Moves all own elements of an object, that are below a limit, to positions
9463// starting at zero. All undefined values are placed after non-undefined values,
9464// and are followed by non-existing element. Does not change the length
9465// property.
9466// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009467RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00009468 ASSERT(args.length() == 2);
9469 CONVERT_CHECKED(JSObject, object, args[0]);
9470 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
9471 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009472}
9473
9474
9475// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009476RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009477 ASSERT(args.length() == 2);
9478 CONVERT_CHECKED(JSArray, from, args[0]);
9479 CONVERT_CHECKED(JSArray, to, args[1]);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009480 HeapObject* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00009481 MaybeObject* maybe_new_map;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009482 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
9483 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009484 maybe_new_map = to->map()->GetFastElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009485 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009486 maybe_new_map = to->map()->GetSlowElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009487 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009488 Object* new_map;
9489 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009490 to->set_map(Map::cast(new_map));
9491 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009492 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009493 Object* obj;
9494 { MaybeObject* maybe_obj = from->ResetElements();
9495 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9496 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009497 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009498 return to;
9499}
9500
9501
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009502// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009503RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009504 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009505 CONVERT_CHECKED(JSObject, object, args[0]);
9506 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009507 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009508 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009509 } else if (object->IsJSArray()) {
9510 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009511 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009512 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009513 }
9514}
9515
9516
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009517RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009518 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009519
9520 ASSERT_EQ(3, args.length());
9521
ager@chromium.orgac091b72010-05-05 07:34:42 +00009522 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009523 Handle<Object> key1 = args.at<Object>(1);
9524 Handle<Object> key2 = args.at<Object>(2);
9525
9526 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009527 if (!key1->ToArrayIndex(&index1)
9528 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009529 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009530 }
9531
ager@chromium.orgac091b72010-05-05 07:34:42 +00009532 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
9533 Handle<Object> tmp1 = GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009534 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009535 Handle<Object> tmp2 = GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009536 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009537
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009538 RETURN_IF_EMPTY_HANDLE(isolate,
9539 SetElement(jsobject, index1, tmp2, kStrictMode));
9540 RETURN_IF_EMPTY_HANDLE(isolate,
9541 SetElement(jsobject, index2, tmp1, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +00009542
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009543 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009544}
9545
9546
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009547// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009548// might have elements. Can either return keys (positive integers) or
9549// intervals (pair of a negative integer (-start-1) followed by a
9550// positive (length)) or undefined values.
9551// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009552RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009553 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009554 HandleScope scope(isolate);
ager@chromium.org5ec48922009-05-05 07:25:34 +00009555 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009556 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009557 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009558 // Create an array and get all the keys into it, then remove all the
9559 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009560 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009561 int keys_length = keys->length();
9562 for (int i = 0; i < keys_length; i++) {
9563 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009564 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009565 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009566 // Zap invalid keys.
9567 keys->set_undefined(i);
9568 }
9569 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009570 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009571 } else {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009572 ASSERT(array->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009573 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009574 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009575 single_interval->set(0, Smi::FromInt(-1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009576 uint32_t actual_length =
9577 static_cast<uint32_t>(FixedArray::cast(array->elements())->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +00009578 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009579 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009580 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009581 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009582 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009583 }
9584}
9585
9586
9587// DefineAccessor takes an optional final argument which is the
9588// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
9589// to the way accessors are implemented, it is set for both the getter
9590// and setter on the first call to DefineAccessor and ignored on
9591// subsequent calls.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009592RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009593 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
9594 // Compute attributes.
9595 PropertyAttributes attributes = NONE;
9596 if (args.length() == 5) {
9597 CONVERT_CHECKED(Smi, attrs, args[4]);
9598 int value = attrs->value();
9599 // Only attribute bits should be set.
9600 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
9601 attributes = static_cast<PropertyAttributes>(value);
9602 }
9603
9604 CONVERT_CHECKED(JSObject, obj, args[0]);
9605 CONVERT_CHECKED(String, name, args[1]);
9606 CONVERT_CHECKED(Smi, flag, args[2]);
9607 CONVERT_CHECKED(JSFunction, fun, args[3]);
9608 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
9609}
9610
9611
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009612RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009613 ASSERT(args.length() == 3);
9614 CONVERT_CHECKED(JSObject, obj, args[0]);
9615 CONVERT_CHECKED(String, name, args[1]);
9616 CONVERT_CHECKED(Smi, flag, args[2]);
9617 return obj->LookupAccessor(name, flag->value() == 0);
9618}
9619
9620
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009621#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009622RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009623 ASSERT(args.length() == 0);
9624 return Execution::DebugBreakHelper();
9625}
9626
9627
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009628// Helper functions for wrapping and unwrapping stack frame ids.
9629static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009630 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009631 return Smi::FromInt(id >> 2);
9632}
9633
9634
9635static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
9636 return static_cast<StackFrame::Id>(wrapped->value() << 2);
9637}
9638
9639
9640// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00009641// args[0]: debug event listener function to set or null or undefined for
9642// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009643// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009644RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009645 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009646 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
9647 args[0]->IsUndefined() ||
9648 args[0]->IsNull());
9649 Handle<Object> callback = args.at<Object>(0);
9650 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009651 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009652
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009653 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009654}
9655
9656
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009657RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +00009658 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009659 isolate->stack_guard()->DebugBreak();
9660 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009661}
9662
9663
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009664static MaybeObject* DebugLookupResultValue(Heap* heap,
9665 Object* receiver,
9666 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +00009667 LookupResult* result,
9668 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009669 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009670 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009671 case NORMAL:
9672 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009673 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009674 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009675 }
9676 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009677 case FIELD:
9678 value =
9679 JSObject::cast(
9680 result->holder())->FastPropertyAt(result->GetFieldIndex());
9681 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009682 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009683 }
9684 return value;
9685 case CONSTANT_FUNCTION:
9686 return result->GetConstantFunction();
9687 case CALLBACKS: {
9688 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00009689 if (structure->IsForeign() || structure->IsAccessorInfo()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009690 MaybeObject* maybe_value = receiver->GetPropertyWithCallback(
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009691 receiver, structure, name, result->holder());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009692 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009693 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009694 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009695 maybe_value = heap->isolate()->pending_exception();
9696 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009697 if (caught_exception != NULL) {
9698 *caught_exception = true;
9699 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009700 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009701 }
9702 return value;
9703 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009704 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009705 }
9706 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009707 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009708 case MAP_TRANSITION:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00009709 case EXTERNAL_ARRAY_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009710 case CONSTANT_TRANSITION:
9711 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009712 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009713 default:
9714 UNREACHABLE();
9715 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009716 UNREACHABLE();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009717 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009718}
9719
9720
ager@chromium.org32912102009-01-16 10:38:43 +00009721// Get debugger related details for an object property.
9722// args[0]: object holding property
9723// args[1]: name of the property
9724//
9725// The array returned contains the following information:
9726// 0: Property value
9727// 1: Property details
9728// 2: Property value is exception
9729// 3: Getter function if defined
9730// 4: Setter function if defined
9731// Items 2-4 are only filled if the property has either a getter or a setter
9732// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009733RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009734 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009735
9736 ASSERT(args.length() == 2);
9737
9738 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9739 CONVERT_ARG_CHECKED(String, name, 1);
9740
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009741 // Make sure to set the current context to the context before the debugger was
9742 // entered (if the debugger is entered). The reason for switching context here
9743 // is that for some property lookups (accessors and interceptors) callbacks
9744 // into the embedding application can occour, and the embedding application
9745 // could have the assumption that its own global context is the current
9746 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009747 SaveContext save(isolate);
9748 if (isolate->debug()->InDebugger()) {
9749 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009750 }
9751
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009752 // Skip the global proxy as it has no properties and always delegates to the
9753 // real global object.
9754 if (obj->IsJSGlobalProxy()) {
9755 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
9756 }
9757
9758
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009759 // Check if the name is trivially convertible to an index and get the element
9760 // if so.
9761 uint32_t index;
9762 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009763 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009764 Object* element_or_char;
9765 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009766 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009767 if (!maybe_element_or_char->ToObject(&element_or_char)) {
9768 return maybe_element_or_char;
9769 }
9770 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00009771 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009772 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009773 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009774 }
9775
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009776 // Find the number of objects making up this.
9777 int length = LocalPrototypeChainLength(*obj);
9778
9779 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009780 Handle<JSObject> jsproto = obj;
9781 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009782 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009783 jsproto->LocalLookup(*name, &result);
9784 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009785 // LookupResult is not GC safe as it holds raw object pointers.
9786 // GC can happen later in this code so put the required fields into
9787 // local variables using handles when required for later use.
9788 PropertyType result_type = result.type();
9789 Handle<Object> result_callback_obj;
9790 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009791 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
9792 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009793 }
9794 Smi* property_details = result.GetPropertyDetails().AsSmi();
9795 // DebugLookupResultValue can cause GC so details from LookupResult needs
9796 // to be copied to handles before this.
9797 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009798 Object* raw_value;
9799 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009800 DebugLookupResultValue(isolate->heap(), *obj, *name,
9801 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009802 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
9803 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009804 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009805
9806 // If the callback object is a fixed array then it contains JavaScript
9807 // getter and/or setter.
9808 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
9809 result_callback_obj->IsFixedArray();
9810 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009811 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009812 details->set(0, *value);
9813 details->set(1, property_details);
9814 if (hasJavaScriptAccessors) {
9815 details->set(2,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009816 caught_exception ? isolate->heap()->true_value()
9817 : isolate->heap()->false_value());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009818 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
9819 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
9820 }
9821
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009822 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009823 }
9824 if (i < length - 1) {
9825 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
9826 }
9827 }
9828
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009829 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009830}
9831
9832
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009833RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009834 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009835
9836 ASSERT(args.length() == 2);
9837
9838 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9839 CONVERT_ARG_CHECKED(String, name, 1);
9840
9841 LookupResult result;
9842 obj->Lookup(*name, &result);
9843 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009844 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009845 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009846 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009847}
9848
9849
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009850// Return the property type calculated from the property details.
9851// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009852RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009853 ASSERT(args.length() == 1);
9854 CONVERT_CHECKED(Smi, details, args[0]);
9855 PropertyType type = PropertyDetails(details).type();
9856 return Smi::FromInt(static_cast<int>(type));
9857}
9858
9859
9860// Return the property attribute calculated from the property details.
9861// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009862RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009863 ASSERT(args.length() == 1);
9864 CONVERT_CHECKED(Smi, details, args[0]);
9865 PropertyAttributes attributes = PropertyDetails(details).attributes();
9866 return Smi::FromInt(static_cast<int>(attributes));
9867}
9868
9869
9870// Return the property insertion index calculated from the property details.
9871// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009872RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009873 ASSERT(args.length() == 1);
9874 CONVERT_CHECKED(Smi, details, args[0]);
9875 int index = PropertyDetails(details).index();
9876 return Smi::FromInt(index);
9877}
9878
9879
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009880// Return property value from named interceptor.
9881// args[0]: object
9882// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009883RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009884 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009885 ASSERT(args.length() == 2);
9886 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9887 RUNTIME_ASSERT(obj->HasNamedInterceptor());
9888 CONVERT_ARG_CHECKED(String, name, 1);
9889
9890 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009891 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009892}
9893
9894
9895// Return element value from indexed interceptor.
9896// args[0]: object
9897// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009898RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009899 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009900 ASSERT(args.length() == 2);
9901 CONVERT_ARG_CHECKED(JSObject, obj, 0);
9902 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
9903 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
9904
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009905 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009906}
9907
9908
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009909RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009910 ASSERT(args.length() >= 1);
9911 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +00009912 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009913 if (isolate->debug()->break_id() == 0 ||
9914 break_id != isolate->debug()->break_id()) {
9915 return isolate->Throw(
9916 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009917 }
9918
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009919 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009920}
9921
9922
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009923RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009924 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009925 ASSERT(args.length() == 1);
9926
9927 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009928 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009929 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
9930 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +00009931 if (!maybe_result->ToObject(&result)) return maybe_result;
9932 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009933
9934 // Count all frames which are relevant to debugging stack trace.
9935 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009936 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009937 if (id == StackFrame::NO_ID) {
9938 // If there is no JavaScript stack frame count is 0.
9939 return Smi::FromInt(0);
9940 }
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009941 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) n++;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009942 return Smi::FromInt(n);
9943}
9944
9945
9946static const int kFrameDetailsFrameIdIndex = 0;
9947static const int kFrameDetailsReceiverIndex = 1;
9948static const int kFrameDetailsFunctionIndex = 2;
9949static const int kFrameDetailsArgumentCountIndex = 3;
9950static const int kFrameDetailsLocalCountIndex = 4;
9951static const int kFrameDetailsSourcePositionIndex = 5;
9952static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009953static const int kFrameDetailsAtReturnIndex = 7;
9954static const int kFrameDetailsDebuggerFrameIndex = 8;
9955static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009956
9957// Return an array with frame details
9958// args[0]: number: break id
9959// args[1]: number: frame index
9960//
9961// The array returned contains the following information:
9962// 0: Frame id
9963// 1: Receiver
9964// 2: Function
9965// 3: Argument count
9966// 4: Local count
9967// 5: Source position
9968// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009969// 7: Is at return
9970// 8: Debugger frame
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009971// Arguments name, value
9972// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00009973// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009974RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009975 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009976 ASSERT(args.length() == 2);
9977
9978 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009979 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009980 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
9981 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +00009982 if (!maybe_check->ToObject(&check)) return maybe_check;
9983 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009984 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009985 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009986
9987 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009988 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009989 if (id == StackFrame::NO_ID) {
9990 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009991 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +00009992 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009993 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009994 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009995 for (; !it.done(); it.Advance()) {
9996 if (count == index) break;
9997 count++;
9998 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009999 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010000
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010001 bool is_optimized_frame =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010002 it.frame()->LookupCode()->kind() == Code::OPTIMIZED_FUNCTION;
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010003
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010004 // Traverse the saved contexts chain to find the active context for the
10005 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010006 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010007 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010008 save = save->prev();
10009 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010010 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010011
10012 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010013 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010014
10015 // Find source position.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010016 int position =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010017 it.frame()->LookupCode()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010018
10019 // Check for constructor frame.
10020 bool constructor = it.frame()->IsConstructor();
10021
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010022 // Get scope info and read from it for local variable information.
10023 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +000010024 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010025 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010026
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010027 // Get the locals names and values into a temporary array.
10028 //
10029 // TODO(1240907): Hide compiler-introduced stack variables
10030 // (e.g. .result)? For users of the debugger, they will probably be
10031 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010032 Handle<FixedArray> locals =
10033 isolate->factory()->NewFixedArray(info.NumberOfLocals() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010034
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010035 // Fill in the values of the locals.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010036 if (is_optimized_frame) {
10037 // If we are inspecting an optimized frame use undefined as the
10038 // value for all locals.
10039 //
10040 // TODO(1140): We should be able to get the correct values
10041 // for locals in optimized frames.
10042 for (int i = 0; i < info.NumberOfLocals(); i++) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010043 locals->set(i * 2, *info.LocalName(i));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010044 locals->set(i * 2 + 1, isolate->heap()->undefined_value());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010045 }
10046 } else {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010047 int i = 0;
10048 for (; i < info.number_of_stack_slots(); ++i) {
10049 // Use the value from the stack.
10050 locals->set(i * 2, *info.LocalName(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010051 locals->set(i * 2 + 1, it.frame()->GetExpression(i));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010052 }
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010053 // Get the context containing declarations.
10054 Handle<Context> context(
10055 Context::cast(it.frame()->context())->declaration_context());
10056 for (; i < info.NumberOfLocals(); ++i) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010057 Handle<String> name = info.LocalName(i);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010058 locals->set(i * 2, *name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010059 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010060 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010061 }
10062 }
10063
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010064 // Check whether this frame is positioned at return. If not top
10065 // frame or if the frame is optimized it cannot be at a return.
10066 bool at_return = false;
10067 if (!is_optimized_frame && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010068 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010069 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010070
10071 // If positioned just before return find the value to be returned and add it
10072 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010073 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010074 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010075 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010076 Address internal_frame_sp = NULL;
10077 while (!it2.done()) {
10078 if (it2.frame()->is_internal()) {
10079 internal_frame_sp = it2.frame()->sp();
10080 } else {
10081 if (it2.frame()->is_java_script()) {
10082 if (it2.frame()->id() == it.frame()->id()) {
10083 // The internal frame just before the JavaScript frame contains the
10084 // value to return on top. A debug break at return will create an
10085 // internal frame to store the return value (eax/rax/r0) before
10086 // entering the debug break exit frame.
10087 if (internal_frame_sp != NULL) {
10088 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010089 Handle<Object>(Memory::Object_at(internal_frame_sp),
10090 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010091 break;
10092 }
10093 }
10094 }
10095
10096 // Indicate that the previous frame was not an internal frame.
10097 internal_frame_sp = NULL;
10098 }
10099 it2.Advance();
10100 }
10101 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010102
10103 // Now advance to the arguments adapter frame (if any). It contains all
10104 // the provided parameters whereas the function frame always have the number
10105 // of arguments matching the functions parameters. The rest of the
10106 // information (except for what is collected above) is the same.
10107 it.AdvanceToArgumentsFrame();
10108
10109 // Find the number of arguments to fill. At least fill the number of
10110 // parameters for the function and fill more if more parameters are provided.
10111 int argument_count = info.number_of_parameters();
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000010112 if (argument_count < it.frame()->ComputeParametersCount()) {
10113 argument_count = it.frame()->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010114 }
10115
10116 // Calculate the size of the result.
10117 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010118 2 * (argument_count + info.NumberOfLocals()) +
10119 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010120 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010121
10122 // Add the frame id.
10123 details->set(kFrameDetailsFrameIdIndex, *frame_id);
10124
10125 // Add the function (same as in function frame).
10126 details->set(kFrameDetailsFunctionIndex, it.frame()->function());
10127
10128 // Add the arguments count.
10129 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
10130
10131 // Add the locals count
10132 details->set(kFrameDetailsLocalCountIndex,
10133 Smi::FromInt(info.NumberOfLocals()));
10134
10135 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +000010136 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010137 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
10138 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010139 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010140 }
10141
10142 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010143 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010144
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010145 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010146 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010147
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010148 // Add information on whether this frame is invoked in the debugger context.
10149 details->set(kFrameDetailsDebuggerFrameIndex,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010150 heap->ToBoolean(*save->context() ==
10151 *isolate->debug()->debug_context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010152
10153 // Fill the dynamic part.
10154 int details_index = kFrameDetailsFirstDynamicIndex;
10155
10156 // Add arguments name and value.
10157 for (int i = 0; i < argument_count; i++) {
10158 // Name of the argument.
10159 if (i < info.number_of_parameters()) {
10160 details->set(details_index++, *info.parameter_name(i));
10161 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010162 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010163 }
10164
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010165 // Parameter value. If we are inspecting an optimized frame, use
10166 // undefined as the value.
10167 //
10168 // TODO(3141533): We should be able to get the actual parameter
10169 // value for optimized frames.
10170 if (!is_optimized_frame &&
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000010171 (i < it.frame()->ComputeParametersCount())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010172 details->set(details_index++, it.frame()->GetParameter(i));
10173 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010174 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010175 }
10176 }
10177
10178 // Add locals name and value from the temporary copy from the function frame.
10179 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
10180 details->set(details_index++, locals->get(i));
10181 }
10182
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010183 // Add the value being returned.
10184 if (at_return) {
10185 details->set(details_index++, *return_value);
10186 }
10187
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010188 // Add the receiver (same as in function frame).
10189 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
10190 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010191 Handle<Object> receiver(it.frame()->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010192 if (!receiver->IsJSObject()) {
10193 // If the receiver is NOT a JSObject we have hit an optimization
10194 // where a value object is not converted into a wrapped JS objects.
10195 // To hide this optimization from the debugger, we wrap the receiver
10196 // by creating correct wrapper object based on the calling frame's
10197 // global context.
10198 it.Advance();
10199 Handle<Context> calling_frames_global_context(
10200 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010201 receiver =
10202 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010203 }
10204 details->set(kFrameDetailsReceiverIndex, *receiver);
10205
10206 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010207 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010208}
10209
10210
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010211// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010212static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010213 Isolate* isolate,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010214 Handle<SerializedScopeInfo> serialized_scope_info,
10215 ScopeInfo<>& scope_info,
10216 Handle<Context> context,
10217 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010218 // Fill all context locals to the context extension.
10219 for (int i = Context::MIN_CONTEXT_SLOTS;
10220 i < scope_info.number_of_context_slots();
10221 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +000010222 int context_index = serialized_scope_info->ContextSlotIndex(
10223 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010224
whesse@chromium.org7b260152011-06-20 15:33:18 +000010225 RETURN_IF_EMPTY_HANDLE_VALUE(
10226 isolate,
10227 SetProperty(scope_object,
10228 scope_info.context_slot_name(i),
10229 Handle<Object>(context->get(context_index), isolate),
10230 NONE,
10231 kNonStrictMode),
10232 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010233 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010234
10235 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010236}
10237
10238
10239// Create a plain JSObject which materializes the local scope for the specified
10240// frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010241static Handle<JSObject> MaterializeLocalScope(Isolate* isolate,
10242 JavaScriptFrame* frame) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010243 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010244 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +000010245 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
10246 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010247
10248 // Allocate and initialize a JSObject with all the arguments, stack locals
10249 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010250 Handle<JSObject> local_scope =
10251 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010252
10253 // First fill all parameters.
10254 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010255 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010256 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010257 SetProperty(local_scope,
10258 scope_info.parameter_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010259 Handle<Object>(frame->GetParameter(i), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010260 NONE,
10261 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010262 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010263 }
10264
10265 // Second fill all stack locals.
10266 for (int i = 0; i < scope_info.number_of_stack_slots(); i++) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010267 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010268 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010269 SetProperty(local_scope,
10270 scope_info.stack_slot_name(i),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010271 Handle<Object>(frame->GetExpression(i), isolate),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010272 NONE,
10273 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010274 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010275 }
10276
10277 // Third fill all context locals.
10278 Handle<Context> frame_context(Context::cast(frame->context()));
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010279 Handle<Context> function_context(frame_context->declaration_context());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010280 if (!CopyContextLocalsToScopeObject(isolate,
10281 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010282 function_context, local_scope)) {
10283 return Handle<JSObject>();
10284 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010285
10286 // Finally copy any properties from the function context extension. This will
10287 // be variables introduced by eval.
10288 if (function_context->closure() == *function) {
10289 if (function_context->has_extension() &&
10290 !function_context->IsGlobalContext()) {
10291 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010292 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010293 for (int i = 0; i < keys->length(); i++) {
10294 // Names of variables introduced by eval are strings.
10295 ASSERT(keys->get(i)->IsString());
10296 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010297 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010298 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010299 SetProperty(local_scope,
10300 key,
10301 GetProperty(ext, key),
10302 NONE,
10303 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010304 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010305 }
10306 }
10307 }
10308 return local_scope;
10309}
10310
10311
10312// Create a plain JSObject which materializes the closure content for the
10313// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010314static Handle<JSObject> MaterializeClosure(Isolate* isolate,
10315 Handle<Context> context) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010316 ASSERT(context->IsFunctionContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010317
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010318 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +000010319 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
10320 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010321
10322 // Allocate and initialize a JSObject with all the content of theis function
10323 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010324 Handle<JSObject> closure_scope =
10325 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010326
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010327 // Fill all context locals to the context extension.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010328 if (!CopyContextLocalsToScopeObject(isolate,
10329 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010330 context, closure_scope)) {
10331 return Handle<JSObject>();
10332 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010333
10334 // Finally copy any properties from the function context extension. This will
10335 // be variables introduced by eval.
10336 if (context->has_extension()) {
10337 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010338 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010339 for (int i = 0; i < keys->length(); i++) {
10340 // Names of variables introduced by eval are strings.
10341 ASSERT(keys->get(i)->IsString());
10342 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010343 RETURN_IF_EMPTY_HANDLE_VALUE(
10344 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010345 SetProperty(closure_scope,
10346 key,
10347 GetProperty(ext, key),
10348 NONE,
10349 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010350 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010351 }
10352 }
10353
10354 return closure_scope;
10355}
10356
10357
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010358// Create a plain JSObject which materializes the scope for the specified
10359// catch context.
10360static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
10361 Handle<Context> context) {
10362 ASSERT(context->IsCatchContext());
10363 Handle<String> name(String::cast(context->extension()));
10364 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX));
10365 Handle<JSObject> catch_scope =
10366 isolate->factory()->NewJSObject(isolate->object_function());
10367 RETURN_IF_EMPTY_HANDLE_VALUE(
10368 isolate,
10369 SetProperty(catch_scope, name, thrown_object, NONE, kNonStrictMode),
10370 Handle<JSObject>());
10371 return catch_scope;
10372}
10373
10374
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010375// Iterate over the actual scopes visible from a stack frame. All scopes are
10376// backed by an actual context except the local scope, which is inserted
10377// "artifically" in the context chain.
10378class ScopeIterator {
10379 public:
10380 enum ScopeType {
10381 ScopeTypeGlobal = 0,
10382 ScopeTypeLocal,
10383 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000010384 ScopeTypeClosure,
ager@chromium.orga1645e22009-09-09 19:27:10 +000010385 ScopeTypeCatch
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010386 };
10387
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010388 ScopeIterator(Isolate* isolate, JavaScriptFrame* frame)
10389 : isolate_(isolate),
10390 frame_(frame),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010391 function_(JSFunction::cast(frame->function())),
10392 context_(Context::cast(frame->context())),
10393 local_done_(false),
10394 at_local_(false) {
10395
10396 // Check whether the first scope is actually a local scope.
10397 if (context_->IsGlobalContext()) {
10398 // If there is a stack slot for .result then this local scope has been
10399 // created for evaluating top level code and it is not a real local scope.
10400 // Checking for the existence of .result seems fragile, but the scope info
10401 // saved with the code object does not otherwise have that information.
ager@chromium.orgb5737492010-07-15 09:29:43 +000010402 int index = function_->shared()->scope_info()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010403 StackSlotIndex(isolate_->heap()->result_symbol());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010404 at_local_ = index < 0;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010405 } else if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010406 at_local_ = true;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010407 } else if (context_->closure() != *function_) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010408 // The context_ is a with or catch block from the outer function.
10409 ASSERT(context_->IsWithContext() || context_->IsCatchContext());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010410 at_local_ = true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010411 }
10412 }
10413
10414 // More scopes?
10415 bool Done() { return context_.is_null(); }
10416
10417 // Move to the next scope.
10418 void Next() {
10419 // If at a local scope mark the local scope as passed.
10420 if (at_local_) {
10421 at_local_ = false;
10422 local_done_ = true;
10423
10424 // If the current context is not associated with the local scope the
10425 // current context is the next real scope, so don't move to the next
10426 // context in this case.
10427 if (context_->closure() != *function_) {
10428 return;
10429 }
10430 }
10431
10432 // The global scope is always the last in the chain.
10433 if (context_->IsGlobalContext()) {
10434 context_ = Handle<Context>();
10435 return;
10436 }
10437
10438 // Move to the next context.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010439 context_ = Handle<Context>(context_->previous(), isolate_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010440
10441 // If passing the local scope indicate that the current scope is now the
10442 // local scope.
10443 if (!local_done_ &&
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010444 (context_->IsGlobalContext() || context_->IsFunctionContext())) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010445 at_local_ = true;
10446 }
10447 }
10448
10449 // Return the type of the current scope.
10450 int Type() {
10451 if (at_local_) {
10452 return ScopeTypeLocal;
10453 }
10454 if (context_->IsGlobalContext()) {
10455 ASSERT(context_->global()->IsGlobalObject());
10456 return ScopeTypeGlobal;
10457 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010458 if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010459 return ScopeTypeClosure;
10460 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010461 if (context_->IsCatchContext()) {
ager@chromium.orga1645e22009-09-09 19:27:10 +000010462 return ScopeTypeCatch;
10463 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010464 ASSERT(context_->IsWithContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010465 return ScopeTypeWith;
10466 }
10467
10468 // Return the JavaScript object with the content of the current scope.
10469 Handle<JSObject> ScopeObject() {
10470 switch (Type()) {
10471 case ScopeIterator::ScopeTypeGlobal:
10472 return Handle<JSObject>(CurrentContext()->global());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010473 case ScopeIterator::ScopeTypeLocal:
10474 // Materialize the content of the local scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010475 return MaterializeLocalScope(isolate_, frame_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010476 case ScopeIterator::ScopeTypeWith:
10477 // Return the with object.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010478 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
10479 case ScopeIterator::ScopeTypeCatch:
10480 return MaterializeCatchScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010481 case ScopeIterator::ScopeTypeClosure:
10482 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010483 return MaterializeClosure(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010484 }
10485 UNREACHABLE();
10486 return Handle<JSObject>();
10487 }
10488
10489 // Return the context for this scope. For the local context there might not
10490 // be an actual context.
10491 Handle<Context> CurrentContext() {
10492 if (at_local_ && context_->closure() != *function_) {
10493 return Handle<Context>();
10494 }
10495 return context_;
10496 }
10497
10498#ifdef DEBUG
10499 // Debug print of the content of the current scope.
10500 void DebugPrint() {
10501 switch (Type()) {
10502 case ScopeIterator::ScopeTypeGlobal:
10503 PrintF("Global:\n");
10504 CurrentContext()->Print();
10505 break;
10506
10507 case ScopeIterator::ScopeTypeLocal: {
10508 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010509 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010510 scope_info.Print();
10511 if (!CurrentContext().is_null()) {
10512 CurrentContext()->Print();
10513 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010514 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010515 if (extension->IsJSContextExtensionObject()) {
10516 extension->Print();
10517 }
10518 }
10519 }
10520 break;
10521 }
10522
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010523 case ScopeIterator::ScopeTypeWith:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010524 PrintF("With:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010525 CurrentContext()->extension()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010526 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010527
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010528 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orga1645e22009-09-09 19:27:10 +000010529 PrintF("Catch:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010530 CurrentContext()->extension()->Print();
10531 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
ager@chromium.orga1645e22009-09-09 19:27:10 +000010532 break;
ager@chromium.orga1645e22009-09-09 19:27:10 +000010533
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010534 case ScopeIterator::ScopeTypeClosure:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010535 PrintF("Closure:\n");
10536 CurrentContext()->Print();
10537 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010538 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010539 if (extension->IsJSContextExtensionObject()) {
10540 extension->Print();
10541 }
10542 }
10543 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010544
10545 default:
10546 UNREACHABLE();
10547 }
10548 PrintF("\n");
10549 }
10550#endif
10551
10552 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010553 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010554 JavaScriptFrame* frame_;
10555 Handle<JSFunction> function_;
10556 Handle<Context> context_;
10557 bool local_done_;
10558 bool at_local_;
10559
10560 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
10561};
10562
10563
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010564RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010565 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010566 ASSERT(args.length() == 2);
10567
10568 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010569 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010570 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10571 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010572 if (!maybe_check->ToObject(&check)) return maybe_check;
10573 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010574 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10575
10576 // Get the frame where the debugging is performed.
10577 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010578 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010579 JavaScriptFrame* frame = it.frame();
10580
10581 // Count the visible scopes.
10582 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010583 for (ScopeIterator it(isolate, frame); !it.Done(); it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010584 n++;
10585 }
10586
10587 return Smi::FromInt(n);
10588}
10589
10590
10591static const int kScopeDetailsTypeIndex = 0;
10592static const int kScopeDetailsObjectIndex = 1;
10593static const int kScopeDetailsSize = 2;
10594
10595// Return an array with scope details
10596// args[0]: number: break id
10597// args[1]: number: frame index
10598// args[2]: number: scope index
10599//
10600// The array returned contains the following information:
10601// 0: Scope type
10602// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010603RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010604 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010605 ASSERT(args.length() == 3);
10606
10607 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010608 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010609 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10610 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010611 if (!maybe_check->ToObject(&check)) return maybe_check;
10612 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010613 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10614 CONVERT_NUMBER_CHECKED(int, index, Int32, args[2]);
10615
10616 // Get the frame where the debugging is performed.
10617 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010618 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010619 JavaScriptFrame* frame = frame_it.frame();
10620
10621 // Find the requested scope.
10622 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010623 ScopeIterator it(isolate, frame);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010624 for (; !it.Done() && n < index; it.Next()) {
10625 n++;
10626 }
10627 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010628 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010629 }
10630
10631 // Calculate the size of the result.
10632 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010633 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010634
10635 // Fill in scope details.
10636 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010637 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010638 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010639 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010640
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010641 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010642}
10643
10644
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010645RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010646 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010647 ASSERT(args.length() == 0);
10648
10649#ifdef DEBUG
10650 // Print the scopes for the top frame.
10651 StackFrameLocator locator;
10652 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010653 for (ScopeIterator it(isolate, frame); !it.Done(); it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010654 it.DebugPrint();
10655 }
10656#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010657 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010658}
10659
10660
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010661RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010662 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010663 ASSERT(args.length() == 1);
10664
10665 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010666 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010667 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10668 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010669 if (!maybe_result->ToObject(&result)) return maybe_result;
10670 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010671
10672 // Count all archived V8 threads.
10673 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010674 for (ThreadState* thread =
10675 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010676 thread != NULL;
10677 thread = thread->Next()) {
10678 n++;
10679 }
10680
10681 // Total number of threads is current thread and archived threads.
10682 return Smi::FromInt(n + 1);
10683}
10684
10685
10686static const int kThreadDetailsCurrentThreadIndex = 0;
10687static const int kThreadDetailsThreadIdIndex = 1;
10688static const int kThreadDetailsSize = 2;
10689
10690// Return an array with thread details
10691// args[0]: number: break id
10692// args[1]: number: thread index
10693//
10694// The array returned contains the following information:
10695// 0: Is current thread?
10696// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010697RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010698 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010699 ASSERT(args.length() == 2);
10700
10701 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010702 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010703 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10704 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010705 if (!maybe_check->ToObject(&check)) return maybe_check;
10706 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010707 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
10708
10709 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010710 Handle<FixedArray> details =
10711 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010712
10713 // Thread index 0 is current thread.
10714 if (index == 0) {
10715 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010716 details->set(kThreadDetailsCurrentThreadIndex,
10717 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010718 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010719 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010720 } else {
10721 // Find the thread with the requested index.
10722 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010723 ThreadState* thread =
10724 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010725 while (index != n && thread != NULL) {
10726 thread = thread->Next();
10727 n++;
10728 }
10729 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010730 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010731 }
10732
10733 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010734 details->set(kThreadDetailsCurrentThreadIndex,
10735 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000010736 details->set(kThreadDetailsThreadIdIndex,
10737 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010738 }
10739
10740 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010741 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000010742}
10743
10744
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010745// Sets the disable break state
10746// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010747RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010748 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010749 ASSERT(args.length() == 1);
10750 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010751 isolate->debug()->set_disable_break(disable_break);
10752 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000010753}
10754
10755
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010756RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010757 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010758 ASSERT(args.length() == 1);
10759
ager@chromium.org5aa501c2009-06-23 07:57:28 +000010760 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
10761 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010762 // Find the number of break points
10763 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010764 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010765 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010766 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010767 Handle<FixedArray>::cast(break_locations));
10768}
10769
10770
10771// Set a break point in a function
10772// args[0]: function
10773// args[1]: number: break source position (within the function source)
10774// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010775RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010776 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010777 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000010778 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
10779 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010780 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10781 RUNTIME_ASSERT(source_position >= 0);
10782 Handle<Object> break_point_object_arg = args.at<Object>(2);
10783
10784 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010785 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
10786 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010787
lrn@chromium.org32d961d2010-06-30 09:09:34 +000010788 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010789}
10790
10791
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010792Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
10793 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000010794 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010795 // Iterate the heap looking for SharedFunctionInfo generated from the
10796 // script. The inner most SharedFunctionInfo containing the source position
10797 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010798 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010799 // which is found is not compiled it is compiled and the heap is iterated
10800 // again as the compilation might create inner functions from the newly
10801 // compiled function and the actual requested break point might be in one of
10802 // these functions.
10803 bool done = false;
10804 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000010805 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010806 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010807 while (!done) {
10808 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010809 for (HeapObject* obj = iterator.next();
10810 obj != NULL; obj = iterator.next()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010811 if (obj->IsSharedFunctionInfo()) {
10812 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
10813 if (shared->script() == *script) {
10814 // If the SharedFunctionInfo found has the requested script data and
10815 // contains the source position it is a candidate.
10816 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +000010817 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010818 start_position = shared->start_position();
10819 }
10820 if (start_position <= position &&
10821 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +000010822 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010823 // candidate this is the new candidate.
10824 if (target.is_null()) {
10825 target_start_position = start_position;
10826 target = shared;
10827 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +000010828 if (target_start_position == start_position &&
10829 shared->end_position() == target->end_position()) {
10830 // If a top-level function contain only one function
10831 // declartion the source for the top-level and the function is
10832 // the same. In that case prefer the non top-level function.
10833 if (!shared->is_toplevel()) {
10834 target_start_position = start_position;
10835 target = shared;
10836 }
10837 } else if (target_start_position <= start_position &&
10838 shared->end_position() <= target->end_position()) {
10839 // This containment check includes equality as a function inside
10840 // a top-level function can share either start or end position
10841 // with the top-level function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010842 target_start_position = start_position;
10843 target = shared;
10844 }
10845 }
10846 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010847 }
10848 }
10849 }
10850
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010851 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010852 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010853 }
10854
10855 // If the candidate found is compiled we are done. NOTE: when lazy
10856 // compilation of inner functions is introduced some additional checking
10857 // needs to be done here to compile inner functions.
10858 done = target->is_compiled();
10859 if (!done) {
10860 // If the candidate is not compiled compile it to reveal any inner
10861 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010862 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010863 }
10864 }
10865
10866 return *target;
10867}
10868
10869
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010870// Changes the state of a break point in a script and returns source position
10871// where break point was set. NOTE: Regarding performance see the NOTE for
10872// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010873// args[0]: script to set break point in
10874// args[1]: number: break source position (within the script source)
10875// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010876RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010877 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010878 ASSERT(args.length() == 3);
10879 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
10880 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
10881 RUNTIME_ASSERT(source_position >= 0);
10882 Handle<Object> break_point_object_arg = args.at<Object>(2);
10883
10884 // Get the script from the script wrapper.
10885 RUNTIME_ASSERT(wrapper->value()->IsScript());
10886 Handle<Script> script(Script::cast(wrapper->value()));
10887
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000010888 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010889 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010890 if (!result->IsUndefined()) {
10891 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
10892 // Find position within function. The script position might be before the
10893 // source position of the first function.
10894 int position;
10895 if (shared->start_position() > source_position) {
10896 position = 0;
10897 } else {
10898 position = source_position - shared->start_position();
10899 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010900 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000010901 position += shared->start_position();
10902 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010903 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010904 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010905}
10906
10907
10908// Clear a break point
10909// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010910RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010911 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010912 ASSERT(args.length() == 1);
10913 Handle<Object> break_point_object_arg = args.at<Object>(0);
10914
10915 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010916 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010917
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010918 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010919}
10920
10921
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010922// Change the state of break on exceptions.
10923// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
10924// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010925RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010926 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010927 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010928 RUNTIME_ASSERT(args[0]->IsNumber());
10929 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010930
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010931 // If the number doesn't match an enum value, the ChangeBreakOnException
10932 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010933 ExceptionBreakType type =
10934 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010935 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010936 isolate->debug()->ChangeBreakOnException(type, enable);
10937 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010938}
10939
10940
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010941// Returns the state of break on exceptions
10942// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010943RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010944 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010945 ASSERT(args.length() == 1);
10946 RUNTIME_ASSERT(args[0]->IsNumber());
10947
10948 ExceptionBreakType type =
10949 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010950 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000010951 return Smi::FromInt(result);
10952}
10953
10954
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010955// Prepare for stepping
10956// args[0]: break id for checking execution state
10957// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000010958// args[2]: number of times to perform the step, for step out it is the number
10959// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010960RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010961 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010962 ASSERT(args.length() == 3);
10963 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010964 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010965 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10966 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010967 if (!maybe_check->ToObject(&check)) return maybe_check;
10968 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010969 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010970 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010971 }
10972
10973 // Get the step action and check validity.
10974 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
10975 if (step_action != StepIn &&
10976 step_action != StepNext &&
10977 step_action != StepOut &&
10978 step_action != StepInMin &&
10979 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010980 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010981 }
10982
10983 // Get the number of steps.
10984 int step_count = NumberToInt32(args[2]);
10985 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010986 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010987 }
10988
ager@chromium.orga1645e22009-09-09 19:27:10 +000010989 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010990 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000010991
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010992 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010993 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
10994 step_count);
10995 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010996}
10997
10998
10999// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011000RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011001 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011002 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011003 isolate->debug()->ClearStepping();
11004 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011005}
11006
11007
11008// Creates a copy of the with context chain. The copy of the context chain is
11009// is linked to the function context supplied.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011010static Handle<Context> CopyWithContextChain(Isolate* isolate,
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011011 Handle<JSFunction> function,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011012 Handle<Context> current,
11013 Handle<Context> base) {
11014 // At the end of the chain. Return the base context to link to.
11015 if (current->IsFunctionContext() || current->IsGlobalContext()) {
11016 return base;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011017 }
11018
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011019 // Recursively copy the with and catch contexts.
11020 HandleScope scope(isolate);
11021 Handle<Context> previous(current->previous());
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011022 Handle<Context> new_previous =
11023 CopyWithContextChain(isolate, function, previous, base);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011024 Handle<Context> new_current;
11025 if (current->IsCatchContext()) {
11026 Handle<String> name(String::cast(current->extension()));
11027 Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
11028 new_current =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011029 isolate->factory()->NewCatchContext(function,
11030 new_previous,
11031 name,
11032 thrown_object);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011033 } else {
11034 Handle<JSObject> extension(JSObject::cast(current->extension()));
11035 new_current =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011036 isolate->factory()->NewWithContext(function, new_previous, extension);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011037 }
11038 return scope.CloseAndEscape(new_current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011039}
11040
11041
11042// Helper function to find or create the arguments object for
11043// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011044static Handle<Object> GetArgumentsObject(Isolate* isolate,
11045 JavaScriptFrame* frame,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011046 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +000011047 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011048 const ScopeInfo<>* sinfo,
11049 Handle<Context> function_context) {
11050 // Try to find the value of 'arguments' to pass as parameter. If it is not
11051 // found (that is the debugged function does not reference 'arguments' and
11052 // does not support eval) then create an 'arguments' object.
11053 int index;
11054 if (sinfo->number_of_stack_slots() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011055 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011056 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011057 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011058 }
11059 }
11060
11061 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011062 index = scope_info->ContextSlotIndex(isolate->heap()->arguments_symbol(),
11063 NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011064 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011065 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011066 }
11067 }
11068
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000011069 const int length = frame->ComputeParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011070 Handle<JSObject> arguments =
11071 isolate->factory()->NewArgumentsObject(function, length);
11072 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011073
11074 AssertNoAllocation no_gc;
11075 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011076 for (int i = 0; i < length; i++) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +000011077 array->set(i, frame->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011078 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000011079 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011080 return arguments;
11081}
11082
11083
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011084static const char kSourceStr[] =
11085 "(function(arguments,__source__){return eval(__source__);})";
11086
11087
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011088// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000011089// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011090// extension part has all the parameters and locals of the function on the
11091// stack frame. A function which calls eval with the code to evaluate is then
11092// compiled in this context and called in this context. As this context
11093// replaces the context of the function on the stack frame a new (empty)
11094// function is created as well to be used as the closure for the context.
11095// This function and the context acts as replacements for the function on the
11096// stack frame presenting the same view of the values of parameters and
11097// local variables as if the piece of JavaScript was evaluated at the point
11098// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011099RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011100 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011101
11102 // Check the execution state and decode arguments frame and source to be
11103 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011104 ASSERT(args.length() == 5);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011105 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011106 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11107 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011108 if (!maybe_check_result->ToObject(&check_result)) {
11109 return maybe_check_result;
11110 }
11111 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011112 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
11113 CONVERT_ARG_CHECKED(String, source, 2);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011114 CONVERT_BOOLEAN_CHECKED(disable_break, args[3]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011115 Handle<Object> additional_context(args[4]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011116
11117 // Handle the processing of break.
11118 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011119
11120 // Get the frame where the debugging is performed.
11121 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011122 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011123 JavaScriptFrame* frame = it.frame();
11124 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +000011125 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011126 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011127
11128 // Traverse the saved contexts chain to find the active context for the
11129 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011130 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000011131 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011132 save = save->prev();
11133 }
11134 ASSERT(save != NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011135 SaveContext savex(isolate);
11136 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011137
11138 // Create the (empty) function replacing the function on the stack frame for
11139 // the purpose of evaluating in the context created below. It is important
11140 // that this function does not describe any parameters and local variables
11141 // in the context. If it does then this will cause problems with the lookup
11142 // in Context::Lookup, where context slots for parameters and local variables
11143 // are looked at before the extension object.
11144 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011145 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
11146 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011147 go_between->set_context(function->context());
11148#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011149 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011150 ASSERT(go_between_sinfo.number_of_parameters() == 0);
11151 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
11152#endif
11153
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011154 // Materialize the content of the local scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011155 Handle<JSObject> local_scope = MaterializeLocalScope(isolate, frame);
11156 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011157
11158 // Allocate a new context for the debug evaluation and set the extension
11159 // object build.
11160 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011161 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
11162 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011163 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011164 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011165 Handle<Context> frame_context(Context::cast(frame->context()));
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011166 Handle<Context> function_context(frame_context->declaration_context());
11167 context = CopyWithContextChain(isolate, go_between, frame_context, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011168
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011169 if (additional_context->IsJSObject()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011170 Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011171 context =
11172 isolate->factory()->NewWithContext(go_between, context, extension);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011173 }
11174
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011175 // Wrap the evaluation statement in a new function compiled in the newly
11176 // created context. The function has one parameter which has to be called
11177 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000011178 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011179 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011180
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011181 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011182 isolate->factory()->NewStringFromAscii(
11183 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011184
11185 // Currently, the eval code will be executed in non-strict mode,
11186 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011187 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000011188 Compiler::CompileEval(function_source,
11189 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011190 context->IsGlobalContext(),
11191 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011192 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011193 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011194 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011195
11196 // Invoke the result of the compilation to get the evaluation function.
11197 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011198 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011199 Handle<Object> evaluation_function =
11200 Execution::Call(compiled_function, receiver, 0, NULL,
11201 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011202 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011203
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011204 Handle<Object> arguments = GetArgumentsObject(isolate, frame,
11205 function, scope_info,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011206 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011207
11208 // Invoke the evaluation function and return the result.
11209 const int argc = 2;
11210 Object** argv[argc] = { arguments.location(),
11211 Handle<Object>::cast(source).location() };
11212 Handle<Object> result =
11213 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
11214 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011215 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011216
11217 // Skip the global proxy as it has no properties and always delegates to the
11218 // real global object.
11219 if (result->IsJSGlobalProxy()) {
11220 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
11221 }
11222
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011223 return *result;
11224}
11225
11226
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011227RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011228 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011229
11230 // Check the execution state and decode arguments frame and source to be
11231 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011232 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011233 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011234 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11235 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011236 if (!maybe_check_result->ToObject(&check_result)) {
11237 return maybe_check_result;
11238 }
11239 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011240 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011241 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011242 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011243
11244 // Handle the processing of break.
11245 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011246
11247 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011248 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011249 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011250 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011251 top = top->prev();
11252 }
11253 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011254 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011255 }
11256
11257 // Get the global context now set to the top context from before the
11258 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011259 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011260
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011261 bool is_global = true;
11262
11263 if (additional_context->IsJSObject()) {
11264 // Create a function context first, than put 'with' context on top of it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011265 Handle<JSFunction> go_between = isolate->factory()->NewFunction(
11266 isolate->factory()->empty_string(),
11267 isolate->factory()->undefined_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011268 go_between->set_context(*context);
11269 context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011270 isolate->factory()->NewFunctionContext(
11271 Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011272 context->set_extension(JSObject::cast(*additional_context));
11273 is_global = false;
11274 }
11275
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011276 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011277 // Currently, the eval code will be executed in non-strict mode,
11278 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011279 Handle<SharedFunctionInfo> shared =
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011280 Compiler::CompileEval(source, context, is_global, kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011281 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011282 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011283 Handle<JSFunction>(
11284 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
11285 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011286
11287 // Invoke the result of the compilation to get the evaluation function.
11288 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011289 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011290 Handle<Object> result =
11291 Execution::Call(compiled_function, receiver, 0, NULL,
11292 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011293 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011294 return *result;
11295}
11296
11297
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011298RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011299 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011300 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011301
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011302 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011303 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011304
11305 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000011306 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000011307 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
11308 // Get the script wrapper in a local handle before calling GetScriptWrapper,
11309 // because using
11310 // instances->set(i, *GetScriptWrapper(script))
11311 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
11312 // already have deferenced the instances handle.
11313 Handle<JSValue> wrapper = GetScriptWrapper(script);
11314 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011315 }
11316
11317 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011318 Handle<JSObject> result =
11319 isolate->factory()->NewJSObject(isolate->array_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011320 Handle<JSArray>::cast(result)->SetContent(*instances);
11321 return *result;
11322}
11323
11324
11325// Helper function used by Runtime_DebugReferencedBy below.
11326static int DebugReferencedBy(JSObject* target,
11327 Object* instance_filter, int max_references,
11328 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011329 JSFunction* arguments_function) {
11330 NoHandleAllocation ha;
11331 AssertNoAllocation no_alloc;
11332
11333 // Iterate the heap.
11334 int count = 0;
11335 JSObject* last = NULL;
11336 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011337 HeapObject* heap_obj = NULL;
11338 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011339 (max_references == 0 || count < max_references)) {
11340 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011341 if (heap_obj->IsJSObject()) {
11342 // Skip context extension objects and argument arrays as these are
11343 // checked in the context of functions using them.
11344 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000011345 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011346 obj->map()->constructor() == arguments_function) {
11347 continue;
11348 }
11349
11350 // Check if the JS object has a reference to the object looked for.
11351 if (obj->ReferencesObject(target)) {
11352 // Check instance filter if supplied. This is normally used to avoid
11353 // references from mirror objects (see Runtime_IsInPrototypeChain).
11354 if (!instance_filter->IsUndefined()) {
11355 Object* V = obj;
11356 while (true) {
11357 Object* prototype = V->GetPrototype();
11358 if (prototype->IsNull()) {
11359 break;
11360 }
11361 if (instance_filter == prototype) {
11362 obj = NULL; // Don't add this object.
11363 break;
11364 }
11365 V = prototype;
11366 }
11367 }
11368
11369 if (obj != NULL) {
11370 // Valid reference found add to instance array if supplied an update
11371 // count.
11372 if (instances != NULL && count < instances_size) {
11373 instances->set(count, obj);
11374 }
11375 last = obj;
11376 count++;
11377 }
11378 }
11379 }
11380 }
11381
11382 // Check for circular reference only. This can happen when the object is only
11383 // referenced from mirrors and has a circular reference in which case the
11384 // object is not really alive and would have been garbage collected if not
11385 // referenced from the mirror.
11386 if (count == 1 && last == target) {
11387 count = 0;
11388 }
11389
11390 // Return the number of referencing objects found.
11391 return count;
11392}
11393
11394
11395// Scan the heap for objects with direct references to an object
11396// args[0]: the object to find references to
11397// args[1]: constructor function for instances to exclude (Mirror)
11398// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011399RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011400 ASSERT(args.length() == 3);
11401
11402 // First perform a full GC in order to avoid references from dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011403 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011404
11405 // Check parameters.
11406 CONVERT_CHECKED(JSObject, target, args[0]);
11407 Object* instance_filter = args[1];
11408 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
11409 instance_filter->IsJSObject());
11410 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
11411 RUNTIME_ASSERT(max_references >= 0);
11412
11413 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011414 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011415 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011416 JSFunction* arguments_function =
11417 JSFunction::cast(arguments_boilerplate->map()->constructor());
11418
11419 // Get the number of referencing objects.
11420 int count;
11421 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000011422 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011423
11424 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011425 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011426 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011427 if (!maybe_object->ToObject(&object)) return maybe_object;
11428 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011429 FixedArray* instances = FixedArray::cast(object);
11430
11431 // Fill the referencing objects.
11432 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000011433 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011434
11435 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011436 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011437 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
11438 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011439 if (!maybe_result->ToObject(&result)) return maybe_result;
11440 }
11441 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011442 return result;
11443}
11444
11445
11446// Helper function used by Runtime_DebugConstructedBy below.
11447static int DebugConstructedBy(JSFunction* constructor, int max_references,
11448 FixedArray* instances, int instances_size) {
11449 AssertNoAllocation no_alloc;
11450
11451 // Iterate the heap.
11452 int count = 0;
11453 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011454 HeapObject* heap_obj = NULL;
11455 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011456 (max_references == 0 || count < max_references)) {
11457 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011458 if (heap_obj->IsJSObject()) {
11459 JSObject* obj = JSObject::cast(heap_obj);
11460 if (obj->map()->constructor() == constructor) {
11461 // Valid reference found add to instance array if supplied an update
11462 // count.
11463 if (instances != NULL && count < instances_size) {
11464 instances->set(count, obj);
11465 }
11466 count++;
11467 }
11468 }
11469 }
11470
11471 // Return the number of referencing objects found.
11472 return count;
11473}
11474
11475
11476// Scan the heap for objects constructed by a specific function.
11477// args[0]: the constructor to find instances of
11478// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011479RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011480 ASSERT(args.length() == 2);
11481
11482 // First perform a full GC in order to avoid dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011483 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011484
11485 // Check parameters.
11486 CONVERT_CHECKED(JSFunction, constructor, args[0]);
11487 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
11488 RUNTIME_ASSERT(max_references >= 0);
11489
11490 // Get the number of referencing objects.
11491 int count;
11492 count = DebugConstructedBy(constructor, max_references, NULL, 0);
11493
11494 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011495 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011496 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011497 if (!maybe_object->ToObject(&object)) return maybe_object;
11498 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011499 FixedArray* instances = FixedArray::cast(object);
11500
11501 // Fill the referencing objects.
11502 count = DebugConstructedBy(constructor, max_references, instances, count);
11503
11504 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011505 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011506 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
11507 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011508 if (!maybe_result->ToObject(&result)) return maybe_result;
11509 }
11510 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011511 return result;
11512}
11513
11514
ager@chromium.orgddb913d2009-01-27 10:01:48 +000011515// Find the effective prototype object as returned by __proto__.
11516// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011517RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011518 ASSERT(args.length() == 1);
11519
11520 CONVERT_CHECKED(JSObject, obj, args[0]);
11521
ager@chromium.orgddb913d2009-01-27 10:01:48 +000011522 // Use the __proto__ accessor.
11523 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011524}
11525
11526
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011527RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000011528 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011529 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011530 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011531}
11532
11533
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011534RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011535#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011536 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011537 ASSERT(args.length() == 1);
11538 // Get the function and make sure it is compiled.
11539 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011540 Handle<SharedFunctionInfo> shared(func->shared());
11541 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011542 return Failure::Exception();
11543 }
11544 func->code()->PrintLn();
11545#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011546 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011547}
ager@chromium.org9085a012009-05-11 19:22:57 +000011548
11549
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011550RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011551#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011552 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011553 ASSERT(args.length() == 1);
11554 // Get the function and make sure it is compiled.
11555 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011556 Handle<SharedFunctionInfo> shared(func->shared());
11557 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011558 return Failure::Exception();
11559 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011560 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011561#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011562 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011563}
11564
11565
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011566RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000011567 NoHandleAllocation ha;
11568 ASSERT(args.length() == 1);
11569
11570 CONVERT_CHECKED(JSFunction, f, args[0]);
11571 return f->shared()->inferred_name();
11572}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000011573
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011574
11575static int FindSharedFunctionInfosForScript(Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011576 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011577 AssertNoAllocation no_allocations;
11578
11579 int counter = 0;
11580 int buffer_size = buffer->length();
11581 HeapIterator iterator;
11582 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
11583 ASSERT(obj != NULL);
11584 if (!obj->IsSharedFunctionInfo()) {
11585 continue;
11586 }
11587 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
11588 if (shared->script() != script) {
11589 continue;
11590 }
11591 if (counter < buffer_size) {
11592 buffer->set(counter, shared);
11593 }
11594 counter++;
11595 }
11596 return counter;
11597}
11598
11599// For a script finds all SharedFunctionInfo's in the heap that points
11600// to this script. Returns JSArray of SharedFunctionInfo wrapped
11601// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011602RUNTIME_FUNCTION(MaybeObject*,
11603 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011604 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011605 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011606 CONVERT_CHECKED(JSValue, script_value, args[0]);
11607
11608 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
11609
11610 const int kBufferSize = 32;
11611
11612 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011613 array = isolate->factory()->NewFixedArray(kBufferSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011614 int number = FindSharedFunctionInfosForScript(*script, *array);
11615 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011616 array = isolate->factory()->NewFixedArray(number);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011617 FindSharedFunctionInfosForScript(*script, *array);
11618 }
11619
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011620 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011621 result->set_length(Smi::FromInt(number));
11622
11623 LiveEdit::WrapSharedFunctionInfos(result);
11624
11625 return *result;
11626}
11627
11628// For a script calculates compilation information about all its functions.
11629// The script source is explicitly specified by the second argument.
11630// The source of the actual script is not used, however it is important that
11631// all generated code keeps references to this particular instance of script.
11632// Returns a JSArray of compilation infos. The array is ordered so that
11633// each function with all its descendant is always stored in a continues range
11634// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011635RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011636 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011637 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011638 CONVERT_CHECKED(JSValue, script, args[0]);
11639 CONVERT_ARG_CHECKED(String, source, 1);
11640 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
11641
11642 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
11643
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011644 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011645 return Failure::Exception();
11646 }
11647
11648 return result;
11649}
11650
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011651// Changes the source of the script to a new_source.
11652// If old_script_name is provided (i.e. is a String), also creates a copy of
11653// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011654RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011655 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011656 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011657 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
11658 CONVERT_ARG_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011659 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011660
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011661 CONVERT_CHECKED(Script, original_script_pointer,
11662 original_script_value->value());
11663 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011664
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011665 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
11666 new_source,
11667 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011668
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011669 if (old_script->IsScript()) {
11670 Handle<Script> script_handle(Script::cast(old_script));
11671 return *(GetScriptWrapper(script_handle));
11672 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011673 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011674 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011675}
11676
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011677
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011678RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011679 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011680 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011681 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
11682 return LiveEdit::FunctionSourceUpdated(shared_info);
11683}
11684
11685
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011686// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011687RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011688 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011689 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011690 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
11691 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
11692
ager@chromium.orgac091b72010-05-05 07:34:42 +000011693 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011694}
11695
11696// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011697RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011698 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011699 HandleScope scope(isolate);
11700 Handle<Object> function_object(args[0], isolate);
11701 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011702
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011703 if (function_object->IsJSValue()) {
11704 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
11705 if (script_object->IsJSValue()) {
11706 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011707 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011708 }
11709
11710 LiveEdit::SetFunctionScript(function_wrapper, script_object);
11711 } else {
11712 // Just ignore this. We may not have a SharedFunctionInfo for some functions
11713 // and we check it in this function.
11714 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011715
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011716 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011717}
11718
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011719
11720// In a code of a parent function replaces original function as embedded object
11721// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011722RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011723 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011724 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011725
11726 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
11727 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
11728 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
11729
11730 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
11731 subst_wrapper);
11732
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011733 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000011734}
11735
11736
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011737// Updates positions of a shared function info (first parameter) according
11738// to script source change. Text change is described in second parameter as
11739// array of groups of 3 numbers:
11740// (change_begin, change_end, change_end_new_position).
11741// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011742RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011743 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011744 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011745 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
11746 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
11747
ager@chromium.orgac091b72010-05-05 07:34:42 +000011748 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011749}
11750
11751
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011752// For array of SharedFunctionInfo's (each wrapped in JSValue)
11753// checks that none of them have activations on stacks (of any thread).
11754// Returns array of the same length with corresponding results of
11755// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011756RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000011757 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011758 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011759 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000011760 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011761
ager@chromium.org357bf652010-04-12 11:30:10 +000011762 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000011763}
11764
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000011765// Compares 2 strings line-by-line, then token-wise and returns diff in form
11766// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
11767// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011768RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011769 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011770 HandleScope scope(isolate);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011771 CONVERT_ARG_CHECKED(String, s1, 0);
11772 CONVERT_ARG_CHECKED(String, s2, 1);
11773
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000011774 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000011775}
11776
11777
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011778// A testing entry. Returns statement position which is the closest to
11779// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011780RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011781 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011782 HandleScope scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011783 CONVERT_ARG_CHECKED(JSFunction, function, 0);
11784 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11785
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011786 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011787
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011788 if (code->kind() != Code::FUNCTION &&
11789 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011790 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011791 }
11792
11793 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011794 int closest_pc = 0;
11795 int distance = kMaxInt;
11796 while (!it.done()) {
11797 int statement_position = static_cast<int>(it.rinfo()->data());
11798 // Check if this break point is closer that what was previously found.
11799 if (source_position <= statement_position &&
11800 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000011801 closest_pc =
11802 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000011803 distance = statement_position - source_position;
11804 // Check whether we can't get any closer.
11805 if (distance == 0) break;
11806 }
11807 it.next();
11808 }
11809
11810 return Smi::FromInt(closest_pc);
11811}
11812
11813
ager@chromium.org357bf652010-04-12 11:30:10 +000011814// Calls specified function with or without entering the debugger.
11815// This is used in unit tests to run code as if debugger is entered or simply
11816// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011817RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000011818 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011819 HandleScope scope(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +000011820 CONVERT_ARG_CHECKED(JSFunction, function, 0);
11821 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
11822
11823 Handle<Object> result;
11824 bool pending_exception;
11825 {
11826 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011827 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000011828 &pending_exception);
11829 } else {
11830 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011831 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000011832 &pending_exception);
11833 }
11834 }
11835 if (!pending_exception) {
11836 return *result;
11837 } else {
11838 return Failure::Exception();
11839 }
11840}
11841
11842
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011843// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011844RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011845 CONVERT_CHECKED(String, arg, args[0]);
11846 SmartPointer<char> flags =
11847 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
11848 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011849 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011850}
11851
11852
11853// Performs a GC.
11854// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011855RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011856 isolate->heap()->CollectAllGarbage(true);
11857 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011858}
11859
11860
11861// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011862RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011863 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011864 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011865 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000011866 }
11867 return Smi::FromInt(usage);
11868}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011869
11870
11871// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011872RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011873#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011874 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011875#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011876 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011877#endif
11878}
11879
11880
11881// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011882RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011883#ifdef LIVE_OBJECT_LIST
11884 return LiveObjectList::Capture();
11885#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011886 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011887#endif
11888}
11889
11890
11891// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011892RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011893#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011894 CONVERT_SMI_ARG_CHECKED(id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011895 bool success = LiveObjectList::Delete(id);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011896 return success ? isolate->heap()->true_value() :
11897 isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011898#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011899 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011900#endif
11901}
11902
11903
11904// Generates the response to a debugger request for a dump of the objects
11905// contained in the difference between the captured live object lists
11906// specified by id1 and id2.
11907// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
11908// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011909RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011910#ifdef LIVE_OBJECT_LIST
11911 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011912 CONVERT_SMI_ARG_CHECKED(id1, 0);
11913 CONVERT_SMI_ARG_CHECKED(id2, 1);
11914 CONVERT_SMI_ARG_CHECKED(start, 2);
11915 CONVERT_SMI_ARG_CHECKED(count, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011916 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
11917 EnterDebugger enter_debugger;
11918 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
11919#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011920 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011921#endif
11922}
11923
11924
11925// Gets the specified object as requested by the debugger.
11926// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011927RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011928#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011929 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011930 Object* result = LiveObjectList::GetObj(obj_id);
11931 return result;
11932#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011933 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011934#endif
11935}
11936
11937
11938// Gets the obj id for the specified address if valid.
11939// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011940RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011941#ifdef LIVE_OBJECT_LIST
11942 HandleScope scope;
11943 CONVERT_ARG_CHECKED(String, address, 0);
11944 Object* result = LiveObjectList::GetObjId(address);
11945 return result;
11946#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011947 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011948#endif
11949}
11950
11951
11952// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011953RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011954#ifdef LIVE_OBJECT_LIST
11955 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011956 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011957 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
11958 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
11959 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
11960 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
11961 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
11962
11963 Handle<JSObject> instance_filter;
11964 if (args[1]->IsJSObject()) {
11965 instance_filter = args.at<JSObject>(1);
11966 }
11967 bool verbose = false;
11968 if (args[2]->IsBoolean()) {
11969 verbose = args[2]->IsTrue();
11970 }
11971 int start = 0;
11972 if (args[3]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011973 start = args.smi_at(3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011974 }
11975 int limit = Smi::kMaxValue;
11976 if (args[4]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011977 limit = args.smi_at(4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011978 }
11979
11980 return LiveObjectList::GetObjRetainers(obj_id,
11981 instance_filter,
11982 verbose,
11983 start,
11984 limit,
11985 filter_obj);
11986#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011987 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011988#endif
11989}
11990
11991
11992// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011993RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011994#ifdef LIVE_OBJECT_LIST
11995 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011996 CONVERT_SMI_ARG_CHECKED(obj_id1, 0);
11997 CONVERT_SMI_ARG_CHECKED(obj_id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011998 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
11999
12000 Handle<JSObject> instance_filter;
12001 if (args[2]->IsJSObject()) {
12002 instance_filter = args.at<JSObject>(2);
12003 }
12004
12005 Object* result =
12006 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
12007 return result;
12008#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012009 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012010#endif
12011}
12012
12013
12014// Generates the response to a debugger request for a list of all
12015// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012016RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012017#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012018 CONVERT_SMI_ARG_CHECKED(start, 0);
12019 CONVERT_SMI_ARG_CHECKED(count, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012020 return LiveObjectList::Info(start, count);
12021#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012022 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012023#endif
12024}
12025
12026
12027// Gets a dump of the specified object as requested by the debugger.
12028// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012029RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012030#ifdef LIVE_OBJECT_LIST
12031 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012032 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012033 Object* result = LiveObjectList::PrintObj(obj_id);
12034 return result;
12035#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012036 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012037#endif
12038}
12039
12040
12041// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012042RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012043#ifdef LIVE_OBJECT_LIST
12044 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012045 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012046#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012047 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012048#endif
12049}
12050
12051
12052// Generates the response to a debugger request for a summary of the types
12053// of objects in the difference between the captured live object lists
12054// specified by id1 and id2.
12055// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12056// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012057RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012058#ifdef LIVE_OBJECT_LIST
12059 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012060 CONVERT_SMI_ARG_CHECKED(id1, 0);
12061 CONVERT_SMI_ARG_CHECKED(id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012062 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
12063
12064 EnterDebugger enter_debugger;
12065 return LiveObjectList::Summarize(id1, id2, filter_obj);
12066#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012067 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012068#endif
12069}
12070
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012071#endif // ENABLE_DEBUGGER_SUPPORT
12072
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012073
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012074#ifdef ENABLE_LOGGING_AND_PROFILING
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012075RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012076 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000012077 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012078
12079 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000012080 CONVERT_CHECKED(Smi, smi_tag, args[1]);
12081 v8::V8::ResumeProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012082 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012083}
12084
12085
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012086RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012087 NoHandleAllocation ha;
ager@chromium.org5c838252010-02-19 08:53:10 +000012088 ASSERT(args.length() == 2);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012089
12090 CONVERT_CHECKED(Smi, smi_modules, args[0]);
ager@chromium.org5c838252010-02-19 08:53:10 +000012091 CONVERT_CHECKED(Smi, smi_tag, args[1]);
12092 v8::V8::PauseProfilerEx(smi_modules->value(), smi_tag->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012093 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012094}
12095
12096#endif // ENABLE_LOGGING_AND_PROFILING
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012097
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012098// Finds the script object from the script data. NOTE: This operation uses
12099// heap traversal to find the function generated for the source position
12100// for the requested break point. For lazily compiled functions several heap
12101// traversals might be required rendering this operation as a rather slow
12102// operation. However for setting break points which is normally done through
12103// some kind of user interaction the performance is not crucial.
12104static Handle<Object> Runtime_GetScriptFromScriptName(
12105 Handle<String> script_name) {
12106 // Scan the heap for Script objects to find the script with the requested
12107 // script data.
12108 Handle<Script> script;
12109 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012110 HeapObject* obj = NULL;
12111 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012112 // If a script is found check if it has the script data requested.
12113 if (obj->IsScript()) {
12114 if (Script::cast(obj)->name()->IsString()) {
12115 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
12116 script = Handle<Script>(Script::cast(obj));
12117 }
12118 }
12119 }
12120 }
12121
12122 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012123 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012124
12125 // Return the script found.
12126 return GetScriptWrapper(script);
12127}
12128
12129
12130// Get the script object from script data. NOTE: Regarding performance
12131// see the NOTE for GetScriptFromScriptData.
12132// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012133RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012134 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012135
12136 ASSERT(args.length() == 1);
12137
12138 CONVERT_CHECKED(String, script_name, args[0]);
12139
12140 // Find the requested script.
12141 Handle<Object> result =
12142 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
12143 return *result;
12144}
12145
12146
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012147// Determines whether the given stack frame should be displayed in
12148// a stack trace. The caller is the error constructor that asked
12149// for the stack trace to be collected. The first time a construct
12150// call to this function is encountered it is skipped. The seen_caller
12151// in/out parameter is used to remember if the caller has been seen
12152// yet.
12153static bool ShowFrameInStackTrace(StackFrame* raw_frame, Object* caller,
12154 bool* seen_caller) {
12155 // Only display JS frames.
12156 if (!raw_frame->is_java_script())
12157 return false;
12158 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
12159 Object* raw_fun = frame->function();
12160 // Not sure when this can happen but skip it just in case.
12161 if (!raw_fun->IsJSFunction())
12162 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012163 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012164 *seen_caller = true;
12165 return false;
12166 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012167 // Skip all frames until we've seen the caller. Also, skip the most
12168 // obvious builtin calls. Some builtin calls (such as Number.ADD
12169 // which is invoked using 'call') are very difficult to recognize
12170 // so we're leaving them in for now.
12171 return *seen_caller && !frame->receiver()->IsJSBuiltinsObject();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012172}
12173
12174
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012175// Collect the raw data for a stack trace. Returns an array of 4
12176// element segments each containing a receiver, function, code and
12177// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012178RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012179 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012180 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012181 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
12182
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012183 HandleScope scope(isolate);
12184 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012185
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000012186 limit = Max(limit, 0); // Ensure that limit is not negative.
12187 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012188 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012189 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012190
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012191 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012192 // If the caller parameter is a function we skip frames until we're
12193 // under it before starting to collect.
12194 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012195 int cursor = 0;
12196 int frames_seen = 0;
12197 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012198 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012199 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012200 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012201 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012202 // Set initial size to the maximum inlining level + 1 for the outermost
12203 // function.
12204 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012205 frame->Summarize(&frames);
12206 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012207 if (cursor + 4 > elements->length()) {
12208 int new_capacity = JSObject::NewElementsCapacity(elements->length());
12209 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012210 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012211 for (int i = 0; i < cursor; i++) {
12212 new_elements->set(i, elements->get(i));
12213 }
12214 elements = new_elements;
12215 }
12216 ASSERT(cursor + 4 <= elements->length());
12217
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012218 Handle<Object> recv = frames[i].receiver();
12219 Handle<JSFunction> fun = frames[i].function();
12220 Handle<Code> code = frames[i].code();
12221 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012222 elements->set(cursor++, *recv);
12223 elements->set(cursor++, *fun);
12224 elements->set(cursor++, *code);
12225 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012226 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012227 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012228 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012229 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012230 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012231 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012232 return *result;
12233}
12234
12235
ager@chromium.org3811b432009-10-28 14:53:37 +000012236// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012237RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000012238 ASSERT_EQ(args.length(), 0);
12239
12240 NoHandleAllocation ha;
12241
12242 const char* version_string = v8::V8::GetVersion();
12243
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012244 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
12245 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000012246}
12247
12248
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012249RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012250 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012251 OS::PrintError("abort: %s\n",
12252 reinterpret_cast<char*>(args[0]) + args.smi_at(1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012253 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012254 OS::Abort();
12255 UNREACHABLE();
12256 return NULL;
12257}
12258
12259
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012260RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012261 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012262 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012263 Object* key = args[1];
12264
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012265 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012266 Object* o = cache->get(finger_index);
12267 if (o == key) {
12268 // The fastest case: hit the same place again.
12269 return cache->get(finger_index + 1);
12270 }
12271
12272 for (int i = finger_index - 2;
12273 i >= JSFunctionResultCache::kEntriesIndex;
12274 i -= 2) {
12275 o = cache->get(i);
12276 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012277 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012278 return cache->get(i + 1);
12279 }
12280 }
12281
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012282 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012283 ASSERT(size <= cache->length());
12284
12285 for (int i = size - 2; i > finger_index; i -= 2) {
12286 o = cache->get(i);
12287 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012288 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012289 return cache->get(i + 1);
12290 }
12291 }
12292
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012293 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012294 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012295
12296 Handle<JSFunctionResultCache> cache_handle(cache);
12297 Handle<Object> key_handle(key);
12298 Handle<Object> value;
12299 {
12300 Handle<JSFunction> factory(JSFunction::cast(
12301 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
12302 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012303 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012304 // This handle is nor shared, nor used later, so it's safe.
12305 Object** argv[] = { key_handle.location() };
12306 bool pending_exception = false;
12307 value = Execution::Call(factory,
12308 receiver,
12309 1,
12310 argv,
12311 &pending_exception);
12312 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012313 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012314
12315#ifdef DEBUG
12316 cache_handle->JSFunctionResultCacheVerify();
12317#endif
12318
12319 // Function invocation may have cleared the cache. Reread all the data.
12320 finger_index = cache_handle->finger_index();
12321 size = cache_handle->size();
12322
12323 // If we have spare room, put new data into it, otherwise evict post finger
12324 // entry which is likely to be the least recently used.
12325 int index = -1;
12326 if (size < cache_handle->length()) {
12327 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
12328 index = size;
12329 } else {
12330 index = finger_index + JSFunctionResultCache::kEntrySize;
12331 if (index == cache_handle->length()) {
12332 index = JSFunctionResultCache::kEntriesIndex;
12333 }
12334 }
12335
12336 ASSERT(index % 2 == 0);
12337 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
12338 ASSERT(index < cache_handle->length());
12339
12340 cache_handle->set(index, *key_handle);
12341 cache_handle->set(index + 1, *value);
12342 cache_handle->set_finger_index(index);
12343
12344#ifdef DEBUG
12345 cache_handle->JSFunctionResultCacheVerify();
12346#endif
12347
12348 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012349}
12350
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012351
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012352RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012353 HandleScope scope(isolate);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012354 CONVERT_ARG_CHECKED(String, type, 0);
12355 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012356 return *isolate->factory()->NewJSMessageObject(
12357 type,
12358 arguments,
12359 0,
12360 0,
12361 isolate->factory()->undefined_value(),
12362 isolate->factory()->undefined_value(),
12363 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012364}
12365
12366
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012367RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012368 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12369 return message->type();
12370}
12371
12372
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012373RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012374 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12375 return message->arguments();
12376}
12377
12378
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012379RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012380 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12381 return Smi::FromInt(message->start_position());
12382}
12383
12384
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012385RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012386 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12387 return message->script();
12388}
12389
12390
kasper.lund44510672008-07-25 07:37:58 +000012391#ifdef DEBUG
12392// ListNatives is ONLY used by the fuzz-natives.js in debug mode
12393// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012394RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000012395 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012396 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012397#define COUNT_ENTRY(Name, argc, ressize) + 1
12398 int entry_count = 0
12399 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
12400 INLINE_FUNCTION_LIST(COUNT_ENTRY)
12401 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
12402#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012403 Factory* factory = isolate->factory();
12404 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012405 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012406 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000012407#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012408 { \
12409 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012410 Handle<String> name; \
12411 /* Inline runtime functions have an underscore in front of the name. */ \
12412 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012413 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012414 Vector<const char>("_" #Name, StrLength("_" #Name))); \
12415 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012416 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012417 Vector<const char>(#Name, StrLength(#Name))); \
12418 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012419 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012420 pair_elements->set(0, *name); \
12421 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012422 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012423 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012424 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012425 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012426 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012427 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012428 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012429 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012430#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012431 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012432 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012433 return *result;
12434}
kasper.lund44510672008-07-25 07:37:58 +000012435#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012436
12437
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012438RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012439 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000012440 CONVERT_CHECKED(String, format, args[0]);
12441 CONVERT_CHECKED(JSArray, elms, args[1]);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012442 Vector<const char> chars = format->ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012443 LOGGER->LogRuntime(chars, elms);
12444 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012445}
12446
12447
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012448RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012449 UNREACHABLE(); // implemented as macro in the parser
12450 return NULL;
12451}
12452
12453
12454// ----------------------------------------------------------------------------
12455// Implementation of Runtime
12456
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012457#define F(name, number_of_args, result_size) \
12458 { Runtime::k##name, Runtime::RUNTIME, #name, \
12459 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012460
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012461
12462#define I(name, number_of_args, result_size) \
12463 { Runtime::kInline##name, Runtime::INLINE, \
12464 "_" #name, NULL, number_of_args, result_size },
12465
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012466static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012467 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012468 INLINE_FUNCTION_LIST(I)
12469 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012470};
12471
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012472
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012473MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
12474 Object* dictionary) {
12475 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012476 ASSERT(dictionary != NULL);
12477 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
12478 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000012479 Object* name_symbol;
12480 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012481 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012482 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
12483 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012484 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012485 { MaybeObject* maybe_dictionary = string_dictionary->Add(
12486 String::cast(name_symbol),
12487 Smi::FromInt(i),
12488 PropertyDetails(NONE, NORMAL));
12489 if (!maybe_dictionary->ToObject(&dictionary)) {
12490 // Non-recoverable failure. Calling code must restart heap
12491 // initialization.
12492 return maybe_dictionary;
12493 }
12494 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012495 }
12496 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012497}
12498
12499
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012500const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
12501 Heap* heap = name->GetHeap();
12502 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012503 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012504 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012505 int function_index = Smi::cast(smi_index)->value();
12506 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012507 }
12508 return NULL;
12509}
12510
12511
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012512const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012513 return &(kIntrinsicFunctions[static_cast<int>(id)]);
12514}
12515
12516
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012517void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012518 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012519 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012520 if (failure->IsRetryAfterGC()) {
12521 // Try to do a garbage collection; ignore it if it fails. The C
12522 // entry stub will throw an out-of-memory exception in that case.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012523 isolate->heap()->CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012524 } else {
12525 // Handle last resort GC and make sure to allow future allocations
12526 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012527 isolate->counters()->gc_last_resort_from_js()->Increment();
12528 isolate->heap()->CollectAllGarbage(false);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012529 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012530}
12531
12532
12533} } // namespace v8::internal