blob: 9d3bb1d83b567480be63d4e4a355beecc636441e [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 }
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000222 case JSObject::NON_STRICT_ARGUMENTS_ELEMENTS:
223 UNIMPLEMENTED();
224 break;
225 case JSObject::EXTERNAL_PIXEL_ELEMENTS:
226 case JSObject::EXTERNAL_BYTE_ELEMENTS:
227 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
228 case JSObject::EXTERNAL_SHORT_ELEMENTS:
229 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
230 case JSObject::EXTERNAL_INT_ELEMENTS:
231 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS:
232 case JSObject::EXTERNAL_FLOAT_ELEMENTS:
233 case JSObject::EXTERNAL_DOUBLE_ELEMENTS:
234 case JSObject::FAST_DOUBLE_ELEMENTS:
235 // No contained objects, nothing to do.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000236 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000237 }
238 return copy;
239}
240
241
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000242RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneLiteralBoilerplate) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000243 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000244 return DeepCopyBoilerplate(isolate, boilerplate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000245}
246
247
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000248RUNTIME_FUNCTION(MaybeObject*, Runtime_CloneShallowLiteralBoilerplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000249 CONVERT_CHECKED(JSObject, boilerplate, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000250 return isolate->heap()->CopyJSObject(boilerplate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000251}
252
253
ager@chromium.org236ad962008-09-25 09:45:57 +0000254static Handle<Map> ComputeObjectLiteralMap(
255 Handle<Context> context,
256 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000257 bool* is_result_from_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000258 Isolate* isolate = context->GetIsolate();
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000259 int properties_length = constant_properties->length();
260 int number_of_properties = properties_length / 2;
ager@chromium.org236ad962008-09-25 09:45:57 +0000261 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000262 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000263 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000264 for (int p = 0; p != properties_length; p += 2) {
265 Object* key = constant_properties->get(p);
266 uint32_t element_index = 0;
267 if (key->IsSymbol()) {
268 number_of_symbol_keys++;
269 } else if (key->ToArrayIndex(&element_index)) {
270 // An index key does not require space in the property backing store.
271 number_of_properties--;
272 } else {
273 // Bail out as a non-symbol non-index key makes caching impossible.
274 // ASSERT to make sure that the if condition after the loop is false.
275 ASSERT(number_of_symbol_keys != number_of_properties);
276 break;
277 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000278 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000279 // If we only have symbols and array indices among keys then we can
280 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000281 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000282 if ((number_of_symbol_keys == number_of_properties) &&
283 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000284 // Create the fixed array with the key.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000285 Handle<FixedArray> keys =
286 isolate->factory()->NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000287 if (number_of_symbol_keys > 0) {
288 int index = 0;
289 for (int p = 0; p < properties_length; p += 2) {
290 Object* key = constant_properties->get(p);
291 if (key->IsSymbol()) {
292 keys->set(index++, key);
293 }
294 }
295 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000296 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000297 *is_result_from_cache = true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000298 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000299 }
300 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000301 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000302 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000303 Handle<Map>(context->object_function()->initial_map()),
304 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000305}
306
307
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000308static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000309 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000310 Handle<FixedArray> literals,
311 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000312
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000313
314static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000315 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000316 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000317 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000318 bool should_have_fast_elements,
319 bool has_function_literal) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000320 // Get the global context from the literals array. This is the
321 // context in which the function was created and we use the object
322 // function from this context to create the object literal. We do
323 // not use the object function from the current global context
324 // because this might be the object function from another context
325 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000326 Handle<Context> context =
327 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
328
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000329 // In case we have function literals, we want the object to be in
330 // slow properties mode for now. We don't go in the map cache because
331 // maps with constant functions can't be shared if the functions are
332 // not the same (which is the common case).
333 bool is_result_from_cache = false;
334 Handle<Map> map = has_function_literal
335 ? Handle<Map>(context->object_function()->initial_map())
336 : ComputeObjectLiteralMap(context,
337 constant_properties,
338 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000339
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000340 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000341
342 // Normalize the elements of the boilerplate to save space if needed.
343 if (!should_have_fast_elements) NormalizeElements(boilerplate);
344
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000345 // Add the constant properties to the boilerplate.
346 int length = constant_properties->length();
347 bool should_transform =
348 !is_result_from_cache && boilerplate->HasFastProperties();
349 if (should_transform || has_function_literal) {
350 // Normalize the properties of object to avoid n^2 behavior
351 // when extending the object multiple properties. Indicate the number of
352 // properties to be added.
353 NormalizeProperties(boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
354 }
355
356 for (int index = 0; index < length; index +=2) {
357 Handle<Object> key(constant_properties->get(index+0), isolate);
358 Handle<Object> value(constant_properties->get(index+1), isolate);
359 if (value->IsFixedArray()) {
360 // The value contains the constant_properties of a
361 // simple object or array literal.
362 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
363 value = CreateLiteralBoilerplate(isolate, literals, array);
364 if (value.is_null()) return value;
365 }
366 Handle<Object> result;
367 uint32_t element_index = 0;
368 if (key->IsSymbol()) {
369 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
370 // Array index as string (uint32).
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000371 result = SetOwnElement(boilerplate,
372 element_index,
373 value,
374 kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000375 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000376 Handle<String> name(String::cast(*key));
377 ASSERT(!name->AsArrayIndex(&element_index));
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000378 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
379 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000380 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000381 } else if (key->ToArrayIndex(&element_index)) {
382 // Array index (uint32).
383 result = SetOwnElement(boilerplate,
384 element_index,
385 value,
386 kNonStrictMode);
387 } else {
388 // Non-uint32 number.
389 ASSERT(key->IsNumber());
390 double num = key->Number();
391 char arr[100];
392 Vector<char> buffer(arr, ARRAY_SIZE(arr));
393 const char* str = DoubleToCString(num, buffer);
394 Handle<String> name =
395 isolate->factory()->NewStringFromAscii(CStrVector(str));
396 result = SetLocalPropertyIgnoreAttributes(boilerplate, name,
397 value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000398 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000399 // If setting the property on the boilerplate throws an
400 // exception, the exception is converted to an empty handle in
401 // the handle based operations. In that case, we need to
402 // convert back to an exception.
403 if (result.is_null()) return result;
404 }
405
406 // Transform to fast properties if necessary. For object literals with
407 // containing function literals we defer this operation until after all
408 // computed properties have been assigned so that we can generate
409 // constant function properties.
410 if (should_transform && !has_function_literal) {
411 TransformToFastProperties(boilerplate,
412 boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000413 }
414
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000415 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000416}
417
418
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000419static Handle<Object> CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000420 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000421 Handle<FixedArray> literals,
422 Handle<FixedArray> elements) {
423 // Create the JSArray.
424 Handle<JSFunction> constructor(
425 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000426 Handle<Object> object = isolate->factory()->NewJSObject(constructor);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000427
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000428 const bool is_cow =
429 (elements->map() == isolate->heap()->fixed_cow_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000430 Handle<FixedArray> copied_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000431 is_cow ? elements : isolate->factory()->CopyFixedArray(elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000432
433 Handle<FixedArray> content = Handle<FixedArray>::cast(copied_elements);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000434 if (is_cow) {
435#ifdef DEBUG
436 // Copy-on-write arrays must be shallow (and simple).
437 for (int i = 0; i < content->length(); i++) {
438 ASSERT(!content->get(i)->IsFixedArray());
439 }
440#endif
441 } else {
442 for (int i = 0; i < content->length(); i++) {
443 if (content->get(i)->IsFixedArray()) {
444 // The value contains the constant_properties of a
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000445 // simple object or array literal.
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000446 Handle<FixedArray> fa(FixedArray::cast(content->get(i)));
447 Handle<Object> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000448 CreateLiteralBoilerplate(isolate, literals, fa);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000449 if (result.is_null()) return result;
450 content->set(i, *result);
451 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000452 }
453 }
454
455 // Set the elements.
456 Handle<JSArray>::cast(object)->SetContent(*content);
457 return object;
458}
459
460
461static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000462 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000463 Handle<FixedArray> literals,
464 Handle<FixedArray> array) {
465 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000466 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000467 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000468 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000469 return CreateObjectLiteralBoilerplate(isolate,
470 literals,
471 elements,
472 true,
473 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000474 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000475 return CreateObjectLiteralBoilerplate(isolate,
476 literals,
477 elements,
478 false,
479 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000480 case CompileTimeValue::ARRAY_LITERAL:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000481 return CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000482 default:
483 UNREACHABLE();
484 return Handle<Object>::null();
485 }
486}
487
488
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000489RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralBoilerplate) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000490 // Takes a FixedArray of elements containing the literal elements of
491 // the array literal and produces JSArray with those elements.
492 // Additionally takes the literals array of the surrounding function
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000493 // which contains the context from which to get the Array function
494 // to use for creating the array literal.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000495 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000496 ASSERT(args.length() == 3);
497 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000498 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000499 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000500
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000501 Handle<Object> object =
502 CreateArrayLiteralBoilerplate(isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000503 if (object.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000504
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000505 // Update the functions literal and return the boilerplate.
506 literals->set(literals_index, *object);
507 return *object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000508}
509
510
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000511RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000512 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000513 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000514 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000515 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000516 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000517 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000518 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
519 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000520
521 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000522 Handle<Object> boilerplate(literals->get(literals_index), isolate);
523 if (*boilerplate == isolate->heap()->undefined_value()) {
524 boilerplate = CreateObjectLiteralBoilerplate(isolate,
525 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000526 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000527 should_have_fast_elements,
528 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000529 if (boilerplate.is_null()) return Failure::Exception();
530 // Update the functions literal and return the boilerplate.
531 literals->set(literals_index, *boilerplate);
532 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000533 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000534}
535
536
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000537RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000538 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000539 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000540 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000541 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000542 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000543 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000544 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
545 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000546
547 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000548 Handle<Object> boilerplate(literals->get(literals_index), isolate);
549 if (*boilerplate == isolate->heap()->undefined_value()) {
550 boilerplate = CreateObjectLiteralBoilerplate(isolate,
551 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000552 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000553 should_have_fast_elements,
554 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000555 if (boilerplate.is_null()) return Failure::Exception();
556 // Update the functions literal and return the boilerplate.
557 literals->set(literals_index, *boilerplate);
558 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000559 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000560}
561
562
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000563RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000564 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000565 ASSERT(args.length() == 3);
566 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000567 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000568 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
569
570 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000571 Handle<Object> boilerplate(literals->get(literals_index), isolate);
572 if (*boilerplate == isolate->heap()->undefined_value()) {
573 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000574 if (boilerplate.is_null()) return Failure::Exception();
575 // Update the functions literal and return the boilerplate.
576 literals->set(literals_index, *boilerplate);
577 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000578 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000579}
580
581
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000582RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000583 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000584 ASSERT(args.length() == 3);
585 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000586 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000587 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
588
589 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000590 Handle<Object> boilerplate(literals->get(literals_index), isolate);
591 if (*boilerplate == isolate->heap()->undefined_value()) {
592 boilerplate = CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000593 if (boilerplate.is_null()) return Failure::Exception();
594 // Update the functions literal and return the boilerplate.
595 literals->set(literals_index, *boilerplate);
596 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000597 if (JSObject::cast(*boilerplate)->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000598 isolate->heap()->fixed_cow_array_map()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000599 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000600 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000601 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000602}
603
604
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000605RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) {
606 ASSERT(args.length() == 2);
607 Object* handler = args[0];
608 Object* prototype = args[1];
609 Object* used_prototype =
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000610 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000611 return isolate->heap()->AllocateJSProxy(handler, used_prototype);
612}
613
614
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000615RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) {
616 ASSERT(args.length() == 1);
617 Object* obj = args[0];
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000618 return isolate->heap()->ToBoolean(obj->IsJSProxy());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000619}
620
621
622RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) {
623 ASSERT(args.length() == 1);
624 CONVERT_CHECKED(JSProxy, proxy, args[0]);
625 return proxy->handler();
626}
627
628
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000629RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) {
630 ASSERT(args.length() == 1);
631 CONVERT_CHECKED(JSProxy, proxy, args[0]);
632 proxy->Fix();
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000633 return isolate->heap()->undefined_value();
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000634}
635
636
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000637RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapInitialize) {
638 HandleScope scope(isolate);
639 ASSERT(args.length() == 1);
640 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
641 ASSERT(weakmap->map()->inobject_properties() == 0);
642 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
643 weakmap->set_table(*table);
644 weakmap->set_next(Smi::FromInt(0));
645 return *weakmap;
646}
647
648
649RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapGet) {
650 NoHandleAllocation ha;
651 ASSERT(args.length() == 2);
652 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
653 // TODO(mstarzinger): Currently we cannot use JSProxy objects as keys
654 // because they cannot be cast to JSObject to get an identity hash code.
655 CONVERT_ARG_CHECKED(JSObject, key, 1);
656 return weakmap->table()->Lookup(*key);
657}
658
659
660RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapSet) {
661 HandleScope scope(isolate);
662 ASSERT(args.length() == 3);
663 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
664 // TODO(mstarzinger): See Runtime_WeakMapGet above.
665 CONVERT_ARG_CHECKED(JSObject, key, 1);
666 Handle<Object> value(args[2]);
667 Handle<ObjectHashTable> table(weakmap->table());
668 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
669 weakmap->set_table(*new_table);
670 return *value;
671}
672
673
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000674RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000675 NoHandleAllocation ha;
676 ASSERT(args.length() == 1);
677 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000678 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000679 return JSObject::cast(obj)->class_name();
680}
681
ager@chromium.org7c537e22008-10-16 08:43:32 +0000682
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000683RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) {
684 NoHandleAllocation ha;
685 ASSERT(args.length() == 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000686 CONVERT_CHECKED(JSReceiver, input_obj, args[0]);
687 Object* obj = input_obj;
688 // We don't expect access checks to be needed on JSProxy objects.
689 ASSERT(!obj->IsAccessCheckNeeded() || obj->IsJSObject());
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000690 do {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000691 if (obj->IsAccessCheckNeeded() &&
692 !isolate->MayNamedAccess(JSObject::cast(obj),
693 isolate->heap()->Proto_symbol(),
694 v8::ACCESS_GET)) {
695 isolate->ReportFailedAccessCheck(JSObject::cast(obj), v8::ACCESS_GET);
696 return isolate->heap()->undefined_value();
697 }
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000698 obj = obj->GetPrototype();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000699 } while (obj->IsJSObject() &&
700 JSObject::cast(obj)->map()->is_hidden_prototype());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000701 return obj;
702}
703
704
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000705RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000706 NoHandleAllocation ha;
707 ASSERT(args.length() == 2);
708 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
709 Object* O = args[0];
710 Object* V = args[1];
711 while (true) {
712 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000713 if (prototype->IsNull()) return isolate->heap()->false_value();
714 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000715 V = prototype;
716 }
717}
718
719
ager@chromium.org9085a012009-05-11 19:22:57 +0000720// Inserts an object as the hidden prototype of another object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000721RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHiddenPrototype) {
ager@chromium.org9085a012009-05-11 19:22:57 +0000722 NoHandleAllocation ha;
723 ASSERT(args.length() == 2);
724 CONVERT_CHECKED(JSObject, jsobject, args[0]);
725 CONVERT_CHECKED(JSObject, proto, args[1]);
726
727 // Sanity checks. The old prototype (that we are replacing) could
728 // theoretically be null, but if it is not null then check that we
729 // didn't already install a hidden prototype here.
730 RUNTIME_ASSERT(!jsobject->GetPrototype()->IsHeapObject() ||
731 !HeapObject::cast(jsobject->GetPrototype())->map()->is_hidden_prototype());
732 RUNTIME_ASSERT(!proto->map()->is_hidden_prototype());
733
734 // Allocate up front before we start altering state in case we get a GC.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000735 Object* map_or_failure;
736 { MaybeObject* maybe_map_or_failure = proto->map()->CopyDropTransitions();
737 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
738 return maybe_map_or_failure;
739 }
740 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000741 Map* new_proto_map = Map::cast(map_or_failure);
742
lrn@chromium.org303ada72010-10-27 09:33:13 +0000743 { MaybeObject* maybe_map_or_failure = jsobject->map()->CopyDropTransitions();
744 if (!maybe_map_or_failure->ToObject(&map_or_failure)) {
745 return maybe_map_or_failure;
746 }
747 }
ager@chromium.org9085a012009-05-11 19:22:57 +0000748 Map* new_map = Map::cast(map_or_failure);
749
750 // Set proto's prototype to be the old prototype of the object.
751 new_proto_map->set_prototype(jsobject->GetPrototype());
752 proto->set_map(new_proto_map);
753 new_proto_map->set_is_hidden_prototype();
754
755 // Set the object's prototype to proto.
756 new_map->set_prototype(proto);
757 jsobject->set_map(new_map);
758
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000759 return isolate->heap()->undefined_value();
ager@chromium.org9085a012009-05-11 19:22:57 +0000760}
761
762
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000763RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConstructCall) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000764 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000765 ASSERT(args.length() == 0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000766 JavaScriptFrameIterator it(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000767 return isolate->heap()->ToBoolean(it.frame()->IsConstructor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000768}
769
770
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000771// Recursively traverses hidden prototypes if property is not found
772static void GetOwnPropertyImplementation(JSObject* obj,
773 String* name,
774 LookupResult* result) {
775 obj->LocalLookupRealNamedProperty(name, result);
776
777 if (!result->IsProperty()) {
778 Object* proto = obj->GetPrototype();
779 if (proto->IsJSObject() &&
780 JSObject::cast(proto)->map()->is_hidden_prototype())
781 GetOwnPropertyImplementation(JSObject::cast(proto),
782 name, result);
783 }
784}
785
786
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000787static bool CheckAccessException(LookupResult* result,
788 v8::AccessType access_type) {
789 if (result->type() == CALLBACKS) {
790 Object* callback = result->GetCallbackObject();
791 if (callback->IsAccessorInfo()) {
792 AccessorInfo* info = AccessorInfo::cast(callback);
793 bool can_access =
794 (access_type == v8::ACCESS_HAS &&
795 (info->all_can_read() || info->all_can_write())) ||
796 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
797 (access_type == v8::ACCESS_SET && info->all_can_write());
798 return can_access;
799 }
800 }
801
802 return false;
803}
804
805
806static bool CheckAccess(JSObject* obj,
807 String* name,
808 LookupResult* result,
809 v8::AccessType access_type) {
810 ASSERT(result->IsProperty());
811
812 JSObject* holder = result->holder();
813 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000814 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000815 while (true) {
816 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000817 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000818 // Access check callback denied the access, but some properties
819 // can have a special permissions which override callbacks descision
820 // (currently see v8::AccessControl).
821 break;
822 }
823
824 if (current == holder) {
825 return true;
826 }
827
828 current = JSObject::cast(current->GetPrototype());
829 }
830
831 // API callbacks can have per callback access exceptions.
832 switch (result->type()) {
833 case CALLBACKS: {
834 if (CheckAccessException(result, access_type)) {
835 return true;
836 }
837 break;
838 }
839 case INTERCEPTOR: {
840 // If the object has an interceptor, try real named properties.
841 // Overwrite the result to fetch the correct property later.
842 holder->LookupRealNamedProperty(name, result);
843 if (result->IsProperty()) {
844 if (CheckAccessException(result, access_type)) {
845 return true;
846 }
847 }
848 break;
849 }
850 default:
851 break;
852 }
853
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000854 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000855 return false;
856}
857
858
859// TODO(1095): we should traverse hidden prototype hierachy as well.
860static bool CheckElementAccess(JSObject* obj,
861 uint32_t index,
862 v8::AccessType access_type) {
863 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000864 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000865 return false;
866 }
867
868 return true;
869}
870
871
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000872// Enumerator used as indices into the array returned from GetOwnProperty
873enum PropertyDescriptorIndices {
874 IS_ACCESSOR_INDEX,
875 VALUE_INDEX,
876 GETTER_INDEX,
877 SETTER_INDEX,
878 WRITABLE_INDEX,
879 ENUMERABLE_INDEX,
880 CONFIGURABLE_INDEX,
881 DESCRIPTOR_SIZE
882};
883
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000884// Returns an array with the property description:
885// if args[1] is not a property on args[0]
886// returns undefined
887// if args[1] is a data property on args[0]
888// [false, value, Writeable, Enumerable, Configurable]
889// if args[1] is an accessor on args[0]
890// [true, GetFunction, SetFunction, Enumerable, Configurable]
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000891RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000892 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000893 Heap* heap = isolate->heap();
894 HandleScope scope(isolate);
895 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
896 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000897 LookupResult result;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000898 CONVERT_ARG_CHECKED(JSObject, obj, 0);
899 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000900
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000901 // This could be an element.
902 uint32_t index;
903 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000904 switch (obj->HasLocalElement(index)) {
905 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000906 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000907
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000908 case JSObject::STRING_CHARACTER_ELEMENT: {
909 // Special handling of string objects according to ECMAScript 5
910 // 15.5.5.2. Note that this might be a string object with elements
911 // other than the actual string value. This is covered by the
912 // subsequent cases.
913 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
914 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000915 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000916
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000917 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000918 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000919 elms->set(WRITABLE_INDEX, heap->false_value());
920 elms->set(ENUMERABLE_INDEX, heap->false_value());
921 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000922 return *desc;
923 }
924
925 case JSObject::INTERCEPTED_ELEMENT:
926 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000927 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000928 Handle<Object> value = GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000929 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000930 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000931 elms->set(WRITABLE_INDEX, heap->true_value());
932 elms->set(ENUMERABLE_INDEX, heap->true_value());
933 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000934 return *desc;
935 }
936
937 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000938 Handle<JSObject> holder = obj;
939 if (obj->IsJSGlobalProxy()) {
940 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000941 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000942 ASSERT(proto->IsJSGlobalObject());
943 holder = Handle<JSObject>(JSObject::cast(proto));
944 }
whesse@chromium.org7b260152011-06-20 15:33:18 +0000945 FixedArray* elements = FixedArray::cast(holder->elements());
946 NumberDictionary* dictionary = NULL;
947 if (elements->map() == heap->non_strict_arguments_elements_map()) {
948 dictionary = NumberDictionary::cast(elements->get(1));
949 } else {
950 dictionary = NumberDictionary::cast(elements);
951 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000952 int entry = dictionary->FindEntry(index);
953 ASSERT(entry != NumberDictionary::kNotFound);
954 PropertyDetails details = dictionary->DetailsAt(entry);
955 switch (details.type()) {
956 case CALLBACKS: {
957 // This is an accessor property with getter and/or setter.
958 FixedArray* callbacks =
959 FixedArray::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000960 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000961 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
962 elms->set(GETTER_INDEX, callbacks->get(0));
963 }
964 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
965 elms->set(SETTER_INDEX, callbacks->get(1));
966 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000967 break;
968 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000969 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000970 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000971 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000972 Handle<Object> value = GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000973 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000974 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000975 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000976 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000977 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000978 default:
979 UNREACHABLE();
980 break;
981 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000982 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
983 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000984 return *desc;
985 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000986 }
987 }
988
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000989 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000990 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000991
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000992 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000993 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000994 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000995
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000996 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000997 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000998 }
999
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001000 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
1001 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001002
1003 bool is_js_accessor = (result.type() == CALLBACKS) &&
1004 (result.GetCallbackObject()->IsFixedArray());
1005
1006 if (is_js_accessor) {
1007 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001008 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001009
1010 FixedArray* structure = FixedArray::cast(result.GetCallbackObject());
1011 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
1012 elms->set(GETTER_INDEX, structure->get(0));
1013 }
1014 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
1015 elms->set(SETTER_INDEX, structure->get(1));
1016 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001017 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001018 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
1019 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001020
1021 PropertyAttributes attrs;
1022 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001023 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001024 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
1025 if (!maybe_value->ToObject(&value)) return maybe_value;
1026 }
1027 elms->set(VALUE_INDEX, value);
1028 }
1029
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001030 return *desc;
1031}
1032
1033
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001034RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001035 ASSERT(args.length() == 1);
1036 CONVERT_CHECKED(JSObject, obj, args[0]);
1037 return obj->PreventExtensions();
1038}
1039
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001040
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001041RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001042 ASSERT(args.length() == 1);
1043 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001044 if (obj->IsJSGlobalProxy()) {
1045 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001046 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001047 ASSERT(proto->IsJSGlobalObject());
1048 obj = JSObject::cast(proto);
1049 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001050 return isolate->heap()->ToBoolean(obj->map()->is_extensible());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001051}
1052
1053
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001054RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001055 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001056 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001057 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
1058 CONVERT_ARG_CHECKED(String, pattern, 1);
1059 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001060 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
1061 if (result.is_null()) return Failure::Exception();
1062 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001063}
1064
1065
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001066RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001067 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001068 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001069 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001070 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001071}
1072
1073
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001074RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001075 ASSERT(args.length() == 1);
1076 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001077 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001078 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001079}
1080
1081
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001082RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001083 ASSERT(args.length() == 2);
1084 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001085 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001086 int index = field->value();
1087 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1088 InstanceType type = templ->map()->instance_type();
1089 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1090 type == OBJECT_TEMPLATE_INFO_TYPE);
1091 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001092 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001093 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1094 } else {
1095 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1096 }
1097 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001098}
1099
1100
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001101RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001102 ASSERT(args.length() == 1);
1103 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001104 Map* old_map = object->map();
1105 bool needs_access_checks = old_map->is_access_check_needed();
1106 if (needs_access_checks) {
1107 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001108 Object* new_map;
1109 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1110 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1111 }
ager@chromium.org32912102009-01-16 10:38:43 +00001112
1113 Map::cast(new_map)->set_is_access_check_needed(false);
1114 object->set_map(Map::cast(new_map));
1115 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001116 return isolate->heap()->ToBoolean(needs_access_checks);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001117}
1118
1119
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001120RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001121 ASSERT(args.length() == 1);
1122 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001123 Map* old_map = object->map();
1124 if (!old_map->is_access_check_needed()) {
1125 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001126 Object* new_map;
1127 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1128 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1129 }
ager@chromium.org32912102009-01-16 10:38:43 +00001130
1131 Map::cast(new_map)->set_is_access_check_needed(true);
1132 object->set_map(Map::cast(new_map));
1133 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001134 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001135}
1136
1137
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001138static Failure* ThrowRedeclarationError(Isolate* isolate,
1139 const char* type,
1140 Handle<String> name) {
1141 HandleScope scope(isolate);
1142 Handle<Object> type_handle =
1143 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001144 Handle<Object> args[2] = { type_handle, name };
1145 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001146 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1147 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001148}
1149
1150
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001151RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001152 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001153 HandleScope scope(isolate);
1154 Handle<GlobalObject> global = Handle<GlobalObject>(
1155 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001156
ager@chromium.org3811b432009-10-28 14:53:37 +00001157 Handle<Context> context = args.at<Context>(0);
1158 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001159 bool is_eval = args.smi_at(2) == 1;
1160 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(args.smi_at(3));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001161 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001162
1163 // Compute the property attributes. According to ECMA-262, section
1164 // 13, page 71, the property must be read-only and
1165 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1166 // property as read-only, so we don't either.
1167 PropertyAttributes base = is_eval ? NONE : DONT_DELETE;
1168
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001169 // Traverse the name/value pairs and set the properties.
1170 int length = pairs->length();
1171 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001172 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001173 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001174 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001175
1176 // We have to declare a global const property. To capture we only
1177 // assign to it when evaluating the assignment for "const x =
1178 // <expr>" the initial value is the hole.
1179 bool is_const_property = value->IsTheHole();
1180
1181 if (value->IsUndefined() || is_const_property) {
1182 // Lookup the property in the global object, and don't set the
1183 // value of the variable if the property is already there.
1184 LookupResult lookup;
1185 global->Lookup(*name, &lookup);
1186 if (lookup.IsProperty()) {
1187 // Determine if the property is local by comparing the holder
1188 // against the global object. The information will be used to
1189 // avoid throwing re-declaration errors when declaring
1190 // variables or constants that exist in the prototype chain.
1191 bool is_local = (*global == lookup.holder());
1192 // Get the property attributes and determine if the property is
1193 // read-only.
1194 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1195 bool is_read_only = (attributes & READ_ONLY) != 0;
1196 if (lookup.type() == INTERCEPTOR) {
1197 // If the interceptor says the property is there, we
1198 // just return undefined without overwriting the property.
1199 // Otherwise, we continue to setting the property.
1200 if (attributes != ABSENT) {
1201 // Check if the existing property conflicts with regards to const.
1202 if (is_local && (is_read_only || is_const_property)) {
1203 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001204 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001205 };
1206 // The property already exists without conflicting: Go to
1207 // the next declaration.
1208 continue;
1209 }
1210 // Fall-through and introduce the absent property by using
1211 // SetProperty.
1212 } else {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001213 // For const properties, we treat a callback with this name
1214 // even in the prototype as a conflicting declaration.
1215 if (is_const_property && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001216 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001217 }
1218 // Otherwise, we check for locally conflicting declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001219 if (is_local && (is_read_only || is_const_property)) {
1220 const char* type = (is_read_only) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001221 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001222 }
1223 // The property already exists without conflicting: Go to
1224 // the next declaration.
1225 continue;
1226 }
1227 }
1228 } else {
1229 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001230 Handle<SharedFunctionInfo> shared =
1231 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001232 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001233 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1234 context,
1235 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001236 value = function;
1237 }
1238
1239 LookupResult lookup;
1240 global->LocalLookup(*name, &lookup);
1241
1242 PropertyAttributes attributes = is_const_property
1243 ? static_cast<PropertyAttributes>(base | READ_ONLY)
1244 : base;
1245
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001246 // There's a local property that we need to overwrite because
1247 // we're either declaring a function or there's an interceptor
1248 // that claims the property is absent.
1249 //
1250 // Check for conflicting re-declarations. We cannot have
1251 // conflicting types in case of intercepted properties because
1252 // they are absent.
1253 if (lookup.IsProperty() &&
1254 (lookup.type() != INTERCEPTOR) &&
1255 (lookup.IsReadOnly() || is_const_property)) {
1256 const char* type = (lookup.IsReadOnly()) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001257 return ThrowRedeclarationError(isolate, type, name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001258 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001259
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001260 // Safari does not allow the invocation of callback setters for
1261 // function declarations. To mimic this behavior, we do not allow
1262 // the invocation of setters for function values. This makes a
1263 // difference for global functions with the same names as event
1264 // handlers such as "function onload() {}". Firefox does call the
1265 // onload setter in those case and Safari does not. We follow
1266 // Safari for compatibility.
1267 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001268 // Do not change DONT_DELETE to false from true.
1269 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
1270 attributes = static_cast<PropertyAttributes>(
1271 attributes | (lookup.GetAttributes() & DONT_DELETE));
1272 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001273 RETURN_IF_EMPTY_HANDLE(isolate,
1274 SetLocalPropertyIgnoreAttributes(global,
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001275 name,
1276 value,
1277 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001278 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001279 RETURN_IF_EMPTY_HANDLE(isolate,
1280 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001281 name,
1282 value,
1283 attributes,
1284 strict_mode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001285 }
1286 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001287
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001288 ASSERT(!isolate->has_pending_exception());
1289 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001290}
1291
1292
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001293RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001294 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001295 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001296
ager@chromium.org7c537e22008-10-16 08:43:32 +00001297 CONVERT_ARG_CHECKED(Context, context, 0);
1298 Handle<String> name(String::cast(args[1]));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001299 PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001300 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001301 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001302
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001303 // Declarations are always done in a function or global context.
1304 context = Handle<Context>(context->declaration_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001305
1306 int index;
1307 PropertyAttributes attributes;
1308 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001309 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001310 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001311 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001312
1313 if (attributes != ABSENT) {
1314 // The name was declared before; check for conflicting
1315 // re-declarations: This is similar to the code in parser.cc in
1316 // the AstBuildingParser::Declare function.
1317 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1318 // Functions are not read-only.
1319 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1320 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001321 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001322 }
1323
1324 // Initialize it if necessary.
1325 if (*initial_value != NULL) {
1326 if (index >= 0) {
1327 // The variable or constant context slot should always be in
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +00001328 // the function context or the arguments object.
1329 if (holder->IsContext()) {
1330 ASSERT(holder.is_identical_to(context));
1331 if (((attributes & READ_ONLY) == 0) ||
1332 context->get(index)->IsTheHole()) {
1333 context->set(index, *initial_value);
1334 }
1335 } else {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001336 // The holder is an arguments object.
1337 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001338 Handle<Object> result = SetElement(arguments, index, initial_value,
1339 kNonStrictMode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001340 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001341 }
1342 } else {
1343 // Slow case: The property is not in the FixedArray part of the context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001344 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001345 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001346 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001347 SetProperty(context_ext, name, initial_value,
1348 mode, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001349 }
1350 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001351
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001352 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001353 // The property is not in the function context. It needs to be
1354 // "declared" in the function context's extension context, or in the
1355 // global context.
1356 Handle<JSObject> context_ext;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001357 if (context->has_extension()) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001358 // The function context's extension context exists - use it.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001359 context_ext = Handle<JSObject>(JSObject::cast(context->extension()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001360 } else {
1361 // The function context's extension context does not exists - allocate
1362 // it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001363 context_ext = isolate->factory()->NewJSObject(
1364 isolate->context_extension_function());
ager@chromium.org7c537e22008-10-16 08:43:32 +00001365 // And store it in the extension slot.
1366 context->set_extension(*context_ext);
1367 }
1368 ASSERT(*context_ext != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001369
ager@chromium.org7c537e22008-10-16 08:43:32 +00001370 // Declare the property by setting it to the initial value if provided,
1371 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1372 // constant declarations).
1373 ASSERT(!context_ext->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001374 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001375 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001376 // Declaring a const context slot is a conflicting declaration if
1377 // there is a callback with that name in a prototype. It is
1378 // allowed to introduce const variables in
1379 // JSContextExtensionObjects. They are treated specially in
1380 // SetProperty and no setters are invoked for those since they are
1381 // not real JSObjects.
1382 if (initial_value->IsTheHole() &&
1383 !context_ext->IsJSContextExtensionObject()) {
1384 LookupResult lookup;
1385 context_ext->Lookup(*name, &lookup);
1386 if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001387 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001388 }
1389 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001390 RETURN_IF_EMPTY_HANDLE(isolate,
1391 SetProperty(context_ext, name, value, mode,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001392 kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001393 }
1394
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001395 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001396}
1397
1398
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001399RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001400 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001401 // args[0] == name
1402 // args[1] == strict_mode
1403 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001404
1405 // Determine if we need to assign to the variable if it already
1406 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001407 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1408 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001409
1410 CONVERT_ARG_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001411 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001412 RUNTIME_ASSERT(args[1]->IsSmi());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001413 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(args.smi_at(1));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001414 ASSERT(strict_mode == kStrictMode || strict_mode == kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001415
1416 // According to ECMA-262, section 12.2, page 62, the property must
1417 // not be deletable.
1418 PropertyAttributes attributes = DONT_DELETE;
1419
1420 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001421 // there, there is a property with this name in the prototype chain.
1422 // We follow Safari and Firefox behavior and only set the property
1423 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001424 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001425 // Note that objects can have hidden prototypes, so we need to traverse
1426 // the whole chain of hidden prototypes to do a 'local' lookup.
1427 JSObject* real_holder = global;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001428 LookupResult lookup;
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001429 while (true) {
1430 real_holder->LocalLookup(*name, &lookup);
1431 if (lookup.IsProperty()) {
1432 // Determine if this is a redeclaration of something read-only.
1433 if (lookup.IsReadOnly()) {
1434 // If we found readonly property on one of hidden prototypes,
1435 // just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001436 if (real_holder != isolate->context()->global()) break;
1437 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001438 }
1439
1440 // Determine if this is a redeclaration of an intercepted read-only
1441 // property and figure out if the property exists at all.
1442 bool found = true;
1443 PropertyType type = lookup.type();
1444 if (type == INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001445 HandleScope handle_scope(isolate);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001446 Handle<JSObject> holder(real_holder);
1447 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1448 real_holder = *holder;
1449 if (intercepted == ABSENT) {
1450 // The interceptor claims the property isn't there. We need to
1451 // make sure to introduce it.
1452 found = false;
1453 } else if ((intercepted & READ_ONLY) != 0) {
1454 // The property is present, but read-only. Since we're trying to
1455 // overwrite it with a variable declaration we must throw a
1456 // re-declaration error. However if we found readonly property
1457 // on one of hidden prototypes, just shadow it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001458 if (real_holder != isolate->context()->global()) break;
1459 return ThrowRedeclarationError(isolate, "const", name);
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001460 }
1461 }
1462
1463 if (found && !assign) {
1464 // The global property is there and we're not assigning any value
1465 // to it. Just return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001466 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001467 }
1468
1469 // Assign the value (or undefined) to the property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001470 Object* value = (assign) ? args[2] : isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001471 return real_holder->SetProperty(
1472 &lookup, *name, value, attributes, strict_mode);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001473 }
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001474
1475 Object* proto = real_holder->GetPrototype();
1476 if (!proto->IsJSObject())
1477 break;
1478
1479 if (!JSObject::cast(proto)->map()->is_hidden_prototype())
1480 break;
1481
1482 real_holder = JSObject::cast(proto);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001483 }
1484
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001485 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001486 if (assign) {
1487 return global->SetProperty(*name, args[2], attributes, strict_mode);
1488 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001489 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001490}
1491
1492
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001493RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001494 // All constants are declared with an initial value. The name
1495 // of the constant is the first argument and the initial value
1496 // is the second.
1497 RUNTIME_ASSERT(args.length() == 2);
1498 CONVERT_ARG_CHECKED(String, name, 0);
1499 Handle<Object> value = args.at<Object>(1);
1500
1501 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001502 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001503
1504 // According to ECMA-262, section 12.2, page 62, the property must
1505 // not be deletable. Since it's a const, it must be READ_ONLY too.
1506 PropertyAttributes attributes =
1507 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1508
1509 // Lookup the property locally in the global object. If it isn't
1510 // there, we add the property and take special precautions to always
1511 // add it as a local property even in case of callbacks in the
1512 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001513 // We use SetLocalPropertyIgnoreAttributes instead
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001514 LookupResult lookup;
1515 global->LocalLookup(*name, &lookup);
1516 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001517 return global->SetLocalPropertyIgnoreAttributes(*name,
1518 *value,
1519 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001520 }
1521
1522 // Determine if this is a redeclaration of something not
1523 // read-only. In case the result is hidden behind an interceptor we
1524 // need to ask it for the property attributes.
1525 if (!lookup.IsReadOnly()) {
1526 if (lookup.type() != INTERCEPTOR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001527 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001528 }
1529
1530 PropertyAttributes intercepted = global->GetPropertyAttribute(*name);
1531
1532 // Throw re-declaration error if the intercepted property is present
1533 // but not read-only.
1534 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001535 return ThrowRedeclarationError(isolate, "var", name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001536 }
1537
1538 // Restore global object from context (in case of GC) and continue
1539 // with setting the value because the property is either absent or
1540 // read-only. We also have to do redo the lookup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001541 HandleScope handle_scope(isolate);
1542 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001543
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001544 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001545 // property through an interceptor and only do it if it's
1546 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001547 // Passing non-strict mode because the property is writable.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001548 RETURN_IF_EMPTY_HANDLE(isolate,
1549 SetProperty(global,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001550 name,
1551 value,
1552 attributes,
1553 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001554 return *value;
1555 }
1556
1557 // Set the value, but only we're assigning the initial value to a
1558 // constant. For now, we determine this by checking if the
1559 // current value is the hole.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001560 // Strict mode handling not needed (const disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001561 PropertyType type = lookup.type();
1562 if (type == FIELD) {
1563 FixedArray* properties = global->properties();
1564 int index = lookup.GetFieldIndex();
1565 if (properties->get(index)->IsTheHole()) {
1566 properties->set(index, *value);
1567 }
1568 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001569 if (global->GetNormalizedProperty(&lookup)->IsTheHole()) {
1570 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001571 }
1572 } else {
1573 // Ignore re-initialization of constants that have already been
1574 // assigned a function value.
1575 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1576 }
1577
1578 // Use the set value as the result of the operation.
1579 return *value;
1580}
1581
1582
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001583RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001584 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001585 ASSERT(args.length() == 3);
1586
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001587 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001588 ASSERT(!value->IsTheHole());
1589 CONVERT_ARG_CHECKED(Context, context, 1);
1590 Handle<String> name(String::cast(args[2]));
1591
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001592 // Initializations are always done in a function or global context.
1593 context = Handle<Context>(context->declaration_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001594
1595 int index;
1596 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001597 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001598 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001599 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001600 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001601
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001602 // In most situations, the property introduced by the const
1603 // declaration should be present in the context extension object.
1604 // However, because declaration and initialization are separate, the
1605 // property might have been deleted (if it was introduced by eval)
1606 // before we reach the initialization point.
1607 //
1608 // Example:
1609 //
1610 // function f() { eval("delete x; const x;"); }
1611 //
1612 // In that case, the initialization behaves like a normal assignment
1613 // to property 'x'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001614 if (index >= 0) {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001615 if (holder->IsContext()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001616 // Property was found in a context. Perform the assignment if we
1617 // found some non-constant or an uninitialized constant.
1618 Handle<Context> context = Handle<Context>::cast(holder);
1619 if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
1620 context->set(index, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001621 }
1622 } else {
1623 // The holder is an arguments object.
1624 ASSERT((attributes & READ_ONLY) == 0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001625 Handle<JSObject> arguments(Handle<JSObject>::cast(holder));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001626 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001627 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001628 SetElement(arguments, index, value, kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001629 }
1630 return *value;
1631 }
1632
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001633 // The property could not be found, we introduce it in the global
1634 // context.
1635 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001636 Handle<JSObject> global = Handle<JSObject>(
1637 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001638 // Strict mode not needed (const disallowed in strict mode).
1639 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001640 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001641 SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001642 return *value;
1643 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001644
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001645 // The property was present in a context extension object.
1646 Handle<JSObject> context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001647
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001648 if (*context_ext == context->extension()) {
1649 // This is the property that was introduced by the const
1650 // declaration. Set it if it hasn't been set before. NOTE: We
1651 // cannot use GetProperty() to get the current value as it
1652 // 'unholes' the value.
1653 LookupResult lookup;
1654 context_ext->LocalLookupRealNamedProperty(*name, &lookup);
1655 ASSERT(lookup.IsProperty()); // the property was declared
1656 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1657
1658 PropertyType type = lookup.type();
1659 if (type == FIELD) {
1660 FixedArray* properties = context_ext->properties();
1661 int index = lookup.GetFieldIndex();
1662 if (properties->get(index)->IsTheHole()) {
1663 properties->set(index, *value);
1664 }
1665 } else if (type == NORMAL) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001666 if (context_ext->GetNormalizedProperty(&lookup)->IsTheHole()) {
1667 context_ext->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001668 }
1669 } else {
1670 // We should not reach here. Any real, named property should be
1671 // either a field or a dictionary slot.
1672 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001673 }
1674 } else {
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001675 // The property was found in a different context extension object.
1676 // Set it if it is not a read-only property.
1677 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001678 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001679 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001680 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001681 SetProperty(context_ext, name, value, attributes, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001682 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001683 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001684
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001685 return *value;
1686}
1687
1688
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001689RUNTIME_FUNCTION(MaybeObject*,
1690 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001691 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001692 ASSERT(args.length() == 2);
1693 CONVERT_ARG_CHECKED(JSObject, object, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001694 CONVERT_SMI_ARG_CHECKED(properties, 1);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001695 if (object->HasFastProperties()) {
1696 NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
1697 }
1698 return *object;
1699}
1700
1701
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001702RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001703 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001704 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001705 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1706 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001707 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001708 // length of a string, i.e. it is always a Smi. We check anyway for security.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001709 CONVERT_SMI_ARG_CHECKED(index, 2);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001710 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001711 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001712 RUNTIME_ASSERT(index >= 0);
1713 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001714 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001715 Handle<Object> result = RegExpImpl::Exec(regexp,
1716 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001717 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001718 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001719 if (result.is_null()) return Failure::Exception();
1720 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001721}
1722
1723
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001724RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001725 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001726 CONVERT_SMI_ARG_CHECKED(elements_count, 0);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00001727 if (elements_count < 0 ||
1728 elements_count > FixedArray::kMaxLength ||
1729 !Smi::IsValid(elements_count)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001730 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001731 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001732 Object* new_object;
1733 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001734 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001735 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1736 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001737 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001738 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1739 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001740 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1741 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001742 {
1743 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001744 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001745 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001746 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001747 }
1748 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001749 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001750 array->set_elements(elements);
1751 array->set_length(Smi::FromInt(elements_count));
1752 // Write in-object properties after the length of the array.
1753 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1754 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1755 return array;
1756}
1757
1758
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001759RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001760 AssertNoAllocation no_alloc;
1761 ASSERT(args.length() == 5);
1762 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1763 CONVERT_CHECKED(String, source, args[1]);
1764
1765 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001766 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001767
1768 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001769 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001770
1771 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001772 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001773
1774 Map* map = regexp->map();
1775 Object* constructor = map->constructor();
1776 if (constructor->IsJSFunction() &&
1777 JSFunction::cast(constructor)->initial_map() == map) {
1778 // If we still have the original map, set in-object properties directly.
1779 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
1780 // TODO(lrn): Consider skipping write barrier on booleans as well.
1781 // Both true and false should be in oldspace at all times.
1782 regexp->InObjectPropertyAtPut(JSRegExp::kGlobalFieldIndex, global);
1783 regexp->InObjectPropertyAtPut(JSRegExp::kIgnoreCaseFieldIndex, ignoreCase);
1784 regexp->InObjectPropertyAtPut(JSRegExp::kMultilineFieldIndex, multiline);
1785 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1786 Smi::FromInt(0),
1787 SKIP_WRITE_BARRIER);
1788 return regexp;
1789 }
1790
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001791 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001792 PropertyAttributes final =
1793 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1794 PropertyAttributes writable =
1795 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001796 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001797 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001798 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001799 source,
1800 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001801 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001802 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001803 global,
1804 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001805 ASSERT(!result->IsFailure());
1806 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001807 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001808 ignoreCase,
1809 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001810 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001811 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001812 multiline,
1813 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001814 ASSERT(!result->IsFailure());
1815 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001816 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001817 Smi::FromInt(0),
1818 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001819 ASSERT(!result->IsFailure());
1820 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001821 return regexp;
1822}
1823
1824
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001825RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001826 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001827 ASSERT(args.length() == 1);
1828 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1829 // This is necessary to enable fast checks for absence of elements
1830 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001831 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001832 return Smi::FromInt(0);
1833}
1834
1835
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001836static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1837 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001838 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001839 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001840 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1841 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1842 Handle<JSFunction> optimized =
1843 isolate->factory()->NewFunction(key,
1844 JS_OBJECT_TYPE,
1845 JSObject::kHeaderSize,
1846 code,
1847 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001848 optimized->shared()->DontAdaptArguments();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001849 SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001850 return optimized;
1851}
1852
1853
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001854RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001855 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001856 ASSERT(args.length() == 1);
1857 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1858
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001859 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1860 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1861 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1862 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1863 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1864 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1865 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001866
1867 return *holder;
1868}
1869
1870
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001871RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultReceiver) {
1872 NoHandleAllocation handle_free;
1873 ASSERT(args.length() == 1);
1874 CONVERT_CHECKED(JSFunction, function, args[0]);
1875 SharedFunctionInfo* shared = function->shared();
1876 if (shared->native() || shared->strict_mode()) {
1877 return isolate->heap()->undefined_value();
1878 }
1879 // Returns undefined for strict or native functions, or
1880 // the associated global receiver for "normal" functions.
1881
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001882 Context* global_context =
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001883 function->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001884 return global_context->global()->global_receiver();
1885}
1886
1887
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001888RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001889 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001890 ASSERT(args.length() == 4);
1891 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001892 int index = args.smi_at(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001893 Handle<String> pattern = args.at<String>(2);
1894 Handle<String> flags = args.at<String>(3);
1895
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001896 // Get the RegExp function from the context in the literals array.
1897 // This is the RegExp function from the context in which the
1898 // function was created. We do not use the RegExp function from the
1899 // current global context because this might be the RegExp function
1900 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001901 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001902 Handle<JSFunction>(
1903 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001904 // Compute the regular expression literal.
1905 bool has_pending_exception;
1906 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001907 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1908 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001909 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001910 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001911 return Failure::Exception();
1912 }
1913 literals->set(index, *regexp);
1914 return *regexp;
1915}
1916
1917
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001918RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001919 NoHandleAllocation ha;
1920 ASSERT(args.length() == 1);
1921
1922 CONVERT_CHECKED(JSFunction, f, args[0]);
1923 return f->shared()->name();
1924}
1925
1926
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001927RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001928 NoHandleAllocation ha;
1929 ASSERT(args.length() == 2);
1930
1931 CONVERT_CHECKED(JSFunction, f, args[0]);
1932 CONVERT_CHECKED(String, name, args[1]);
1933 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001934 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001935}
1936
1937
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001938RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionNameShouldPrintAsAnonymous) {
1939 NoHandleAllocation ha;
1940 ASSERT(args.length() == 1);
1941 CONVERT_CHECKED(JSFunction, f, args[0]);
1942 return isolate->heap()->ToBoolean(
1943 f->shared()->name_should_print_as_anonymous());
1944}
1945
1946
1947RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionMarkNameShouldPrintAsAnonymous) {
1948 NoHandleAllocation ha;
1949 ASSERT(args.length() == 1);
1950 CONVERT_CHECKED(JSFunction, f, args[0]);
1951 f->shared()->set_name_should_print_as_anonymous(true);
1952 return isolate->heap()->undefined_value();
1953}
1954
1955
whesse@chromium.org7b260152011-06-20 15:33:18 +00001956RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetBound) {
1957 HandleScope scope(isolate);
1958 ASSERT(args.length() == 1);
1959
1960 CONVERT_CHECKED(JSFunction, fun, args[0]);
1961 fun->shared()->set_bound(true);
1962 return isolate->heap()->undefined_value();
1963}
1964
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001965RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001966 NoHandleAllocation ha;
1967 ASSERT(args.length() == 1);
1968
1969 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001970 Object* obj = f->RemovePrototype();
1971 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001972
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001973 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001974}
1975
1976
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001977RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001978 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001979 ASSERT(args.length() == 1);
1980
1981 CONVERT_CHECKED(JSFunction, fun, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001982 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
1983 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001984
1985 return *GetScriptWrapper(Handle<Script>::cast(script));
1986}
1987
1988
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001989RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001990 NoHandleAllocation ha;
1991 ASSERT(args.length() == 1);
1992
1993 CONVERT_CHECKED(JSFunction, f, args[0]);
1994 return f->shared()->GetSourceCode();
1995}
1996
1997
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001998RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001999 NoHandleAllocation ha;
2000 ASSERT(args.length() == 1);
2001
2002 CONVERT_CHECKED(JSFunction, fun, args[0]);
2003 int pos = fun->shared()->start_position();
2004 return Smi::FromInt(pos);
2005}
2006
2007
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002008RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002009 ASSERT(args.length() == 2);
2010
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002011 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002012 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
2013
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002014 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
2015
2016 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002017 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002018}
2019
2020
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002021RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002022 NoHandleAllocation ha;
2023 ASSERT(args.length() == 2);
2024
2025 CONVERT_CHECKED(JSFunction, fun, args[0]);
2026 CONVERT_CHECKED(String, name, args[1]);
2027 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002028 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002029}
2030
2031
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002032RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002033 NoHandleAllocation ha;
2034 ASSERT(args.length() == 2);
2035
2036 CONVERT_CHECKED(JSFunction, fun, args[0]);
2037 CONVERT_CHECKED(Smi, length, args[1]);
2038 fun->shared()->set_length(length->value());
2039 return length;
2040}
2041
2042
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002043// Creates a local, readonly, property called length with the correct
2044// length (when read by the user). This effectively overwrites the
2045// interceptor used to normally provide the length.
2046RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionSetLength) {
2047 NoHandleAllocation ha;
2048 ASSERT(args.length() == 2);
2049 CONVERT_CHECKED(JSFunction, fun, args[0]);
2050 CONVERT_CHECKED(Smi, length, args[1]);
2051 MaybeObject* maybe_name =
2052 isolate->heap()->AllocateStringFromAscii(CStrVector("length"));
2053 String* name;
2054 if (!maybe_name->To(&name)) return maybe_name;
2055 PropertyAttributes attr =
2056 static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
2057 return fun->AddProperty(name, length, attr, kNonStrictMode);
2058}
2059
2060
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002061RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002062 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002063 ASSERT(args.length() == 2);
2064
2065 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002066 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00002067 Object* obj;
2068 { MaybeObject* maybe_obj =
2069 Accessors::FunctionSetPrototype(fun, args[1], NULL);
2070 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2071 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002072 return args[0]; // return TOS
2073}
2074
2075
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002076RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) {
2077 NoHandleAllocation ha;
2078 RUNTIME_ASSERT(args.length() == 1);
2079 CONVERT_CHECKED(JSFunction, function, args[0]);
2080
2081 MaybeObject* maybe_name =
2082 isolate->heap()->AllocateStringFromAscii(CStrVector("prototype"));
2083 String* name;
2084 if (!maybe_name->To(&name)) return maybe_name;
2085
2086 if (function->HasFastProperties()) {
2087 // Construct a new field descriptor with updated attributes.
2088 DescriptorArray* instance_desc = function->map()->instance_descriptors();
2089 int index = instance_desc->Search(name);
2090 ASSERT(index != DescriptorArray::kNotFound);
2091 PropertyDetails details(instance_desc->GetDetails(index));
2092 CallbacksDescriptor new_desc(name,
2093 instance_desc->GetValue(index),
2094 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2095 details.index());
2096 // Construct a new field descriptors array containing the new descriptor.
2097 Object* descriptors_unchecked;
2098 { MaybeObject* maybe_descriptors_unchecked =
2099 instance_desc->CopyInsert(&new_desc, REMOVE_TRANSITIONS);
2100 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
2101 return maybe_descriptors_unchecked;
2102 }
2103 }
2104 DescriptorArray* new_descriptors =
2105 DescriptorArray::cast(descriptors_unchecked);
2106 // Create a new map featuring the new field descriptors array.
2107 Object* map_unchecked;
2108 { MaybeObject* maybe_map_unchecked = function->map()->CopyDropDescriptors();
2109 if (!maybe_map_unchecked->ToObject(&map_unchecked)) {
2110 return maybe_map_unchecked;
2111 }
2112 }
2113 Map* new_map = Map::cast(map_unchecked);
2114 new_map->set_instance_descriptors(new_descriptors);
2115 function->set_map(new_map);
2116 } else { // Dictionary properties.
2117 // Directly manipulate the property details.
2118 int entry = function->property_dictionary()->FindEntry(name);
2119 ASSERT(entry != StringDictionary::kNotFound);
2120 PropertyDetails details = function->property_dictionary()->DetailsAt(entry);
2121 PropertyDetails new_details(
2122 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2123 details.type(),
2124 details.index());
2125 function->property_dictionary()->DetailsAtPut(entry, new_details);
2126 }
2127 return function;
2128}
2129
2130
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002131RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002132 NoHandleAllocation ha;
2133 ASSERT(args.length() == 1);
2134
2135 CONVERT_CHECKED(JSFunction, f, args[0]);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002136 return isolate->heap()->ToBoolean(f->shared()->IsApiFunction());
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002137}
2138
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002139
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002140RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002141 NoHandleAllocation ha;
2142 ASSERT(args.length() == 1);
2143
2144 CONVERT_CHECKED(JSFunction, f, args[0]);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002145 return isolate->heap()->ToBoolean(f->IsBuiltin());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002146}
2147
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002148
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002149RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002150 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002151 ASSERT(args.length() == 2);
2152
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002153 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002154 Handle<Object> code = args.at<Object>(1);
2155
2156 Handle<Context> context(target->context());
2157
2158 if (!code->IsNull()) {
2159 RUNTIME_ASSERT(code->IsJSFunction());
2160 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002161 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002162
2163 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002164 return Failure::Exception();
2165 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002166 // Since we don't store the source for this we should never
2167 // optimize this.
2168 shared->code()->set_optimizable(false);
2169
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002170 // Set the code, scope info, formal parameter count,
2171 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00002172 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002173 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002174 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002175 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002176 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002177 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002178 // Set the source code of the target function to undefined.
2179 // SetCode is only used for built-in constructors like String,
2180 // Array, and Object, and some web code
2181 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002182 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002183 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002184 // Clear the optimization hints related to the compiled code as these are no
2185 // longer valid when the code is overwritten.
2186 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002187 context = Handle<Context>(fun->context());
2188
2189 // Make sure we get a fresh copy of the literal vector to avoid
2190 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002191 int number_of_literals = fun->NumberOfLiterals();
2192 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002193 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002194 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002195 // Insert the object, regexp and array functions in the literals
2196 // array prefix. These are the functions that will be used when
2197 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002198 literals->set(JSFunction::kLiteralGlobalContextIndex,
2199 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002200 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002201 // It's okay to skip the write barrier here because the literals
2202 // are guaranteed to be in old space.
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002203 target->set_literals(*literals, SKIP_WRITE_BARRIER);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002204 target->set_next_function_link(isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002205 }
2206
2207 target->set_context(*context);
2208 return *target;
2209}
2210
2211
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002212RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002213 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002214 ASSERT(args.length() == 2);
2215 CONVERT_ARG_CHECKED(JSFunction, function, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002216 CONVERT_SMI_ARG_CHECKED(num, 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002217 RUNTIME_ASSERT(num >= 0);
2218 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002219 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002220}
2221
2222
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002223MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2224 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002225 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002226 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002227 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002228 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002229 }
2230 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002231 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002232}
2233
2234
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002235RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002236 NoHandleAllocation ha;
2237 ASSERT(args.length() == 2);
2238
2239 CONVERT_CHECKED(String, subject, args[0]);
2240 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002241 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002242
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002243 uint32_t i = 0;
2244 if (index->IsSmi()) {
2245 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002246 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002247 i = value;
2248 } else {
2249 ASSERT(index->IsHeapNumber());
2250 double value = HeapNumber::cast(index)->value();
2251 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002252 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002253
2254 // Flatten the string. If someone wants to get a char at an index
2255 // in a cons string, it is likely that more indices will be
2256 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002257 Object* flat;
2258 { MaybeObject* maybe_flat = subject->TryFlatten();
2259 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2260 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002261 subject = String::cast(flat);
2262
2263 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002264 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002265 }
2266
2267 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002268}
2269
2270
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002271RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002272 NoHandleAllocation ha;
2273 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002274 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002275}
2276
lrn@chromium.org25156de2010-04-06 13:10:27 +00002277
2278class FixedArrayBuilder {
2279 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002280 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2281 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002282 length_(0) {
2283 // Require a non-zero initial size. Ensures that doubling the size to
2284 // extend the array will work.
2285 ASSERT(initial_capacity > 0);
2286 }
2287
2288 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2289 : array_(backing_store),
2290 length_(0) {
2291 // Require a non-zero initial size. Ensures that doubling the size to
2292 // extend the array will work.
2293 ASSERT(backing_store->length() > 0);
2294 }
2295
2296 bool HasCapacity(int elements) {
2297 int length = array_->length();
2298 int required_length = length_ + elements;
2299 return (length >= required_length);
2300 }
2301
2302 void EnsureCapacity(int elements) {
2303 int length = array_->length();
2304 int required_length = length_ + elements;
2305 if (length < required_length) {
2306 int new_length = length;
2307 do {
2308 new_length *= 2;
2309 } while (new_length < required_length);
2310 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002311 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002312 array_->CopyTo(0, *extended_array, 0, length_);
2313 array_ = extended_array;
2314 }
2315 }
2316
2317 void Add(Object* value) {
2318 ASSERT(length_ < capacity());
2319 array_->set(length_, value);
2320 length_++;
2321 }
2322
2323 void Add(Smi* value) {
2324 ASSERT(length_ < capacity());
2325 array_->set(length_, value);
2326 length_++;
2327 }
2328
2329 Handle<FixedArray> array() {
2330 return array_;
2331 }
2332
2333 int length() {
2334 return length_;
2335 }
2336
2337 int capacity() {
2338 return array_->length();
2339 }
2340
2341 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002342 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002343 result_array->set_length(Smi::FromInt(length_));
2344 return result_array;
2345 }
2346
2347 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
2348 target_array->set_elements(*array_);
2349 target_array->set_length(Smi::FromInt(length_));
2350 return target_array;
2351 }
2352
2353 private:
2354 Handle<FixedArray> array_;
2355 int length_;
2356};
2357
2358
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002359// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002360const int kStringBuilderConcatHelperLengthBits = 11;
2361const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002362
2363template <typename schar>
2364static inline void StringBuilderConcatHelper(String*,
2365 schar*,
2366 FixedArray*,
2367 int);
2368
lrn@chromium.org25156de2010-04-06 13:10:27 +00002369typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2370 StringBuilderSubstringLength;
2371typedef BitField<int,
2372 kStringBuilderConcatHelperLengthBits,
2373 kStringBuilderConcatHelperPositionBits>
2374 StringBuilderSubstringPosition;
2375
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002376
2377class ReplacementStringBuilder {
2378 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002379 ReplacementStringBuilder(Heap* heap,
2380 Handle<String> subject,
2381 int estimated_part_count)
2382 : heap_(heap),
2383 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002384 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002385 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002386 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002387 // Require a non-zero initial size. Ensures that doubling the size to
2388 // extend the array will work.
2389 ASSERT(estimated_part_count > 0);
2390 }
2391
lrn@chromium.org25156de2010-04-06 13:10:27 +00002392 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2393 int from,
2394 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002395 ASSERT(from >= 0);
2396 int length = to - from;
2397 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002398 if (StringBuilderSubstringLength::is_valid(length) &&
2399 StringBuilderSubstringPosition::is_valid(from)) {
2400 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2401 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002402 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002403 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002404 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002405 builder->Add(Smi::FromInt(-length));
2406 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002407 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002408 }
2409
2410
2411 void EnsureCapacity(int elements) {
2412 array_builder_.EnsureCapacity(elements);
2413 }
2414
2415
2416 void AddSubjectSlice(int from, int to) {
2417 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002418 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002419 }
2420
2421
2422 void AddString(Handle<String> string) {
2423 int length = string->length();
2424 ASSERT(length > 0);
2425 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002426 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002427 is_ascii_ = false;
2428 }
2429 IncrementCharacterCount(length);
2430 }
2431
2432
2433 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002434 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002435 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002436 }
2437
2438 Handle<String> joined_string;
2439 if (is_ascii_) {
ager@chromium.org04921a82011-06-27 13:21:41 +00002440 Handle<SeqAsciiString> seq = NewRawAsciiString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002441 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002442 char* char_buffer = seq->GetChars();
2443 StringBuilderConcatHelper(*subject_,
2444 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002445 *array_builder_.array(),
2446 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002447 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002448 } else {
2449 // Non-ASCII.
ager@chromium.org04921a82011-06-27 13:21:41 +00002450 Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002451 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002452 uc16* char_buffer = seq->GetChars();
2453 StringBuilderConcatHelper(*subject_,
2454 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002455 *array_builder_.array(),
2456 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002457 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002458 }
2459 return joined_string;
2460 }
2461
2462
2463 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002464 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002465 V8::FatalProcessOutOfMemory("String.replace result too large.");
2466 }
2467 character_count_ += by;
2468 }
2469
lrn@chromium.org25156de2010-04-06 13:10:27 +00002470 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002471 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002472 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002473
lrn@chromium.org25156de2010-04-06 13:10:27 +00002474 private:
ager@chromium.org04921a82011-06-27 13:21:41 +00002475 Handle<SeqAsciiString> NewRawAsciiString(int length) {
2476 return heap_->isolate()->factory()->NewRawAsciiString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002477 }
2478
2479
ager@chromium.org04921a82011-06-27 13:21:41 +00002480 Handle<SeqTwoByteString> NewRawTwoByteString(int length) {
2481 return heap_->isolate()->factory()->NewRawTwoByteString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002482 }
2483
2484
2485 void AddElement(Object* element) {
2486 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002487 ASSERT(array_builder_.capacity() > array_builder_.length());
2488 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002489 }
2490
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002491 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002492 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002493 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002494 int character_count_;
2495 bool is_ascii_;
2496};
2497
2498
2499class CompiledReplacement {
2500 public:
2501 CompiledReplacement()
2502 : parts_(1), replacement_substrings_(0) {}
2503
2504 void Compile(Handle<String> replacement,
2505 int capture_count,
2506 int subject_length);
2507
2508 void Apply(ReplacementStringBuilder* builder,
2509 int match_from,
2510 int match_to,
2511 Handle<JSArray> last_match_info);
2512
2513 // Number of distinct parts of the replacement pattern.
2514 int parts() {
2515 return parts_.length();
2516 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002517
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002518 private:
2519 enum PartType {
2520 SUBJECT_PREFIX = 1,
2521 SUBJECT_SUFFIX,
2522 SUBJECT_CAPTURE,
2523 REPLACEMENT_SUBSTRING,
2524 REPLACEMENT_STRING,
2525
2526 NUMBER_OF_PART_TYPES
2527 };
2528
2529 struct ReplacementPart {
2530 static inline ReplacementPart SubjectMatch() {
2531 return ReplacementPart(SUBJECT_CAPTURE, 0);
2532 }
2533 static inline ReplacementPart SubjectCapture(int capture_index) {
2534 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2535 }
2536 static inline ReplacementPart SubjectPrefix() {
2537 return ReplacementPart(SUBJECT_PREFIX, 0);
2538 }
2539 static inline ReplacementPart SubjectSuffix(int subject_length) {
2540 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2541 }
2542 static inline ReplacementPart ReplacementString() {
2543 return ReplacementPart(REPLACEMENT_STRING, 0);
2544 }
2545 static inline ReplacementPart ReplacementSubString(int from, int to) {
2546 ASSERT(from >= 0);
2547 ASSERT(to > from);
2548 return ReplacementPart(-from, to);
2549 }
2550
2551 // If tag <= 0 then it is the negation of a start index of a substring of
2552 // the replacement pattern, otherwise it's a value from PartType.
2553 ReplacementPart(int tag, int data)
2554 : tag(tag), data(data) {
2555 // Must be non-positive or a PartType value.
2556 ASSERT(tag < NUMBER_OF_PART_TYPES);
2557 }
2558 // Either a value of PartType or a non-positive number that is
2559 // the negation of an index into the replacement string.
2560 int tag;
2561 // The data value's interpretation depends on the value of tag:
2562 // tag == SUBJECT_PREFIX ||
2563 // tag == SUBJECT_SUFFIX: data is unused.
2564 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2565 // tag == REPLACEMENT_SUBSTRING ||
2566 // tag == REPLACEMENT_STRING: data is index into array of substrings
2567 // of the replacement string.
2568 // tag <= 0: Temporary representation of the substring of the replacement
2569 // string ranging over -tag .. data.
2570 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2571 // substring objects.
2572 int data;
2573 };
2574
2575 template<typename Char>
2576 static void ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
2577 Vector<Char> characters,
2578 int capture_count,
2579 int subject_length) {
2580 int length = characters.length();
2581 int last = 0;
2582 for (int i = 0; i < length; i++) {
2583 Char c = characters[i];
2584 if (c == '$') {
2585 int next_index = i + 1;
2586 if (next_index == length) { // No next character!
2587 break;
2588 }
2589 Char c2 = characters[next_index];
2590 switch (c2) {
2591 case '$':
2592 if (i > last) {
2593 // There is a substring before. Include the first "$".
2594 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2595 last = next_index + 1; // Continue after the second "$".
2596 } else {
2597 // Let the next substring start with the second "$".
2598 last = next_index;
2599 }
2600 i = next_index;
2601 break;
2602 case '`':
2603 if (i > last) {
2604 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2605 }
2606 parts->Add(ReplacementPart::SubjectPrefix());
2607 i = next_index;
2608 last = i + 1;
2609 break;
2610 case '\'':
2611 if (i > last) {
2612 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2613 }
2614 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2615 i = next_index;
2616 last = i + 1;
2617 break;
2618 case '&':
2619 if (i > last) {
2620 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2621 }
2622 parts->Add(ReplacementPart::SubjectMatch());
2623 i = next_index;
2624 last = i + 1;
2625 break;
2626 case '0':
2627 case '1':
2628 case '2':
2629 case '3':
2630 case '4':
2631 case '5':
2632 case '6':
2633 case '7':
2634 case '8':
2635 case '9': {
2636 int capture_ref = c2 - '0';
2637 if (capture_ref > capture_count) {
2638 i = next_index;
2639 continue;
2640 }
2641 int second_digit_index = next_index + 1;
2642 if (second_digit_index < length) {
2643 // Peek ahead to see if we have two digits.
2644 Char c3 = characters[second_digit_index];
2645 if ('0' <= c3 && c3 <= '9') { // Double digits.
2646 int double_digit_ref = capture_ref * 10 + c3 - '0';
2647 if (double_digit_ref <= capture_count) {
2648 next_index = second_digit_index;
2649 capture_ref = double_digit_ref;
2650 }
2651 }
2652 }
2653 if (capture_ref > 0) {
2654 if (i > last) {
2655 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2656 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002657 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002658 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2659 last = next_index + 1;
2660 }
2661 i = next_index;
2662 break;
2663 }
2664 default:
2665 i = next_index;
2666 break;
2667 }
2668 }
2669 }
2670 if (length > last) {
2671 if (last == 0) {
2672 parts->Add(ReplacementPart::ReplacementString());
2673 } else {
2674 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2675 }
2676 }
2677 }
2678
2679 ZoneList<ReplacementPart> parts_;
2680 ZoneList<Handle<String> > replacement_substrings_;
2681};
2682
2683
2684void CompiledReplacement::Compile(Handle<String> replacement,
2685 int capture_count,
2686 int subject_length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002687 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002688 AssertNoAllocation no_alloc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002689 String::FlatContent content = replacement->GetFlatContent();
2690 ASSERT(content.IsFlat());
2691 if (content.IsAscii()) {
2692 ParseReplacementPattern(&parts_,
2693 content.ToAsciiVector(),
2694 capture_count,
2695 subject_length);
2696 } else {
2697 ASSERT(content.IsTwoByte());
2698 ParseReplacementPattern(&parts_,
2699 content.ToUC16Vector(),
2700 capture_count,
2701 subject_length);
2702 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002703 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002704 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002705 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002706 int substring_index = 0;
2707 for (int i = 0, n = parts_.length(); i < n; i++) {
2708 int tag = parts_[i].tag;
2709 if (tag <= 0) { // A replacement string slice.
2710 int from = -tag;
2711 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002712 replacement_substrings_.Add(
2713 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002714 parts_[i].tag = REPLACEMENT_SUBSTRING;
2715 parts_[i].data = substring_index;
2716 substring_index++;
2717 } else if (tag == REPLACEMENT_STRING) {
2718 replacement_substrings_.Add(replacement);
2719 parts_[i].data = substring_index;
2720 substring_index++;
2721 }
2722 }
2723}
2724
2725
2726void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2727 int match_from,
2728 int match_to,
2729 Handle<JSArray> last_match_info) {
2730 for (int i = 0, n = parts_.length(); i < n; i++) {
2731 ReplacementPart part = parts_[i];
2732 switch (part.tag) {
2733 case SUBJECT_PREFIX:
2734 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2735 break;
2736 case SUBJECT_SUFFIX: {
2737 int subject_length = part.data;
2738 if (match_to < subject_length) {
2739 builder->AddSubjectSlice(match_to, subject_length);
2740 }
2741 break;
2742 }
2743 case SUBJECT_CAPTURE: {
2744 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002745 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002746 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2747 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2748 if (from >= 0 && to > from) {
2749 builder->AddSubjectSlice(from, to);
2750 }
2751 break;
2752 }
2753 case REPLACEMENT_SUBSTRING:
2754 case REPLACEMENT_STRING:
2755 builder->AddString(replacement_substrings_[part.data]);
2756 break;
2757 default:
2758 UNREACHABLE();
2759 }
2760 }
2761}
2762
2763
2764
lrn@chromium.org303ada72010-10-27 09:33:13 +00002765MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002766 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002767 String* subject,
2768 JSRegExp* regexp,
2769 String* replacement,
2770 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002771 ASSERT(subject->IsFlat());
2772 ASSERT(replacement->IsFlat());
2773
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002774 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002775
2776 int length = subject->length();
2777 Handle<String> subject_handle(subject);
2778 Handle<JSRegExp> regexp_handle(regexp);
2779 Handle<String> replacement_handle(replacement);
2780 Handle<JSArray> last_match_info_handle(last_match_info);
2781 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2782 subject_handle,
2783 0,
2784 last_match_info_handle);
2785 if (match.is_null()) {
2786 return Failure::Exception();
2787 }
2788 if (match->IsNull()) {
2789 return *subject_handle;
2790 }
2791
2792 int capture_count = regexp_handle->CaptureCount();
2793
2794 // CompiledReplacement uses zone allocation.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002795 ZoneScope zone(isolate, DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002796 CompiledReplacement compiled_replacement;
2797 compiled_replacement.Compile(replacement_handle,
2798 capture_count,
2799 length);
2800
2801 bool is_global = regexp_handle->GetFlags().is_global();
2802
2803 // Guessing the number of parts that the final result string is built
2804 // from. Global regexps can match any number of times, so we guess
2805 // conservatively.
2806 int expected_parts =
2807 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002808 ReplacementStringBuilder builder(isolate->heap(),
2809 subject_handle,
2810 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002811
2812 // Index of end of last match.
2813 int prev = 0;
2814
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002815 // Number of parts added by compiled replacement plus preceeding
2816 // string and possibly suffix after last match. It is possible for
2817 // all components to use two elements when encoded as two smis.
2818 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002819 bool matched = true;
2820 do {
2821 ASSERT(last_match_info_handle->HasFastElements());
2822 // Increase the capacity of the builder before entering local handle-scope,
2823 // so its internal buffer can safely allocate a new handle if it grows.
2824 builder.EnsureCapacity(parts_added_per_loop);
2825
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002826 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002827 int start, end;
2828 {
2829 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002830 FixedArray* match_info_array =
2831 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002832
2833 ASSERT_EQ(capture_count * 2 + 2,
2834 RegExpImpl::GetLastCaptureCount(match_info_array));
2835 start = RegExpImpl::GetCapture(match_info_array, 0);
2836 end = RegExpImpl::GetCapture(match_info_array, 1);
2837 }
2838
2839 if (prev < start) {
2840 builder.AddSubjectSlice(prev, start);
2841 }
2842 compiled_replacement.Apply(&builder,
2843 start,
2844 end,
2845 last_match_info_handle);
2846 prev = end;
2847
2848 // Only continue checking for global regexps.
2849 if (!is_global) break;
2850
2851 // Continue from where the match ended, unless it was an empty match.
2852 int next = end;
2853 if (start == end) {
2854 next = end + 1;
2855 if (next > length) break;
2856 }
2857
2858 match = RegExpImpl::Exec(regexp_handle,
2859 subject_handle,
2860 next,
2861 last_match_info_handle);
2862 if (match.is_null()) {
2863 return Failure::Exception();
2864 }
2865 matched = !match->IsNull();
2866 } while (matched);
2867
2868 if (prev < length) {
2869 builder.AddSubjectSlice(prev, length);
2870 }
2871
2872 return *(builder.ToString());
2873}
2874
2875
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002876template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00002877MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002878 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002879 String* subject,
2880 JSRegExp* regexp,
2881 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002882 ASSERT(subject->IsFlat());
2883
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002884 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002885
2886 Handle<String> subject_handle(subject);
2887 Handle<JSRegExp> regexp_handle(regexp);
2888 Handle<JSArray> last_match_info_handle(last_match_info);
2889 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2890 subject_handle,
2891 0,
2892 last_match_info_handle);
2893 if (match.is_null()) return Failure::Exception();
2894 if (match->IsNull()) return *subject_handle;
2895
2896 ASSERT(last_match_info_handle->HasFastElements());
2897
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002898 int start, end;
2899 {
2900 AssertNoAllocation match_info_array_is_not_in_a_handle;
2901 FixedArray* match_info_array =
2902 FixedArray::cast(last_match_info_handle->elements());
2903
2904 start = RegExpImpl::GetCapture(match_info_array, 0);
2905 end = RegExpImpl::GetCapture(match_info_array, 1);
2906 }
2907
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00002908 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002909 int new_length = length - (end - start);
2910 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002911 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002912 }
2913 Handle<ResultSeqString> answer;
2914 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002915 answer = Handle<ResultSeqString>::cast(
2916 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002917 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002918 answer = Handle<ResultSeqString>::cast(
2919 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002920 }
2921
2922 // If the regexp isn't global, only match once.
2923 if (!regexp_handle->GetFlags().is_global()) {
2924 if (start > 0) {
2925 String::WriteToFlat(*subject_handle,
2926 answer->GetChars(),
2927 0,
2928 start);
2929 }
2930 if (end < length) {
2931 String::WriteToFlat(*subject_handle,
2932 answer->GetChars() + start,
2933 end,
2934 length);
2935 }
2936 return *answer;
2937 }
2938
2939 int prev = 0; // Index of end of last match.
2940 int next = 0; // Start of next search (prev unless last match was empty).
2941 int position = 0;
2942
2943 do {
2944 if (prev < start) {
2945 // Add substring subject[prev;start] to answer string.
2946 String::WriteToFlat(*subject_handle,
2947 answer->GetChars() + position,
2948 prev,
2949 start);
2950 position += start - prev;
2951 }
2952 prev = end;
2953 next = end;
2954 // Continue from where the match ended, unless it was an empty match.
2955 if (start == end) {
2956 next++;
2957 if (next > length) break;
2958 }
2959 match = RegExpImpl::Exec(regexp_handle,
2960 subject_handle,
2961 next,
2962 last_match_info_handle);
2963 if (match.is_null()) return Failure::Exception();
2964 if (match->IsNull()) break;
2965
2966 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002967 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002968 {
2969 AssertNoAllocation match_info_array_is_not_in_a_handle;
2970 FixedArray* match_info_array =
2971 FixedArray::cast(last_match_info_handle->elements());
2972 start = RegExpImpl::GetCapture(match_info_array, 0);
2973 end = RegExpImpl::GetCapture(match_info_array, 1);
2974 }
2975 } while (true);
2976
2977 if (prev < length) {
2978 // Add substring subject[prev;length] to answer string.
2979 String::WriteToFlat(*subject_handle,
2980 answer->GetChars() + position,
2981 prev,
2982 length);
2983 position += length - prev;
2984 }
2985
2986 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002987 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002988 }
2989
2990 // Shorten string and fill
2991 int string_size = ResultSeqString::SizeFor(position);
2992 int allocated_string_size = ResultSeqString::SizeFor(new_length);
2993 int delta = allocated_string_size - string_size;
2994
2995 answer->set_length(position);
2996 if (delta == 0) return *answer;
2997
2998 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002999 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003000
3001 return *answer;
3002}
3003
3004
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003005RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003006 ASSERT(args.length() == 4);
3007
3008 CONVERT_CHECKED(String, subject, args[0]);
3009 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003010 Object* flat_subject;
3011 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
3012 if (!maybe_flat_subject->ToObject(&flat_subject)) {
3013 return maybe_flat_subject;
3014 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003015 }
3016 subject = String::cast(flat_subject);
3017 }
3018
3019 CONVERT_CHECKED(String, replacement, args[2]);
3020 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003021 Object* flat_replacement;
3022 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
3023 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
3024 return maybe_flat_replacement;
3025 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003026 }
3027 replacement = String::cast(flat_replacement);
3028 }
3029
3030 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
3031 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
3032
3033 ASSERT(last_match_info->HasFastElements());
3034
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003035 if (replacement->length() == 0) {
3036 if (subject->HasOnlyAsciiChars()) {
3037 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003038 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003039 } else {
3040 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003041 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003042 }
3043 }
3044
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003045 return StringReplaceRegExpWithString(isolate,
3046 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003047 regexp,
3048 replacement,
3049 last_match_info);
3050}
3051
3052
ager@chromium.org7c537e22008-10-16 08:43:32 +00003053// Perform string match of pattern on subject, starting at start index.
3054// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003055// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003056int Runtime::StringMatch(Isolate* isolate,
3057 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00003058 Handle<String> pat,
3059 int start_index) {
3060 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003061 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00003062
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003063 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003064 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003065
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003066 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00003067 if (start_index + pattern_length > subject_length) return -1;
3068
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003069 if (!sub->IsFlat()) FlattenString(sub);
3070 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00003071
ager@chromium.org7c537e22008-10-16 08:43:32 +00003072 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003073 // Extract flattened substrings of cons strings before determining asciiness.
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003074 String::FlatContent seq_sub = sub->GetFlatContent();
3075 String::FlatContent seq_pat = pat->GetFlatContent();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003076
ager@chromium.org7c537e22008-10-16 08:43:32 +00003077 // dispatch on type of strings
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003078 if (seq_pat.IsAscii()) {
3079 Vector<const char> pat_vector = seq_pat.ToAsciiVector();
3080 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003081 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003082 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003083 pat_vector,
3084 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003085 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003086 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003087 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003088 pat_vector,
3089 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003090 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003091 Vector<const uc16> pat_vector = seq_pat.ToUC16Vector();
3092 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003093 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003094 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003095 pat_vector,
3096 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003097 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003098 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003099 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003100 pat_vector,
3101 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003102}
3103
3104
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003105RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003106 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003107 ASSERT(args.length() == 3);
3108
ager@chromium.org7c537e22008-10-16 08:43:32 +00003109 CONVERT_ARG_CHECKED(String, sub, 0);
3110 CONVERT_ARG_CHECKED(String, pat, 1);
3111
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003112 Object* index = args[2];
3113 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003114 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003115
ager@chromium.org870a0b62008-11-04 11:43:05 +00003116 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003117 int position =
3118 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003119 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003120}
3121
3122
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003123template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003124static int StringMatchBackwards(Vector<const schar> subject,
3125 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003126 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003127 int pattern_length = pattern.length();
3128 ASSERT(pattern_length >= 1);
3129 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003130
3131 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003132 for (int i = 0; i < pattern_length; i++) {
3133 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003134 if (c > String::kMaxAsciiCharCode) {
3135 return -1;
3136 }
3137 }
3138 }
3139
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003140 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003141 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003142 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003143 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003144 while (j < pattern_length) {
3145 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003146 break;
3147 }
3148 j++;
3149 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003150 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003151 return i;
3152 }
3153 }
3154 return -1;
3155}
3156
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003157RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003158 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003159 ASSERT(args.length() == 3);
3160
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003161 CONVERT_ARG_CHECKED(String, sub, 0);
3162 CONVERT_ARG_CHECKED(String, pat, 1);
3163
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003164 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003165 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003166 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003167
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003168 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003169 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003170
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003171 if (start_index + pat_length > sub_length) {
3172 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00003173 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003174
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003175 if (pat_length == 0) {
3176 return Smi::FromInt(start_index);
3177 }
3178
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003179 if (!sub->IsFlat()) FlattenString(sub);
3180 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003181
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003182 int position = -1;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003183 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3184
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003185 String::FlatContent sub_content = sub->GetFlatContent();
3186 String::FlatContent pat_content = pat->GetFlatContent();
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003187
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003188 if (pat_content.IsAscii()) {
3189 Vector<const char> pat_vector = pat_content.ToAsciiVector();
3190 if (sub_content.IsAscii()) {
3191 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003192 pat_vector,
3193 start_index);
3194 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003195 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003196 pat_vector,
3197 start_index);
3198 }
3199 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003200 Vector<const uc16> pat_vector = pat_content.ToUC16Vector();
3201 if (sub_content.IsAscii()) {
3202 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003203 pat_vector,
3204 start_index);
3205 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003206 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003207 pat_vector,
3208 start_index);
3209 }
3210 }
3211
3212 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003213}
3214
3215
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003216RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003217 NoHandleAllocation ha;
3218 ASSERT(args.length() == 2);
3219
3220 CONVERT_CHECKED(String, str1, args[0]);
3221 CONVERT_CHECKED(String, str2, args[1]);
3222
3223 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003224 int str1_length = str1->length();
3225 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003226
3227 // Decide trivial cases without flattening.
3228 if (str1_length == 0) {
3229 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3230 return Smi::FromInt(-str2_length);
3231 } else {
3232 if (str2_length == 0) return Smi::FromInt(str1_length);
3233 }
3234
3235 int end = str1_length < str2_length ? str1_length : str2_length;
3236
3237 // No need to flatten if we are going to find the answer on the first
3238 // character. At this point we know there is at least one character
3239 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003240 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003241 if (d != 0) return Smi::FromInt(d);
3242
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003243 str1->TryFlatten();
3244 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003245
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003246 StringInputBuffer& buf1 =
3247 *isolate->runtime_state()->string_locale_compare_buf1();
3248 StringInputBuffer& buf2 =
3249 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003250
3251 buf1.Reset(str1);
3252 buf2.Reset(str2);
3253
3254 for (int i = 0; i < end; i++) {
3255 uint16_t char1 = buf1.GetNext();
3256 uint16_t char2 = buf2.GetNext();
3257 if (char1 != char2) return Smi::FromInt(char1 - char2);
3258 }
3259
3260 return Smi::FromInt(str1_length - str2_length);
3261}
3262
3263
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003264RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003265 NoHandleAllocation ha;
3266 ASSERT(args.length() == 3);
3267
3268 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003269 int start, end;
3270 // We have a fast integer-only case here to avoid a conversion to double in
3271 // the common case where from and to are Smis.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003272 if (args[1]->IsSmi() && args[2]->IsSmi()) {
3273 CONVERT_SMI_ARG_CHECKED(from_number, 1);
3274 CONVERT_SMI_ARG_CHECKED(to_number, 2);
3275 start = from_number;
3276 end = to_number;
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003277 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003278 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
3279 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003280 start = FastD2I(from_number);
3281 end = FastD2I(to_number);
3282 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003283 RUNTIME_ASSERT(end >= start);
3284 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003285 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003286 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003287 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003288}
3289
3290
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003291RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003292 ASSERT_EQ(3, args.length());
3293
3294 CONVERT_ARG_CHECKED(String, subject, 0);
3295 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3296 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
3297 HandleScope handles;
3298
3299 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3300
3301 if (match.is_null()) {
3302 return Failure::Exception();
3303 }
3304 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003305 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003306 }
3307 int length = subject->length();
3308
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003309 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003310 ZoneList<int> offsets(8);
ager@chromium.org04921a82011-06-27 13:21:41 +00003311 int start;
3312 int end;
ager@chromium.org41826e72009-03-30 13:30:57 +00003313 do {
ager@chromium.org41826e72009-03-30 13:30:57 +00003314 {
3315 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003316 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003317 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3318 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3319 }
3320 offsets.Add(start);
3321 offsets.Add(end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003322 if (start == end) if (++end > length) break;
3323 match = RegExpImpl::Exec(regexp, subject, end, regexp_info);
ager@chromium.org41826e72009-03-30 13:30:57 +00003324 if (match.is_null()) {
3325 return Failure::Exception();
3326 }
3327 } while (!match->IsNull());
3328 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003329 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org04921a82011-06-27 13:21:41 +00003330 Handle<String> substring = isolate->factory()->
3331 NewSubString(subject, offsets.at(0), offsets.at(1));
3332 elements->set(0, *substring);
3333 for (int i = 1; i < matches ; i++) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003334 int from = offsets.at(i * 2);
3335 int to = offsets.at(i * 2 + 1);
ager@chromium.org04921a82011-06-27 13:21:41 +00003336 Handle<String> substring = isolate->factory()->
3337 NewProperSubString(subject, from, to);
3338 elements->set(i, *substring);
ager@chromium.org41826e72009-03-30 13:30:57 +00003339 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003340 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003341 result->set_length(Smi::FromInt(matches));
3342 return *result;
3343}
3344
3345
lrn@chromium.org25156de2010-04-06 13:10:27 +00003346// Two smis before and after the match, for very long strings.
3347const int kMaxBuilderEntriesPerRegExpMatch = 5;
3348
3349
3350static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3351 Handle<JSArray> last_match_info,
3352 int match_start,
3353 int match_end) {
3354 // Fill last_match_info with a single capture.
3355 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3356 AssertNoAllocation no_gc;
3357 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3358 RegExpImpl::SetLastCaptureCount(elements, 2);
3359 RegExpImpl::SetLastInput(elements, *subject);
3360 RegExpImpl::SetLastSubject(elements, *subject);
3361 RegExpImpl::SetCapture(elements, 0, match_start);
3362 RegExpImpl::SetCapture(elements, 1, match_end);
3363}
3364
3365
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003366template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003367static bool SearchStringMultiple(Isolate* isolate,
3368 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003369 Vector<const PatternChar> pattern,
3370 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003371 FixedArrayBuilder* builder,
3372 int* match_pos) {
3373 int pos = *match_pos;
3374 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003375 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003376 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003377 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003378 while (pos <= max_search_start) {
3379 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3380 *match_pos = pos;
3381 return false;
3382 }
3383 // Position of end of previous match.
3384 int match_end = pos + pattern_length;
3385 int new_pos = search.Search(subject, match_end);
3386 if (new_pos >= 0) {
3387 // A match.
3388 if (new_pos > match_end) {
3389 ReplacementStringBuilder::AddSubjectSlice(builder,
3390 match_end,
3391 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003392 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003393 pos = new_pos;
3394 builder->Add(pattern_string);
3395 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003396 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003397 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003398 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003399
lrn@chromium.org25156de2010-04-06 13:10:27 +00003400 if (pos < max_search_start) {
3401 ReplacementStringBuilder::AddSubjectSlice(builder,
3402 pos + pattern_length,
3403 subject_length);
3404 }
3405 *match_pos = pos;
3406 return true;
3407}
3408
3409
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003410static bool SearchStringMultiple(Isolate* isolate,
3411 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003412 Handle<String> pattern,
3413 Handle<JSArray> last_match_info,
3414 FixedArrayBuilder* builder) {
3415 ASSERT(subject->IsFlat());
3416 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003417
3418 // Treating as if a previous match was before first character.
3419 int match_pos = -pattern->length();
3420
3421 for (;;) { // Break when search complete.
3422 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3423 AssertNoAllocation no_gc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003424 String::FlatContent subject_content = subject->GetFlatContent();
3425 String::FlatContent pattern_content = pattern->GetFlatContent();
3426 if (subject_content.IsAscii()) {
3427 Vector<const char> subject_vector = subject_content.ToAsciiVector();
3428 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003429 if (SearchStringMultiple(isolate,
3430 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003431 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003432 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003433 builder,
3434 &match_pos)) break;
3435 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003436 if (SearchStringMultiple(isolate,
3437 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003438 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003439 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003440 builder,
3441 &match_pos)) break;
3442 }
3443 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003444 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
3445 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003446 if (SearchStringMultiple(isolate,
3447 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003448 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003449 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003450 builder,
3451 &match_pos)) break;
3452 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003453 if (SearchStringMultiple(isolate,
3454 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003455 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003456 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003457 builder,
3458 &match_pos)) break;
3459 }
3460 }
3461 }
3462
3463 if (match_pos >= 0) {
3464 SetLastMatchInfoNoCaptures(subject,
3465 last_match_info,
3466 match_pos,
3467 match_pos + pattern->length());
3468 return true;
3469 }
3470 return false; // No matches at all.
3471}
3472
3473
3474static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003475 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003476 Handle<String> subject,
3477 Handle<JSRegExp> regexp,
3478 Handle<JSArray> last_match_array,
3479 FixedArrayBuilder* builder) {
3480 ASSERT(subject->IsFlat());
3481 int match_start = -1;
3482 int match_end = 0;
3483 int pos = 0;
3484 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3485 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3486
3487 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003488 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003489 int subject_length = subject->length();
ager@chromium.org04921a82011-06-27 13:21:41 +00003490 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003491
3492 for (;;) { // Break on failure, return on exception.
3493 RegExpImpl::IrregexpResult result =
3494 RegExpImpl::IrregexpExecOnce(regexp,
3495 subject,
3496 pos,
3497 register_vector);
3498 if (result == RegExpImpl::RE_SUCCESS) {
3499 match_start = register_vector[0];
3500 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3501 if (match_end < match_start) {
3502 ReplacementStringBuilder::AddSubjectSlice(builder,
3503 match_end,
3504 match_start);
3505 }
3506 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003507 HandleScope loop_scope(isolate);
ager@chromium.org04921a82011-06-27 13:21:41 +00003508 if (!first) {
3509 builder->Add(*isolate->factory()->NewProperSubString(subject,
3510 match_start,
3511 match_end));
3512 } else {
3513 builder->Add(*isolate->factory()->NewSubString(subject,
3514 match_start,
3515 match_end));
3516 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003517 if (match_start != match_end) {
3518 pos = match_end;
3519 } else {
3520 pos = match_end + 1;
3521 if (pos > subject_length) break;
3522 }
3523 } else if (result == RegExpImpl::RE_FAILURE) {
3524 break;
3525 } else {
3526 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3527 return result;
3528 }
ager@chromium.org04921a82011-06-27 13:21:41 +00003529 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003530 }
3531
3532 if (match_start >= 0) {
3533 if (match_end < subject_length) {
3534 ReplacementStringBuilder::AddSubjectSlice(builder,
3535 match_end,
3536 subject_length);
3537 }
3538 SetLastMatchInfoNoCaptures(subject,
3539 last_match_array,
3540 match_start,
3541 match_end);
3542 return RegExpImpl::RE_SUCCESS;
3543 } else {
3544 return RegExpImpl::RE_FAILURE; // No matches at all.
3545 }
3546}
3547
3548
3549static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003550 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003551 Handle<String> subject,
3552 Handle<JSRegExp> regexp,
3553 Handle<JSArray> last_match_array,
3554 FixedArrayBuilder* builder) {
3555
3556 ASSERT(subject->IsFlat());
3557 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3558 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3559
3560 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003561 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003562
3563 RegExpImpl::IrregexpResult result =
3564 RegExpImpl::IrregexpExecOnce(regexp,
3565 subject,
3566 0,
3567 register_vector);
3568
3569 int capture_count = regexp->CaptureCount();
3570 int subject_length = subject->length();
3571
3572 // Position to search from.
3573 int pos = 0;
3574 // End of previous match. Differs from pos if match was empty.
3575 int match_end = 0;
3576 if (result == RegExpImpl::RE_SUCCESS) {
3577 // Need to keep a copy of the previous match for creating last_match_info
3578 // at the end, so we have two vectors that we swap between.
3579 OffsetsVector registers2(required_registers);
3580 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00003581 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003582 do {
3583 int match_start = register_vector[0];
3584 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3585 if (match_end < match_start) {
3586 ReplacementStringBuilder::AddSubjectSlice(builder,
3587 match_end,
3588 match_start);
3589 }
3590 match_end = register_vector[1];
3591
3592 {
3593 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003594 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003595 // Arguments array to replace function is match, captures, index and
3596 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003597 Handle<FixedArray> elements =
3598 isolate->factory()->NewFixedArray(3 + capture_count);
ager@chromium.org04921a82011-06-27 13:21:41 +00003599 Handle<String> match;
3600 if (!first) {
3601 match = isolate->factory()->NewProperSubString(subject,
3602 match_start,
3603 match_end);
3604 } else {
3605 match = isolate->factory()->NewSubString(subject,
3606 match_start,
3607 match_end);
3608 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003609 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003610 for (int i = 1; i <= capture_count; i++) {
3611 int start = register_vector[i * 2];
3612 if (start >= 0) {
3613 int end = register_vector[i * 2 + 1];
3614 ASSERT(start <= end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003615 Handle<String> substring;
3616 if (!first) {
3617 substring = isolate->factory()->NewProperSubString(subject,
3618 start,
3619 end);
3620 } else {
3621 substring = isolate->factory()->NewSubString(subject, start, end);
3622 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003623 elements->set(i, *substring);
3624 } else {
3625 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003626 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003627 }
3628 }
3629 elements->set(capture_count + 1, Smi::FromInt(match_start));
3630 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003631 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003632 }
3633 // Swap register vectors, so the last successful match is in
3634 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003635 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003636 prev_register_vector = register_vector;
3637 register_vector = tmp;
3638
3639 if (match_end > match_start) {
3640 pos = match_end;
3641 } else {
3642 pos = match_end + 1;
3643 if (pos > subject_length) {
3644 break;
3645 }
3646 }
3647
3648 result = RegExpImpl::IrregexpExecOnce(regexp,
3649 subject,
3650 pos,
3651 register_vector);
ager@chromium.org04921a82011-06-27 13:21:41 +00003652 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003653 } while (result == RegExpImpl::RE_SUCCESS);
3654
3655 if (result != RegExpImpl::RE_EXCEPTION) {
3656 // Finished matching, with at least one match.
3657 if (match_end < subject_length) {
3658 ReplacementStringBuilder::AddSubjectSlice(builder,
3659 match_end,
3660 subject_length);
3661 }
3662
3663 int last_match_capture_count = (capture_count + 1) * 2;
3664 int last_match_array_size =
3665 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3666 last_match_array->EnsureSize(last_match_array_size);
3667 AssertNoAllocation no_gc;
3668 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3669 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3670 RegExpImpl::SetLastSubject(elements, *subject);
3671 RegExpImpl::SetLastInput(elements, *subject);
3672 for (int i = 0; i < last_match_capture_count; i++) {
3673 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3674 }
3675 return RegExpImpl::RE_SUCCESS;
3676 }
3677 }
3678 // No matches at all, return failure or exception result directly.
3679 return result;
3680}
3681
3682
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003683RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003684 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003685 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003686
3687 CONVERT_ARG_CHECKED(String, subject, 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003688 if (!subject->IsFlat()) FlattenString(subject);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003689 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3690 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3691 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3692
3693 ASSERT(last_match_info->HasFastElements());
3694 ASSERT(regexp->GetFlags().is_global());
3695 Handle<FixedArray> result_elements;
3696 if (result_array->HasFastElements()) {
3697 result_elements =
3698 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
ager@chromium.org04921a82011-06-27 13:21:41 +00003699 }
3700 if (result_elements.is_null() || result_elements->length() < 16) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003701 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003702 }
3703 FixedArrayBuilder builder(result_elements);
3704
3705 if (regexp->TypeTag() == JSRegExp::ATOM) {
3706 Handle<String> pattern(
3707 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003708 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003709 if (SearchStringMultiple(isolate, subject, pattern,
3710 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003711 return *builder.ToJSArray(result_array);
3712 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003713 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003714 }
3715
3716 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3717
3718 RegExpImpl::IrregexpResult result;
3719 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003720 result = SearchRegExpNoCaptureMultiple(isolate,
3721 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003722 regexp,
3723 last_match_info,
3724 &builder);
3725 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003726 result = SearchRegExpMultiple(isolate,
3727 subject,
3728 regexp,
3729 last_match_info,
3730 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003731 }
3732 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003733 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003734 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3735 return Failure::Exception();
3736}
3737
3738
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003739RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003740 NoHandleAllocation ha;
3741 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003742 CONVERT_SMI_ARG_CHECKED(radix, 1);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003743 RUNTIME_ASSERT(2 <= radix && radix <= 36);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003744
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003745 // Fast case where the result is a one character string.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003746 if (args[0]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003747 int value = args.smi_at(0);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003748 if (value >= 0 && value < radix) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003749 // Character array used for conversion.
3750 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003751 return isolate->heap()->
3752 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003753 }
3754 }
3755
3756 // Slow case.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003757 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003758 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003759 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003760 }
3761 if (isinf(value)) {
3762 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003763 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003764 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003765 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003766 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003767 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003768 MaybeObject* result =
3769 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003770 DeleteArray(str);
3771 return result;
3772}
3773
3774
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003775RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003776 NoHandleAllocation ha;
3777 ASSERT(args.length() == 2);
3778
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003779 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003780 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003781 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003782 }
3783 if (isinf(value)) {
3784 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003785 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003786 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003787 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003788 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003789 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003790 int f = FastD2I(f_number);
3791 RUNTIME_ASSERT(f >= 0);
3792 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003793 MaybeObject* res =
3794 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003795 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003796 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003797}
3798
3799
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003800RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003801 NoHandleAllocation ha;
3802 ASSERT(args.length() == 2);
3803
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003804 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003805 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003806 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003807 }
3808 if (isinf(value)) {
3809 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003810 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003811 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003812 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003813 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003814 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003815 int f = FastD2I(f_number);
3816 RUNTIME_ASSERT(f >= -1 && f <= 20);
3817 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003818 MaybeObject* res =
3819 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003820 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003821 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003822}
3823
3824
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003825RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003826 NoHandleAllocation ha;
3827 ASSERT(args.length() == 2);
3828
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003829 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003830 if (isnan(value)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003831 return isolate->heap()->AllocateStringFromAscii(CStrVector("NaN"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003832 }
3833 if (isinf(value)) {
3834 if (value < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003835 return isolate->heap()->AllocateStringFromAscii(CStrVector("-Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003836 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003837 return isolate->heap()->AllocateStringFromAscii(CStrVector("Infinity"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003838 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003839 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003840 int f = FastD2I(f_number);
3841 RUNTIME_ASSERT(f >= 1 && f <= 21);
3842 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003843 MaybeObject* res =
3844 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003845 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003846 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003847}
3848
3849
3850// Returns a single character string where first character equals
3851// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003852static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003853 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003854 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00003855 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003856 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003857 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003858 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003859}
3860
3861
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003862MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
3863 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003864 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003865 // Handle [] indexing on Strings
3866 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003867 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
3868 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003869 }
3870
3871 // Handle [] indexing on String objects
3872 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003873 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
3874 Handle<Object> result =
3875 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
3876 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003877 }
3878
3879 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003880 Handle<Object> prototype = GetPrototype(object);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003881 return prototype->GetElement(index);
3882 }
3883
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003884 return GetElement(object, index);
3885}
3886
3887
lrn@chromium.org303ada72010-10-27 09:33:13 +00003888MaybeObject* Runtime::GetElement(Handle<Object> object, uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003889 return object->GetElement(index);
3890}
3891
3892
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003893MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
3894 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003895 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003896 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003897
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003898 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003899 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003900 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003901 isolate->factory()->NewTypeError("non_object_property_load",
3902 HandleVector(args, 2));
3903 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003904 }
3905
3906 // Check if the given key is an array index.
3907 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003908 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003909 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003910 }
3911
3912 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003913 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003914 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003915 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003916 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003917 bool has_pending_exception = false;
3918 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003919 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003920 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003921 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003922 }
3923
ager@chromium.org32912102009-01-16 10:38:43 +00003924 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003925 // the element if so.
3926 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003927 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003928 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003929 return object->GetProperty(*name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003930 }
3931}
3932
3933
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003934RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003935 NoHandleAllocation ha;
3936 ASSERT(args.length() == 2);
3937
3938 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003939 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003940
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003941 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003942}
3943
3944
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003945// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003946RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00003947 NoHandleAllocation ha;
3948 ASSERT(args.length() == 2);
3949
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003950 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00003951 // itself.
3952 //
3953 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00003954 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00003955 // global proxy object never has properties. This is the case
3956 // because the global proxy object forwards everything to its hidden
3957 // prototype including local lookups.
3958 //
3959 // Additionally, we need to make sure that we do not cache results
3960 // for objects that require access checks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003961 if (args[0]->IsJSObject() &&
3962 !args[0]->IsJSGlobalProxy() &&
ager@chromium.org8bb60582008-12-11 12:02:20 +00003963 !args[0]->IsAccessCheckNeeded() &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003964 args[1]->IsString()) {
3965 JSObject* receiver = JSObject::cast(args[0]);
3966 String* key = String::cast(args[1]);
3967 if (receiver->HasFastProperties()) {
3968 // Attempt to use lookup cache.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003969 Map* receiver_map = receiver->map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003970 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
3971 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00003972 if (offset != -1) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003973 Object* value = receiver->FastPropertyAt(offset);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003974 return value->IsTheHole() ? isolate->heap()->undefined_value() : value;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003975 }
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003976 // Lookup cache miss. Perform lookup and update the cache if appropriate.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003977 LookupResult result;
3978 receiver->LocalLookup(key, &result);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00003979 if (result.IsProperty() && result.type() == FIELD) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003980 int offset = result.GetFieldIndex();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003981 keyed_lookup_cache->Update(receiver_map, key, offset);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003982 return receiver->FastPropertyAt(offset);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003983 }
3984 } else {
3985 // Attempt dictionary lookup.
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00003986 StringDictionary* dictionary = receiver->property_dictionary();
3987 int entry = dictionary->FindEntry(key);
3988 if ((entry != StringDictionary::kNotFound) &&
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003989 (dictionary->DetailsAt(entry).type() == NORMAL)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00003990 Object* value = dictionary->ValueAt(entry);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00003991 if (!receiver->IsGlobalObject()) return value;
3992 value = JSGlobalPropertyCell::cast(value)->value();
3993 if (!value->IsTheHole()) return value;
3994 // If value is the hole do the general lookup.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003995 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00003996 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003997 } else if (args[0]->IsString() && args[1]->IsSmi()) {
3998 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003999 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004000 Handle<String> str = args.at<String>(0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004001 int index = args.smi_at(1);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004002 if (index >= 0 && index < str->length()) {
4003 Handle<Object> result = GetCharAt(str, index);
4004 return *result;
4005 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004006 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004007
4008 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004009 return Runtime::GetObjectProperty(isolate,
4010 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00004011 args.at<Object>(1));
4012}
4013
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004014// Implements part of 8.12.9 DefineOwnProperty.
4015// There are 3 cases that lead here:
4016// Step 4b - define a new accessor property.
4017// Steps 9c & 12 - replace an existing data property with an accessor property.
4018// Step 12 - update an existing accessor property with an accessor or generic
4019// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004020RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004021 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004022 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004023 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4024 CONVERT_CHECKED(String, name, args[1]);
4025 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004026 Object* fun = args[3];
4027 RUNTIME_ASSERT(fun->IsJSFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00004028 CONVERT_CHECKED(Smi, flag_attr, args[4]);
4029 int unchecked = flag_attr->value();
4030 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4031 RUNTIME_ASSERT(!obj->IsNull());
4032 LookupResult result;
4033 obj->LocalLookupRealNamedProperty(name, &result);
4034
4035 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4036 // If an existing property is either FIELD, NORMAL or CONSTANT_FUNCTION
4037 // delete it to avoid running into trouble in DefineAccessor, which
4038 // handles this incorrectly if the property is readonly (does nothing)
4039 if (result.IsProperty() &&
4040 (result.type() == FIELD || result.type() == NORMAL
4041 || result.type() == CONSTANT_FUNCTION)) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004042 Object* ok;
4043 { MaybeObject* maybe_ok =
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004044 obj->DeleteProperty(name, JSReceiver::NORMAL_DELETION);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004045 if (!maybe_ok->ToObject(&ok)) return maybe_ok;
4046 }
ager@chromium.org5c838252010-02-19 08:53:10 +00004047 }
4048 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
4049}
4050
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004051// Implements part of 8.12.9 DefineOwnProperty.
4052// There are 3 cases that lead here:
4053// Step 4a - define a new data property.
4054// Steps 9b & 12 - replace an existing accessor property with a data property.
4055// Step 12 - update an existing data property with a data or generic
4056// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004057RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004058 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004059 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004060 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
4061 CONVERT_ARG_CHECKED(String, name, 1);
4062 Handle<Object> obj_value = args.at<Object>(2);
4063
4064 CONVERT_CHECKED(Smi, flag, args[3]);
4065 int unchecked = flag->value();
4066 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4067
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004068 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4069
4070 // Check if this is an element.
4071 uint32_t index;
4072 bool is_element = name->AsArrayIndex(&index);
4073
4074 // Special case for elements if any of the flags are true.
4075 // If elements are in fast case we always implicitly assume that:
4076 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
4077 if (((unchecked & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0) &&
4078 is_element) {
4079 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004080 if (js_object->IsJSGlobalProxy()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004081 // We do not need to do access checks here since these has already
4082 // been performed by the call to GetOwnProperty.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004083 Handle<Object> proto(js_object->GetPrototype());
4084 // If proxy is detached, ignore the assignment. Alternatively,
4085 // we could throw an exception.
4086 if (proto->IsNull()) return *obj_value;
4087 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004088 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004089 Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004090 // Make sure that we never go back to fast case.
4091 dictionary->set_requires_slow_elements();
4092 PropertyDetails details = PropertyDetails(attr, NORMAL);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004093 Handle<NumberDictionary> extended_dictionary =
4094 NumberDictionarySet(dictionary, index, obj_value, details);
4095 if (*extended_dictionary != *dictionary) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004096 if (js_object->GetElementsKind() ==
4097 JSObject::NON_STRICT_ARGUMENTS_ELEMENTS) {
4098 FixedArray::cast(js_object->elements())->set(1, *extended_dictionary);
4099 } else {
4100 js_object->set_elements(*extended_dictionary);
4101 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004102 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004103 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004104 }
4105
ager@chromium.org5c838252010-02-19 08:53:10 +00004106 LookupResult result;
whesse@chromium.org7b260152011-06-20 15:33:18 +00004107 js_object->LocalLookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00004108
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004109 // To be compatible with safari we do not change the value on API objects
4110 // in defineProperty. Firefox disagrees here, and actually changes the value.
4111 if (result.IsProperty() &&
4112 (result.type() == CALLBACKS) &&
4113 result.GetCallbackObject()->IsAccessorInfo()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004114 return isolate->heap()->undefined_value();
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004115 }
4116
ager@chromium.org5c838252010-02-19 08:53:10 +00004117 // Take special care when attributes are different and there is already
4118 // a property. For simplicity we normalize the property which enables us
4119 // to not worry about changing the instance_descriptor and creating a new
4120 // map. The current version of SetObjectProperty does not handle attributes
4121 // correctly in the case where a property is a field and is reset with
4122 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004123 if (result.IsProperty() &&
4124 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004125 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004126 if (js_object->IsJSGlobalProxy()) {
4127 // Since the result is a property, the prototype will exist so
4128 // we don't have to check for null.
4129 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004130 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004131 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004132 // Use IgnoreAttributes version since a readonly property may be
4133 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004134 return js_object->SetLocalPropertyIgnoreAttributes(*name,
4135 *obj_value,
4136 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004137 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004138
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004139 return Runtime::ForceSetObjectProperty(isolate,
4140 js_object,
4141 name,
4142 obj_value,
4143 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004144}
4145
4146
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004147// Special case for elements if any of the flags are true.
4148// If elements are in fast case we always implicitly assume that:
4149// DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
4150static MaybeObject* NormalizeObjectSetElement(Isolate* isolate,
4151 Handle<JSObject> js_object,
4152 uint32_t index,
4153 Handle<Object> value,
4154 PropertyAttributes attr) {
4155 // Normalize the elements to enable attributes on the property.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004156 Handle<NumberDictionary> dictionary = NormalizeElements(js_object);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004157 // Make sure that we never go back to fast case.
4158 dictionary->set_requires_slow_elements();
4159 PropertyDetails details = PropertyDetails(attr, NORMAL);
4160 Handle<NumberDictionary> extended_dictionary =
4161 NumberDictionarySet(dictionary, index, value, details);
4162 if (*extended_dictionary != *dictionary) {
4163 js_object->set_elements(*extended_dictionary);
4164 }
4165 return *value;
4166}
4167
4168
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004169MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
4170 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004171 Handle<Object> key,
4172 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004173 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004174 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004175 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004176
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004177 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004178 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004179 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004180 isolate->factory()->NewTypeError("non_object_property_store",
4181 HandleVector(args, 2));
4182 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004183 }
4184
4185 // If the object isn't a JavaScript object, we ignore the store.
4186 if (!object->IsJSObject()) return *value;
4187
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004188 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
4189
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004190 // Check if the given key is an array index.
4191 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004192 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004193 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4194 // of a string using [] notation. We need to support this too in
4195 // JavaScript.
4196 // In the case of a String object we just need to redirect the assignment to
4197 // the underlying string if the index is in range. Since the underlying
4198 // string does nothing with the assignment then we can ignore such
4199 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004200 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004201 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004202 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004203
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004204 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4205 return NormalizeObjectSetElement(isolate, js_object, index, value, attr);
4206 }
4207
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004208 Handle<Object> result = SetElement(js_object, index, value, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004209 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004210 return *value;
4211 }
4212
4213 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004214 Handle<Object> result;
4215 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004216 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4217 return NormalizeObjectSetElement(isolate,
4218 js_object,
4219 index,
4220 value,
4221 attr);
4222 }
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004223 result = SetElement(js_object, index, value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004224 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004225 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004226 key_string->TryFlatten();
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004227 result = SetProperty(js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004228 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004229 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004230 return *value;
4231 }
4232
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004233 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004234 bool has_pending_exception = false;
4235 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4236 if (has_pending_exception) return Failure::Exception();
4237 Handle<String> name = Handle<String>::cast(converted);
4238
4239 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004240 return js_object->SetElement(index, *value, strict_mode, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004241 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004242 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004243 }
4244}
4245
4246
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004247MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4248 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004249 Handle<Object> key,
4250 Handle<Object> value,
4251 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004252 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004253
4254 // Check if the given key is an array index.
4255 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004256 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004257 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4258 // of a string using [] notation. We need to support this too in
4259 // JavaScript.
4260 // In the case of a String object we just need to redirect the assignment to
4261 // the underlying string if the index is in range. Since the underlying
4262 // string does nothing with the assignment then we can ignore such
4263 // assignments.
4264 if (js_object->IsStringObjectWithCharacterAt(index)) {
4265 return *value;
4266 }
4267
whesse@chromium.org7b260152011-06-20 15:33:18 +00004268 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004269 }
4270
4271 if (key->IsString()) {
4272 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004273 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004274 } else {
4275 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004276 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004277 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4278 *value,
4279 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004280 }
4281 }
4282
4283 // Call-back into JavaScript to convert the key to a string.
4284 bool has_pending_exception = false;
4285 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4286 if (has_pending_exception) return Failure::Exception();
4287 Handle<String> name = Handle<String>::cast(converted);
4288
4289 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004290 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004291 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004292 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004293 }
4294}
4295
4296
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004297MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004298 Handle<JSReceiver> receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004299 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004300 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004301
4302 // Check if the given key is an array index.
4303 uint32_t index;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004304 if (receiver->IsJSObject() && key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004305 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4306 // characters of a string using [] notation. In the case of a
4307 // String object we just need to redirect the deletion to the
4308 // underlying string if the index is in range. Since the
4309 // underlying string does nothing with the deletion, we can ignore
4310 // such deletions.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004311 if (receiver->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004312 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004313 }
4314
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004315 return JSObject::cast(*receiver)->DeleteElement(
4316 index, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004317 }
4318
4319 Handle<String> key_string;
4320 if (key->IsString()) {
4321 key_string = Handle<String>::cast(key);
4322 } else {
4323 // Call-back into JavaScript to convert the key to a string.
4324 bool has_pending_exception = false;
4325 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4326 if (has_pending_exception) return Failure::Exception();
4327 key_string = Handle<String>::cast(converted);
4328 }
4329
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004330 key_string->TryFlatten();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004331 return receiver->DeleteProperty(*key_string, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004332}
4333
4334
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004335RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004336 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004337 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004338
4339 Handle<Object> object = args.at<Object>(0);
4340 Handle<Object> key = args.at<Object>(1);
4341 Handle<Object> value = args.at<Object>(2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004342 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004343 RUNTIME_ASSERT(
4344 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004345 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004346 PropertyAttributes attributes =
4347 static_cast<PropertyAttributes>(unchecked_attributes);
4348
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004349 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004350 if (args.length() == 5) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004351 CONVERT_SMI_ARG_CHECKED(strict_unchecked, 4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004352 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
4353 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004354 strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004355 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004356
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004357 return Runtime::SetObjectProperty(isolate,
4358 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004359 key,
4360 value,
4361 attributes,
4362 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004363}
4364
4365
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004366// Set the native flag on the function.
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004367// This is used to decide if we should transform null and undefined
4368// into the global object when doing call and apply.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004369RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004370 NoHandleAllocation ha;
4371 RUNTIME_ASSERT(args.length() == 1);
4372
4373 Handle<Object> object = args.at<Object>(0);
4374
4375 if (object->IsJSFunction()) {
4376 JSFunction* func = JSFunction::cast(*object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004377 func->shared()->set_native(true);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004378 }
4379 return isolate->heap()->undefined_value();
4380}
4381
4382
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004383// Set a local property, even if it is READ_ONLY. If the property does not
4384// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004385RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004386 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004387 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004388 CONVERT_CHECKED(JSObject, object, args[0]);
4389 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004390 // Compute attributes.
4391 PropertyAttributes attributes = NONE;
4392 if (args.length() == 4) {
4393 CONVERT_CHECKED(Smi, value_obj, args[3]);
4394 int unchecked_value = value_obj->value();
4395 // Only attribute bits should be set.
4396 RUNTIME_ASSERT(
4397 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4398 attributes = static_cast<PropertyAttributes>(unchecked_value);
4399 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004400
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004401 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004402 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004403}
4404
4405
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004406RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004407 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004408 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004409
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004410 CONVERT_CHECKED(JSReceiver, object, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004411 CONVERT_CHECKED(String, key, args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004412 CONVERT_SMI_ARG_CHECKED(strict, 2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004413 return object->DeleteProperty(key, (strict == kStrictMode)
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004414 ? JSReceiver::STRICT_DELETION
4415 : JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004416}
4417
4418
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004419static Object* HasLocalPropertyImplementation(Isolate* isolate,
4420 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004421 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004422 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004423 // Handle hidden prototypes. If there's a hidden prototype above this thing
4424 // then we have to check it for properties, because they are supposed to
4425 // look like they are on this object.
4426 Handle<Object> proto(object->GetPrototype());
4427 if (proto->IsJSObject() &&
4428 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004429 return HasLocalPropertyImplementation(isolate,
4430 Handle<JSObject>::cast(proto),
4431 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004432 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004433 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004434}
4435
4436
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004437RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004438 NoHandleAllocation ha;
4439 ASSERT(args.length() == 2);
4440 CONVERT_CHECKED(String, key, args[1]);
4441
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004442 uint32_t index;
4443 const bool key_is_array_index = key->AsArrayIndex(&index);
4444
ager@chromium.org9085a012009-05-11 19:22:57 +00004445 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004446 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004447 if (obj->IsJSObject()) {
4448 JSObject* object = JSObject::cast(obj);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004449 // Fast case: either the key is a real named property or it is not
4450 // an array index and there are no interceptors or hidden
4451 // prototypes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004452 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004453 Map* map = object->map();
4454 if (!key_is_array_index &&
4455 !map->has_named_interceptor() &&
4456 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4457 return isolate->heap()->false_value();
4458 }
4459 // Slow case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004460 HandleScope scope(isolate);
4461 return HasLocalPropertyImplementation(isolate,
4462 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004463 Handle<String>(key));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004464 } else if (obj->IsString() && key_is_array_index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004465 // Well, there is one exception: Handle [] on strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004466 String* string = String::cast(obj);
4467 if (index < static_cast<uint32_t>(string->length())) {
4468 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004469 }
4470 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004471 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004472}
4473
4474
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004475RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004476 NoHandleAllocation na;
4477 ASSERT(args.length() == 2);
4478
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004479 // Only JS receivers can have properties.
4480 if (args[0]->IsJSReceiver()) {
4481 JSReceiver* receiver = JSReceiver::cast(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004482 CONVERT_CHECKED(String, key, args[1]);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00004483 if (receiver->HasProperty(key)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004484 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004485 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004486}
4487
4488
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004489RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004490 NoHandleAllocation na;
4491 ASSERT(args.length() == 2);
4492
4493 // Only JS objects can have elements.
4494 if (args[0]->IsJSObject()) {
4495 JSObject* object = JSObject::cast(args[0]);
4496 CONVERT_CHECKED(Smi, index_obj, args[1]);
4497 uint32_t index = index_obj->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004498 if (object->HasElement(index)) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004499 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004500 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004501}
4502
4503
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004504RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004505 NoHandleAllocation ha;
4506 ASSERT(args.length() == 2);
4507
4508 CONVERT_CHECKED(JSObject, object, args[0]);
4509 CONVERT_CHECKED(String, key, args[1]);
4510
4511 uint32_t index;
4512 if (key->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004513 return isolate->heap()->ToBoolean(object->HasElement(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004514 }
4515
ager@chromium.org870a0b62008-11-04 11:43:05 +00004516 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004517 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004518}
4519
4520
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004521RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004522 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004523 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00004524 CONVERT_ARG_CHECKED(JSObject, object, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004525 return *GetKeysFor(object);
4526}
4527
4528
4529// Returns either a FixedArray as Runtime_GetPropertyNames,
4530// or, if the given object has an enum cache that contains
4531// all enumerable properties of the object and its prototypes
4532// have none, the map of the object. This is used to speed up
4533// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004534RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004535 ASSERT(args.length() == 1);
4536
4537 CONVERT_CHECKED(JSObject, raw_object, args[0]);
4538
4539 if (raw_object->IsSimpleEnum()) return raw_object->map();
4540
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004541 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004542 Handle<JSObject> object(raw_object);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004543 Handle<FixedArray> content = GetKeysInFixedArrayFor(object,
4544 INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004545
4546 // Test again, since cache may have been built by preceding call.
4547 if (object->IsSimpleEnum()) return object->map();
4548
4549 return *content;
4550}
4551
4552
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004553// Find the length of the prototype chain that is to to handled as one. If a
4554// prototype object is hidden it is to be viewed as part of the the object it
4555// is prototype for.
4556static int LocalPrototypeChainLength(JSObject* obj) {
4557 int count = 1;
4558 Object* proto = obj->GetPrototype();
4559 while (proto->IsJSObject() &&
4560 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4561 count++;
4562 proto = JSObject::cast(proto)->GetPrototype();
4563 }
4564 return count;
4565}
4566
4567
4568// Return the names of the local named properties.
4569// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004570RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004571 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004572 ASSERT(args.length() == 1);
4573 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004574 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004575 }
4576 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4577
4578 // Skip the global proxy as it has no properties and always delegates to the
4579 // real global object.
4580 if (obj->IsJSGlobalProxy()) {
4581 // Only collect names if access is permitted.
4582 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004583 !isolate->MayNamedAccess(*obj,
4584 isolate->heap()->undefined_value(),
4585 v8::ACCESS_KEYS)) {
4586 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4587 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004588 }
4589 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4590 }
4591
4592 // Find the number of objects making up this.
4593 int length = LocalPrototypeChainLength(*obj);
4594
4595 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004596 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004597 int total_property_count = 0;
4598 Handle<JSObject> jsproto = obj;
4599 for (int i = 0; i < length; i++) {
4600 // Only collect names if access is permitted.
4601 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004602 !isolate->MayNamedAccess(*jsproto,
4603 isolate->heap()->undefined_value(),
4604 v8::ACCESS_KEYS)) {
4605 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4606 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004607 }
4608 int n;
4609 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4610 local_property_count[i] = n;
4611 total_property_count += n;
4612 if (i < length - 1) {
4613 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4614 }
4615 }
4616
4617 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004618 Handle<FixedArray> names =
4619 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004620
4621 // Get the property names.
4622 jsproto = obj;
4623 int proto_with_hidden_properties = 0;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004624 int next_copy_index = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004625 for (int i = 0; i < length; i++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004626 jsproto->GetLocalPropertyNames(*names, next_copy_index);
4627 next_copy_index += local_property_count[i];
vegorov@chromium.org7943d462011-08-01 11:41:52 +00004628 if (jsproto->HasHiddenProperties()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004629 proto_with_hidden_properties++;
4630 }
4631 if (i < length - 1) {
4632 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4633 }
4634 }
4635
4636 // Filter out name of hidden propeties object.
4637 if (proto_with_hidden_properties > 0) {
4638 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004639 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004640 names->length() - proto_with_hidden_properties);
4641 int dest_pos = 0;
4642 for (int i = 0; i < total_property_count; i++) {
4643 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004644 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004645 continue;
4646 }
4647 names->set(dest_pos++, name);
4648 }
4649 }
4650
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004651 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004652}
4653
4654
4655// Return the names of the local indexed properties.
4656// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004657RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004658 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004659 ASSERT(args.length() == 1);
4660 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004661 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004662 }
4663 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4664
4665 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004666 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004667 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004668 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004669}
4670
4671
4672// Return information on whether an object has a named or indexed interceptor.
4673// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004674RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004675 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004676 ASSERT(args.length() == 1);
4677 if (!args[0]->IsJSObject()) {
4678 return Smi::FromInt(0);
4679 }
4680 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4681
4682 int result = 0;
4683 if (obj->HasNamedInterceptor()) result |= 2;
4684 if (obj->HasIndexedInterceptor()) result |= 1;
4685
4686 return Smi::FromInt(result);
4687}
4688
4689
4690// Return property names from named interceptor.
4691// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004692RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004693 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004694 ASSERT(args.length() == 1);
4695 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4696
4697 if (obj->HasNamedInterceptor()) {
4698 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
4699 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4700 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004701 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004702}
4703
4704
4705// Return element names from indexed interceptor.
4706// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004707RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004708 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004709 ASSERT(args.length() == 1);
4710 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4711
4712 if (obj->HasIndexedInterceptor()) {
4713 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
4714 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
4715 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004716 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004717}
4718
4719
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004720RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004721 ASSERT_EQ(args.length(), 1);
4722 CONVERT_CHECKED(JSObject, raw_object, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004723 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004724 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004725
4726 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00004727 // Do access checks before going to the global object.
4728 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004729 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00004730 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004731 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
4732 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00004733 }
4734
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004735 Handle<Object> proto(object->GetPrototype());
4736 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004737 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004738 object = Handle<JSObject>::cast(proto);
4739 }
4740
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004741 Handle<FixedArray> contents = GetKeysInFixedArrayFor(object,
4742 LOCAL_ONLY);
4743 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
4744 // property array and since the result is mutable we have to create
4745 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004746 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004747 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004748 for (int i = 0; i < length; i++) {
4749 Object* entry = contents->get(i);
4750 if (entry->IsString()) {
4751 copy->set(i, entry);
4752 } else {
4753 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004754 HandleScope scope(isolate);
4755 Handle<Object> entry_handle(entry, isolate);
4756 Handle<Object> entry_str =
4757 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00004758 copy->set(i, *entry_str);
4759 }
4760 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004761 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00004762}
4763
4764
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004765RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004766 NoHandleAllocation ha;
4767 ASSERT(args.length() == 1);
4768
4769 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00004770 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004771 it.AdvanceToArgumentsFrame();
4772 JavaScriptFrame* frame = it.frame();
4773
4774 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00004775 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004776
4777 // Try to convert the key to an index. If successful and within
4778 // index return the the argument from the frame.
4779 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004780 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004781 return frame->GetParameter(index);
4782 }
4783
4784 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004785 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004786 bool exception = false;
4787 Handle<Object> converted =
4788 Execution::ToString(args.at<Object>(0), &exception);
4789 if (exception) return Failure::Exception();
4790 Handle<String> key = Handle<String>::cast(converted);
4791
4792 // Try to convert the string key into an array index.
4793 if (key->AsArrayIndex(&index)) {
4794 if (index < n) {
4795 return frame->GetParameter(index);
4796 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004797 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004798 }
4799 }
4800
4801 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004802 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
4803 if (key->Equals(isolate->heap()->callee_symbol())) {
4804 Object* function = frame->function();
4805 if (function->IsJSFunction() &&
4806 JSFunction::cast(function)->shared()->strict_mode()) {
4807 return isolate->Throw(*isolate->factory()->NewTypeError(
4808 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
4809 }
4810 return function;
4811 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004812
4813 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004814 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004815}
4816
4817
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004818RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004819 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004820
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004821 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004822 Handle<Object> object = args.at<Object>(0);
4823 if (object->IsJSObject()) {
4824 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
ager@chromium.org5c838252010-02-19 08:53:10 +00004825 if (!js_object->HasFastProperties() && !js_object->IsGlobalObject()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004826 MaybeObject* ok = js_object->TransformToFastProperties(0);
4827 if (ok->IsRetryAfterGC()) return ok;
ager@chromium.org5c838252010-02-19 08:53:10 +00004828 }
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004829 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004830 return *object;
4831}
4832
4833
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004834RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004835 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004836
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004837 ASSERT(args.length() == 1);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004838 Handle<Object> object = args.at<Object>(0);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004839 if (object->IsJSObject() && !object->IsJSGlobalProxy()) {
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004840 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
lrn@chromium.org303ada72010-10-27 09:33:13 +00004841 NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
kasperl@chromium.org7ccf0242009-03-04 12:22:05 +00004842 }
kasperl@chromium.org061ef742009-02-27 12:16:20 +00004843 return *object;
4844}
4845
4846
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004847RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004848 NoHandleAllocation ha;
4849 ASSERT(args.length() == 1);
4850
4851 return args[0]->ToBoolean();
4852}
4853
4854
4855// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
4856// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004857RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004858 NoHandleAllocation ha;
4859
4860 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004861 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004862 HeapObject* heap_obj = HeapObject::cast(obj);
4863
4864 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004865 if (heap_obj->map()->is_undetectable()) {
4866 return isolate->heap()->undefined_symbol();
4867 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004868
4869 InstanceType instance_type = heap_obj->map()->instance_type();
4870 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004871 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004872 }
4873
4874 switch (instance_type) {
4875 case ODDBALL_TYPE:
4876 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004877 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004878 }
4879 if (heap_obj->IsNull()) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00004880 return FLAG_harmony_typeof
4881 ? isolate->heap()->null_symbol()
4882 : isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004883 }
4884 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004885 return isolate->heap()->undefined_symbol();
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00004886 case JS_FUNCTION_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004887 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004888 default:
4889 // For any kind of object not handled above, the spec rule for
4890 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004891 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004892 }
4893}
4894
4895
lrn@chromium.org25156de2010-04-06 13:10:27 +00004896static bool AreDigits(const char*s, int from, int to) {
4897 for (int i = from; i < to; i++) {
4898 if (s[i] < '0' || s[i] > '9') return false;
4899 }
4900
4901 return true;
4902}
4903
4904
4905static int ParseDecimalInteger(const char*s, int from, int to) {
4906 ASSERT(to - from < 10); // Overflow is not possible.
4907 ASSERT(from < to);
4908 int d = s[from] - '0';
4909
4910 for (int i = from + 1; i < to; i++) {
4911 d = 10 * d + (s[i] - '0');
4912 }
4913
4914 return d;
4915}
4916
4917
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004918RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004919 NoHandleAllocation ha;
4920 ASSERT(args.length() == 1);
4921 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004922 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004923
4924 // Fast case: short integer or some sorts of junk values.
4925 int len = subject->length();
4926 if (subject->IsSeqAsciiString()) {
4927 if (len == 0) return Smi::FromInt(0);
4928
4929 char const* data = SeqAsciiString::cast(subject)->GetChars();
4930 bool minus = (data[0] == '-');
4931 int start_pos = (minus ? 1 : 0);
4932
4933 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004934 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004935 } else if (data[start_pos] > '9') {
4936 // Fast check for a junk value. A valid string may start from a
4937 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
4938 // the 'I' character ('Infinity'). All of that have codes not greater than
4939 // '9' except 'I'.
4940 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004941 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004942 }
4943 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
4944 // The maximal/minimal smi has 10 digits. If the string has less digits we
4945 // know it will fit into the smi-data type.
4946 int d = ParseDecimalInteger(data, start_pos, len);
4947 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004948 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004949 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004950 } else if (!subject->HasHashCode() &&
4951 len <= String::kMaxArrayIndexSize &&
4952 (len == 1 || data[0] != '0')) {
4953 // String hash is not calculated yet but all the data are present.
4954 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00004955 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004956#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00004957 subject->Hash(); // Force hash calculation.
4958 ASSERT_EQ(static_cast<int>(subject->hash_field()),
4959 static_cast<int>(hash));
4960#endif
4961 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004962 }
4963 return Smi::FromInt(d);
4964 }
4965 }
4966
4967 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00004968 return isolate->heap()->NumberFromDouble(
4969 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004970}
4971
4972
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004973RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004974 NoHandleAllocation ha;
4975 ASSERT(args.length() == 1);
4976
4977 CONVERT_CHECKED(JSArray, codes, args[0]);
4978 int length = Smi::cast(codes->length())->value();
4979
4980 // Check if the string can be ASCII.
4981 int i;
4982 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00004983 Object* element;
4984 { MaybeObject* maybe_element = codes->GetElement(i);
4985 // We probably can't get an exception here, but just in order to enforce
4986 // the checking of inputs in the runtime calls we check here.
4987 if (!maybe_element->ToObject(&element)) return maybe_element;
4988 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004989 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
4990 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
4991 break;
4992 }
4993
lrn@chromium.org303ada72010-10-27 09:33:13 +00004994 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004995 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004996 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004997 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004998 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004999 }
5000
lrn@chromium.org303ada72010-10-27 09:33:13 +00005001 Object* object = NULL;
5002 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005003 String* result = String::cast(object);
5004 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005005 Object* element;
5006 { MaybeObject* maybe_element = codes->GetElement(i);
5007 if (!maybe_element->ToObject(&element)) return maybe_element;
5008 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005009 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005010 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005011 }
5012 return result;
5013}
5014
5015
5016// kNotEscaped is generated by the following:
5017//
5018// #!/bin/perl
5019// for (my $i = 0; $i < 256; $i++) {
5020// print "\n" if $i % 16 == 0;
5021// my $c = chr($i);
5022// my $escaped = 1;
5023// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
5024// print $escaped ? "0, " : "1, ";
5025// }
5026
5027
5028static bool IsNotEscaped(uint16_t character) {
5029 // Only for 8 bit characters, the rest are always escaped (in a different way)
5030 ASSERT(character < 256);
5031 static const char kNotEscaped[256] = {
5032 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5033 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5034 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
5035 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
5036 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5037 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
5038 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5039 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
5040 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5041 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5042 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5043 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5044 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5045 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5046 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5047 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5048 };
5049 return kNotEscaped[character] != 0;
5050}
5051
5052
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005053RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005054 const char hex_chars[] = "0123456789ABCDEF";
5055 NoHandleAllocation ha;
5056 ASSERT(args.length() == 1);
5057 CONVERT_CHECKED(String, source, args[0]);
5058
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005059 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005060
5061 int escaped_length = 0;
5062 int length = source->length();
5063 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005064 Access<StringInputBuffer> buffer(
5065 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005066 buffer->Reset(source);
5067 while (buffer->has_more()) {
5068 uint16_t character = buffer->GetNext();
5069 if (character >= 256) {
5070 escaped_length += 6;
5071 } else if (IsNotEscaped(character)) {
5072 escaped_length++;
5073 } else {
5074 escaped_length += 3;
5075 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005076 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005077 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005078 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005079 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005080 return Failure::OutOfMemoryException();
5081 }
5082 }
5083 }
5084 // No length change implies no change. Return original string if no change.
5085 if (escaped_length == length) {
5086 return source;
5087 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005088 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005089 { MaybeObject* maybe_o =
5090 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005091 if (!maybe_o->ToObject(&o)) return maybe_o;
5092 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005093 String* destination = String::cast(o);
5094 int dest_position = 0;
5095
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005096 Access<StringInputBuffer> buffer(
5097 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005098 buffer->Rewind();
5099 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005100 uint16_t chr = buffer->GetNext();
5101 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005102 destination->Set(dest_position, '%');
5103 destination->Set(dest_position+1, 'u');
5104 destination->Set(dest_position+2, hex_chars[chr >> 12]);
5105 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
5106 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
5107 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005108 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005109 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005110 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005111 dest_position++;
5112 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005113 destination->Set(dest_position, '%');
5114 destination->Set(dest_position+1, hex_chars[chr >> 4]);
5115 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005116 dest_position += 3;
5117 }
5118 }
5119 return destination;
5120}
5121
5122
5123static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
5124 static const signed char kHexValue['g'] = {
5125 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5126 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5127 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5128 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
5129 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5130 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5131 -1, 10, 11, 12, 13, 14, 15 };
5132
5133 if (character1 > 'f') return -1;
5134 int hi = kHexValue[character1];
5135 if (hi == -1) return -1;
5136 if (character2 > 'f') return -1;
5137 int lo = kHexValue[character2];
5138 if (lo == -1) return -1;
5139 return (hi << 4) + lo;
5140}
5141
5142
ager@chromium.org870a0b62008-11-04 11:43:05 +00005143static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005144 int i,
5145 int length,
5146 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005147 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00005148 int32_t hi = 0;
5149 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005150 if (character == '%' &&
5151 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005152 source->Get(i + 1) == 'u' &&
5153 (hi = TwoDigitHex(source->Get(i + 2),
5154 source->Get(i + 3))) != -1 &&
5155 (lo = TwoDigitHex(source->Get(i + 4),
5156 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005157 *step = 6;
5158 return (hi << 8) + lo;
5159 } else if (character == '%' &&
5160 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005161 (lo = TwoDigitHex(source->Get(i + 1),
5162 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005163 *step = 3;
5164 return lo;
5165 } else {
5166 *step = 1;
5167 return character;
5168 }
5169}
5170
5171
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005172RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005173 NoHandleAllocation ha;
5174 ASSERT(args.length() == 1);
5175 CONVERT_CHECKED(String, source, args[0]);
5176
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005177 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005178
5179 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005180 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005181
5182 int unescaped_length = 0;
5183 for (int i = 0; i < length; unescaped_length++) {
5184 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005185 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005186 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005187 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005188 i += step;
5189 }
5190
5191 // No length change implies no change. Return original string if no change.
5192 if (unescaped_length == length)
5193 return source;
5194
lrn@chromium.org303ada72010-10-27 09:33:13 +00005195 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005196 { MaybeObject* maybe_o =
5197 ascii ?
5198 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
5199 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005200 if (!maybe_o->ToObject(&o)) return maybe_o;
5201 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005202 String* destination = String::cast(o);
5203
5204 int dest_position = 0;
5205 for (int i = 0; i < length; dest_position++) {
5206 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005207 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005208 i += step;
5209 }
5210 return destination;
5211}
5212
5213
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005214static const unsigned int kQuoteTableLength = 128u;
5215
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005216static const int kJsonQuotesCharactersPerEntry = 8;
5217static const char* const JsonQuotes =
5218 "\\u0000 \\u0001 \\u0002 \\u0003 "
5219 "\\u0004 \\u0005 \\u0006 \\u0007 "
5220 "\\b \\t \\n \\u000b "
5221 "\\f \\r \\u000e \\u000f "
5222 "\\u0010 \\u0011 \\u0012 \\u0013 "
5223 "\\u0014 \\u0015 \\u0016 \\u0017 "
5224 "\\u0018 \\u0019 \\u001a \\u001b "
5225 "\\u001c \\u001d \\u001e \\u001f "
5226 " ! \\\" # "
5227 "$ % & ' "
5228 "( ) * + "
5229 ", - . / "
5230 "0 1 2 3 "
5231 "4 5 6 7 "
5232 "8 9 : ; "
5233 "< = > ? "
5234 "@ A B C "
5235 "D E F G "
5236 "H I J K "
5237 "L M N O "
5238 "P Q R S "
5239 "T U V W "
5240 "X Y Z [ "
5241 "\\\\ ] ^ _ "
5242 "` a b c "
5243 "d e f g "
5244 "h i j k "
5245 "l m n o "
5246 "p q r s "
5247 "t u v w "
5248 "x y z { "
5249 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005250
5251
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005252// For a string that is less than 32k characters it should always be
5253// possible to allocate it in new space.
5254static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5255
5256
5257// Doing JSON quoting cannot make the string more than this many times larger.
5258static const int kJsonQuoteWorstCaseBlowup = 6;
5259
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005260static const int kSpaceForQuotesAndComma = 3;
5261static const int kSpaceForBrackets = 2;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005262
5263// Covers the entire ASCII range (all other characters are unchanged by JSON
5264// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005265static const byte JsonQuoteLengths[kQuoteTableLength] = {
5266 6, 6, 6, 6, 6, 6, 6, 6,
5267 2, 2, 2, 6, 2, 2, 6, 6,
5268 6, 6, 6, 6, 6, 6, 6, 6,
5269 6, 6, 6, 6, 6, 6, 6, 6,
5270 1, 1, 2, 1, 1, 1, 1, 1,
5271 1, 1, 1, 1, 1, 1, 1, 1,
5272 1, 1, 1, 1, 1, 1, 1, 1,
5273 1, 1, 1, 1, 1, 1, 1, 1,
5274 1, 1, 1, 1, 1, 1, 1, 1,
5275 1, 1, 1, 1, 1, 1, 1, 1,
5276 1, 1, 1, 1, 1, 1, 1, 1,
5277 1, 1, 1, 1, 2, 1, 1, 1,
5278 1, 1, 1, 1, 1, 1, 1, 1,
5279 1, 1, 1, 1, 1, 1, 1, 1,
5280 1, 1, 1, 1, 1, 1, 1, 1,
5281 1, 1, 1, 1, 1, 1, 1, 1,
5282};
5283
5284
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005285template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005286MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005287
5288
5289template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005290MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5291 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005292}
5293
5294
5295template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005296MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5297 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005298}
5299
5300
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005301template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005302static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5303 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005304 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005305 const Char* read_cursor = characters.start();
5306 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005307 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005308 int quoted_length = kSpaceForQuotes;
5309 while (read_cursor < end) {
5310 Char c = *(read_cursor++);
5311 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5312 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005313 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005314 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005315 }
5316 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005317 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5318 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005319 Object* new_object;
5320 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005321 return new_alloc;
5322 }
5323 StringType* new_string = StringType::cast(new_object);
5324
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005325 Char* write_cursor = reinterpret_cast<Char*>(
5326 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005327 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005328 *(write_cursor++) = '"';
5329
5330 read_cursor = characters.start();
5331 while (read_cursor < end) {
5332 Char c = *(read_cursor++);
5333 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5334 *(write_cursor++) = c;
5335 } else {
5336 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5337 const char* replacement = JsonQuotes +
5338 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5339 for (int i = 0; i < len; i++) {
5340 *write_cursor++ = *replacement++;
5341 }
5342 }
5343 }
5344 *(write_cursor++) = '"';
5345 return new_string;
5346}
5347
5348
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005349template <typename SinkChar, typename SourceChar>
5350static inline SinkChar* WriteQuoteJsonString(
5351 Isolate* isolate,
5352 SinkChar* write_cursor,
5353 Vector<const SourceChar> characters) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005354 // SinkChar is only char if SourceChar is guaranteed to be char.
5355 ASSERT(sizeof(SinkChar) >= sizeof(SourceChar));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005356 const SourceChar* read_cursor = characters.start();
5357 const SourceChar* end = read_cursor + characters.length();
5358 *(write_cursor++) = '"';
5359 while (read_cursor < end) {
5360 SourceChar c = *(read_cursor++);
5361 if (sizeof(SourceChar) > 1u &&
5362 static_cast<unsigned>(c) >= kQuoteTableLength) {
5363 *(write_cursor++) = static_cast<SinkChar>(c);
5364 } else {
5365 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5366 const char* replacement = JsonQuotes +
5367 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5368 write_cursor[0] = replacement[0];
5369 if (len > 1) {
5370 write_cursor[1] = replacement[1];
5371 if (len > 2) {
5372 ASSERT(len == 6);
5373 write_cursor[2] = replacement[2];
5374 write_cursor[3] = replacement[3];
5375 write_cursor[4] = replacement[4];
5376 write_cursor[5] = replacement[5];
5377 }
5378 }
5379 write_cursor += len;
5380 }
5381 }
5382 *(write_cursor++) = '"';
5383 return write_cursor;
5384}
5385
5386
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005387template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005388static MaybeObject* QuoteJsonString(Isolate* isolate,
5389 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005390 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005391 isolate->counters()->quote_json_char_count()->Increment(length);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005392 int worst_case_length =
5393 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005394 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005395 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005396 }
5397
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005398 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5399 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005400 Object* new_object;
5401 if (!new_alloc->ToObject(&new_object)) {
5402 return new_alloc;
5403 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005404 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005405 // Even if our string is small enough to fit in new space we still have to
5406 // handle it being allocated in old space as may happen in the third
5407 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5408 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005409 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005410 }
5411 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005412 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005413
5414 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5415 Char* write_cursor = reinterpret_cast<Char*>(
5416 new_string->address() + SeqAsciiString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005417 if (comma) *(write_cursor++) = ',';
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005418 write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
5419 write_cursor,
5420 characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005421 int final_length = static_cast<int>(
5422 write_cursor - reinterpret_cast<Char*>(
5423 new_string->address() + SeqAsciiString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005424 isolate->heap()->new_space()->
5425 template ShrinkStringAtAllocationBoundary<StringType>(
5426 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005427 return new_string;
5428}
5429
5430
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005431RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005432 NoHandleAllocation ha;
5433 CONVERT_CHECKED(String, str, args[0]);
5434 if (!str->IsFlat()) {
5435 MaybeObject* try_flatten = str->TryFlatten();
5436 Object* flat;
5437 if (!try_flatten->ToObject(&flat)) {
5438 return try_flatten;
5439 }
5440 str = String::cast(flat);
5441 ASSERT(str->IsFlat());
5442 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005443 String::FlatContent flat = str->GetFlatContent();
5444 ASSERT(flat.IsFlat());
5445 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005446 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005447 flat.ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005448 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005449 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005450 flat.ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005451 }
5452}
5453
5454
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005455RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005456 NoHandleAllocation ha;
5457 CONVERT_CHECKED(String, str, args[0]);
5458 if (!str->IsFlat()) {
5459 MaybeObject* try_flatten = str->TryFlatten();
5460 Object* flat;
5461 if (!try_flatten->ToObject(&flat)) {
5462 return try_flatten;
5463 }
5464 str = String::cast(flat);
5465 ASSERT(str->IsFlat());
5466 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005467 String::FlatContent flat = str->GetFlatContent();
5468 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005469 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005470 flat.ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005471 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005472 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005473 flat.ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005474 }
5475}
5476
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005477
5478template <typename Char, typename StringType>
5479static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
5480 FixedArray* array,
5481 int worst_case_length) {
5482 int length = array->length();
5483
5484 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5485 worst_case_length);
5486 Object* new_object;
5487 if (!new_alloc->ToObject(&new_object)) {
5488 return new_alloc;
5489 }
5490 if (!isolate->heap()->new_space()->Contains(new_object)) {
5491 // Even if our string is small enough to fit in new space we still have to
5492 // handle it being allocated in old space as may happen in the third
5493 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5494 // CEntryStub::GenerateCore.
5495 return isolate->heap()->undefined_value();
5496 }
5497 AssertNoAllocation no_gc;
5498 StringType* new_string = StringType::cast(new_object);
5499 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5500
5501 STATIC_ASSERT(SeqTwoByteString::kHeaderSize == SeqAsciiString::kHeaderSize);
5502 Char* write_cursor = reinterpret_cast<Char*>(
5503 new_string->address() + SeqAsciiString::kHeaderSize);
5504 *(write_cursor++) = '[';
5505 for (int i = 0; i < length; i++) {
5506 if (i != 0) *(write_cursor++) = ',';
5507 String* str = String::cast(array->get(i));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005508 String::FlatContent content = str->GetFlatContent();
5509 ASSERT(content.IsFlat());
5510 if (content.IsTwoByte()) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005511 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
5512 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005513 content.ToUC16Vector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005514 } else {
5515 write_cursor = WriteQuoteJsonString<Char, char>(isolate,
5516 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005517 content.ToAsciiVector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005518 }
5519 }
5520 *(write_cursor++) = ']';
5521
5522 int final_length = static_cast<int>(
5523 write_cursor - reinterpret_cast<Char*>(
5524 new_string->address() + SeqAsciiString::kHeaderSize));
5525 isolate->heap()->new_space()->
5526 template ShrinkStringAtAllocationBoundary<StringType>(
5527 new_string, final_length);
5528 return new_string;
5529}
5530
5531
5532RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
5533 NoHandleAllocation ha;
5534 ASSERT(args.length() == 1);
5535 CONVERT_CHECKED(JSArray, array, args[0]);
5536
5537 if (!array->HasFastElements()) return isolate->heap()->undefined_value();
5538 FixedArray* elements = FixedArray::cast(array->elements());
5539 int n = elements->length();
5540 bool ascii = true;
5541 int total_length = 0;
5542
5543 for (int i = 0; i < n; i++) {
5544 Object* elt = elements->get(i);
5545 if (!elt->IsString()) return isolate->heap()->undefined_value();
5546 String* element = String::cast(elt);
5547 if (!element->IsFlat()) return isolate->heap()->undefined_value();
5548 total_length += element->length();
5549 if (ascii && element->IsTwoByteRepresentation()) {
5550 ascii = false;
5551 }
5552 }
5553
5554 int worst_case_length =
5555 kSpaceForBrackets + n * kSpaceForQuotesAndComma
5556 + total_length * kJsonQuoteWorstCaseBlowup;
5557
5558 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5559 return isolate->heap()->undefined_value();
5560 }
5561
5562 if (ascii) {
5563 return QuoteJsonStringArray<char, SeqAsciiString>(isolate,
5564 elements,
5565 worst_case_length);
5566 } else {
5567 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
5568 elements,
5569 worst_case_length);
5570 }
5571}
5572
5573
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005574RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005575 NoHandleAllocation ha;
5576
5577 CONVERT_CHECKED(String, s, args[0]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005578 CONVERT_SMI_ARG_CHECKED(radix, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005579
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005580 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005581
lrn@chromium.org25156de2010-04-06 13:10:27 +00005582 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005583 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005584 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005585}
5586
5587
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005588RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005589 NoHandleAllocation ha;
5590 CONVERT_CHECKED(String, str, args[0]);
5591
5592 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005593 double value = StringToDouble(isolate->unicode_cache(),
5594 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005595
5596 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005597 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005598}
5599
5600
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005601template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005602MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005603 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005604 String* s,
5605 int length,
5606 int input_string_length,
5607 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005608 // We try this twice, once with the assumption that the result is no longer
5609 // than the input and, if that assumption breaks, again with the exact
5610 // length. This may not be pretty, but it is nicer than what was here before
5611 // and I hereby claim my vaffel-is.
5612 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005613 // Allocate the resulting string.
5614 //
5615 // NOTE: This assumes that the upper/lower case of an ascii
5616 // character is also ascii. This is currently the case, but it
5617 // might break in the future if we implement more context and locale
5618 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005619 Object* o;
5620 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005621 ? isolate->heap()->AllocateRawAsciiString(length)
5622 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005623 if (!maybe_o->ToObject(&o)) return maybe_o;
5624 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005625 String* result = String::cast(o);
5626 bool has_changed_character = false;
5627
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005628 // Convert all characters to upper case, assuming that they will fit
5629 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005630 Access<StringInputBuffer> buffer(
5631 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005632 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005633 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005634 // We can assume that the string is not empty
5635 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005636 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005637 bool has_next = buffer->has_more();
5638 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005639 int char_length = mapping->get(current, next, chars);
5640 if (char_length == 0) {
5641 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005642 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005643 i++;
5644 } else if (char_length == 1) {
5645 // Common case: converting the letter resulted in one character.
5646 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005647 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005648 has_changed_character = true;
5649 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005650 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005651 // We've assumed that the result would be as long as the
5652 // input but here is a character that converts to several
5653 // characters. No matter, we calculate the exact length
5654 // of the result and try the whole thing again.
5655 //
5656 // Note that this leaves room for optimization. We could just
5657 // memcpy what we already have to the result string. Also,
5658 // the result string is the last object allocated we could
5659 // "realloc" it and probably, in the vast majority of cases,
5660 // extend the existing string to be able to hold the full
5661 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00005662 int next_length = 0;
5663 if (has_next) {
5664 next_length = mapping->get(next, 0, chars);
5665 if (next_length == 0) next_length = 1;
5666 }
5667 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005668 while (buffer->has_more()) {
5669 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005670 // NOTE: we use 0 as the next character here because, while
5671 // the next character may affect what a character converts to,
5672 // it does not in any case affect the length of what it convert
5673 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005674 int char_length = mapping->get(current, 0, chars);
5675 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00005676 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005677 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005678 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005679 return Failure::OutOfMemoryException();
5680 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005681 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005682 // Try again with the real length.
5683 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005684 } else {
5685 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005686 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005687 i++;
5688 }
5689 has_changed_character = true;
5690 }
5691 current = next;
5692 }
5693 if (has_changed_character) {
5694 return result;
5695 } else {
5696 // If we didn't actually change anything in doing the conversion
5697 // we simple return the result and let the converted string
5698 // become garbage; there is no reason to keep two identical strings
5699 // alive.
5700 return s;
5701 }
5702}
5703
5704
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005705namespace {
5706
lrn@chromium.org303ada72010-10-27 09:33:13 +00005707static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
5708
5709
5710// Given a word and two range boundaries returns a word with high bit
5711// set in every byte iff the corresponding input byte was strictly in
5712// the range (m, n). All the other bits in the result are cleared.
5713// This function is only useful when it can be inlined and the
5714// boundaries are statically known.
5715// Requires: all bytes in the input word and the boundaries must be
5716// ascii (less than 0x7F).
5717static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
5718 // Every byte in an ascii string is less than or equal to 0x7F.
5719 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
5720 // Use strict inequalities since in edge cases the function could be
5721 // further simplified.
5722 ASSERT(0 < m && m < n && n < 0x7F);
5723 // Has high bit set in every w byte less than n.
5724 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
5725 // Has high bit set in every w byte greater than m.
5726 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
5727 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
5728}
5729
5730
5731enum AsciiCaseConversion {
5732 ASCII_TO_LOWER,
5733 ASCII_TO_UPPER
5734};
5735
5736
5737template <AsciiCaseConversion dir>
5738struct FastAsciiConverter {
5739 static bool Convert(char* dst, char* src, int length) {
5740#ifdef DEBUG
5741 char* saved_dst = dst;
5742 char* saved_src = src;
5743#endif
5744 // We rely on the distance between upper and lower case letters
5745 // being a known power of 2.
5746 ASSERT('a' - 'A' == (1 << 5));
5747 // Boundaries for the range of input characters than require conversion.
5748 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
5749 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
5750 bool changed = false;
5751 char* const limit = src + length;
5752#ifdef V8_HOST_CAN_READ_UNALIGNED
5753 // Process the prefix of the input that requires no conversion one
5754 // (machine) word at a time.
5755 while (src <= limit - sizeof(uintptr_t)) {
5756 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5757 if (AsciiRangeMask(w, lo, hi) != 0) {
5758 changed = true;
5759 break;
5760 }
5761 *reinterpret_cast<uintptr_t*>(dst) = w;
5762 src += sizeof(uintptr_t);
5763 dst += sizeof(uintptr_t);
5764 }
5765 // Process the remainder of the input performing conversion when
5766 // required one word at a time.
5767 while (src <= limit - sizeof(uintptr_t)) {
5768 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
5769 uintptr_t m = AsciiRangeMask(w, lo, hi);
5770 // The mask has high (7th) bit set in every byte that needs
5771 // conversion and we know that the distance between cases is
5772 // 1 << 5.
5773 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
5774 src += sizeof(uintptr_t);
5775 dst += sizeof(uintptr_t);
5776 }
5777#endif
5778 // Process the last few bytes of the input (or the whole input if
5779 // unaligned access is not supported).
5780 while (src < limit) {
5781 char c = *src;
5782 if (lo < c && c < hi) {
5783 c ^= (1 << 5);
5784 changed = true;
5785 }
5786 *dst = c;
5787 ++src;
5788 ++dst;
5789 }
5790#ifdef DEBUG
5791 CheckConvert(saved_dst, saved_src, length, changed);
5792#endif
5793 return changed;
5794 }
5795
5796#ifdef DEBUG
5797 static void CheckConvert(char* dst, char* src, int length, bool changed) {
5798 bool expected_changed = false;
5799 for (int i = 0; i < length; i++) {
5800 if (dst[i] == src[i]) continue;
5801 expected_changed = true;
5802 if (dir == ASCII_TO_LOWER) {
5803 ASSERT('A' <= src[i] && src[i] <= 'Z');
5804 ASSERT(dst[i] == src[i] + ('a' - 'A'));
5805 } else {
5806 ASSERT(dir == ASCII_TO_UPPER);
5807 ASSERT('a' <= src[i] && src[i] <= 'z');
5808 ASSERT(dst[i] == src[i] - ('a' - 'A'));
5809 }
5810 }
5811 ASSERT(expected_changed == changed);
5812 }
5813#endif
5814};
5815
5816
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005817struct ToLowerTraits {
5818 typedef unibrow::ToLowercase UnibrowConverter;
5819
lrn@chromium.org303ada72010-10-27 09:33:13 +00005820 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005821};
5822
5823
5824struct ToUpperTraits {
5825 typedef unibrow::ToUppercase UnibrowConverter;
5826
lrn@chromium.org303ada72010-10-27 09:33:13 +00005827 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005828};
5829
5830} // namespace
5831
5832
5833template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005834MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005835 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005836 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005837 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005838 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005839 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005840 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005841
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005842 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005843 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005844 if (length == 0) return s;
5845
5846 // Simpler handling of ascii strings.
5847 //
5848 // NOTE: This assumes that the upper/lower case of an ascii
5849 // character is also ascii. This is currently the case, but it
5850 // might break in the future if we implement more context and locale
5851 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005852 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005853 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005854 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005855 if (!maybe_o->ToObject(&o)) return maybe_o;
5856 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005857 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005858 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00005859 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005860 return has_changed_character ? result : s;
5861 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005862
lrn@chromium.org303ada72010-10-27 09:33:13 +00005863 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005864 { MaybeObject* maybe_answer =
5865 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005866 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5867 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005868 if (answer->IsSmi()) {
5869 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005870 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005871 ConvertCaseHelper(isolate,
5872 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005873 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
5874 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005875 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005876 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005877}
5878
5879
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005880RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005881 return ConvertCase<ToLowerTraits>(
5882 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005883}
5884
5885
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005886RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005887 return ConvertCase<ToUpperTraits>(
5888 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005889}
5890
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005891
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005892static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
5893 return unibrow::WhiteSpace::Is(c) || c == 0x200b;
5894}
5895
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005896
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005897RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005898 NoHandleAllocation ha;
5899 ASSERT(args.length() == 3);
5900
5901 CONVERT_CHECKED(String, s, args[0]);
5902 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
5903 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
5904
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005905 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005906 int length = s->length();
5907
5908 int left = 0;
5909 if (trimLeft) {
5910 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
5911 left++;
5912 }
5913 }
5914
5915 int right = length;
5916 if (trimRight) {
5917 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
5918 right--;
5919 }
5920 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00005921 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005922}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005923
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005924
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005925void FindAsciiStringIndices(Vector<const char> subject,
5926 char pattern,
5927 ZoneList<int>* indices,
5928 unsigned int limit) {
5929 ASSERT(limit > 0);
5930 // Collect indices of pattern in subject using memchr.
5931 // Stop after finding at most limit values.
5932 const char* subject_start = reinterpret_cast<const char*>(subject.start());
5933 const char* subject_end = subject_start + subject.length();
5934 const char* pos = subject_start;
5935 while (limit > 0) {
5936 pos = reinterpret_cast<const char*>(
5937 memchr(pos, pattern, subject_end - pos));
5938 if (pos == NULL) return;
5939 indices->Add(static_cast<int>(pos - subject_start));
5940 pos++;
5941 limit--;
5942 }
5943}
5944
5945
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005946template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005947void FindStringIndices(Isolate* isolate,
5948 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005949 Vector<const PatternChar> pattern,
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005950 ZoneList<int>* indices,
5951 unsigned int limit) {
5952 ASSERT(limit > 0);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005953 // Collect indices of pattern in subject.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005954 // Stop after finding at most limit values.
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005955 int pattern_length = pattern.length();
5956 int index = 0;
ricow@chromium.org4f693d62011-07-04 14:01:31 +00005957 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00005958 while (limit > 0) {
5959 index = search.Search(subject, index);
5960 if (index < 0) return;
5961 indices->Add(index);
5962 index += pattern_length;
5963 limit--;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005964 }
5965}
5966
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005967
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005968RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005969 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005970 HandleScope handle_scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005971 CONVERT_ARG_CHECKED(String, subject, 0);
5972 CONVERT_ARG_CHECKED(String, pattern, 1);
5973 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
5974
5975 int subject_length = subject->length();
5976 int pattern_length = pattern->length();
5977 RUNTIME_ASSERT(pattern_length > 0);
5978
5979 // The limit can be very large (0xffffffffu), but since the pattern
5980 // isn't empty, we can never create more parts than ~half the length
5981 // of the subject.
5982
5983 if (!subject->IsFlat()) FlattenString(subject);
5984
5985 static const int kMaxInitialListCapacity = 16;
5986
danno@chromium.org40cb8782011-05-25 07:58:50 +00005987 ZoneScope scope(isolate, DELETE_ON_EXIT);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00005988
5989 // Find (up to limit) indices of separator and end-of-string in subject
5990 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
5991 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005992 if (!pattern->IsFlat()) FlattenString(pattern);
5993
5994 // No allocation block.
5995 {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005996 AssertNoAllocation no_gc;
5997 String::FlatContent subject_content = subject->GetFlatContent();
5998 String::FlatContent pattern_content = pattern->GetFlatContent();
5999 ASSERT(subject_content.IsFlat());
6000 ASSERT(pattern_content.IsFlat());
6001 if (subject_content.IsAscii()) {
6002 Vector<const char> subject_vector = subject_content.ToAsciiVector();
6003 if (pattern_content.IsAscii()) {
6004 Vector<const char> pattern_vector = pattern_content.ToAsciiVector();
ricow@chromium.org4f693d62011-07-04 14:01:31 +00006005 if (pattern_vector.length() == 1) {
6006 FindAsciiStringIndices(subject_vector,
6007 pattern_vector[0],
6008 &indices,
6009 limit);
6010 } else {
6011 FindStringIndices(isolate,
6012 subject_vector,
6013 pattern_vector,
6014 &indices,
6015 limit);
6016 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006017 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006018 FindStringIndices(isolate,
6019 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006020 pattern_content.ToUC16Vector(),
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006021 &indices,
6022 limit);
6023 }
6024 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006025 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006026 if (pattern->IsAsciiRepresentation()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006027 FindStringIndices(isolate,
6028 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006029 pattern_content.ToAsciiVector(),
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006030 &indices,
6031 limit);
6032 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006033 FindStringIndices(isolate,
6034 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006035 pattern_content.ToUC16Vector(),
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006036 &indices,
6037 limit);
6038 }
6039 }
6040 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006041
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006042 if (static_cast<uint32_t>(indices.length()) < limit) {
6043 indices.Add(subject_length);
6044 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006045
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006046 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006047
6048 // Create JSArray of substrings separated by separator.
6049 int part_count = indices.length();
6050
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006051 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006052 result->set_length(Smi::FromInt(part_count));
6053
6054 ASSERT(result->HasFastElements());
6055
6056 if (part_count == 1 && indices.at(0) == subject_length) {
6057 FixedArray::cast(result->elements())->set(0, *subject);
6058 return *result;
6059 }
6060
6061 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
6062 int part_start = 0;
6063 for (int i = 0; i < part_count; i++) {
6064 HandleScope local_loop_handle;
6065 int part_end = indices.at(i);
6066 Handle<String> substring =
ager@chromium.org04921a82011-06-27 13:21:41 +00006067 isolate->factory()->NewProperSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006068 elements->set(i, *substring);
6069 part_start = part_end + pattern_length;
6070 }
6071
6072 return *result;
6073}
6074
6075
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006076// Copies ascii characters to the given fixed array looking up
6077// one-char strings in the cache. Gives up on the first char that is
6078// not in the cache and fills the remainder with smi zeros. Returns
6079// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006080static int CopyCachedAsciiCharsToArray(Heap* heap,
6081 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006082 FixedArray* elements,
6083 int length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006084 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006085 FixedArray* ascii_cache = heap->single_character_string_cache();
6086 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006087 int i;
6088 for (i = 0; i < length; ++i) {
6089 Object* value = ascii_cache->get(chars[i]);
6090 if (value == undefined) break;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006091 ASSERT(!heap->InNewSpace(value));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006092 elements->set(i, value, SKIP_WRITE_BARRIER);
6093 }
6094 if (i < length) {
6095 ASSERT(Smi::FromInt(0) == 0);
6096 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
6097 }
6098#ifdef DEBUG
6099 for (int j = 0; j < length; ++j) {
6100 Object* element = elements->get(j);
6101 ASSERT(element == Smi::FromInt(0) ||
6102 (element->IsString() && String::cast(element)->LooksValid()));
6103 }
6104#endif
6105 return i;
6106}
6107
6108
6109// Converts a String to JSArray.
6110// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006111RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006112 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006113 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006114 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006115 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006116
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006117 s = FlattenGetString(s);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006118 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006119
6120 Handle<FixedArray> elements;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006121 int position = 0;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006122 if (s->IsFlat() && s->IsAsciiRepresentation()) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006123 // Try using cached chars where possible.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006124 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006125 { MaybeObject* maybe_obj =
6126 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006127 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6128 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006129 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006130 String::FlatContent content = s->GetFlatContent();
6131 if (content.IsAscii()) {
6132 Vector<const char> chars = content.ToAsciiVector();
6133 // Note, this will initialize all elements (not only the prefix)
6134 // to prevent GC from seeing partially initialized array.
6135 position = CopyCachedAsciiCharsToArray(isolate->heap(),
6136 chars.start(),
6137 *elements,
6138 length);
6139 } else {
6140 MemsetPointer(elements->data_start(),
6141 isolate->heap()->undefined_value(),
6142 length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006143 }
6144 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006145 elements = isolate->factory()->NewFixedArray(length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006146 }
6147 for (int i = position; i < length; ++i) {
6148 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
6149 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006150 }
6151
6152#ifdef DEBUG
6153 for (int i = 0; i < length; ++i) {
6154 ASSERT(String::cast(elements->get(i))->length() == 1);
6155 }
6156#endif
6157
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006158 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006159}
6160
6161
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006162RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006163 NoHandleAllocation ha;
6164 ASSERT(args.length() == 1);
6165 CONVERT_CHECKED(String, value, args[0]);
6166 return value->ToObject();
6167}
6168
6169
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006170bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006171 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006172 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006173 return char_length == 0;
6174}
6175
6176
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006177RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006178 NoHandleAllocation ha;
6179 ASSERT(args.length() == 1);
6180
6181 Object* number = args[0];
6182 RUNTIME_ASSERT(number->IsNumber());
6183
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006184 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006185}
6186
6187
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006188RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00006189 NoHandleAllocation ha;
6190 ASSERT(args.length() == 1);
6191
6192 Object* number = args[0];
6193 RUNTIME_ASSERT(number->IsNumber());
6194
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006195 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00006196}
6197
6198
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006199RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006200 NoHandleAllocation ha;
6201 ASSERT(args.length() == 1);
6202
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006203 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006204
6205 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6206 if (number > 0 && number <= Smi::kMaxValue) {
6207 return Smi::FromInt(static_cast<int>(number));
6208 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006209 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006210}
6211
6212
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006213RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006214 NoHandleAllocation ha;
6215 ASSERT(args.length() == 1);
6216
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006217 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006218
6219 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6220 if (number > 0 && number <= Smi::kMaxValue) {
6221 return Smi::FromInt(static_cast<int>(number));
6222 }
6223
6224 double double_value = DoubleToInteger(number);
6225 // Map both -0 and +0 to +0.
6226 if (double_value == 0) double_value = 0;
6227
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006228 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006229}
6230
6231
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006232RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006233 NoHandleAllocation ha;
6234 ASSERT(args.length() == 1);
6235
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006236 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006237 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006238}
6239
6240
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006241RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006242 NoHandleAllocation ha;
6243 ASSERT(args.length() == 1);
6244
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006245 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006246
6247 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6248 if (number > 0 && number <= Smi::kMaxValue) {
6249 return Smi::FromInt(static_cast<int>(number));
6250 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006251 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006252}
6253
6254
ager@chromium.org870a0b62008-11-04 11:43:05 +00006255// Converts a Number to a Smi, if possible. Returns NaN if the number is not
6256// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006257RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00006258 NoHandleAllocation ha;
6259 ASSERT(args.length() == 1);
6260
6261 Object* obj = args[0];
6262 if (obj->IsSmi()) {
6263 return obj;
6264 }
6265 if (obj->IsHeapNumber()) {
6266 double value = HeapNumber::cast(obj)->value();
6267 int int_value = FastD2I(value);
6268 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
6269 return Smi::FromInt(int_value);
6270 }
6271 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006272 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006273}
6274
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006275
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006276RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006277 NoHandleAllocation ha;
6278 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006279 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006280}
6281
6282
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006283RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006284 NoHandleAllocation ha;
6285 ASSERT(args.length() == 2);
6286
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006287 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6288 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006289 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006290}
6291
6292
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006293RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006294 NoHandleAllocation ha;
6295 ASSERT(args.length() == 2);
6296
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006297 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6298 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006299 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006300}
6301
6302
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006303RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006304 NoHandleAllocation ha;
6305 ASSERT(args.length() == 2);
6306
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006307 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6308 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006309 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006310}
6311
6312
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006313RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006314 NoHandleAllocation ha;
6315 ASSERT(args.length() == 1);
6316
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006317 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006318 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006319}
6320
6321
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006322RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006323 NoHandleAllocation ha;
6324 ASSERT(args.length() == 0);
6325
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006326 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006327}
6328
6329
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006330RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006331 NoHandleAllocation ha;
6332 ASSERT(args.length() == 2);
6333
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006334 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6335 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006336 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006337}
6338
6339
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006340RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006341 NoHandleAllocation ha;
6342 ASSERT(args.length() == 2);
6343
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006344 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6345 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006346
ager@chromium.org3811b432009-10-28 14:53:37 +00006347 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006348 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006349 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006350}
6351
6352
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006353RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006354 NoHandleAllocation ha;
6355 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006356 CONVERT_CHECKED(String, str1, args[0]);
6357 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006358 isolate->counters()->string_add_runtime()->Increment();
6359 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006360}
6361
6362
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006363template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006364static inline void StringBuilderConcatHelper(String* special,
6365 sinkchar* sink,
6366 FixedArray* fixed_array,
6367 int array_length) {
6368 int position = 0;
6369 for (int i = 0; i < array_length; i++) {
6370 Object* element = fixed_array->get(i);
6371 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006372 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006373 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006374 int pos;
6375 int len;
6376 if (encoded_slice > 0) {
6377 // Position and length encoded in one smi.
6378 pos = StringBuilderSubstringPosition::decode(encoded_slice);
6379 len = StringBuilderSubstringLength::decode(encoded_slice);
6380 } else {
6381 // Position and length encoded in two smis.
6382 Object* obj = fixed_array->get(++i);
6383 ASSERT(obj->IsSmi());
6384 pos = Smi::cast(obj)->value();
6385 len = -encoded_slice;
6386 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00006387 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00006388 sink + position,
6389 pos,
6390 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006391 position += len;
6392 } else {
6393 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006394 int element_length = string->length();
6395 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006396 position += element_length;
6397 }
6398 }
6399}
6400
6401
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006402RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006403 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006404 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006405 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006406 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006407 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006408 return Failure::OutOfMemoryException();
6409 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006410 int array_length = args.smi_at(1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006411 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006412
6413 // This assumption is used by the slice encoding in one or two smis.
6414 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6415
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006416 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006417 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006418 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006419 }
6420 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006421 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006422 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006423 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006424
6425 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006426 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006427 } else if (array_length == 1) {
6428 Object* first = fixed_array->get(0);
6429 if (first->IsString()) return first;
6430 }
6431
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006432 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006433 int position = 0;
6434 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006435 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006436 Object* elt = fixed_array->get(i);
6437 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006438 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006439 int smi_value = Smi::cast(elt)->value();
6440 int pos;
6441 int len;
6442 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006443 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006444 pos = StringBuilderSubstringPosition::decode(smi_value);
6445 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006446 } else {
6447 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006448 len = -smi_value;
6449 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006450 i++;
6451 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006452 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006453 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006454 Object* next_smi = fixed_array->get(i);
6455 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006456 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006457 }
6458 pos = Smi::cast(next_smi)->value();
6459 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006460 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006461 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006462 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006463 ASSERT(pos >= 0);
6464 ASSERT(len >= 0);
6465 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006466 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006467 }
6468 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006469 } else if (elt->IsString()) {
6470 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006471 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006472 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006473 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006474 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006475 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006476 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006477 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006478 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006479 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006480 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006481 return Failure::OutOfMemoryException();
6482 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006483 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006484 }
6485
6486 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006487 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006488
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006489 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006490 { MaybeObject* maybe_object =
6491 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006492 if (!maybe_object->ToObject(&object)) return maybe_object;
6493 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006494 SeqAsciiString* answer = SeqAsciiString::cast(object);
6495 StringBuilderConcatHelper(special,
6496 answer->GetChars(),
6497 fixed_array,
6498 array_length);
6499 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006500 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006501 { MaybeObject* maybe_object =
6502 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006503 if (!maybe_object->ToObject(&object)) return maybe_object;
6504 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006505 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6506 StringBuilderConcatHelper(special,
6507 answer->GetChars(),
6508 fixed_array,
6509 array_length);
6510 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006511 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006512}
6513
6514
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006515RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006516 NoHandleAllocation ha;
6517 ASSERT(args.length() == 3);
6518 CONVERT_CHECKED(JSArray, array, args[0]);
6519 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006520 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006521 return Failure::OutOfMemoryException();
6522 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006523 int array_length = args.smi_at(1);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006524 CONVERT_CHECKED(String, separator, args[2]);
6525
6526 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006527 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006528 }
6529 FixedArray* fixed_array = FixedArray::cast(array->elements());
6530 if (fixed_array->length() < array_length) {
6531 array_length = fixed_array->length();
6532 }
6533
6534 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006535 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006536 } else if (array_length == 1) {
6537 Object* first = fixed_array->get(0);
6538 if (first->IsString()) return first;
6539 }
6540
6541 int separator_length = separator->length();
6542 int max_nof_separators =
6543 (String::kMaxLength + separator_length - 1) / separator_length;
6544 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006545 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006546 return Failure::OutOfMemoryException();
6547 }
6548 int length = (array_length - 1) * separator_length;
6549 for (int i = 0; i < array_length; i++) {
6550 Object* element_obj = fixed_array->get(i);
6551 if (!element_obj->IsString()) {
6552 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006553 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006554 }
6555 String* element = String::cast(element_obj);
6556 int increment = element->length();
6557 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006558 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006559 return Failure::OutOfMemoryException();
6560 }
6561 length += increment;
6562 }
6563
6564 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006565 { MaybeObject* maybe_object =
6566 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006567 if (!maybe_object->ToObject(&object)) return maybe_object;
6568 }
6569 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6570
6571 uc16* sink = answer->GetChars();
6572#ifdef DEBUG
6573 uc16* end = sink + length;
6574#endif
6575
6576 String* first = String::cast(fixed_array->get(0));
6577 int first_length = first->length();
6578 String::WriteToFlat(first, sink, 0, first_length);
6579 sink += first_length;
6580
6581 for (int i = 1; i < array_length; i++) {
6582 ASSERT(sink + separator_length <= end);
6583 String::WriteToFlat(separator, sink, 0, separator_length);
6584 sink += separator_length;
6585
6586 String* element = String::cast(fixed_array->get(i));
6587 int element_length = element->length();
6588 ASSERT(sink + element_length <= end);
6589 String::WriteToFlat(element, sink, 0, element_length);
6590 sink += element_length;
6591 }
6592 ASSERT(sink == end);
6593
6594 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6595 return answer;
6596}
6597
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006598template <typename Char>
6599static void JoinSparseArrayWithSeparator(FixedArray* elements,
6600 int elements_length,
6601 uint32_t array_length,
6602 String* separator,
6603 Vector<Char> buffer) {
6604 int previous_separator_position = 0;
6605 int separator_length = separator->length();
6606 int cursor = 0;
6607 for (int i = 0; i < elements_length; i += 2) {
6608 int position = NumberToInt32(elements->get(i));
6609 String* string = String::cast(elements->get(i + 1));
6610 int string_length = string->length();
6611 if (string->length() > 0) {
6612 while (previous_separator_position < position) {
6613 String::WriteToFlat<Char>(separator, &buffer[cursor],
6614 0, separator_length);
6615 cursor += separator_length;
6616 previous_separator_position++;
6617 }
6618 String::WriteToFlat<Char>(string, &buffer[cursor],
6619 0, string_length);
6620 cursor += string->length();
6621 }
6622 }
6623 if (separator_length > 0) {
6624 // Array length must be representable as a signed 32-bit number,
6625 // otherwise the total string length would have been too large.
6626 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6627 int last_array_index = static_cast<int>(array_length - 1);
6628 while (previous_separator_position < last_array_index) {
6629 String::WriteToFlat<Char>(separator, &buffer[cursor],
6630 0, separator_length);
6631 cursor += separator_length;
6632 previous_separator_position++;
6633 }
6634 }
6635 ASSERT(cursor <= buffer.length());
6636}
6637
6638
6639RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6640 NoHandleAllocation ha;
6641 ASSERT(args.length() == 3);
6642 CONVERT_CHECKED(JSArray, elements_array, args[0]);
6643 RUNTIME_ASSERT(elements_array->HasFastElements());
6644 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
6645 CONVERT_CHECKED(String, separator, args[2]);
6646 // elements_array is fast-mode JSarray of alternating positions
6647 // (increasing order) and strings.
6648 // array_length is length of original array (used to add separators);
6649 // separator is string to put between elements. Assumed to be non-empty.
6650
6651 // Find total length of join result.
6652 int string_length = 0;
6653 bool is_ascii = true;
6654 int max_string_length = SeqAsciiString::kMaxLength;
6655 bool overflow = false;
6656 CONVERT_NUMBER_CHECKED(int, elements_length,
6657 Int32, elements_array->length());
6658 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
6659 FixedArray* elements = FixedArray::cast(elements_array->elements());
6660 for (int i = 0; i < elements_length; i += 2) {
6661 RUNTIME_ASSERT(elements->get(i)->IsNumber());
6662 CONVERT_CHECKED(String, string, elements->get(i + 1));
6663 int length = string->length();
6664 if (is_ascii && !string->IsAsciiRepresentation()) {
6665 is_ascii = false;
6666 max_string_length = SeqTwoByteString::kMaxLength;
6667 }
6668 if (length > max_string_length ||
6669 max_string_length - length < string_length) {
6670 overflow = true;
6671 break;
6672 }
6673 string_length += length;
6674 }
6675 int separator_length = separator->length();
6676 if (!overflow && separator_length > 0) {
6677 if (array_length <= 0x7fffffffu) {
6678 int separator_count = static_cast<int>(array_length) - 1;
6679 int remaining_length = max_string_length - string_length;
6680 if ((remaining_length / separator_length) >= separator_count) {
6681 string_length += separator_length * (array_length - 1);
6682 } else {
6683 // Not room for the separators within the maximal string length.
6684 overflow = true;
6685 }
6686 } else {
6687 // Nonempty separator and at least 2^31-1 separators necessary
6688 // means that the string is too large to create.
6689 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
6690 overflow = true;
6691 }
6692 }
6693 if (overflow) {
6694 // Throw OutOfMemory exception for creating too large a string.
6695 V8::FatalProcessOutOfMemory("Array join result too large.");
6696 }
6697
6698 if (is_ascii) {
6699 MaybeObject* result_allocation =
6700 isolate->heap()->AllocateRawAsciiString(string_length);
6701 if (result_allocation->IsFailure()) return result_allocation;
6702 SeqAsciiString* result_string =
6703 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
6704 JoinSparseArrayWithSeparator<char>(elements,
6705 elements_length,
6706 array_length,
6707 separator,
6708 Vector<char>(result_string->GetChars(),
6709 string_length));
6710 return result_string;
6711 } else {
6712 MaybeObject* result_allocation =
6713 isolate->heap()->AllocateRawTwoByteString(string_length);
6714 if (result_allocation->IsFailure()) return result_allocation;
6715 SeqTwoByteString* result_string =
6716 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
6717 JoinSparseArrayWithSeparator<uc16>(elements,
6718 elements_length,
6719 array_length,
6720 separator,
6721 Vector<uc16>(result_string->GetChars(),
6722 string_length));
6723 return result_string;
6724 }
6725}
6726
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006727
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006728RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006729 NoHandleAllocation ha;
6730 ASSERT(args.length() == 2);
6731
6732 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6733 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006734 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006735}
6736
6737
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006738RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006739 NoHandleAllocation ha;
6740 ASSERT(args.length() == 2);
6741
6742 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6743 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006744 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006745}
6746
6747
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006748RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006749 NoHandleAllocation ha;
6750 ASSERT(args.length() == 2);
6751
6752 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6753 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006754 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006755}
6756
6757
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006758RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006759 NoHandleAllocation ha;
6760 ASSERT(args.length() == 1);
6761
6762 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006763 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006764}
6765
6766
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006767RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006768 NoHandleAllocation ha;
6769 ASSERT(args.length() == 2);
6770
6771 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6772 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006773 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006774}
6775
6776
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006777RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006778 NoHandleAllocation ha;
6779 ASSERT(args.length() == 2);
6780
6781 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
6782 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006783 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006784}
6785
6786
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006787RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006788 NoHandleAllocation ha;
6789 ASSERT(args.length() == 2);
6790
6791 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6792 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006793 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006794}
6795
6796
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006797RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006798 NoHandleAllocation ha;
6799 ASSERT(args.length() == 2);
6800
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006801 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6802 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006803 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
6804 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
6805 if (x == y) return Smi::FromInt(EQUAL);
6806 Object* result;
6807 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
6808 result = Smi::FromInt(EQUAL);
6809 } else {
6810 result = Smi::FromInt(NOT_EQUAL);
6811 }
6812 return result;
6813}
6814
6815
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006816RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006817 NoHandleAllocation ha;
6818 ASSERT(args.length() == 2);
6819
6820 CONVERT_CHECKED(String, x, args[0]);
6821 CONVERT_CHECKED(String, y, args[1]);
6822
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006823 bool not_equal = !x->Equals(y);
6824 // This is slightly convoluted because the value that signifies
6825 // equality is 0 and inequality is 1 so we have to negate the result
6826 // from String::Equals.
6827 ASSERT(not_equal == 0 || not_equal == 1);
6828 STATIC_CHECK(EQUAL == 0);
6829 STATIC_CHECK(NOT_EQUAL == 1);
6830 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006831}
6832
6833
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006834RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006835 NoHandleAllocation ha;
6836 ASSERT(args.length() == 3);
6837
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006838 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6839 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006840 if (isnan(x) || isnan(y)) return args[2];
6841 if (x == y) return Smi::FromInt(EQUAL);
6842 if (isless(x, y)) return Smi::FromInt(LESS);
6843 return Smi::FromInt(GREATER);
6844}
6845
6846
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006847// Compare two Smis as if they were converted to strings and then
6848// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006849RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006850 NoHandleAllocation ha;
6851 ASSERT(args.length() == 2);
6852
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006853 // Extract the integer values from the Smis.
6854 CONVERT_CHECKED(Smi, x, args[0]);
6855 CONVERT_CHECKED(Smi, y, args[1]);
6856 int x_value = x->value();
6857 int y_value = y->value();
6858
6859 // If the integers are equal so are the string representations.
6860 if (x_value == y_value) return Smi::FromInt(EQUAL);
6861
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006862 // If one of the integers is zero the normal integer order is the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006863 // same as the lexicographic order of the string representations.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006864 if (x_value == 0 || y_value == 0)
6865 return Smi::FromInt(x_value < y_value ? LESS : GREATER);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006866
ager@chromium.org32912102009-01-16 10:38:43 +00006867 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006868 // smallest because the char code of '-' is less than the char code
6869 // of any digit. Otherwise, we make both values positive.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006870
6871 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
6872 // architectures using 32-bit Smis.
6873 uint32_t x_scaled = x_value;
6874 uint32_t y_scaled = y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006875 if (x_value < 0 || y_value < 0) {
6876 if (y_value >= 0) return Smi::FromInt(LESS);
6877 if (x_value >= 0) return Smi::FromInt(GREATER);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006878 x_scaled = -x_value;
6879 y_scaled = -y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006880 }
6881
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006882 static const uint32_t kPowersOf10[] = {
6883 1, 10, 100, 1000, 10*1000, 100*1000,
6884 1000*1000, 10*1000*1000, 100*1000*1000,
6885 1000*1000*1000
6886 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006887
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006888 // If the integers have the same number of decimal digits they can be
6889 // compared directly as the numeric order is the same as the
6890 // lexicographic order. If one integer has fewer digits, it is scaled
6891 // by some power of 10 to have the same number of digits as the longer
6892 // integer. If the scaled integers are equal it means the shorter
6893 // integer comes first in the lexicographic order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006894
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006895 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
6896 int x_log2 = IntegerLog2(x_scaled);
6897 int x_log10 = ((x_log2 + 1) * 1233) >> 12;
6898 x_log10 -= x_scaled < kPowersOf10[x_log10];
6899
6900 int y_log2 = IntegerLog2(y_scaled);
6901 int y_log10 = ((y_log2 + 1) * 1233) >> 12;
6902 y_log10 -= y_scaled < kPowersOf10[y_log10];
6903
6904 int tie = EQUAL;
6905
6906 if (x_log10 < y_log10) {
6907 // X has fewer digits. We would like to simply scale up X but that
6908 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
6909 // be scaled up to 9_000_000_000. So we scale up by the next
6910 // smallest power and scale down Y to drop one digit. It is OK to
6911 // drop one digit from the longer integer since the final digit is
6912 // past the length of the shorter integer.
6913 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
6914 y_scaled /= 10;
6915 tie = LESS;
6916 } else if (y_log10 < x_log10) {
6917 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
6918 x_scaled /= 10;
6919 tie = GREATER;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006920 }
6921
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00006922 if (x_scaled < y_scaled) return Smi::FromInt(LESS);
6923 if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
6924 return Smi::FromInt(tie);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00006925}
6926
6927
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006928static Object* StringInputBufferCompare(RuntimeState* state,
6929 String* x,
6930 String* y) {
6931 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
6932 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006933 bufx.Reset(x);
6934 bufy.Reset(y);
6935 while (bufx.has_more() && bufy.has_more()) {
6936 int d = bufx.GetNext() - bufy.GetNext();
6937 if (d < 0) return Smi::FromInt(LESS);
6938 else if (d > 0) return Smi::FromInt(GREATER);
6939 }
6940
6941 // x is (non-trivial) prefix of y:
6942 if (bufy.has_more()) return Smi::FromInt(LESS);
6943 // y is prefix of x:
6944 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
6945}
6946
6947
6948static Object* FlatStringCompare(String* x, String* y) {
6949 ASSERT(x->IsFlat());
6950 ASSERT(y->IsFlat());
6951 Object* equal_prefix_result = Smi::FromInt(EQUAL);
6952 int prefix_length = x->length();
6953 if (y->length() < prefix_length) {
6954 prefix_length = y->length();
6955 equal_prefix_result = Smi::FromInt(GREATER);
6956 } else if (y->length() > prefix_length) {
6957 equal_prefix_result = Smi::FromInt(LESS);
6958 }
6959 int r;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006960 String::FlatContent x_content = x->GetFlatContent();
6961 String::FlatContent y_content = y->GetFlatContent();
6962 if (x_content.IsAscii()) {
6963 Vector<const char> x_chars = x_content.ToAsciiVector();
6964 if (y_content.IsAscii()) {
6965 Vector<const char> y_chars = y_content.ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006966 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006967 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006968 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006969 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6970 }
6971 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006972 Vector<const uc16> x_chars = x_content.ToUC16Vector();
6973 if (y_content.IsAscii()) {
6974 Vector<const char> y_chars = y_content.ToAsciiVector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006975 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6976 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006977 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006978 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
6979 }
6980 }
6981 Object* result;
6982 if (r == 0) {
6983 result = equal_prefix_result;
6984 } else {
6985 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
6986 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006987 ASSERT(result ==
6988 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006989 return result;
6990}
6991
6992
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006993RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006994 NoHandleAllocation ha;
6995 ASSERT(args.length() == 2);
6996
6997 CONVERT_CHECKED(String, x, args[0]);
6998 CONVERT_CHECKED(String, y, args[1]);
6999
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007000 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007001
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007002 // A few fast case tests before we flatten.
7003 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007004 if (y->length() == 0) {
7005 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007006 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007007 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007008 return Smi::FromInt(LESS);
7009 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007010
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007011 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007012 if (d < 0) return Smi::FromInt(LESS);
7013 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007014
lrn@chromium.org303ada72010-10-27 09:33:13 +00007015 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007016 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007017 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7018 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007019 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007020 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7021 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007022
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007023 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007024 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007025}
7026
7027
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007028RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007029 NoHandleAllocation ha;
7030 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007031 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007032
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007033 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007034 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007035}
7036
7037
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007038RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007039 NoHandleAllocation ha;
7040 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007041 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007042
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007043 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007044 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007045}
7046
7047
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007048RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007049 NoHandleAllocation ha;
7050 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007051 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007052
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007053 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007054 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007055}
7056
7057
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007058static const double kPiDividedBy4 = 0.78539816339744830962;
7059
7060
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007061RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007062 NoHandleAllocation ha;
7063 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007064 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007065
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007066 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7067 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007068 double result;
7069 if (isinf(x) && isinf(y)) {
7070 // Make sure that the result in case of two infinite arguments
7071 // is a multiple of Pi / 4. The sign of the result is determined
7072 // by the first argument (x) and the sign of the second argument
7073 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007074 int multiplier = (x < 0) ? -1 : 1;
7075 if (y < 0) multiplier *= 3;
7076 result = multiplier * kPiDividedBy4;
7077 } else {
7078 result = atan2(x, y);
7079 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007080 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007081}
7082
7083
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007084RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007085 NoHandleAllocation ha;
7086 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007087 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007088
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007089 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007090 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007091}
7092
7093
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007094RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007095 NoHandleAllocation ha;
7096 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007097 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007098
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007099 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007100 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007101}
7102
7103
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007104RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007105 NoHandleAllocation ha;
7106 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007107 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007108
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007109 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007110 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007111}
7112
7113
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007114RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007115 NoHandleAllocation ha;
7116 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007117 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007118
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007119 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007120 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007121}
7122
7123
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007124RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007125 NoHandleAllocation ha;
7126 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007127 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007128
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007129 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007130 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007131}
7132
7133
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007134RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007135 NoHandleAllocation ha;
7136 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007137 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007138
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007139 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007140
7141 // If the second argument is a smi, it is much faster to call the
7142 // custom powi() function than the generic pow().
7143 if (args[1]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007144 int y = args.smi_at(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007145 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007146 }
7147
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007148 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007149 return isolate->heap()->AllocateHeapNumber(power_double_double(x, y));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007150}
7151
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007152// Fast version of Math.pow if we know that y is not an integer and
7153// y is not -0.5 or 0.5. Used as slowcase from codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007154RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007155 NoHandleAllocation ha;
7156 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007157 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7158 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007159 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007160 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007161 } else if (isnan(y) || ((x == 1 || x == -1) && isinf(y))) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007162 return isolate->heap()->nan_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007163 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007164 return isolate->heap()->AllocateHeapNumber(pow(x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007165 }
7166}
7167
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007168
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007169RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007170 NoHandleAllocation ha;
7171 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007172 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007173
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007174 if (!args[0]->IsHeapNumber()) {
7175 // Must be smi. Return the argument unchanged for all the other types
7176 // to make fuzz-natives test happy.
7177 return args[0];
7178 }
7179
7180 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
7181
7182 double value = number->value();
7183 int exponent = number->get_exponent();
7184 int sign = number->get_sign();
7185
danno@chromium.org160a7b02011-04-18 15:51:38 +00007186 if (exponent < -1) {
7187 // Number in range ]-0.5..0.5[. These always round to +/-zero.
7188 if (sign) return isolate->heap()->minus_zero_value();
7189 return Smi::FromInt(0);
7190 }
7191
7192 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
7193 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
7194 // agument holds for 32-bit smis).
7195 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007196 return Smi::FromInt(static_cast<int>(value + 0.5));
7197 }
7198
7199 // If the magnitude is big enough, there's no place for fraction part. If we
7200 // try to add 0.5 to this number, 1.0 will be added instead.
7201 if (exponent >= 52) {
7202 return number;
7203 }
7204
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007205 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007206
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007207 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007208 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007209}
7210
7211
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007212RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007213 NoHandleAllocation ha;
7214 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007215 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007216
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007217 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007218 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007219}
7220
7221
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007222RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007223 NoHandleAllocation ha;
7224 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007225 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007226
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007227 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007228 return isolate->heap()->AllocateHeapNumber(sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007229}
7230
7231
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007232RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007233 NoHandleAllocation ha;
7234 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007235 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007236
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007237 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007238 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007239}
7240
7241
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007242static int MakeDay(int year, int month, int day) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007243 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
7244 181, 212, 243, 273, 304, 334};
7245 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
7246 182, 213, 244, 274, 305, 335};
7247
7248 year += month / 12;
7249 month %= 12;
7250 if (month < 0) {
7251 year--;
7252 month += 12;
7253 }
7254
7255 ASSERT(month >= 0);
7256 ASSERT(month < 12);
7257
7258 // year_delta is an arbitrary number such that:
7259 // a) year_delta = -1 (mod 400)
7260 // b) year + year_delta > 0 for years in the range defined by
7261 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
7262 // Jan 1 1970. This is required so that we don't run into integer
7263 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007264 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007265 // operations.
7266 static const int year_delta = 399999;
7267 static const int base_day = 365 * (1970 + year_delta) +
7268 (1970 + year_delta) / 4 -
7269 (1970 + year_delta) / 100 +
7270 (1970 + year_delta) / 400;
7271
7272 int year1 = year + year_delta;
7273 int day_from_year = 365 * year1 +
7274 year1 / 4 -
7275 year1 / 100 +
7276 year1 / 400 -
7277 base_day;
7278
7279 if (year % 4 || (year % 100 == 0 && year % 400 != 0)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007280 return day_from_year + day_from_month[month] + day - 1;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007281 }
7282
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007283 return day_from_year + day_from_month_leap[month] + day - 1;
7284}
7285
7286
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007287RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007288 NoHandleAllocation ha;
7289 ASSERT(args.length() == 3);
7290
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007291 CONVERT_SMI_ARG_CHECKED(year, 0);
7292 CONVERT_SMI_ARG_CHECKED(month, 1);
7293 CONVERT_SMI_ARG_CHECKED(date, 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007294
7295 return Smi::FromInt(MakeDay(year, month, date));
7296}
7297
7298
7299static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
7300static const int kDaysIn4Years = 4 * 365 + 1;
7301static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
7302static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
7303static const int kDays1970to2000 = 30 * 365 + 7;
7304static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
7305 kDays1970to2000;
7306static const int kYearsOffset = 400000;
7307
7308static const char kDayInYear[] = {
7309 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7310 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7311 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7312 22, 23, 24, 25, 26, 27, 28,
7313 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7314 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7315 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7316 22, 23, 24, 25, 26, 27, 28, 29, 30,
7317 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7318 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7319 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7320 22, 23, 24, 25, 26, 27, 28, 29, 30,
7321 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7322 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7323 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7324 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7325 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7326 22, 23, 24, 25, 26, 27, 28, 29, 30,
7327 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7328 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7329 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7330 22, 23, 24, 25, 26, 27, 28, 29, 30,
7331 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7332 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7333
7334 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7335 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7336 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7337 22, 23, 24, 25, 26, 27, 28,
7338 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7339 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7340 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7341 22, 23, 24, 25, 26, 27, 28, 29, 30,
7342 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7343 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7344 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7345 22, 23, 24, 25, 26, 27, 28, 29, 30,
7346 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7347 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7348 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7349 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7350 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7351 22, 23, 24, 25, 26, 27, 28, 29, 30,
7352 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7353 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7354 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7355 22, 23, 24, 25, 26, 27, 28, 29, 30,
7356 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7357 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7358
7359 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7360 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7361 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7362 22, 23, 24, 25, 26, 27, 28, 29,
7363 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7364 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7365 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7366 22, 23, 24, 25, 26, 27, 28, 29, 30,
7367 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7368 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7369 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7370 22, 23, 24, 25, 26, 27, 28, 29, 30,
7371 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7372 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7373 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7374 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7375 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7376 22, 23, 24, 25, 26, 27, 28, 29, 30,
7377 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7378 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7379 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7380 22, 23, 24, 25, 26, 27, 28, 29, 30,
7381 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7382 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7383
7384 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7385 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7386 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7387 22, 23, 24, 25, 26, 27, 28,
7388 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7389 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7390 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7391 22, 23, 24, 25, 26, 27, 28, 29, 30,
7392 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7393 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7394 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7395 22, 23, 24, 25, 26, 27, 28, 29, 30,
7396 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7397 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7398 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7399 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7400 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7401 22, 23, 24, 25, 26, 27, 28, 29, 30,
7402 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7403 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7404 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7405 22, 23, 24, 25, 26, 27, 28, 29, 30,
7406 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7407 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
7408
7409static const char kMonthInYear[] = {
7410 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,
7411 0, 0, 0, 0, 0, 0,
7412 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,
7413 1, 1, 1,
7414 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,
7415 2, 2, 2, 2, 2, 2,
7416 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,
7417 3, 3, 3, 3, 3,
7418 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,
7419 4, 4, 4, 4, 4, 4,
7420 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,
7421 5, 5, 5, 5, 5,
7422 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,
7423 6, 6, 6, 6, 6, 6,
7424 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,
7425 7, 7, 7, 7, 7, 7,
7426 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,
7427 8, 8, 8, 8, 8,
7428 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,
7429 9, 9, 9, 9, 9, 9,
7430 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7431 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7432 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7433 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7434
7435 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,
7436 0, 0, 0, 0, 0, 0,
7437 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,
7438 1, 1, 1,
7439 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,
7440 2, 2, 2, 2, 2, 2,
7441 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,
7442 3, 3, 3, 3, 3,
7443 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,
7444 4, 4, 4, 4, 4, 4,
7445 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,
7446 5, 5, 5, 5, 5,
7447 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,
7448 6, 6, 6, 6, 6, 6,
7449 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,
7450 7, 7, 7, 7, 7, 7,
7451 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,
7452 8, 8, 8, 8, 8,
7453 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,
7454 9, 9, 9, 9, 9, 9,
7455 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7456 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7457 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7458 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7459
7460 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,
7461 0, 0, 0, 0, 0, 0,
7462 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,
7463 1, 1, 1, 1,
7464 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,
7465 2, 2, 2, 2, 2, 2,
7466 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,
7467 3, 3, 3, 3, 3,
7468 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,
7469 4, 4, 4, 4, 4, 4,
7470 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,
7471 5, 5, 5, 5, 5,
7472 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,
7473 6, 6, 6, 6, 6, 6,
7474 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,
7475 7, 7, 7, 7, 7, 7,
7476 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,
7477 8, 8, 8, 8, 8,
7478 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,
7479 9, 9, 9, 9, 9, 9,
7480 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7481 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7482 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7483 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7484
7485 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,
7486 0, 0, 0, 0, 0, 0,
7487 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,
7488 1, 1, 1,
7489 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,
7490 2, 2, 2, 2, 2, 2,
7491 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,
7492 3, 3, 3, 3, 3,
7493 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,
7494 4, 4, 4, 4, 4, 4,
7495 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,
7496 5, 5, 5, 5, 5,
7497 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,
7498 6, 6, 6, 6, 6, 6,
7499 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,
7500 7, 7, 7, 7, 7, 7,
7501 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,
7502 8, 8, 8, 8, 8,
7503 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,
7504 9, 9, 9, 9, 9, 9,
7505 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7506 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7507 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7508 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
7509
7510
7511// This function works for dates from 1970 to 2099.
7512static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007513 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007514#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007515 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007516#endif
7517
7518 year = 1970 + (4 * date + 2) / kDaysIn4Years;
7519 date %= kDaysIn4Years;
7520
7521 month = kMonthInYear[date];
7522 day = kDayInYear[date];
7523
7524 ASSERT(MakeDay(year, month, day) == save_date);
7525}
7526
7527
7528static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007529 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007530#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007531 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007532#endif
7533
7534 date += kDaysOffset;
7535 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
7536 date %= kDaysIn400Years;
7537
7538 ASSERT(MakeDay(year, 0, 1) + date == save_date);
7539
7540 date--;
7541 int yd1 = date / kDaysIn100Years;
7542 date %= kDaysIn100Years;
7543 year += 100 * yd1;
7544
7545 date++;
7546 int yd2 = date / kDaysIn4Years;
7547 date %= kDaysIn4Years;
7548 year += 4 * yd2;
7549
7550 date--;
7551 int yd3 = date / 365;
7552 date %= 365;
7553 year += yd3;
7554
7555 bool is_leap = (!yd1 || yd2) && !yd3;
7556
7557 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007558 ASSERT(is_leap || (date >= 0));
7559 ASSERT((date < 365) || (is_leap && (date < 366)));
7560 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
7561 ASSERT(is_leap || ((MakeDay(year, 0, 1) + date) == save_date));
7562 ASSERT(!is_leap || ((MakeDay(year, 0, 1) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007563
7564 if (is_leap) {
7565 day = kDayInYear[2*365 + 1 + date];
7566 month = kMonthInYear[2*365 + 1 + date];
7567 } else {
7568 day = kDayInYear[date];
7569 month = kMonthInYear[date];
7570 }
7571
7572 ASSERT(MakeDay(year, month, day) == save_date);
7573}
7574
7575
7576static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007577 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007578 if (date >= 0 && date < 32 * kDaysIn4Years) {
7579 DateYMDFromTimeAfter1970(date, year, month, day);
7580 } else {
7581 DateYMDFromTimeSlow(date, year, month, day);
7582 }
7583}
7584
7585
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007586RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007587 NoHandleAllocation ha;
7588 ASSERT(args.length() == 2);
7589
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007590 CONVERT_DOUBLE_ARG_CHECKED(t, 0);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007591 CONVERT_CHECKED(JSArray, res_array, args[1]);
7592
7593 int year, month, day;
7594 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7595
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007596 RUNTIME_ASSERT(res_array->elements()->map() ==
7597 isolate->heap()->fixed_array_map());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007598 FixedArray* elms = FixedArray::cast(res_array->elements());
7599 RUNTIME_ASSERT(elms->length() == 3);
7600
7601 elms->set(0, Smi::FromInt(year));
7602 elms->set(1, Smi::FromInt(month));
7603 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007604
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007605 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007606}
7607
7608
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007609RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007610 HandleScope scope(isolate);
7611 ASSERT(args.length() == 3);
7612
7613 Handle<JSFunction> callee = args.at<JSFunction>(0);
7614 Object** parameters = reinterpret_cast<Object**>(args[1]);
7615 const int argument_count = Smi::cast(args[2])->value();
7616
7617 Handle<JSObject> result =
7618 isolate->factory()->NewArgumentsObject(callee, argument_count);
7619 // Allocate the elements if needed.
7620 int parameter_count = callee->shared()->formal_parameter_count();
7621 if (argument_count > 0) {
7622 if (parameter_count > 0) {
7623 int mapped_count = Min(argument_count, parameter_count);
7624 Handle<FixedArray> parameter_map =
7625 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
7626 parameter_map->set_map(
7627 isolate->heap()->non_strict_arguments_elements_map());
7628
7629 Handle<Map> old_map(result->map());
7630 Handle<Map> new_map =
7631 isolate->factory()->CopyMapDropTransitions(old_map);
7632 new_map->set_elements_kind(JSObject::NON_STRICT_ARGUMENTS_ELEMENTS);
7633
7634 result->set_map(*new_map);
7635 result->set_elements(*parameter_map);
7636
7637 // Store the context and the arguments array at the beginning of the
7638 // parameter map.
7639 Handle<Context> context(isolate->context());
7640 Handle<FixedArray> arguments =
7641 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7642 parameter_map->set(0, *context);
7643 parameter_map->set(1, *arguments);
7644
7645 // Loop over the actual parameters backwards.
7646 int index = argument_count - 1;
7647 while (index >= mapped_count) {
7648 // These go directly in the arguments array and have no
7649 // corresponding slot in the parameter map.
7650 arguments->set(index, *(parameters - index - 1));
7651 --index;
7652 }
7653
7654 ScopeInfo<> scope_info(callee->shared()->scope_info());
7655 while (index >= 0) {
7656 // Detect duplicate names to the right in the parameter list.
7657 Handle<String> name = scope_info.parameter_name(index);
7658 int context_slot_count = scope_info.number_of_context_slots();
7659 bool duplicate = false;
7660 for (int j = index + 1; j < parameter_count; ++j) {
7661 if (scope_info.parameter_name(j).is_identical_to(name)) {
7662 duplicate = true;
7663 break;
7664 }
7665 }
7666
7667 if (duplicate) {
7668 // This goes directly in the arguments array with a hole in the
7669 // parameter map.
7670 arguments->set(index, *(parameters - index - 1));
7671 parameter_map->set_the_hole(index + 2);
7672 } else {
7673 // The context index goes in the parameter map with a hole in the
7674 // arguments array.
7675 int context_index = -1;
7676 for (int j = Context::MIN_CONTEXT_SLOTS;
7677 j < context_slot_count;
7678 ++j) {
7679 if (scope_info.context_slot_name(j).is_identical_to(name)) {
7680 context_index = j;
7681 break;
7682 }
7683 }
7684 ASSERT(context_index >= 0);
7685 arguments->set_the_hole(index);
7686 parameter_map->set(index + 2, Smi::FromInt(context_index));
7687 }
7688
7689 --index;
7690 }
7691 } else {
7692 // If there is no aliasing, the arguments object elements are not
7693 // special in any way.
7694 Handle<FixedArray> elements =
7695 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7696 result->set_elements(*elements);
7697 for (int i = 0; i < argument_count; ++i) {
7698 elements->set(i, *(parameters - i - 1));
7699 }
7700 }
7701 }
7702 return *result;
7703}
7704
7705
7706RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007707 NoHandleAllocation ha;
7708 ASSERT(args.length() == 3);
7709
7710 JSFunction* callee = JSFunction::cast(args[0]);
7711 Object** parameters = reinterpret_cast<Object**>(args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007712 const int length = args.smi_at(2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007713
lrn@chromium.org303ada72010-10-27 09:33:13 +00007714 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007715 { MaybeObject* maybe_result =
7716 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007717 if (!maybe_result->ToObject(&result)) return maybe_result;
7718 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007719 // Allocate the elements if needed.
7720 if (length > 0) {
7721 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007722 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007723 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007724 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7725 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007726
7727 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00007728 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007729 array->set_map(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007730 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00007731
7732 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007733 for (int i = 0; i < length; i++) {
7734 array->set(i, *--parameters, mode);
7735 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00007736 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007737 }
7738 return result;
7739}
7740
7741
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007742RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007743 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007744 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00007745 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00007746 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007747 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007748
whesse@chromium.org7b260152011-06-20 15:33:18 +00007749 // The caller ensures that we pretenure closures that are assigned
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007750 // directly to properties.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00007751 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007752 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007753 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
7754 context,
7755 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007756 return *result;
7757}
7758
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007759
7760static SmartPointer<Object**> GetNonBoundArguments(int bound_argc,
7761 int* total_argc) {
7762 // Find frame containing arguments passed to the caller.
7763 JavaScriptFrameIterator it;
7764 JavaScriptFrame* frame = it.frame();
7765 List<JSFunction*> functions(2);
7766 frame->GetFunctions(&functions);
7767 if (functions.length() > 1) {
7768 int inlined_frame_index = functions.length() - 1;
7769 JSFunction* inlined_function = functions[inlined_frame_index];
7770 int args_count = inlined_function->shared()->formal_parameter_count();
7771 ScopedVector<SlotRef> args_slots(args_count);
7772 SlotRef::ComputeSlotMappingForArguments(frame,
7773 inlined_frame_index,
7774 &args_slots);
7775
7776 *total_argc = bound_argc + args_count;
7777 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7778 for (int i = 0; i < args_count; i++) {
7779 Handle<Object> val = args_slots[i].GetValue();
7780 param_data[bound_argc + i] = val.location();
7781 }
7782 return param_data;
7783 } else {
7784 it.AdvanceToArgumentsFrame();
7785 frame = it.frame();
7786 int args_count = frame->ComputeParametersCount();
7787
7788 *total_argc = bound_argc + args_count;
7789 SmartPointer<Object**> param_data(NewArray<Object**>(*total_argc));
7790 for (int i = 0; i < args_count; i++) {
7791 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
7792 param_data[bound_argc + i] = val.location();
7793 }
7794 return param_data;
7795 }
7796}
7797
7798
7799RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007800 HandleScope scope(isolate);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007801 ASSERT(args.length() == 2);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007802 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007803 CONVERT_ARG_CHECKED(JSFunction, function, 0);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007804
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007805 // Second argument is either null or an array of bound arguments.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007806 Handle<FixedArray> bound_args;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007807 int bound_argc = 0;
7808 if (!args[1]->IsNull()) {
7809 CONVERT_ARG_CHECKED(JSArray, params, 1);
7810 RUNTIME_ASSERT(params->HasFastElements());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007811 bound_args = Handle<FixedArray>(FixedArray::cast(params->elements()));
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007812 bound_argc = Smi::cast(params->length())->value();
7813 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007814
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007815 int total_argc = 0;
7816 SmartPointer<Object**> param_data =
7817 GetNonBoundArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007818 for (int i = 0; i < bound_argc; i++) {
7819 Handle<Object> val = Handle<Object>(bound_args->get(i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007820 param_data[i] = val.location();
7821 }
7822
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007823 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007824 Handle<Object> result =
7825 Execution::New(function, total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007826 if (exception) {
7827 return Failure::Exception();
7828 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00007829
whesse@chromium.orge90029b2010-08-02 11:52:17 +00007830 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00007831 return *result;
7832}
7833
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007834
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007835static void TrySettingInlineConstructStub(Isolate* isolate,
7836 Handle<JSFunction> function) {
7837 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00007838 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007839 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00007840 }
7841 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007842 ConstructStubCompiler compiler;
ager@chromium.orgbeb25712010-11-29 08:02:25 +00007843 MaybeObject* code = compiler.CompileConstructStub(*function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007844 if (!code->IsFailure()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00007845 function->shared()->set_construct_stub(
7846 Code::cast(code->ToObjectUnchecked()));
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007847 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007848 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007849}
7850
7851
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007852RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007853 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007854 ASSERT(args.length() == 1);
7855
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007856 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007857
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007858 // If the constructor isn't a proper function we throw a type error.
7859 if (!constructor->IsJSFunction()) {
7860 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7861 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007862 isolate->factory()->NewTypeError("not_constructor", arguments);
7863 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007864 }
7865
7866 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007867
7868 // If function should not have prototype, construction is not allowed. In this
7869 // case generated code bailouts here, since function has no initial_map.
whesse@chromium.org7b260152011-06-20 15:33:18 +00007870 if (!function->should_have_prototype() && !function->shared()->bound()) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007871 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
7872 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007873 isolate->factory()->NewTypeError("not_constructor", arguments);
7874 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007875 }
7876
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007877#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007878 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007879 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007880 if (debug->StepInActive()) {
7881 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007882 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00007883#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007884
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007885 if (function->has_initial_map()) {
7886 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007887 // The 'Function' function ignores the receiver object when
7888 // called using 'new' and creates a new JSFunction object that
7889 // is returned. The receiver object is only used for error
7890 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007891 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007892 // allocate JSFunctions since it does not properly initialize
7893 // the shared part of the function. Since the receiver is
7894 // ignored anyway, we use the global object as the receiver
7895 // instead of a new JSFunction object. This way, errors are
7896 // reported the same way whether or not 'Function' is called
7897 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007898 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007899 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007900 }
7901
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007902 // The function should be compiled for the optimization hints to be
7903 // available. We cannot use EnsureCompiled because that forces a
7904 // compilation through the shared function info which makes it
7905 // impossible for us to optimize.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007906 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007907 if (!function->is_compiled()) CompileLazy(function, CLEAR_EXCEPTION);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007908
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007909 if (!function->has_initial_map() &&
7910 shared->IsInobjectSlackTrackingInProgress()) {
7911 // The tracking is already in progress for another function. We can only
7912 // track one initial_map at a time, so we force the completion before the
7913 // function is called as a constructor for the first time.
7914 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007915 }
7916
7917 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007918 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
7919 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007920 // Delay setting the stub if inobject slack tracking is in progress.
7921 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007922 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007923 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007924
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007925 isolate->counters()->constructed_objects()->Increment();
7926 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00007927
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007928 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007929}
7930
7931
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007932RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007933 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007934 ASSERT(args.length() == 1);
7935
7936 CONVERT_ARG_CHECKED(JSFunction, function, 0);
7937 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007938 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007939
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007940 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00007941}
7942
7943
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007944RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007945 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007946 ASSERT(args.length() == 1);
7947
7948 Handle<JSFunction> function = args.at<JSFunction>(0);
7949#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00007950 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007951 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007952 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007953 PrintF("]\n");
7954 }
7955#endif
7956
kasperl@chromium.org71affb52009-05-26 05:44:31 +00007957 // Compile the target function. Here we compile using CompileLazyInLoop in
7958 // order to get the optimized version. This helps code like delta-blue
7959 // that calls performance-critical routines through constructors. A
7960 // constructor call doesn't use a CallIC, it uses a LoadIC followed by a
7961 // direct call. Since the in-loop tracking takes place through CallICs
7962 // this means that things called through constructors are never known to
7963 // be in loops. We compile them as if they are in loops here just in case.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007964 ASSERT(!function->is_compiled());
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00007965 if (!CompileLazyInLoop(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007966 return Failure::Exception();
7967 }
7968
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007969 // All done. Return the compiled code.
7970 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007971 return function->code();
7972}
7973
7974
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007975RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007976 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007977 ASSERT(args.length() == 1);
7978 Handle<JSFunction> function = args.at<JSFunction>(0);
7979 // If the function is not optimizable or debugger is active continue using the
7980 // code from the full compiler.
7981 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007982 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007983 if (FLAG_trace_opt) {
7984 PrintF("[failed to optimize ");
7985 function->PrintName();
7986 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
7987 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00007988 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007989 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007990 function->ReplaceCode(function->shared()->code());
7991 return function->code();
7992 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00007993 if (CompileOptimized(function, AstNode::kNoNumber, CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00007994 return function->code();
7995 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00007996 if (FLAG_trace_opt) {
7997 PrintF("[failed to optimize ");
7998 function->PrintName();
7999 PrintF(": optimized compilation failed]\n");
8000 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008001 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008002 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008003}
8004
8005
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008006RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008007 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008008 ASSERT(args.length() == 1);
8009 RUNTIME_ASSERT(args[0]->IsSmi());
8010 Deoptimizer::BailoutType type =
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008011 static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008012 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
8013 ASSERT(isolate->heap()->IsAllocationAllowed());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008014 int frames = deoptimizer->output_count();
8015
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008016 deoptimizer->MaterializeHeapNumbers();
8017 delete deoptimizer;
8018
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008019 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008020 JavaScriptFrame* frame = NULL;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008021 for (int i = 0; i < frames - 1; i++) it.Advance();
8022 frame = it.frame();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008023
8024 RUNTIME_ASSERT(frame->function()->IsJSFunction());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008025 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008026 Handle<Object> arguments;
8027 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008028 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008029 if (arguments.is_null()) {
8030 // FunctionGetArguments can't throw an exception, so cast away the
8031 // doubt with an assert.
8032 arguments = Handle<Object>(
8033 Accessors::FunctionGetArguments(*function,
8034 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008035 ASSERT(*arguments != isolate->heap()->null_value());
8036 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008037 }
8038 frame->SetExpression(i, *arguments);
8039 }
8040 }
8041
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008042 if (type == Deoptimizer::EAGER) {
8043 RUNTIME_ASSERT(function->IsOptimized());
8044 } else {
8045 RUNTIME_ASSERT(!function->IsOptimized());
8046 }
8047
8048 // Avoid doing too much work when running with --always-opt and keep
8049 // the optimized code around.
8050 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008051 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008052 }
8053
8054 // Count the number of optimized activations of the function.
8055 int activations = 0;
8056 while (!it.done()) {
8057 JavaScriptFrame* frame = it.frame();
8058 if (frame->is_optimized() && frame->function() == *function) {
8059 activations++;
8060 }
8061 it.Advance();
8062 }
8063
8064 // TODO(kasperl): For now, we cannot support removing the optimized
8065 // code when we have recursive invocations of the same function.
8066 if (activations == 0) {
8067 if (FLAG_trace_deopt) {
8068 PrintF("[removing optimized code for: ");
8069 function->PrintName();
8070 PrintF("]\n");
8071 }
8072 function->ReplaceCode(function->shared()->code());
8073 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008074 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008075}
8076
8077
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008078RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008079 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008080 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008081 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008082}
8083
8084
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008085RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008086 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008087 ASSERT(args.length() == 1);
8088 CONVERT_ARG_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008089 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008090
8091 Deoptimizer::DeoptimizeFunction(*function);
8092
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008093 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008094}
8095
8096
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008097RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
8098#if defined(USE_SIMULATOR)
8099 return isolate->heap()->true_value();
8100#else
8101 return isolate->heap()->false_value();
8102#endif
8103}
8104
8105
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008106RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
8107 HandleScope scope(isolate);
8108 ASSERT(args.length() == 1);
8109 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8110 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
8111 function->MarkForLazyRecompilation();
8112 return isolate->heap()->undefined_value();
8113}
8114
8115
lrn@chromium.org1c092762011-05-09 09:42:16 +00008116RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
8117 HandleScope scope(isolate);
8118 ASSERT(args.length() == 1);
8119 if (!V8::UseCrankshaft()) {
8120 return Smi::FromInt(4); // 4 == "never".
8121 }
8122 if (FLAG_always_opt) {
8123 return Smi::FromInt(3); // 3 == "always".
8124 }
8125 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8126 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
8127 : Smi::FromInt(2); // 2 == "no".
8128}
8129
8130
8131RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
8132 HandleScope scope(isolate);
8133 ASSERT(args.length() == 1);
8134 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8135 return Smi::FromInt(function->shared()->opt_count());
8136}
8137
8138
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008139RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008140 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008141 ASSERT(args.length() == 1);
8142 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8143
8144 // We're not prepared to handle a function with arguments object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008145 ASSERT(!function->shared()->uses_arguments());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008146
8147 // We have hit a back edge in an unoptimized frame for a function that was
8148 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008149 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008150 // Keep track of whether we've succeeded in optimizing.
8151 bool succeeded = unoptimized->optimizable();
8152 if (succeeded) {
8153 // If we are trying to do OSR when there are already optimized
8154 // activations of the function, it means (a) the function is directly or
8155 // indirectly recursive and (b) an optimized invocation has been
8156 // deoptimized so that we are currently in an unoptimized activation.
8157 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008158 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008159 while (succeeded && !it.done()) {
8160 JavaScriptFrame* frame = it.frame();
8161 succeeded = !frame->is_optimized() || frame->function() != *function;
8162 it.Advance();
8163 }
8164 }
8165
8166 int ast_id = AstNode::kNoNumber;
8167 if (succeeded) {
8168 // The top JS function is this one, the PC is somewhere in the
8169 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008170 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008171 JavaScriptFrame* frame = it.frame();
8172 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008173 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008174 ASSERT(unoptimized->contains(frame->pc()));
8175
8176 // Use linear search of the unoptimized code's stack check table to find
8177 // the AST id matching the PC.
8178 Address start = unoptimized->instruction_start();
8179 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008180 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008181 uint32_t table_length = Memory::uint32_at(table_cursor);
8182 table_cursor += kIntSize;
8183 for (unsigned i = 0; i < table_length; ++i) {
8184 // Table entries are (AST id, pc offset) pairs.
8185 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
8186 if (pc_offset == target_pc_offset) {
8187 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
8188 break;
8189 }
8190 table_cursor += 2 * kIntSize;
8191 }
8192 ASSERT(ast_id != AstNode::kNoNumber);
8193 if (FLAG_trace_osr) {
8194 PrintF("[replacing on-stack at AST id %d in ", ast_id);
8195 function->PrintName();
8196 PrintF("]\n");
8197 }
8198
8199 // Try to compile the optimized code. A true return value from
8200 // CompileOptimized means that compilation succeeded, not necessarily
8201 // that optimization succeeded.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008202 if (CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
8203 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008204 DeoptimizationInputData* data = DeoptimizationInputData::cast(
8205 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008206 if (data->OsrPcOffset()->value() >= 0) {
8207 if (FLAG_trace_osr) {
8208 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008209 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008210 }
8211 ASSERT(data->OsrAstId()->value() == ast_id);
8212 } else {
8213 // We may never generate the desired OSR entry if we emit an
8214 // early deoptimize.
8215 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008216 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008217 } else {
8218 succeeded = false;
8219 }
8220 }
8221
8222 // Revert to the original stack checks in the original unoptimized code.
8223 if (FLAG_trace_osr) {
8224 PrintF("[restoring original stack checks in ");
8225 function->PrintName();
8226 PrintF("]\n");
8227 }
8228 StackCheckStub check_stub;
8229 Handle<Code> check_code = check_stub.GetCode();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00008230 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008231 Deoptimizer::RevertStackCheckCode(*unoptimized,
8232 *check_code,
8233 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008234
8235 // Allow OSR only at nesting level zero again.
8236 unoptimized->set_allow_osr_at_loop_nesting_level(0);
8237
8238 // If the optimization attempt succeeded, return the AST id tagged as a
8239 // smi. This tells the builtin that we need to translate the unoptimized
8240 // frame to an optimized one.
8241 if (succeeded) {
8242 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
8243 return Smi::FromInt(ast_id);
8244 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008245 if (function->IsMarkedForLazyRecompilation()) {
8246 function->ReplaceCode(function->shared()->code());
8247 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008248 return Smi::FromInt(-1);
8249 }
8250}
8251
8252
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008253RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008254 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008255 ASSERT(args.length() == 1);
8256 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8257 return *Execution::GetFunctionDelegate(args.at<Object>(0));
8258}
8259
8260
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008261RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008262 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008263 ASSERT(args.length() == 1);
8264 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8265 return *Execution::GetConstructorDelegate(args.at<Object>(0));
8266}
8267
8268
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008269RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008270 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00008271 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008272
kasper.lund7276f142008-07-30 08:49:36 +00008273 CONVERT_CHECKED(JSFunction, function, args[0]);
ager@chromium.orgb5737492010-07-15 09:29:43 +00008274 int length = function->shared()->scope_info()->NumberOfContextSlots();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008275 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008276 { MaybeObject* maybe_result =
8277 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008278 if (!maybe_result->ToObject(&result)) return maybe_result;
8279 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008280
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008281 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008282
kasper.lund7276f142008-07-30 08:49:36 +00008283 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008284}
8285
lrn@chromium.org303ada72010-10-27 09:33:13 +00008286
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008287RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
8288 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008289 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008290 JSObject* extension_object;
8291 if (args[0]->IsJSObject()) {
8292 extension_object = JSObject::cast(args[0]);
8293 } else {
8294 // Convert the object to a proper JavaScript object.
8295 MaybeObject* maybe_js_object = args[0]->ToObject();
8296 if (!maybe_js_object->To(&extension_object)) {
8297 if (Failure::cast(maybe_js_object)->IsInternalError()) {
8298 HandleScope scope(isolate);
8299 Handle<Object> handle = args.at<Object>(0);
8300 Handle<Object> result =
8301 isolate->factory()->NewTypeError("with_expression",
8302 HandleVector(&handle, 1));
8303 return isolate->Throw(*result);
8304 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008305 return maybe_js_object;
8306 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008307 }
8308 }
8309
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008310 JSFunction* function;
8311 if (args[1]->IsSmi()) {
8312 // A smi sentinel indicates a context nested inside global code rather
8313 // than some function. There is a canonical empty function that can be
8314 // gotten from the global context.
8315 function = isolate->context()->global_context()->closure();
8316 } else {
8317 function = JSFunction::cast(args[1]);
8318 }
8319
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008320 Context* context;
8321 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008322 isolate->heap()->AllocateWithContext(function,
8323 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008324 extension_object);
8325 if (!maybe_context->To(&context)) return maybe_context;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008326 isolate->set_context(context);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008327 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008328}
8329
8330
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008331RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008332 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008333 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008334 String* name = String::cast(args[0]);
8335 Object* thrown_object = args[1];
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008336 JSFunction* function;
8337 if (args[2]->IsSmi()) {
8338 // A smi sentinel indicates a context nested inside global code rather
8339 // than some function. There is a canonical empty function that can be
8340 // gotten from the global context.
8341 function = isolate->context()->global_context()->closure();
8342 } else {
8343 function = JSFunction::cast(args[2]);
8344 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008345 Context* context;
8346 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008347 isolate->heap()->AllocateCatchContext(function,
8348 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008349 name,
8350 thrown_object);
8351 if (!maybe_context->To(&context)) return maybe_context;
8352 isolate->set_context(context);
8353 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008354}
8355
8356
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008357RUNTIME_FUNCTION(MaybeObject*, Runtime_PushBlockContext) {
8358 NoHandleAllocation ha;
8359 ASSERT(args.length() == 2);
8360 SerializedScopeInfo* scope_info = SerializedScopeInfo::cast(args[0]);
8361 JSFunction* function;
8362 if (args[1]->IsSmi()) {
8363 // A smi sentinel indicates a context nested inside global code rather
8364 // than some function. There is a canonical empty function that can be
8365 // gotten from the global context.
8366 function = isolate->context()->global_context()->closure();
8367 } else {
8368 function = JSFunction::cast(args[1]);
8369 }
8370 Context* context;
8371 MaybeObject* maybe_context =
8372 isolate->heap()->AllocateBlockContext(function,
8373 isolate->context(),
8374 scope_info);
8375 if (!maybe_context->To(&context)) return maybe_context;
8376 isolate->set_context(context);
8377 return context;
8378}
8379
8380
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008381RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008382 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008383 ASSERT(args.length() == 2);
8384
8385 CONVERT_ARG_CHECKED(Context, context, 0);
8386 CONVERT_ARG_CHECKED(String, name, 1);
8387
8388 int index;
8389 PropertyAttributes attributes;
8390 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008391 BindingFlags binding_flags;
8392 Handle<Object> holder = context->Lookup(name,
8393 flags,
8394 &index,
8395 &attributes,
8396 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008397
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008398 // If the slot was not found the result is true.
8399 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008400 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008401 }
8402
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008403 // If the slot was found in a context, it should be DONT_DELETE.
8404 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008405 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008406 }
8407
8408 // The slot was found in a JSObject, either a context extension object,
8409 // the global object, or an arguments object. Try to delete it
8410 // (respecting DONT_DELETE). For consistency with V8's usual behavior,
8411 // which allows deleting all parameters in functions that mention
8412 // 'arguments', we do this even for the case of slots found on an
8413 // arguments object. The slot was found on an arguments object if the
8414 // index is non-negative.
8415 Handle<JSObject> object = Handle<JSObject>::cast(holder);
8416 if (index >= 0) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00008417 return object->DeleteElement(index, JSReceiver::NORMAL_DELETION);
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008418 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00008419 return object->DeleteProperty(*name, JSReceiver::NORMAL_DELETION);
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008420 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008421}
8422
8423
ager@chromium.orga1645e22009-09-09 19:27:10 +00008424// A mechanism to return a pair of Object pointers in registers (if possible).
8425// How this is achieved is calling convention-dependent.
8426// All currently supported x86 compiles uses calling conventions that are cdecl
8427// variants where a 64-bit value is returned in two 32-bit registers
8428// (edx:eax on ia32, r1:r0 on ARM).
8429// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
8430// In Win64 calling convention, a struct of two pointers is returned in memory,
8431// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008432#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008433struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008434 MaybeObject* x;
8435 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008436};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008437
lrn@chromium.org303ada72010-10-27 09:33:13 +00008438static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008439 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008440 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
8441 // In Win64 they are assigned to a hidden first argument.
8442 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008443}
8444#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008445typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008446static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008447 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008448 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008449}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008450#endif
8451
8452
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008453static inline MaybeObject* Unhole(Heap* heap,
8454 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00008455 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008456 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
8457 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008458 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008459}
8460
8461
danno@chromium.org40cb8782011-05-25 07:58:50 +00008462static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
8463 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008464 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008465 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008466 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008467 JSFunction* context_extension_function =
8468 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008469 // If the holder isn't a context extension object, we just return it
8470 // as the receiver. This allows arguments objects to be used as
8471 // receivers, but only if they are put in the context scope chain
8472 // explicitly via a with-statement.
8473 Object* constructor = holder->map()->constructor();
8474 if (constructor != context_extension_function) return holder;
danno@chromium.org40cb8782011-05-25 07:58:50 +00008475 // Fall back to using the global object as the implicit receiver if
8476 // the property turns out to be a local variable allocated in a
8477 // context extension object - introduced via eval. Implicit global
8478 // receivers are indicated with the hole value.
8479 return isolate->heap()->the_hole_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008480}
8481
8482
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008483static ObjectPair LoadContextSlotHelper(Arguments args,
8484 Isolate* isolate,
8485 bool throw_error) {
8486 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00008487 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008488
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008489 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008490 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008491 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008492 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008493 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008494
8495 int index;
8496 PropertyAttributes attributes;
8497 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008498 BindingFlags binding_flags;
8499 Handle<Object> holder = context->Lookup(name,
8500 flags,
8501 &index,
8502 &attributes,
8503 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008504
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008505 // If the index is non-negative, the slot has been found in a local
8506 // variable or a parameter. Read it from the context object or the
8507 // arguments object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008508 if (index >= 0) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008509 // If the "property" we were looking for is a local variable or an
8510 // argument in a context, the receiver is the global object; see
8511 // ECMA-262, 3rd., 10.1.6 and 10.2.3.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008512 //
8513 // Use the hole as the receiver to signal that the receiver is
8514 // implicit and that the global receiver should be used.
8515 Handle<Object> receiver = isolate->factory()->the_hole_value();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008516 MaybeObject* value = (holder->IsContext())
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008517 ? Context::cast(*holder)->get(index)
8518 : JSObject::cast(*holder)->GetElement(index);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008519 // Check for uninitialized bindings.
8520 if (holder->IsContext() &&
8521 binding_flags == MUTABLE_CHECK_INITIALIZED &&
8522 value->IsTheHole()) {
8523 Handle<Object> reference_error =
8524 isolate->factory()->NewReferenceError("not_defined",
8525 HandleVector(&name, 1));
8526 return MakePair(isolate->Throw(*reference_error), NULL);
8527 } else {
8528 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
8529 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008530 }
8531
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008532 // If the holder is found, we read the property from it.
8533 if (!holder.is_null() && holder->IsJSObject()) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00008534 ASSERT(Handle<JSObject>::cast(holder)->HasProperty(*name));
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008535 JSObject* object = JSObject::cast(*holder);
danno@chromium.org40cb8782011-05-25 07:58:50 +00008536 Object* receiver;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008537 if (object->IsGlobalObject()) {
8538 receiver = GlobalObject::cast(object)->global_receiver();
8539 } else if (context->is_exception_holder(*holder)) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008540 // Use the hole as the receiver to signal that the receiver is
8541 // implicit and that the global receiver should be used.
8542 receiver = isolate->heap()->the_hole_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008543 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008544 receiver = ComputeReceiverForNonGlobal(isolate, object);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008545 }
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008546
8547 // GetProperty below can cause GC.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008548 Handle<Object> receiver_handle(receiver);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008549
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008550 // No need to unhole the value here. This is taken care of by the
8551 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008552 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00008553 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008554 }
8555
8556 if (throw_error) {
8557 // The property doesn't exist - throw exception.
8558 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008559 isolate->factory()->NewReferenceError("not_defined",
8560 HandleVector(&name, 1));
8561 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008562 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00008563 // The property doesn't exist - return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008564 return MakePair(isolate->heap()->undefined_value(),
8565 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008566 }
8567}
8568
8569
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008570RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008571 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008572}
8573
8574
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008575RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008576 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008577}
8578
8579
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008580RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008581 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008582 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008583
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008584 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008585 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008586 CONVERT_ARG_CHECKED(String, name, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008587 CONVERT_SMI_ARG_CHECKED(strict_unchecked, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008588 RUNTIME_ASSERT(strict_unchecked == kStrictMode ||
8589 strict_unchecked == kNonStrictMode);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008590 StrictModeFlag strict_mode = static_cast<StrictModeFlag>(strict_unchecked);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008591
8592 int index;
8593 PropertyAttributes attributes;
8594 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008595 BindingFlags binding_flags;
8596 Handle<Object> holder = context->Lookup(name,
8597 flags,
8598 &index,
8599 &attributes,
8600 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008601
8602 if (index >= 0) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008603 if (holder->IsContext()) {
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008604 Handle<Context> context = Handle<Context>::cast(holder);
8605 if (binding_flags == MUTABLE_CHECK_INITIALIZED &&
8606 context->get(index)->IsTheHole()) {
8607 Handle<Object> error =
8608 isolate->factory()->NewReferenceError("not_defined",
8609 HandleVector(&name, 1));
8610 return isolate->Throw(*error);
8611 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008612 // Ignore if read_only variable.
8613 if ((attributes & READ_ONLY) == 0) {
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008614 // Context is a fixed array and set cannot fail.
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008615 context->set(index, *value);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008616 } else if (strict_mode == kStrictMode) {
8617 // Setting read only property in strict mode.
8618 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008619 isolate->factory()->NewTypeError("strict_cannot_assign",
8620 HandleVector(&name, 1));
8621 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008622 }
8623 } else {
8624 ASSERT((attributes & READ_ONLY) == 0);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008625 Handle<Object> result =
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008626 SetElement(Handle<JSObject>::cast(holder), index, value, strict_mode);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008627 if (result.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008628 ASSERT(isolate->has_pending_exception());
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008629 return Failure::Exception();
8630 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008631 }
8632 return *value;
8633 }
8634
8635 // Slow case: The property is not in a FixedArray context.
8636 // It is either in an JSObject extension context or it was not found.
8637 Handle<JSObject> context_ext;
8638
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008639 if (!holder.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008640 // The property exists in the extension context.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008641 context_ext = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008642 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008643 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008644 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008645
8646 if (strict_mode == kStrictMode) {
8647 // Throw in strict mode (assignment to undefined variable).
8648 Handle<Object> error =
8649 isolate->factory()->NewReferenceError(
8650 "not_defined", HandleVector(&name, 1));
8651 return isolate->Throw(*error);
8652 }
8653 // In non-strict mode, the property is stored in the global context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008654 attributes = NONE;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008655 context_ext = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008656 }
8657
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008658 // Set the property, but ignore if read_only variable on the context
8659 // extension object itself.
8660 if ((attributes & READ_ONLY) == 0 ||
8661 (context_ext->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008662 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008663 isolate,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00008664 SetProperty(context_ext, name, value, NONE, strict_mode));
8665 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00008666 // Setting read only property in strict mode.
8667 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008668 isolate->factory()->NewTypeError(
8669 "strict_cannot_assign", HandleVector(&name, 1));
8670 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008671 }
8672 return *value;
8673}
8674
8675
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008676RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008677 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008678 ASSERT(args.length() == 1);
8679
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008680 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008681}
8682
8683
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008684RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008685 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008686 ASSERT(args.length() == 1);
8687
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008688 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008689}
8690
8691
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008692RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008693 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008694 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008695}
8696
8697
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008698RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008699 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008700 ASSERT(args.length() == 1);
8701
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008702 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008703 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008704 isolate->factory()->NewReferenceError("not_defined",
8705 HandleVector(&name, 1));
8706 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008707}
8708
8709
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008710RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00008711 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008712
8713 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008714 if (isolate->stack_guard()->IsStackOverflow()) {
8715 NoHandleAllocation na;
8716 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00008717 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008718
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008719 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008720}
8721
8722
8723// NOTE: These PrintXXX functions are defined for all builds (not just
8724// DEBUG builds) because we may want to be able to trace function
8725// calls in all modes.
8726static void PrintString(String* str) {
8727 // not uncommon to have empty strings
8728 if (str->length() > 0) {
8729 SmartPointer<char> s =
8730 str->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
8731 PrintF("%s", *s);
8732 }
8733}
8734
8735
8736static void PrintObject(Object* obj) {
8737 if (obj->IsSmi()) {
8738 PrintF("%d", Smi::cast(obj)->value());
8739 } else if (obj->IsString() || obj->IsSymbol()) {
8740 PrintString(String::cast(obj));
8741 } else if (obj->IsNumber()) {
8742 PrintF("%g", obj->Number());
8743 } else if (obj->IsFailure()) {
8744 PrintF("<failure>");
8745 } else if (obj->IsUndefined()) {
8746 PrintF("<undefined>");
8747 } else if (obj->IsNull()) {
8748 PrintF("<null>");
8749 } else if (obj->IsTrue()) {
8750 PrintF("<true>");
8751 } else if (obj->IsFalse()) {
8752 PrintF("<false>");
8753 } else {
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00008754 PrintF("%p", reinterpret_cast<void*>(obj));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008755 }
8756}
8757
8758
8759static int StackSize() {
8760 int n = 0;
8761 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
8762 return n;
8763}
8764
8765
8766static void PrintTransition(Object* result) {
8767 // indentation
8768 { const int nmax = 80;
8769 int n = StackSize();
8770 if (n <= nmax)
8771 PrintF("%4d:%*s", n, n, "");
8772 else
8773 PrintF("%4d:%*s", n, nmax, "...");
8774 }
8775
8776 if (result == NULL) {
8777 // constructor calls
8778 JavaScriptFrameIterator it;
8779 JavaScriptFrame* frame = it.frame();
8780 if (frame->IsConstructor()) PrintF("new ");
8781 // function name
8782 Object* fun = frame->function();
8783 if (fun->IsJSFunction()) {
8784 PrintObject(JSFunction::cast(fun)->shared()->name());
8785 } else {
8786 PrintObject(fun);
8787 }
8788 // function arguments
8789 // (we are intentionally only printing the actually
8790 // supplied parameters, not all parameters required)
8791 PrintF("(this=");
8792 PrintObject(frame->receiver());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00008793 const int length = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008794 for (int i = 0; i < length; i++) {
8795 PrintF(", ");
8796 PrintObject(frame->GetParameter(i));
8797 }
8798 PrintF(") {\n");
8799
8800 } else {
8801 // function result
8802 PrintF("} -> ");
8803 PrintObject(result);
8804 PrintF("\n");
8805 }
8806}
8807
8808
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008809RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008810 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008811 NoHandleAllocation ha;
8812 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008813 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008814}
8815
8816
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008817RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008818 NoHandleAllocation ha;
8819 PrintTransition(args[0]);
8820 return args[0]; // return TOS
8821}
8822
8823
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008824RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008825 NoHandleAllocation ha;
8826 ASSERT(args.length() == 1);
8827
8828#ifdef DEBUG
8829 if (args[0]->IsString()) {
8830 // If we have a string, assume it's a code "marker"
8831 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008832 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008833 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00008834 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
8835 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008836 } else {
8837 PrintF("DebugPrint: ");
8838 }
8839 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008840 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00008841 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00008842 HeapObject::cast(args[0])->map()->Print();
8843 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008844#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008845 // ShortPrint is available in release mode. Print is not.
8846 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008847#endif
8848 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00008849 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008850
8851 return args[0]; // return TOS
8852}
8853
8854
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008855RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008856 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008857 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008858 isolate->PrintStack();
8859 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008860}
8861
8862
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008863RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008864 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008865 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008866
8867 // According to ECMA-262, section 15.9.1, page 117, the precision of
8868 // the number in a Date object representing a particular instant in
8869 // time is milliseconds. Therefore, we floor the result of getting
8870 // the OS time.
8871 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008872 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008873}
8874
8875
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008876RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008877 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008878 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008879
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008880 CONVERT_ARG_CHECKED(String, str, 0);
8881 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008882
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008883 CONVERT_ARG_CHECKED(JSArray, output, 1);
8884 RUNTIME_ASSERT(output->HasFastElements());
8885
8886 AssertNoAllocation no_allocation;
8887
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00008888 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008889 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
8890 bool result;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00008891 String::FlatContent str_content = str->GetFlatContent();
8892 if (str_content.IsAscii()) {
8893 result = DateParser::Parse(str_content.ToAsciiVector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008894 output_array,
8895 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008896 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00008897 ASSERT(str_content.IsTwoByte());
8898 result = DateParser::Parse(str_content.ToUC16Vector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008899 output_array,
8900 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00008901 }
8902
8903 if (result) {
8904 return *output;
8905 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008906 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008907 }
8908}
8909
8910
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008911RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008912 NoHandleAllocation ha;
8913 ASSERT(args.length() == 1);
8914
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008915 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00008916 const char* zone = OS::LocalTimezone(x);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008917 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008918}
8919
8920
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008921RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008922 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00008923 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008924
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008925 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008926}
8927
8928
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008929RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008930 NoHandleAllocation ha;
8931 ASSERT(args.length() == 1);
8932
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008933 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008934 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008935}
8936
8937
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008938RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008939 ASSERT(args.length() == 1);
8940 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008941 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008942 return JSGlobalObject::cast(global)->global_receiver();
8943}
8944
8945
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008946RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008947 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008948 ASSERT_EQ(1, args.length());
8949 CONVERT_ARG_CHECKED(String, source, 0);
8950
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00008951 source = Handle<String>(source->TryFlattenGetString());
8952 // Optimized fast case where we only have ascii characters.
8953 Handle<Object> result;
8954 if (source->IsSeqAsciiString()) {
8955 result = JsonParser<true>::Parse(source);
8956 } else {
8957 result = JsonParser<false>::Parse(source);
8958 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008959 if (result.is_null()) {
8960 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008961 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008962 return Failure::Exception();
8963 }
8964 return *result;
8965}
8966
8967
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008968bool CodeGenerationFromStringsAllowed(Isolate* isolate,
8969 Handle<Context> context) {
8970 if (context->allow_code_gen_from_strings()->IsFalse()) {
8971 // Check with callback if set.
8972 AllowCodeGenerationFromStringsCallback callback =
8973 isolate->allow_code_gen_callback();
8974 if (callback == NULL) {
8975 // No callback set and code generation disallowed.
8976 return false;
8977 } else {
8978 // Callback set. Let it decide if code generation is allowed.
8979 VMState state(isolate, EXTERNAL);
8980 return callback(v8::Utils::ToLocal(context));
8981 }
8982 }
8983 return true;
8984}
8985
8986
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008987RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008988 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00008989 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00008990 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00008991
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008992 // Extract global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008993 Handle<Context> context(isolate->context()->global_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00008994
8995 // Check if global context allows code generation from
8996 // strings. Throw an exception if it doesn't.
8997 if (!CodeGenerationFromStringsAllowed(isolate, context)) {
8998 return isolate->Throw(*isolate->factory()->NewError(
8999 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9000 }
9001
9002 // Compile source string in the global context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009003 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(source,
9004 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009005 true,
9006 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009007 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009008 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009009 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
9010 context,
9011 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009012 return *fun;
9013}
9014
9015
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009016static ObjectPair CompileGlobalEval(Isolate* isolate,
9017 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009018 Handle<Object> receiver,
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00009019 StrictModeFlag strict_mode) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009020 Handle<Context> context = Handle<Context>(isolate->context());
9021 Handle<Context> global_context = Handle<Context>(context->global_context());
9022
9023 // Check if global context allows code generation from
9024 // strings. Throw an exception if it doesn't.
9025 if (!CodeGenerationFromStringsAllowed(isolate, global_context)) {
9026 isolate->Throw(*isolate->factory()->NewError(
9027 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9028 return MakePair(Failure::Exception(), NULL);
9029 }
9030
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009031 // Deal with a normal eval call with a string argument. Compile it
9032 // and return the compiled function bound in the local context.
9033 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
9034 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009035 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009036 context->IsGlobalContext(),
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00009037 strict_mode);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009038 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009039 Handle<JSFunction> compiled =
9040 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009041 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009042 return MakePair(*compiled, *receiver);
9043}
9044
9045
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009046RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009047 ASSERT(args.length() == 4);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009048
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009049 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009050 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009051 Handle<Object> receiver; // Will be overwritten.
9052
9053 // Compute the calling context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009054 Handle<Context> context = Handle<Context>(isolate->context(), isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009055#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009056 // Make sure Isolate::context() agrees with the old code that traversed
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009057 // the stack frames to compute the context.
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009058 StackFrameLocator locator;
9059 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009060 ASSERT(Context::cast(frame->context()) == *context);
9061#endif
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009062
9063 // Find where the 'eval' symbol is bound. It is unaliased only if
9064 // it is bound in the global context.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009065 int index = -1;
9066 PropertyAttributes attributes = ABSENT;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009067 BindingFlags binding_flags;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009068 while (true) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009069 receiver = context->Lookup(isolate->factory()->eval_symbol(),
9070 FOLLOW_PROTOTYPE_CHAIN,
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009071 &index,
9072 &attributes,
9073 &binding_flags);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009074 // Stop search when eval is found or when the global context is
9075 // reached.
9076 if (attributes != ABSENT || context->IsGlobalContext()) break;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009077 context = Handle<Context>(context->previous(), isolate);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009078 }
9079
iposva@chromium.org245aa852009-02-10 00:49:54 +00009080 // If eval could not be resolved, it has been deleted and we need to
9081 // throw a reference error.
9082 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009083 Handle<Object> name = isolate->factory()->eval_symbol();
iposva@chromium.org245aa852009-02-10 00:49:54 +00009084 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009085 isolate->factory()->NewReferenceError("not_defined",
9086 HandleVector(&name, 1));
9087 return MakePair(isolate->Throw(*reference_error), NULL);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009088 }
9089
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009090 if (!context->IsGlobalContext()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009091 // 'eval' is not bound in the global context. Just call the function
9092 // with the given arguments. This is not necessarily the global eval.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00009093 if (receiver->IsContext() || receiver->IsJSContextExtensionObject()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009094 receiver = isolate->factory()->the_hole_value();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009095 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009096 return MakePair(*callee, *receiver);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009097 }
9098
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009099 // 'eval' is bound in the global context, but it may have been overwritten.
9100 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009101 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009102 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009103 return MakePair(*callee, isolate->heap()->the_hole_value());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009104 }
9105
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009106 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009107 return CompileGlobalEval(isolate,
9108 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009109 args.at<Object>(2),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009110 static_cast<StrictModeFlag>(args.smi_at(3)));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009111}
9112
9113
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009114RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEvalNoLookup) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009115 ASSERT(args.length() == 4);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009116
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009117 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009118 Handle<Object> callee = args.at<Object>(0);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009119
9120 // 'eval' is bound in the global context, but it may have been overwritten.
9121 // Compare it to the builtin 'GlobalEval' function to make sure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009122 if (*callee != isolate->global_context()->global_eval_fun() ||
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009123 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009124 return MakePair(*callee, isolate->heap()->the_hole_value());
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009125 }
9126
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009127 ASSERT(args[3]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009128 return CompileGlobalEval(isolate,
9129 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009130 args.at<Object>(2),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009131 static_cast<StrictModeFlag>(args.smi_at(3)));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009132}
9133
9134
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009135RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009136 // This utility adjusts the property attributes for newly created Function
9137 // object ("new Function(...)") by changing the map.
9138 // All it does is changing the prototype property to enumerable
9139 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009140 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009141 ASSERT(args.length() == 1);
9142 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009143
9144 Handle<Map> map = func->shared()->strict_mode()
9145 ? isolate->strict_mode_function_instance_map()
9146 : isolate->function_instance_map();
9147
9148 ASSERT(func->map()->instance_type() == map->instance_type());
9149 ASSERT(func->map()->instance_size() == map->instance_size());
9150 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009151 return *func;
9152}
9153
9154
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009155RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009156 // Allocate a block of memory in NewSpace (filled with a filler).
9157 // Use as fallback for allocation in generated code when NewSpace
9158 // is full.
9159 ASSERT(args.length() == 1);
9160 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
9161 int size = size_smi->value();
9162 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
9163 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009164 Heap* heap = isolate->heap();
9165 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009166 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009167 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009168 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009169 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009170 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009171 }
9172 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009173 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009174}
9175
9176
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009177// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009178// array. Returns true if the element was pushed on the stack and
9179// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009180RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009181 ASSERT(args.length() == 2);
9182 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009183 CONVERT_CHECKED(JSObject, element, args[1]);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009184 RUNTIME_ASSERT(array->HasFastElements());
9185 int length = Smi::cast(array->length())->value();
9186 FixedArray* elements = FixedArray::cast(array->elements());
9187 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009188 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009189 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009190 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009191 // Strict not needed. Used for cycle detection in Array join implementation.
whesse@chromium.org7b260152011-06-20 15:33:18 +00009192 { MaybeObject* maybe_obj =
9193 array->SetFastElement(length, element, kNonStrictMode, true);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009194 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9195 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009196 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009197}
9198
9199
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009200/**
9201 * A simple visitor visits every element of Array's.
9202 * The backend storage can be a fixed array for fast elements case,
9203 * or a dictionary for sparse array. Since Dictionary is a subtype
9204 * of FixedArray, the class can be used by both fast and slow cases.
9205 * The second parameter of the constructor, fast_elements, specifies
9206 * whether the storage is a FixedArray or Dictionary.
9207 *
9208 * An index limit is used to deal with the situation that a result array
9209 * length overflows 32-bit non-negative integer.
9210 */
9211class ArrayConcatVisitor {
9212 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009213 ArrayConcatVisitor(Isolate* isolate,
9214 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009215 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009216 isolate_(isolate),
9217 storage_(Handle<FixedArray>::cast(
9218 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009219 index_offset_(0u),
9220 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009221
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009222 ~ArrayConcatVisitor() {
9223 clear_storage();
9224 }
9225
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009226 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009227 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009228 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009229
9230 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009231 if (index < static_cast<uint32_t>(storage_->length())) {
9232 storage_->set(index, *elm);
9233 return;
9234 }
9235 // Our initial estimate of length was foiled, possibly by
9236 // getters on the arrays increasing the length of later arrays
9237 // during iteration.
9238 // This shouldn't happen in anything but pathological cases.
9239 SetDictionaryMode(index);
9240 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009241 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009242 ASSERT(!fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009243 Handle<NumberDictionary> dict(NumberDictionary::cast(*storage_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009244 Handle<NumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009245 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009246 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009247 // Dictionary needed to grow.
9248 clear_storage();
9249 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009250 }
9251}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009252
9253 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009254 if (JSObject::kMaxElementCount - index_offset_ < delta) {
9255 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009256 } else {
9257 index_offset_ += delta;
9258 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009259 }
9260
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009261 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009262 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009263 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009264 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009265 Handle<Map> map;
9266 if (fast_elements_) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009267 map = isolate_->factory()->GetFastElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009268 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009269 map = isolate_->factory()->GetSlowElementsMap(Handle<Map>(array->map()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009270 }
9271 array->set_map(*map);
9272 array->set_length(*length);
9273 array->set_elements(*storage_);
9274 return array;
9275 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00009276
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009277 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009278 // Convert storage to dictionary mode.
9279 void SetDictionaryMode(uint32_t index) {
9280 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009281 Handle<FixedArray> current_storage(*storage_);
9282 Handle<NumberDictionary> slow_storage(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009283 isolate_->factory()->NewNumberDictionary(current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009284 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
9285 for (uint32_t i = 0; i < current_length; i++) {
9286 HandleScope loop_scope;
9287 Handle<Object> element(current_storage->get(i));
9288 if (!element->IsTheHole()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009289 Handle<NumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009290 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009291 if (!new_storage.is_identical_to(slow_storage)) {
9292 slow_storage = loop_scope.CloseAndEscape(new_storage);
9293 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009294 }
9295 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009296 clear_storage();
9297 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009298 fast_elements_ = false;
9299 }
9300
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009301 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009302 isolate_->global_handles()->Destroy(
9303 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009304 }
9305
9306 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009307 storage_ = Handle<FixedArray>::cast(
9308 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009309 }
9310
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009311 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009312 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009313 // Index after last seen index. Always less than or equal to
9314 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009315 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009316 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009317};
9318
9319
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009320static uint32_t EstimateElementCount(Handle<JSArray> array) {
9321 uint32_t length = static_cast<uint32_t>(array->length()->Number());
9322 int element_count = 0;
9323 switch (array->GetElementsKind()) {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009324 case JSObject::FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009325 // Fast elements can't have lengths that are not representable by
9326 // a 32-bit signed integer.
9327 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
9328 int fast_length = static_cast<int>(length);
9329 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
9330 for (int i = 0; i < fast_length; i++) {
9331 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009332 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009333 break;
9334 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009335 case JSObject::DICTIONARY_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009336 Handle<NumberDictionary> dictionary(
9337 NumberDictionary::cast(array->elements()));
9338 int capacity = dictionary->Capacity();
9339 for (int i = 0; i < capacity; i++) {
9340 Handle<Object> key(dictionary->KeyAt(i));
9341 if (dictionary->IsKey(*key)) {
9342 element_count++;
9343 }
9344 }
9345 break;
9346 }
9347 default:
9348 // External arrays are always dense.
9349 return length;
9350 }
9351 // As an estimate, we assume that the prototype doesn't contain any
9352 // inherited elements.
9353 return element_count;
9354}
9355
9356
9357
9358template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009359static void IterateExternalArrayElements(Isolate* isolate,
9360 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009361 bool elements_are_ints,
9362 bool elements_are_guaranteed_smis,
9363 ArrayConcatVisitor* visitor) {
9364 Handle<ExternalArrayClass> array(
9365 ExternalArrayClass::cast(receiver->elements()));
9366 uint32_t len = static_cast<uint32_t>(array->length());
9367
9368 ASSERT(visitor != NULL);
9369 if (elements_are_ints) {
9370 if (elements_are_guaranteed_smis) {
9371 for (uint32_t j = 0; j < len; j++) {
9372 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009373 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009374 visitor->visit(j, e);
9375 }
9376 } else {
9377 for (uint32_t j = 0; j < len; j++) {
9378 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009379 int64_t val = static_cast<int64_t>(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009380 if (Smi::IsValid(static_cast<intptr_t>(val))) {
9381 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
9382 visitor->visit(j, e);
9383 } else {
9384 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009385 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009386 visitor->visit(j, e);
9387 }
9388 }
9389 }
9390 } else {
9391 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009392 HandleScope loop_scope(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009393 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009394 visitor->visit(j, e);
9395 }
9396 }
9397}
9398
9399
9400// Used for sorting indices in a List<uint32_t>.
9401static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
9402 uint32_t a = *ap;
9403 uint32_t b = *bp;
9404 return (a == b) ? 0 : (a < b) ? -1 : 1;
9405}
9406
9407
9408static void CollectElementIndices(Handle<JSObject> object,
9409 uint32_t range,
9410 List<uint32_t>* indices) {
9411 JSObject::ElementsKind kind = object->GetElementsKind();
9412 switch (kind) {
9413 case JSObject::FAST_ELEMENTS: {
9414 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
9415 uint32_t length = static_cast<uint32_t>(elements->length());
9416 if (range < length) length = range;
9417 for (uint32_t i = 0; i < length; i++) {
9418 if (!elements->get(i)->IsTheHole()) {
9419 indices->Add(i);
9420 }
9421 }
9422 break;
9423 }
9424 case JSObject::DICTIONARY_ELEMENTS: {
9425 Handle<NumberDictionary> dict(NumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009426 uint32_t capacity = dict->Capacity();
9427 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009428 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009429 Handle<Object> k(dict->KeyAt(j));
9430 if (dict->IsKey(*k)) {
9431 ASSERT(k->IsNumber());
9432 uint32_t index = static_cast<uint32_t>(k->Number());
9433 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009434 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009435 }
9436 }
9437 }
9438 break;
9439 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009440 default: {
9441 int dense_elements_length;
9442 switch (kind) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009443 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009444 dense_elements_length =
9445 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009446 break;
9447 }
9448 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009449 dense_elements_length =
9450 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009451 break;
9452 }
9453 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009454 dense_elements_length =
9455 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009456 break;
9457 }
9458 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009459 dense_elements_length =
9460 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009461 break;
9462 }
9463 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009464 dense_elements_length =
9465 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009466 break;
9467 }
9468 case JSObject::EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009469 dense_elements_length =
9470 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009471 break;
9472 }
9473 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009474 dense_elements_length =
9475 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009476 break;
9477 }
9478 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009479 dense_elements_length =
9480 ExternalFloatArray::cast(object->elements())->length();
9481 break;
9482 }
9483 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
9484 dense_elements_length =
9485 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009486 break;
9487 }
9488 default:
9489 UNREACHABLE();
9490 dense_elements_length = 0;
9491 break;
9492 }
9493 uint32_t length = static_cast<uint32_t>(dense_elements_length);
9494 if (range <= length) {
9495 length = range;
9496 // We will add all indices, so we might as well clear it first
9497 // and avoid duplicates.
9498 indices->Clear();
9499 }
9500 for (uint32_t i = 0; i < length; i++) {
9501 indices->Add(i);
9502 }
9503 if (length == range) return; // All indices accounted for already.
9504 break;
9505 }
9506 }
9507
9508 Handle<Object> prototype(object->GetPrototype());
9509 if (prototype->IsJSObject()) {
9510 // The prototype will usually have no inherited element indices,
9511 // but we have to check.
9512 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
9513 }
9514}
9515
9516
9517/**
9518 * A helper function that visits elements of a JSArray in numerical
9519 * order.
9520 *
9521 * The visitor argument called for each existing element in the array
9522 * with the element index and the element's value.
9523 * Afterwards it increments the base-index of the visitor by the array
9524 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009525 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009526 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009527static bool IterateElements(Isolate* isolate,
9528 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009529 ArrayConcatVisitor* visitor) {
9530 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
9531 switch (receiver->GetElementsKind()) {
9532 case JSObject::FAST_ELEMENTS: {
9533 // Run through the elements FixedArray and use HasElement and GetElement
9534 // to check the prototype for missing elements.
9535 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
9536 int fast_length = static_cast<int>(length);
9537 ASSERT(fast_length <= elements->length());
9538 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009539 HandleScope loop_scope(isolate);
9540 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009541 if (!element_value->IsTheHole()) {
9542 visitor->visit(j, element_value);
9543 } else if (receiver->HasElement(j)) {
9544 // Call GetElement on receiver, not its prototype, or getters won't
9545 // have the correct receiver.
9546 element_value = GetElement(receiver, j);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009547 if (element_value.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009548 visitor->visit(j, element_value);
9549 }
9550 }
9551 break;
9552 }
9553 case JSObject::DICTIONARY_ELEMENTS: {
9554 Handle<NumberDictionary> dict(receiver->element_dictionary());
9555 List<uint32_t> indices(dict->Capacity() / 2);
9556 // Collect all indices in the object and the prototypes less
9557 // than length. This might introduce duplicates in the indices list.
9558 CollectElementIndices(receiver, length, &indices);
9559 indices.Sort(&compareUInt32);
9560 int j = 0;
9561 int n = indices.length();
9562 while (j < n) {
9563 HandleScope loop_scope;
9564 uint32_t index = indices[j];
9565 Handle<Object> element = GetElement(receiver, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009566 if (element.is_null()) return false;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009567 visitor->visit(index, element);
9568 // Skip to next different index (i.e., omit duplicates).
9569 do {
9570 j++;
9571 } while (j < n && indices[j] == index);
9572 }
9573 break;
9574 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009575 case JSObject::EXTERNAL_PIXEL_ELEMENTS: {
9576 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
9577 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009578 for (uint32_t j = 0; j < length; j++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009579 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009580 visitor->visit(j, e);
9581 }
9582 break;
9583 }
9584 case JSObject::EXTERNAL_BYTE_ELEMENTS: {
9585 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009586 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009587 break;
9588 }
9589 case JSObject::EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
9590 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009591 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009592 break;
9593 }
9594 case JSObject::EXTERNAL_SHORT_ELEMENTS: {
9595 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009596 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009597 break;
9598 }
9599 case JSObject::EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
9600 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009601 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009602 break;
9603 }
9604 case JSObject::EXTERNAL_INT_ELEMENTS: {
9605 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009606 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009607 break;
9608 }
9609 case JSObject::EXTERNAL_UNSIGNED_INT_ELEMENTS: {
9610 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009611 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009612 break;
9613 }
9614 case JSObject::EXTERNAL_FLOAT_ELEMENTS: {
9615 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009616 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009617 break;
9618 }
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009619 case JSObject::EXTERNAL_DOUBLE_ELEMENTS: {
9620 IterateExternalArrayElements<ExternalDoubleArray, double>(
9621 isolate, receiver, false, false, visitor);
9622 break;
9623 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009624 default:
9625 UNREACHABLE();
9626 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009627 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009628 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009629 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009630}
9631
9632
9633/**
9634 * Array::concat implementation.
9635 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009636 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009637 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009638 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009639RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009640 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009641 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009642
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009643 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
9644 int argument_count = static_cast<int>(arguments->length()->Number());
9645 RUNTIME_ASSERT(arguments->HasFastElements());
9646 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009647
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009648 // Pass 1: estimate the length and number of elements of the result.
9649 // The actual length can be larger if any of the arguments have getters
9650 // that mutate other arguments (but will otherwise be precise).
9651 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009652
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009653 uint32_t estimate_result_length = 0;
9654 uint32_t estimate_nof_elements = 0;
9655 {
9656 for (int i = 0; i < argument_count; i++) {
9657 HandleScope loop_scope;
9658 Handle<Object> obj(elements->get(i));
9659 uint32_t length_estimate;
9660 uint32_t element_estimate;
9661 if (obj->IsJSArray()) {
9662 Handle<JSArray> array(Handle<JSArray>::cast(obj));
9663 length_estimate =
9664 static_cast<uint32_t>(array->length()->Number());
9665 element_estimate =
9666 EstimateElementCount(array);
9667 } else {
9668 length_estimate = 1;
9669 element_estimate = 1;
9670 }
9671 // Avoid overflows by capping at kMaxElementCount.
9672 if (JSObject::kMaxElementCount - estimate_result_length <
9673 length_estimate) {
9674 estimate_result_length = JSObject::kMaxElementCount;
9675 } else {
9676 estimate_result_length += length_estimate;
9677 }
9678 if (JSObject::kMaxElementCount - estimate_nof_elements <
9679 element_estimate) {
9680 estimate_nof_elements = JSObject::kMaxElementCount;
9681 } else {
9682 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009683 }
9684 }
9685 }
9686
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009687 // If estimated number of elements is more than half of length, a
9688 // fixed array (fast case) is more time and space-efficient than a
9689 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009690 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009691
9692 Handle<FixedArray> storage;
9693 if (fast_case) {
9694 // The backing storage array must have non-existing elements to
9695 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009696 storage = isolate->factory()->NewFixedArrayWithHoles(
9697 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009698 } else {
9699 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
9700 uint32_t at_least_space_for = estimate_nof_elements +
9701 (estimate_nof_elements >> 2);
9702 storage = Handle<FixedArray>::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009703 isolate->factory()->NewNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009704 }
9705
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009706 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009707
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009708 for (int i = 0; i < argument_count; i++) {
9709 Handle<Object> obj(elements->get(i));
9710 if (obj->IsJSArray()) {
9711 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009712 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009713 return Failure::Exception();
9714 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009715 } else {
9716 visitor.visit(0, obj);
9717 visitor.increase_index_offset(1);
9718 }
9719 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009720
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009721 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009722}
9723
9724
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009725// This will not allocate (flatten the string), but it may run
9726// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009727RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009728 NoHandleAllocation ha;
9729 ASSERT(args.length() == 1);
9730
9731 CONVERT_CHECKED(String, string, args[0]);
9732 StringInputBuffer buffer(string);
9733 while (buffer.has_more()) {
9734 uint16_t character = buffer.GetNext();
9735 PrintF("%c", character);
9736 }
9737 return string;
9738}
9739
ager@chromium.org5ec48922009-05-05 07:25:34 +00009740// Moves all own elements of an object, that are below a limit, to positions
9741// starting at zero. All undefined values are placed after non-undefined values,
9742// and are followed by non-existing element. Does not change the length
9743// property.
9744// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009745RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00009746 ASSERT(args.length() == 2);
9747 CONVERT_CHECKED(JSObject, object, args[0]);
9748 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
9749 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009750}
9751
9752
9753// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009754RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009755 ASSERT(args.length() == 2);
9756 CONVERT_CHECKED(JSArray, from, args[0]);
9757 CONVERT_CHECKED(JSArray, to, args[1]);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00009758 FixedArrayBase* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +00009759 MaybeObject* maybe_new_map;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009760 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
9761 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009762 maybe_new_map = to->map()->GetFastElementsMap();
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00009763 } else if (new_elements->map() ==
9764 isolate->heap()->fixed_double_array_map()) {
9765 maybe_new_map = to->map()->GetFastDoubleElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009766 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009767 maybe_new_map = to->map()->GetSlowElementsMap();
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009768 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009769 Object* new_map;
9770 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00009771 to->set_map(Map::cast(new_map));
9772 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009773 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009774 Object* obj;
9775 { MaybeObject* maybe_obj = from->ResetElements();
9776 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9777 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009778 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009779 return to;
9780}
9781
9782
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009783// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009784RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009785 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009786 CONVERT_CHECKED(JSObject, object, args[0]);
9787 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009788 if (elements->IsDictionary()) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +00009789 return Smi::FromInt(NumberDictionary::cast(elements)->NumberOfElements());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009790 } else if (object->IsJSArray()) {
9791 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009792 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009793 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009794 }
9795}
9796
9797
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009798RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009799 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009800
9801 ASSERT_EQ(3, args.length());
9802
ager@chromium.orgac091b72010-05-05 07:34:42 +00009803 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009804 Handle<Object> key1 = args.at<Object>(1);
9805 Handle<Object> key2 = args.at<Object>(2);
9806
9807 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009808 if (!key1->ToArrayIndex(&index1)
9809 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009810 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009811 }
9812
ager@chromium.orgac091b72010-05-05 07:34:42 +00009813 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
9814 Handle<Object> tmp1 = GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009815 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009816 Handle<Object> tmp2 = GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009817 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +00009818
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009819 RETURN_IF_EMPTY_HANDLE(isolate,
9820 SetElement(jsobject, index1, tmp2, kStrictMode));
9821 RETURN_IF_EMPTY_HANDLE(isolate,
9822 SetElement(jsobject, index2, tmp1, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +00009823
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009824 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00009825}
9826
9827
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009828// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00009829// might have elements. Can either return keys (positive integers) or
9830// intervals (pair of a negative integer (-start-1) followed by a
9831// positive (length)) or undefined values.
9832// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009833RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009834 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009835 HandleScope scope(isolate);
ager@chromium.org5ec48922009-05-05 07:25:34 +00009836 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009837 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009838 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009839 // Create an array and get all the keys into it, then remove all the
9840 // keys that are not integers in the range 0 to length-1.
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00009841 Handle<FixedArray> keys = GetKeysInFixedArrayFor(array, INCLUDE_PROTOS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009842 int keys_length = keys->length();
9843 for (int i = 0; i < keys_length; i++) {
9844 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009845 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009846 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009847 // Zap invalid keys.
9848 keys->set_undefined(i);
9849 }
9850 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009851 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009852 } else {
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00009853 ASSERT(array->HasFastElements() || array->HasFastDoubleElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009854 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009855 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00009856 single_interval->set(0, Smi::FromInt(-1));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00009857 FixedArrayBase* elements = FixedArrayBase::cast(array->elements());
ricow@chromium.org30ce4112010-05-31 10:38:25 +00009858 uint32_t actual_length =
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +00009859 static_cast<uint32_t>(elements->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +00009860 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009861 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009862 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009863 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009864 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009865 }
9866}
9867
9868
9869// DefineAccessor takes an optional final argument which is the
9870// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
9871// to the way accessors are implemented, it is set for both the getter
9872// and setter on the first call to DefineAccessor and ignored on
9873// subsequent calls.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009874RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009875 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
9876 // Compute attributes.
9877 PropertyAttributes attributes = NONE;
9878 if (args.length() == 5) {
9879 CONVERT_CHECKED(Smi, attrs, args[4]);
9880 int value = attrs->value();
9881 // Only attribute bits should be set.
9882 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
9883 attributes = static_cast<PropertyAttributes>(value);
9884 }
9885
9886 CONVERT_CHECKED(JSObject, obj, args[0]);
9887 CONVERT_CHECKED(String, name, args[1]);
9888 CONVERT_CHECKED(Smi, flag, args[2]);
9889 CONVERT_CHECKED(JSFunction, fun, args[3]);
9890 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
9891}
9892
9893
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009894RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009895 ASSERT(args.length() == 3);
9896 CONVERT_CHECKED(JSObject, obj, args[0]);
9897 CONVERT_CHECKED(String, name, args[1]);
9898 CONVERT_CHECKED(Smi, flag, args[2]);
9899 return obj->LookupAccessor(name, flag->value() == 0);
9900}
9901
9902
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009903#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009904RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00009905 ASSERT(args.length() == 0);
9906 return Execution::DebugBreakHelper();
9907}
9908
9909
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009910// Helper functions for wrapping and unwrapping stack frame ids.
9911static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00009912 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009913 return Smi::FromInt(id >> 2);
9914}
9915
9916
9917static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
9918 return static_cast<StackFrame::Id>(wrapped->value() << 2);
9919}
9920
9921
9922// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00009923// args[0]: debug event listener function to set or null or undefined for
9924// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009925// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009926RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009927 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +00009928 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
9929 args[0]->IsUndefined() ||
9930 args[0]->IsNull());
9931 Handle<Object> callback = args.at<Object>(0);
9932 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009933 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009934
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009935 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009936}
9937
9938
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009939RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +00009940 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009941 isolate->stack_guard()->DebugBreak();
9942 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009943}
9944
9945
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009946static MaybeObject* DebugLookupResultValue(Heap* heap,
9947 Object* receiver,
9948 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +00009949 LookupResult* result,
9950 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009951 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009952 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009953 case NORMAL:
9954 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009955 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009956 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009957 }
9958 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009959 case FIELD:
9960 value =
9961 JSObject::cast(
9962 result->holder())->FastPropertyAt(result->GetFieldIndex());
9963 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009964 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009965 }
9966 return value;
9967 case CONSTANT_FUNCTION:
9968 return result->GetConstantFunction();
9969 case CALLBACKS: {
9970 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +00009971 if (structure->IsForeign() || structure->IsAccessorInfo()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00009972 MaybeObject* maybe_value = receiver->GetPropertyWithCallback(
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00009973 receiver, structure, name, result->holder());
lrn@chromium.org303ada72010-10-27 09:33:13 +00009974 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00009975 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009976 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009977 maybe_value = heap->isolate()->pending_exception();
9978 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009979 if (caught_exception != NULL) {
9980 *caught_exception = true;
9981 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009982 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009983 }
9984 return value;
9985 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009986 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +00009987 }
9988 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009989 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009990 case MAP_TRANSITION:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00009991 case EXTERNAL_ARRAY_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009992 case CONSTANT_TRANSITION:
9993 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009994 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009995 default:
9996 UNREACHABLE();
9997 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009998 UNREACHABLE();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009999 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010000}
10001
10002
ager@chromium.org32912102009-01-16 10:38:43 +000010003// Get debugger related details for an object property.
10004// args[0]: object holding property
10005// args[1]: name of the property
10006//
10007// The array returned contains the following information:
10008// 0: Property value
10009// 1: Property details
10010// 2: Property value is exception
10011// 3: Getter function if defined
10012// 4: Setter function if defined
10013// Items 2-4 are only filled if the property has either a getter or a setter
10014// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010015RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010016 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010017
10018 ASSERT(args.length() == 2);
10019
10020 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10021 CONVERT_ARG_CHECKED(String, name, 1);
10022
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010023 // Make sure to set the current context to the context before the debugger was
10024 // entered (if the debugger is entered). The reason for switching context here
10025 // is that for some property lookups (accessors and interceptors) callbacks
10026 // into the embedding application can occour, and the embedding application
10027 // could have the assumption that its own global context is the current
10028 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010029 SaveContext save(isolate);
10030 if (isolate->debug()->InDebugger()) {
10031 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010032 }
10033
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010034 // Skip the global proxy as it has no properties and always delegates to the
10035 // real global object.
10036 if (obj->IsJSGlobalProxy()) {
10037 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
10038 }
10039
10040
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010041 // Check if the name is trivially convertible to an index and get the element
10042 // if so.
10043 uint32_t index;
10044 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010045 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010046 Object* element_or_char;
10047 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010048 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010049 if (!maybe_element_or_char->ToObject(&element_or_char)) {
10050 return maybe_element_or_char;
10051 }
10052 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010053 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010054 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010055 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010056 }
10057
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010058 // Find the number of objects making up this.
10059 int length = LocalPrototypeChainLength(*obj);
10060
10061 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010062 Handle<JSObject> jsproto = obj;
10063 for (int i = 0; i < length; i++) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010064 LookupResult result;
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010065 jsproto->LocalLookup(*name, &result);
10066 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010067 // LookupResult is not GC safe as it holds raw object pointers.
10068 // GC can happen later in this code so put the required fields into
10069 // local variables using handles when required for later use.
10070 PropertyType result_type = result.type();
10071 Handle<Object> result_callback_obj;
10072 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010073 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
10074 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010075 }
10076 Smi* property_details = result.GetPropertyDetails().AsSmi();
10077 // DebugLookupResultValue can cause GC so details from LookupResult needs
10078 // to be copied to handles before this.
10079 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010080 Object* raw_value;
10081 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010082 DebugLookupResultValue(isolate->heap(), *obj, *name,
10083 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010084 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
10085 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010086 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010087
10088 // If the callback object is a fixed array then it contains JavaScript
10089 // getter and/or setter.
10090 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
10091 result_callback_obj->IsFixedArray();
10092 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010093 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010094 details->set(0, *value);
10095 details->set(1, property_details);
10096 if (hasJavaScriptAccessors) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010097 details->set(2, isolate->heap()->ToBoolean(caught_exception));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010098 details->set(3, FixedArray::cast(*result_callback_obj)->get(0));
10099 details->set(4, FixedArray::cast(*result_callback_obj)->get(1));
10100 }
10101
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010102 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010103 }
10104 if (i < length - 1) {
10105 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
10106 }
10107 }
10108
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010109 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010110}
10111
10112
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010113RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010114 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010115
10116 ASSERT(args.length() == 2);
10117
10118 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10119 CONVERT_ARG_CHECKED(String, name, 1);
10120
10121 LookupResult result;
10122 obj->Lookup(*name, &result);
10123 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010124 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010125 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010126 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010127}
10128
10129
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010130// Return the property type calculated from the property details.
10131// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010132RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010133 ASSERT(args.length() == 1);
10134 CONVERT_CHECKED(Smi, details, args[0]);
10135 PropertyType type = PropertyDetails(details).type();
10136 return Smi::FromInt(static_cast<int>(type));
10137}
10138
10139
10140// Return the property attribute calculated from the property details.
10141// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010142RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010143 ASSERT(args.length() == 1);
10144 CONVERT_CHECKED(Smi, details, args[0]);
10145 PropertyAttributes attributes = PropertyDetails(details).attributes();
10146 return Smi::FromInt(static_cast<int>(attributes));
10147}
10148
10149
10150// Return the property insertion index calculated from the property details.
10151// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010152RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010153 ASSERT(args.length() == 1);
10154 CONVERT_CHECKED(Smi, details, args[0]);
10155 int index = PropertyDetails(details).index();
10156 return Smi::FromInt(index);
10157}
10158
10159
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010160// Return property value from named interceptor.
10161// args[0]: object
10162// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010163RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010164 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010165 ASSERT(args.length() == 2);
10166 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10167 RUNTIME_ASSERT(obj->HasNamedInterceptor());
10168 CONVERT_ARG_CHECKED(String, name, 1);
10169
10170 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010171 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010172}
10173
10174
10175// Return element value from indexed interceptor.
10176// args[0]: object
10177// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010178RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010179 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010180 ASSERT(args.length() == 2);
10181 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10182 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
10183 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
10184
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010185 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010186}
10187
10188
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010189RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010190 ASSERT(args.length() >= 1);
10191 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +000010192 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010193 if (isolate->debug()->break_id() == 0 ||
10194 break_id != isolate->debug()->break_id()) {
10195 return isolate->Throw(
10196 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010197 }
10198
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010199 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010200}
10201
10202
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010203RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010204 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010205 ASSERT(args.length() == 1);
10206
10207 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010208 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010209 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10210 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010211 if (!maybe_result->ToObject(&result)) return maybe_result;
10212 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010213
10214 // Count all frames which are relevant to debugging stack trace.
10215 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010216 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010217 if (id == StackFrame::NO_ID) {
10218 // If there is no JavaScript stack frame count is 0.
10219 return Smi::FromInt(0);
10220 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010221
10222 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
10223 n += it.frame()->GetInlineCount();
10224 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010225 return Smi::FromInt(n);
10226}
10227
10228
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010229class FrameInspector {
10230 public:
10231 FrameInspector(JavaScriptFrame* frame,
10232 int inlined_frame_index,
10233 Isolate* isolate)
10234 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
10235 // Calculate the deoptimized frame.
10236 if (frame->is_optimized()) {
10237 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
10238 frame, inlined_frame_index, isolate);
10239 }
10240 has_adapted_arguments_ = frame_->has_adapted_arguments();
10241 is_optimized_ = frame_->is_optimized();
10242 }
10243
10244 ~FrameInspector() {
10245 // Get rid of the calculated deoptimized frame if any.
10246 if (deoptimized_frame_ != NULL) {
10247 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_,
10248 isolate_);
10249 }
10250 }
10251
10252 int GetParametersCount() {
10253 return is_optimized_
10254 ? deoptimized_frame_->parameters_count()
10255 : frame_->ComputeParametersCount();
10256 }
10257 int expression_count() { return deoptimized_frame_->expression_count(); }
10258 Object* GetFunction() {
10259 return is_optimized_
10260 ? deoptimized_frame_->GetFunction()
10261 : frame_->function();
10262 }
10263 Object* GetParameter(int index) {
10264 return is_optimized_
10265 ? deoptimized_frame_->GetParameter(index)
10266 : frame_->GetParameter(index);
10267 }
10268 Object* GetExpression(int index) {
10269 return is_optimized_
10270 ? deoptimized_frame_->GetExpression(index)
10271 : frame_->GetExpression(index);
10272 }
10273
10274 // To inspect all the provided arguments the frame might need to be
10275 // replaced with the arguments frame.
10276 void SetArgumentsFrame(JavaScriptFrame* frame) {
10277 ASSERT(has_adapted_arguments_);
10278 frame_ = frame;
10279 is_optimized_ = frame_->is_optimized();
10280 ASSERT(!is_optimized_);
10281 }
10282
10283 private:
10284 JavaScriptFrame* frame_;
10285 DeoptimizedFrameInfo* deoptimized_frame_;
10286 Isolate* isolate_;
10287 bool is_optimized_;
10288 bool has_adapted_arguments_;
10289
10290 DISALLOW_COPY_AND_ASSIGN(FrameInspector);
10291};
10292
10293
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010294static const int kFrameDetailsFrameIdIndex = 0;
10295static const int kFrameDetailsReceiverIndex = 1;
10296static const int kFrameDetailsFunctionIndex = 2;
10297static const int kFrameDetailsArgumentCountIndex = 3;
10298static const int kFrameDetailsLocalCountIndex = 4;
10299static const int kFrameDetailsSourcePositionIndex = 5;
10300static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010301static const int kFrameDetailsAtReturnIndex = 7;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010302static const int kFrameDetailsFlagsIndex = 8;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010303static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010304
10305// Return an array with frame details
10306// args[0]: number: break id
10307// args[1]: number: frame index
10308//
10309// The array returned contains the following information:
10310// 0: Frame id
10311// 1: Receiver
10312// 2: Function
10313// 3: Argument count
10314// 4: Local count
10315// 5: Source position
10316// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010317// 7: Is at return
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010318// 8: Flags
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010319// Arguments name, value
10320// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010321// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010322RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010323 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010324 ASSERT(args.length() == 2);
10325
10326 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010327 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010328 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10329 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010330 if (!maybe_check->ToObject(&check)) return maybe_check;
10331 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010332 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010333 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010334
10335 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010336 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010337 if (id == StackFrame::NO_ID) {
10338 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010339 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010340 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010341
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010342 int inlined_frame_index = 0; // Inlined frame index in optimized frame.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010343
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010344 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010345 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010346 for (; !it.done(); it.Advance()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010347 if (index < count + it.frame()->GetInlineCount()) break;
10348 count += it.frame()->GetInlineCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010349 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010350 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010351
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010352 if (it.frame()->is_optimized()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010353 inlined_frame_index =
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010354 it.frame()->GetInlineCount() - (index - count) - 1;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010355 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010356 FrameInspector frame_inspector(it.frame(), inlined_frame_index, isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010357
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010358 // Traverse the saved contexts chain to find the active context for the
10359 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010360 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010361 while (save != NULL && !save->below(it.frame())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010362 save = save->prev();
10363 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +000010364 ASSERT(save != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010365
10366 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010367 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010368
10369 // Find source position.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010370 int position =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010371 it.frame()->LookupCode()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010372
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010373 // Check for constructor frame. Inlined frames cannot be construct calls.
10374 bool inlined_frame =
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010375 it.frame()->is_optimized() && inlined_frame_index != 0;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010376 bool constructor = !inlined_frame && it.frame()->IsConstructor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010377
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010378 // Get scope info and read from it for local variable information.
10379 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010380 Handle<SharedFunctionInfo> shared(function->shared());
10381 Handle<SerializedScopeInfo> scope_info(shared->scope_info());
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010382 ASSERT(*scope_info != SerializedScopeInfo::Empty());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010383 ScopeInfo<> info(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010384
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010385 // Get the locals names and values into a temporary array.
10386 //
10387 // TODO(1240907): Hide compiler-introduced stack variables
10388 // (e.g. .result)? For users of the debugger, they will probably be
10389 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010390 Handle<FixedArray> locals =
10391 isolate->factory()->NewFixedArray(info.NumberOfLocals() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010392
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010393 // Fill in the values of the locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010394 int i = 0;
10395 for (; i < info.number_of_stack_slots(); ++i) {
10396 // Use the value from the stack.
10397 locals->set(i * 2, *info.LocalName(i));
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010398 locals->set(i * 2 + 1, frame_inspector.GetExpression(i));
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010399 }
10400 if (i < info.NumberOfLocals()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010401 // Get the context containing declarations.
10402 Handle<Context> context(
10403 Context::cast(it.frame()->context())->declaration_context());
10404 for (; i < info.NumberOfLocals(); ++i) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010405 Handle<String> name = info.LocalName(i);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010406 locals->set(i * 2, *name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010407 locals->set(i * 2 + 1,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010408 context->get(scope_info->ContextSlotIndex(*name, NULL)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010409 }
10410 }
10411
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010412 // Check whether this frame is positioned at return. If not top
10413 // frame or if the frame is optimized it cannot be at a return.
10414 bool at_return = false;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010415 if (!it.frame()->is_optimized() && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010416 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010417 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010418
10419 // If positioned just before return find the value to be returned and add it
10420 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010421 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010422 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010423 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010424 Address internal_frame_sp = NULL;
10425 while (!it2.done()) {
10426 if (it2.frame()->is_internal()) {
10427 internal_frame_sp = it2.frame()->sp();
10428 } else {
10429 if (it2.frame()->is_java_script()) {
10430 if (it2.frame()->id() == it.frame()->id()) {
10431 // The internal frame just before the JavaScript frame contains the
10432 // value to return on top. A debug break at return will create an
10433 // internal frame to store the return value (eax/rax/r0) before
10434 // entering the debug break exit frame.
10435 if (internal_frame_sp != NULL) {
10436 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010437 Handle<Object>(Memory::Object_at(internal_frame_sp),
10438 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010439 break;
10440 }
10441 }
10442 }
10443
10444 // Indicate that the previous frame was not an internal frame.
10445 internal_frame_sp = NULL;
10446 }
10447 it2.Advance();
10448 }
10449 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010450
10451 // Now advance to the arguments adapter frame (if any). It contains all
10452 // the provided parameters whereas the function frame always have the number
10453 // of arguments matching the functions parameters. The rest of the
10454 // information (except for what is collected above) is the same.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010455 if (it.frame()->has_adapted_arguments()) {
10456 it.AdvanceToArgumentsFrame();
10457 frame_inspector.SetArgumentsFrame(it.frame());
10458 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010459
10460 // Find the number of arguments to fill. At least fill the number of
10461 // parameters for the function and fill more if more parameters are provided.
10462 int argument_count = info.number_of_parameters();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010463 if (argument_count < frame_inspector.GetParametersCount()) {
10464 argument_count = frame_inspector.GetParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010465 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010466#ifdef DEBUG
10467 if (it.frame()->is_optimized()) {
10468 ASSERT_EQ(argument_count, frame_inspector.GetParametersCount());
10469 }
10470#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010471
10472 // Calculate the size of the result.
10473 int details_size = kFrameDetailsFirstDynamicIndex +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010474 2 * (argument_count + info.NumberOfLocals()) +
10475 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010476 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010477
10478 // Add the frame id.
10479 details->set(kFrameDetailsFrameIdIndex, *frame_id);
10480
10481 // Add the function (same as in function frame).
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010482 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010483
10484 // Add the arguments count.
10485 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
10486
10487 // Add the locals count
10488 details->set(kFrameDetailsLocalCountIndex,
10489 Smi::FromInt(info.NumberOfLocals()));
10490
10491 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +000010492 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010493 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
10494 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010495 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010496 }
10497
10498 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010499 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010500
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010501 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010502 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010503
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010504 // Add flags to indicate information on whether this frame is
10505 // bit 0: invoked in the debugger context.
10506 // bit 1: optimized frame.
10507 // bit 2: inlined in optimized frame
10508 int flags = 0;
10509 if (*save->context() == *isolate->debug()->debug_context()) {
10510 flags |= 1 << 0;
10511 }
10512 if (it.frame()->is_optimized()) {
10513 flags |= 1 << 1;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010514 flags |= inlined_frame_index << 2;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010515 }
10516 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010517
10518 // Fill the dynamic part.
10519 int details_index = kFrameDetailsFirstDynamicIndex;
10520
10521 // Add arguments name and value.
10522 for (int i = 0; i < argument_count; i++) {
10523 // Name of the argument.
10524 if (i < info.number_of_parameters()) {
10525 details->set(details_index++, *info.parameter_name(i));
10526 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010527 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010528 }
10529
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010530 // Parameter value.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010531 if (i < it.frame()->ComputeParametersCount()) {
10532 // Get the value from the stack.
10533 details->set(details_index++, frame_inspector.GetParameter(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010534 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010535 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010536 }
10537 }
10538
10539 // Add locals name and value from the temporary copy from the function frame.
10540 for (int i = 0; i < info.NumberOfLocals() * 2; i++) {
10541 details->set(details_index++, locals->get(i));
10542 }
10543
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010544 // Add the value being returned.
10545 if (at_return) {
10546 details->set(details_index++, *return_value);
10547 }
10548
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010549 // Add the receiver (same as in function frame).
10550 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
10551 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010552 Handle<Object> receiver(it.frame()->receiver(), isolate);
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010553 if (!receiver->IsJSObject() && !shared->strict_mode() && !shared->native()) {
10554 // If the receiver is not a JSObject and the function is not a
10555 // builtin or strict-mode we have hit an optimization where a
10556 // value object is not converted into a wrapped JS objects. To
10557 // hide this optimization from the debugger, we wrap the receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010558 // by creating correct wrapper object based on the calling frame's
10559 // global context.
10560 it.Advance();
10561 Handle<Context> calling_frames_global_context(
10562 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010563 receiver =
10564 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010565 }
10566 details->set(kFrameDetailsReceiverIndex, *receiver);
10567
10568 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010569 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010570}
10571
10572
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010573// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010574static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010575 Isolate* isolate,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010576 Handle<SerializedScopeInfo> serialized_scope_info,
10577 ScopeInfo<>& scope_info,
10578 Handle<Context> context,
10579 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010580 // Fill all context locals to the context extension.
10581 for (int i = Context::MIN_CONTEXT_SLOTS;
10582 i < scope_info.number_of_context_slots();
10583 i++) {
ager@chromium.orgb5737492010-07-15 09:29:43 +000010584 int context_index = serialized_scope_info->ContextSlotIndex(
10585 *scope_info.context_slot_name(i), NULL);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010586
whesse@chromium.org7b260152011-06-20 15:33:18 +000010587 RETURN_IF_EMPTY_HANDLE_VALUE(
10588 isolate,
10589 SetProperty(scope_object,
10590 scope_info.context_slot_name(i),
10591 Handle<Object>(context->get(context_index), isolate),
10592 NONE,
10593 kNonStrictMode),
10594 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010595 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010596
10597 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010598}
10599
10600
10601// Create a plain JSObject which materializes the local scope for the specified
10602// frame.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010603static Handle<JSObject> MaterializeLocalScope(
10604 Isolate* isolate,
10605 JavaScriptFrame* frame,
10606 int inlined_frame_index) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010607 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010608 Handle<SharedFunctionInfo> shared(function->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +000010609 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
10610 ScopeInfo<> scope_info(*serialized_scope_info);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010611 FrameInspector frame_inspector(frame, inlined_frame_index, isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010612
10613 // Allocate and initialize a JSObject with all the arguments, stack locals
10614 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010615 Handle<JSObject> local_scope =
10616 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010617
10618 // First fill all parameters.
10619 for (int i = 0; i < scope_info.number_of_parameters(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010620 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010621 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010622 SetProperty(local_scope,
10623 scope_info.parameter_name(i),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010624 Handle<Object>(frame_inspector.GetParameter(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010625 NONE,
10626 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010627 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010628 }
10629
10630 // Second fill all stack locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010631 for (int i = 0; i < scope_info.number_of_stack_slots(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010632 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010633 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010634 SetProperty(local_scope,
10635 scope_info.stack_slot_name(i),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010636 Handle<Object>(frame_inspector.GetExpression(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010637 NONE,
10638 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010639 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010640 }
10641
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010642 if (scope_info.number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
10643 // Third fill all context locals.
10644 Handle<Context> frame_context(Context::cast(frame->context()));
10645 Handle<Context> function_context(frame_context->declaration_context());
10646 if (!CopyContextLocalsToScopeObject(isolate,
10647 serialized_scope_info, scope_info,
10648 function_context, local_scope)) {
10649 return Handle<JSObject>();
10650 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010651
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010652 // Finally copy any properties from the function context extension.
10653 // These will be variables introduced by eval.
10654 if (function_context->closure() == *function) {
10655 if (function_context->has_extension() &&
10656 !function_context->IsGlobalContext()) {
10657 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
10658 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
10659 for (int i = 0; i < keys->length(); i++) {
10660 // Names of variables introduced by eval are strings.
10661 ASSERT(keys->get(i)->IsString());
10662 Handle<String> key(String::cast(keys->get(i)));
10663 RETURN_IF_EMPTY_HANDLE_VALUE(
10664 isolate,
10665 SetProperty(local_scope,
10666 key,
10667 GetProperty(ext, key),
10668 NONE,
10669 kNonStrictMode),
10670 Handle<JSObject>());
10671 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010672 }
10673 }
10674 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010675
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010676 return local_scope;
10677}
10678
10679
10680// Create a plain JSObject which materializes the closure content for the
10681// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010682static Handle<JSObject> MaterializeClosure(Isolate* isolate,
10683 Handle<Context> context) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010684 ASSERT(context->IsFunctionContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010685
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010686 Handle<SharedFunctionInfo> shared(context->closure()->shared());
ager@chromium.orgb5737492010-07-15 09:29:43 +000010687 Handle<SerializedScopeInfo> serialized_scope_info(shared->scope_info());
10688 ScopeInfo<> scope_info(*serialized_scope_info);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010689
10690 // Allocate and initialize a JSObject with all the content of theis function
10691 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010692 Handle<JSObject> closure_scope =
10693 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010694
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010695 // Fill all context locals to the context extension.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010696 if (!CopyContextLocalsToScopeObject(isolate,
10697 serialized_scope_info, scope_info,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010698 context, closure_scope)) {
10699 return Handle<JSObject>();
10700 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010701
10702 // Finally copy any properties from the function context extension. This will
10703 // be variables introduced by eval.
10704 if (context->has_extension()) {
10705 Handle<JSObject> ext(JSObject::cast(context->extension()));
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010706 Handle<FixedArray> keys = GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010707 for (int i = 0; i < keys->length(); i++) {
10708 // Names of variables introduced by eval are strings.
10709 ASSERT(keys->get(i)->IsString());
10710 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010711 RETURN_IF_EMPTY_HANDLE_VALUE(
10712 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000010713 SetProperty(closure_scope,
10714 key,
10715 GetProperty(ext, key),
10716 NONE,
10717 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010718 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010719 }
10720 }
10721
10722 return closure_scope;
10723}
10724
10725
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010726// Create a plain JSObject which materializes the scope for the specified
10727// catch context.
10728static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
10729 Handle<Context> context) {
10730 ASSERT(context->IsCatchContext());
10731 Handle<String> name(String::cast(context->extension()));
10732 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX));
10733 Handle<JSObject> catch_scope =
10734 isolate->factory()->NewJSObject(isolate->object_function());
10735 RETURN_IF_EMPTY_HANDLE_VALUE(
10736 isolate,
10737 SetProperty(catch_scope, name, thrown_object, NONE, kNonStrictMode),
10738 Handle<JSObject>());
10739 return catch_scope;
10740}
10741
10742
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010743// Create a plain JSObject which materializes the block scope for the specified
10744// block context.
10745static Handle<JSObject> MaterializeBlockScope(
10746 Isolate* isolate,
10747 Handle<Context> context) {
10748 ASSERT(context->IsBlockContext());
10749 Handle<SerializedScopeInfo> serialized_scope_info(
10750 SerializedScopeInfo::cast(context->extension()));
10751 ScopeInfo<> scope_info(*serialized_scope_info);
10752
10753 // Allocate and initialize a JSObject with all the arguments, stack locals
10754 // heap locals and extension properties of the debugged function.
10755 Handle<JSObject> block_scope =
10756 isolate->factory()->NewJSObject(isolate->object_function());
10757
10758 // Fill all context locals.
10759 if (scope_info.number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
10760 if (!CopyContextLocalsToScopeObject(isolate,
10761 serialized_scope_info, scope_info,
10762 context, block_scope)) {
10763 return Handle<JSObject>();
10764 }
10765 }
10766
10767 return block_scope;
10768}
10769
10770
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010771// Iterate over the actual scopes visible from a stack frame. All scopes are
10772// backed by an actual context except the local scope, which is inserted
10773// "artifically" in the context chain.
10774class ScopeIterator {
10775 public:
10776 enum ScopeType {
10777 ScopeTypeGlobal = 0,
10778 ScopeTypeLocal,
10779 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000010780 ScopeTypeClosure,
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010781 ScopeTypeCatch,
10782 ScopeTypeBlock
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010783 };
10784
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010785 ScopeIterator(Isolate* isolate,
10786 JavaScriptFrame* frame,
10787 int inlined_frame_index)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010788 : isolate_(isolate),
10789 frame_(frame),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010790 inlined_frame_index_(inlined_frame_index),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010791 function_(JSFunction::cast(frame->function())),
10792 context_(Context::cast(frame->context())),
10793 local_done_(false),
10794 at_local_(false) {
10795
10796 // Check whether the first scope is actually a local scope.
10797 if (context_->IsGlobalContext()) {
10798 // If there is a stack slot for .result then this local scope has been
10799 // created for evaluating top level code and it is not a real local scope.
10800 // Checking for the existence of .result seems fragile, but the scope info
10801 // saved with the code object does not otherwise have that information.
ager@chromium.orgb5737492010-07-15 09:29:43 +000010802 int index = function_->shared()->scope_info()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010803 StackSlotIndex(isolate_->heap()->result_symbol());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010804 at_local_ = index < 0;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010805 } else if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010806 at_local_ = true;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010807 } else if (context_->closure() != *function_) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010808 // The context_ is a block or with or catch block from the outer function.
10809 ASSERT(context_->IsWithContext() ||
10810 context_->IsCatchContext() ||
10811 context_->IsBlockContext());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000010812 at_local_ = true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010813 }
10814 }
10815
10816 // More scopes?
10817 bool Done() { return context_.is_null(); }
10818
10819 // Move to the next scope.
10820 void Next() {
10821 // If at a local scope mark the local scope as passed.
10822 if (at_local_) {
10823 at_local_ = false;
10824 local_done_ = true;
10825
10826 // If the current context is not associated with the local scope the
10827 // current context is the next real scope, so don't move to the next
10828 // context in this case.
10829 if (context_->closure() != *function_) {
10830 return;
10831 }
10832 }
10833
10834 // The global scope is always the last in the chain.
10835 if (context_->IsGlobalContext()) {
10836 context_ = Handle<Context>();
10837 return;
10838 }
10839
10840 // Move to the next context.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010841 context_ = Handle<Context>(context_->previous(), isolate_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010842
10843 // If passing the local scope indicate that the current scope is now the
10844 // local scope.
10845 if (!local_done_ &&
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010846 (context_->IsGlobalContext() || context_->IsFunctionContext())) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010847 at_local_ = true;
10848 }
10849 }
10850
10851 // Return the type of the current scope.
10852 int Type() {
10853 if (at_local_) {
10854 return ScopeTypeLocal;
10855 }
10856 if (context_->IsGlobalContext()) {
10857 ASSERT(context_->global()->IsGlobalObject());
10858 return ScopeTypeGlobal;
10859 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010860 if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010861 return ScopeTypeClosure;
10862 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010863 if (context_->IsCatchContext()) {
ager@chromium.orga1645e22009-09-09 19:27:10 +000010864 return ScopeTypeCatch;
10865 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010866 if (context_->IsBlockContext()) {
10867 return ScopeTypeBlock;
10868 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010869 ASSERT(context_->IsWithContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010870 return ScopeTypeWith;
10871 }
10872
10873 // Return the JavaScript object with the content of the current scope.
10874 Handle<JSObject> ScopeObject() {
10875 switch (Type()) {
10876 case ScopeIterator::ScopeTypeGlobal:
10877 return Handle<JSObject>(CurrentContext()->global());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010878 case ScopeIterator::ScopeTypeLocal:
10879 // Materialize the content of the local scope into a JSObject.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010880 return MaterializeLocalScope(isolate_, frame_, inlined_frame_index_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010881 case ScopeIterator::ScopeTypeWith:
10882 // Return the with object.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010883 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
10884 case ScopeIterator::ScopeTypeCatch:
10885 return MaterializeCatchScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010886 case ScopeIterator::ScopeTypeClosure:
10887 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010888 return MaterializeClosure(isolate_, CurrentContext());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010889 case ScopeIterator::ScopeTypeBlock:
10890 return MaterializeBlockScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010891 }
10892 UNREACHABLE();
10893 return Handle<JSObject>();
10894 }
10895
10896 // Return the context for this scope. For the local context there might not
10897 // be an actual context.
10898 Handle<Context> CurrentContext() {
10899 if (at_local_ && context_->closure() != *function_) {
10900 return Handle<Context>();
10901 }
10902 return context_;
10903 }
10904
10905#ifdef DEBUG
10906 // Debug print of the content of the current scope.
10907 void DebugPrint() {
10908 switch (Type()) {
10909 case ScopeIterator::ScopeTypeGlobal:
10910 PrintF("Global:\n");
10911 CurrentContext()->Print();
10912 break;
10913
10914 case ScopeIterator::ScopeTypeLocal: {
10915 PrintF("Local:\n");
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010916 ScopeInfo<> scope_info(function_->shared()->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010917 scope_info.Print();
10918 if (!CurrentContext().is_null()) {
10919 CurrentContext()->Print();
10920 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010921 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010922 if (extension->IsJSContextExtensionObject()) {
10923 extension->Print();
10924 }
10925 }
10926 }
10927 break;
10928 }
10929
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010930 case ScopeIterator::ScopeTypeWith:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010931 PrintF("With:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010932 CurrentContext()->extension()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010933 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010934
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010935 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orga1645e22009-09-09 19:27:10 +000010936 PrintF("Catch:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010937 CurrentContext()->extension()->Print();
10938 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
ager@chromium.orga1645e22009-09-09 19:27:10 +000010939 break;
ager@chromium.orga1645e22009-09-09 19:27:10 +000010940
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010941 case ScopeIterator::ScopeTypeClosure:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010942 PrintF("Closure:\n");
10943 CurrentContext()->Print();
10944 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000010945 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010946 if (extension->IsJSContextExtensionObject()) {
10947 extension->Print();
10948 }
10949 }
10950 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010951
10952 default:
10953 UNREACHABLE();
10954 }
10955 PrintF("\n");
10956 }
10957#endif
10958
10959 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010960 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010961 JavaScriptFrame* frame_;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010962 int inlined_frame_index_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010963 Handle<JSFunction> function_;
10964 Handle<Context> context_;
10965 bool local_done_;
10966 bool at_local_;
10967
10968 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
10969};
10970
10971
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010972RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010973 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010974 ASSERT(args.length() == 2);
10975
10976 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010977 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010978 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10979 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010980 if (!maybe_check->ToObject(&check)) return maybe_check;
10981 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010982 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
10983
10984 // Get the frame where the debugging is performed.
10985 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010986 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010987 JavaScriptFrame* frame = it.frame();
10988
10989 // Count the visible scopes.
10990 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010991 for (ScopeIterator it(isolate, frame, 0);
10992 !it.Done();
10993 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010994 n++;
10995 }
10996
10997 return Smi::FromInt(n);
10998}
10999
11000
11001static const int kScopeDetailsTypeIndex = 0;
11002static const int kScopeDetailsObjectIndex = 1;
11003static const int kScopeDetailsSize = 2;
11004
11005// Return an array with scope details
11006// args[0]: number: break id
11007// args[1]: number: frame index
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011008// args[2]: number: inlined frame index
11009// args[3]: number: scope index
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011010//
11011// The array returned contains the following information:
11012// 0: Scope type
11013// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011014RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011015 HandleScope scope(isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011016 ASSERT(args.length() == 4);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011017
11018 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011019 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011020 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11021 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011022 if (!maybe_check->ToObject(&check)) return maybe_check;
11023 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011024 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011025 CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]);
11026 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011027
11028 // Get the frame where the debugging is performed.
11029 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011030 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011031 JavaScriptFrame* frame = frame_it.frame();
11032
11033 // Find the requested scope.
11034 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011035 ScopeIterator it(isolate, frame, inlined_frame_index);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011036 for (; !it.Done() && n < index; it.Next()) {
11037 n++;
11038 }
11039 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011040 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011041 }
11042
11043 // Calculate the size of the result.
11044 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011045 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011046
11047 // Fill in scope details.
11048 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011049 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011050 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011051 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011052
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011053 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011054}
11055
11056
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011057RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011058 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011059 ASSERT(args.length() == 0);
11060
11061#ifdef DEBUG
11062 // Print the scopes for the top frame.
11063 StackFrameLocator locator;
11064 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011065 for (ScopeIterator it(isolate, frame, 0);
11066 !it.Done();
11067 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011068 it.DebugPrint();
11069 }
11070#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011071 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011072}
11073
11074
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011075RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011076 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011077 ASSERT(args.length() == 1);
11078
11079 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011080 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011081 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
11082 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011083 if (!maybe_result->ToObject(&result)) return maybe_result;
11084 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011085
11086 // Count all archived V8 threads.
11087 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011088 for (ThreadState* thread =
11089 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011090 thread != NULL;
11091 thread = thread->Next()) {
11092 n++;
11093 }
11094
11095 // Total number of threads is current thread and archived threads.
11096 return Smi::FromInt(n + 1);
11097}
11098
11099
11100static const int kThreadDetailsCurrentThreadIndex = 0;
11101static const int kThreadDetailsThreadIdIndex = 1;
11102static const int kThreadDetailsSize = 2;
11103
11104// Return an array with thread details
11105// args[0]: number: break id
11106// args[1]: number: thread index
11107//
11108// The array returned contains the following information:
11109// 0: Is current thread?
11110// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011111RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011112 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011113 ASSERT(args.length() == 2);
11114
11115 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011116 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011117 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11118 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011119 if (!maybe_check->ToObject(&check)) return maybe_check;
11120 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011121 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
11122
11123 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011124 Handle<FixedArray> details =
11125 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011126
11127 // Thread index 0 is current thread.
11128 if (index == 0) {
11129 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011130 details->set(kThreadDetailsCurrentThreadIndex,
11131 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011132 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011133 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011134 } else {
11135 // Find the thread with the requested index.
11136 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011137 ThreadState* thread =
11138 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011139 while (index != n && thread != NULL) {
11140 thread = thread->Next();
11141 n++;
11142 }
11143 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011144 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011145 }
11146
11147 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011148 details->set(kThreadDetailsCurrentThreadIndex,
11149 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011150 details->set(kThreadDetailsThreadIdIndex,
11151 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011152 }
11153
11154 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011155 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011156}
11157
11158
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011159// Sets the disable break state
11160// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011161RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011162 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011163 ASSERT(args.length() == 1);
11164 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011165 isolate->debug()->set_disable_break(disable_break);
11166 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011167}
11168
11169
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011170RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011171 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011172 ASSERT(args.length() == 1);
11173
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011174 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
11175 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011176 // Find the number of break points
11177 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011178 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011179 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011180 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011181 Handle<FixedArray>::cast(break_locations));
11182}
11183
11184
11185// Set a break point in a function
11186// args[0]: function
11187// args[1]: number: break source position (within the function source)
11188// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011189RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011190 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011191 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011192 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
11193 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011194 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11195 RUNTIME_ASSERT(source_position >= 0);
11196 Handle<Object> break_point_object_arg = args.at<Object>(2);
11197
11198 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011199 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
11200 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011201
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011202 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011203}
11204
11205
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011206Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
11207 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011208 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011209 // Iterate the heap looking for SharedFunctionInfo generated from the
11210 // script. The inner most SharedFunctionInfo containing the source position
11211 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011212 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011213 // which is found is not compiled it is compiled and the heap is iterated
11214 // again as the compilation might create inner functions from the newly
11215 // compiled function and the actual requested break point might be in one of
11216 // these functions.
11217 bool done = false;
11218 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000011219 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011220 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011221 while (!done) {
11222 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011223 for (HeapObject* obj = iterator.next();
11224 obj != NULL; obj = iterator.next()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011225 if (obj->IsSharedFunctionInfo()) {
11226 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
11227 if (shared->script() == *script) {
11228 // If the SharedFunctionInfo found has the requested script data and
11229 // contains the source position it is a candidate.
11230 int start_position = shared->function_token_position();
ager@chromium.org236ad962008-09-25 09:45:57 +000011231 if (start_position == RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011232 start_position = shared->start_position();
11233 }
11234 if (start_position <= position &&
11235 position <= shared->end_position()) {
ager@chromium.org32912102009-01-16 10:38:43 +000011236 // If there is no candidate or this function is within the current
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011237 // candidate this is the new candidate.
11238 if (target.is_null()) {
11239 target_start_position = start_position;
11240 target = shared;
11241 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +000011242 if (target_start_position == start_position &&
11243 shared->end_position() == target->end_position()) {
11244 // If a top-level function contain only one function
11245 // declartion the source for the top-level and the function is
11246 // the same. In that case prefer the non top-level function.
11247 if (!shared->is_toplevel()) {
11248 target_start_position = start_position;
11249 target = shared;
11250 }
11251 } else if (target_start_position <= start_position &&
11252 shared->end_position() <= target->end_position()) {
11253 // This containment check includes equality as a function inside
11254 // a top-level function can share either start or end position
11255 // with the top-level function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011256 target_start_position = start_position;
11257 target = shared;
11258 }
11259 }
11260 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011261 }
11262 }
11263 }
11264
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011265 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011266 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011267 }
11268
11269 // If the candidate found is compiled we are done. NOTE: when lazy
11270 // compilation of inner functions is introduced some additional checking
11271 // needs to be done here to compile inner functions.
11272 done = target->is_compiled();
11273 if (!done) {
11274 // If the candidate is not compiled compile it to reveal any inner
11275 // functions which might contain the requested source position.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011276 CompileLazyShared(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011277 }
11278 }
11279
11280 return *target;
11281}
11282
11283
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011284// Changes the state of a break point in a script and returns source position
11285// where break point was set. NOTE: Regarding performance see the NOTE for
11286// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011287// args[0]: script to set break point in
11288// args[1]: number: break source position (within the script source)
11289// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011290RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011291 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011292 ASSERT(args.length() == 3);
11293 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
11294 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11295 RUNTIME_ASSERT(source_position >= 0);
11296 Handle<Object> break_point_object_arg = args.at<Object>(2);
11297
11298 // Get the script from the script wrapper.
11299 RUNTIME_ASSERT(wrapper->value()->IsScript());
11300 Handle<Script> script(Script::cast(wrapper->value()));
11301
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011302 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011303 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011304 if (!result->IsUndefined()) {
11305 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
11306 // Find position within function. The script position might be before the
11307 // source position of the first function.
11308 int position;
11309 if (shared->start_position() > source_position) {
11310 position = 0;
11311 } else {
11312 position = source_position - shared->start_position();
11313 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011314 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011315 position += shared->start_position();
11316 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011317 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011318 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011319}
11320
11321
11322// Clear a break point
11323// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011324RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011325 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011326 ASSERT(args.length() == 1);
11327 Handle<Object> break_point_object_arg = args.at<Object>(0);
11328
11329 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011330 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011331
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011332 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011333}
11334
11335
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011336// Change the state of break on exceptions.
11337// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
11338// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011339RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011340 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011341 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011342 RUNTIME_ASSERT(args[0]->IsNumber());
11343 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011344
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011345 // If the number doesn't match an enum value, the ChangeBreakOnException
11346 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011347 ExceptionBreakType type =
11348 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011349 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011350 isolate->debug()->ChangeBreakOnException(type, enable);
11351 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011352}
11353
11354
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011355// Returns the state of break on exceptions
11356// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011357RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011358 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011359 ASSERT(args.length() == 1);
11360 RUNTIME_ASSERT(args[0]->IsNumber());
11361
11362 ExceptionBreakType type =
11363 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011364 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011365 return Smi::FromInt(result);
11366}
11367
11368
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011369// Prepare for stepping
11370// args[0]: break id for checking execution state
11371// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000011372// args[2]: number of times to perform the step, for step out it is the number
11373// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011374RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011375 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011376 ASSERT(args.length() == 3);
11377 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011378 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011379 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11380 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011381 if (!maybe_check->ToObject(&check)) return maybe_check;
11382 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011383 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011384 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011385 }
11386
11387 // Get the step action and check validity.
11388 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
11389 if (step_action != StepIn &&
11390 step_action != StepNext &&
11391 step_action != StepOut &&
11392 step_action != StepInMin &&
11393 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011394 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011395 }
11396
11397 // Get the number of steps.
11398 int step_count = NumberToInt32(args[2]);
11399 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011400 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011401 }
11402
ager@chromium.orga1645e22009-09-09 19:27:10 +000011403 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011404 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011405
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011406 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011407 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
11408 step_count);
11409 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011410}
11411
11412
11413// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011414RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011415 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011416 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011417 isolate->debug()->ClearStepping();
11418 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011419}
11420
11421
11422// Creates a copy of the with context chain. The copy of the context chain is
11423// is linked to the function context supplied.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011424static Handle<Context> CopyWithContextChain(Isolate* isolate,
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011425 Handle<JSFunction> function,
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011426 Handle<Context> current,
11427 Handle<Context> base) {
11428 // At the end of the chain. Return the base context to link to.
11429 if (current->IsFunctionContext() || current->IsGlobalContext()) {
11430 return base;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011431 }
11432
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011433 // Recursively copy the with and catch contexts.
11434 HandleScope scope(isolate);
11435 Handle<Context> previous(current->previous());
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011436 Handle<Context> new_previous =
11437 CopyWithContextChain(isolate, function, previous, base);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011438 Handle<Context> new_current;
11439 if (current->IsCatchContext()) {
11440 Handle<String> name(String::cast(current->extension()));
11441 Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
11442 new_current =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011443 isolate->factory()->NewCatchContext(function,
11444 new_previous,
11445 name,
11446 thrown_object);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011447 } else if (current->IsBlockContext()) {
11448 Handle<SerializedScopeInfo> scope_info(
11449 SerializedScopeInfo::cast(current->extension()));
11450 new_current =
11451 isolate->factory()->NewBlockContext(function, new_previous, scope_info);
danno@chromium.orgb6451162011-08-17 14:33:23 +000011452 // Copy context slots.
11453 int num_context_slots = scope_info->NumberOfContextSlots();
11454 for (int i = Context::MIN_CONTEXT_SLOTS; i < num_context_slots; ++i) {
11455 new_current->set(i, current->get(i));
11456 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011457 } else {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011458 ASSERT(current->IsWithContext());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011459 Handle<JSObject> extension(JSObject::cast(current->extension()));
11460 new_current =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011461 isolate->factory()->NewWithContext(function, new_previous, extension);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011462 }
11463 return scope.CloseAndEscape(new_current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011464}
11465
11466
11467// Helper function to find or create the arguments object for
11468// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011469static Handle<Object> GetArgumentsObject(Isolate* isolate,
11470 JavaScriptFrame* frame,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011471 int inlined_frame_index,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011472 Handle<JSFunction> function,
ager@chromium.orgb5737492010-07-15 09:29:43 +000011473 Handle<SerializedScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011474 const ScopeInfo<>* sinfo,
11475 Handle<Context> function_context) {
11476 // Try to find the value of 'arguments' to pass as parameter. If it is not
11477 // found (that is the debugged function does not reference 'arguments' and
11478 // does not support eval) then create an 'arguments' object.
11479 int index;
11480 if (sinfo->number_of_stack_slots() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011481 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011482 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011483 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011484 }
11485 }
11486
11487 if (sinfo->number_of_context_slots() > Context::MIN_CONTEXT_SLOTS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011488 index = scope_info->ContextSlotIndex(isolate->heap()->arguments_symbol(),
11489 NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011490 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011491 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011492 }
11493 }
11494
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011495 FrameInspector frame_inspector(frame, inlined_frame_index, isolate);
11496
11497 int length = frame_inspector.GetParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011498 Handle<JSObject> arguments =
11499 isolate->factory()->NewArgumentsObject(function, length);
11500 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011501
11502 AssertNoAllocation no_gc;
11503 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011504 for (int i = 0; i < length; i++) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011505 array->set(i, frame_inspector.GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011506 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000011507 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011508 return arguments;
11509}
11510
11511
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011512static const char kSourceStr[] =
11513 "(function(arguments,__source__){return eval(__source__);})";
11514
11515
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011516// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000011517// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011518// extension part has all the parameters and locals of the function on the
11519// stack frame. A function which calls eval with the code to evaluate is then
11520// compiled in this context and called in this context. As this context
11521// replaces the context of the function on the stack frame a new (empty)
11522// function is created as well to be used as the closure for the context.
11523// This function and the context acts as replacements for the function on the
11524// stack frame presenting the same view of the values of parameters and
11525// local variables as if the piece of JavaScript was evaluated at the point
11526// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011527RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011528 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011529
11530 // Check the execution state and decode arguments frame and source to be
11531 // evaluated.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011532 ASSERT(args.length() == 6);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011533 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011534 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11535 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011536 if (!maybe_check_result->ToObject(&check_result)) {
11537 return maybe_check_result;
11538 }
11539 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011540 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011541 CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]);
11542 CONVERT_ARG_CHECKED(String, source, 3);
11543 CONVERT_BOOLEAN_CHECKED(disable_break, args[4]);
11544 Handle<Object> additional_context(args[5]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011545
11546 // Handle the processing of break.
11547 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011548
11549 // Get the frame where the debugging is performed.
11550 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011551 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011552 JavaScriptFrame* frame = it.frame();
11553 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.orgb5737492010-07-15 09:29:43 +000011554 Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011555 ScopeInfo<> sinfo(*scope_info);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011556
11557 // Traverse the saved contexts chain to find the active context for the
11558 // selected frame.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011559 SaveContext* save = isolate->save_context();
ager@chromium.orga74f0da2008-12-03 16:05:52 +000011560 while (save != NULL && !save->below(frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011561 save = save->prev();
11562 }
11563 ASSERT(save != NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011564 SaveContext savex(isolate);
11565 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011566
11567 // Create the (empty) function replacing the function on the stack frame for
11568 // the purpose of evaluating in the context created below. It is important
11569 // that this function does not describe any parameters and local variables
11570 // in the context. If it does then this will cause problems with the lookup
11571 // in Context::Lookup, where context slots for parameters and local variables
11572 // are looked at before the extension object.
11573 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011574 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
11575 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011576 go_between->set_context(function->context());
11577#ifdef DEBUG
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011578 ScopeInfo<> go_between_sinfo(go_between->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011579 ASSERT(go_between_sinfo.number_of_parameters() == 0);
11580 ASSERT(go_between_sinfo.number_of_context_slots() == 0);
11581#endif
11582
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011583 // Materialize the content of the local scope into a JSObject.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011584 Handle<JSObject> local_scope = MaterializeLocalScope(
11585 isolate, frame, inlined_frame_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011586 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011587
11588 // Allocate a new context for the debug evaluation and set the extension
11589 // object build.
11590 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011591 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
11592 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011593 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011594 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011595 Handle<Context> frame_context(Context::cast(frame->context()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000011596 Handle<Context> function_context;
11597 // Get the function's context if it has one.
11598 if (scope_info->HasHeapAllocatedLocals()) {
11599 function_context = Handle<Context>(frame_context->declaration_context());
11600 }
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011601 context = CopyWithContextChain(isolate, go_between, frame_context, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011602
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011603 if (additional_context->IsJSObject()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011604 Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000011605 context =
11606 isolate->factory()->NewWithContext(go_between, context, extension);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011607 }
11608
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011609 // Wrap the evaluation statement in a new function compiled in the newly
11610 // created context. The function has one parameter which has to be called
11611 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000011612 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011613 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011614
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011615 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011616 isolate->factory()->NewStringFromAscii(
11617 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011618
11619 // Currently, the eval code will be executed in non-strict mode,
11620 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011621 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000011622 Compiler::CompileEval(function_source,
11623 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011624 context->IsGlobalContext(),
11625 kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011626 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011627 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011628 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011629
11630 // Invoke the result of the compilation to get the evaluation function.
11631 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011632 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011633 Handle<Object> evaluation_function =
11634 Execution::Call(compiled_function, receiver, 0, NULL,
11635 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011636 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011637
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011638 Handle<Object> arguments = GetArgumentsObject(isolate,
11639 frame, inlined_frame_index,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011640 function, scope_info,
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011641 &sinfo, function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011642
11643 // Invoke the evaluation function and return the result.
11644 const int argc = 2;
11645 Object** argv[argc] = { arguments.location(),
11646 Handle<Object>::cast(source).location() };
11647 Handle<Object> result =
11648 Execution::Call(Handle<JSFunction>::cast(evaluation_function), receiver,
11649 argc, argv, &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011650 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011651
11652 // Skip the global proxy as it has no properties and always delegates to the
11653 // real global object.
11654 if (result->IsJSGlobalProxy()) {
11655 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
11656 }
11657
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011658 return *result;
11659}
11660
11661
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011662RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011663 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011664
11665 // Check the execution state and decode arguments frame and source to be
11666 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011667 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011668 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011669 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
11670 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011671 if (!maybe_check_result->ToObject(&check_result)) {
11672 return maybe_check_result;
11673 }
11674 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011675 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011676 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011677 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000011678
11679 // Handle the processing of break.
11680 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011681
11682 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011683 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011684 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011685 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011686 top = top->prev();
11687 }
11688 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011689 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011690 }
11691
11692 // Get the global context now set to the top context from before the
11693 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011694 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011695
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011696 bool is_global = true;
11697
11698 if (additional_context->IsJSObject()) {
11699 // Create a function context first, than put 'with' context on top of it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011700 Handle<JSFunction> go_between = isolate->factory()->NewFunction(
11701 isolate->factory()->empty_string(),
11702 isolate->factory()->undefined_value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011703 go_between->set_context(*context);
11704 context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011705 isolate->factory()->NewFunctionContext(
11706 Context::MIN_CONTEXT_SLOTS, go_between);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000011707 context->set_extension(JSObject::cast(*additional_context));
11708 is_global = false;
11709 }
11710
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011711 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011712 // Currently, the eval code will be executed in non-strict mode,
11713 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011714 Handle<SharedFunctionInfo> shared =
ricow@chromium.org83aa5492011-02-07 12:42:56 +000011715 Compiler::CompileEval(source, context, is_global, kNonStrictMode);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000011716 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011717 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011718 Handle<JSFunction>(
11719 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
11720 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011721
11722 // Invoke the result of the compilation to get the evaluation function.
11723 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011724 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011725 Handle<Object> result =
11726 Execution::Call(compiled_function, receiver, 0, NULL,
11727 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000011728 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011729 return *result;
11730}
11731
11732
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011733RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011734 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011735 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011736
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011737 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011738 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011739
11740 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000011741 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000011742 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
11743 // Get the script wrapper in a local handle before calling GetScriptWrapper,
11744 // because using
11745 // instances->set(i, *GetScriptWrapper(script))
11746 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
11747 // already have deferenced the instances handle.
11748 Handle<JSValue> wrapper = GetScriptWrapper(script);
11749 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011750 }
11751
11752 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011753 Handle<JSObject> result =
11754 isolate->factory()->NewJSObject(isolate->array_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011755 Handle<JSArray>::cast(result)->SetContent(*instances);
11756 return *result;
11757}
11758
11759
11760// Helper function used by Runtime_DebugReferencedBy below.
11761static int DebugReferencedBy(JSObject* target,
11762 Object* instance_filter, int max_references,
11763 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011764 JSFunction* arguments_function) {
11765 NoHandleAllocation ha;
11766 AssertNoAllocation no_alloc;
11767
11768 // Iterate the heap.
11769 int count = 0;
11770 JSObject* last = NULL;
11771 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011772 HeapObject* heap_obj = NULL;
11773 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011774 (max_references == 0 || count < max_references)) {
11775 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011776 if (heap_obj->IsJSObject()) {
11777 // Skip context extension objects and argument arrays as these are
11778 // checked in the context of functions using them.
11779 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000011780 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011781 obj->map()->constructor() == arguments_function) {
11782 continue;
11783 }
11784
11785 // Check if the JS object has a reference to the object looked for.
11786 if (obj->ReferencesObject(target)) {
11787 // Check instance filter if supplied. This is normally used to avoid
11788 // references from mirror objects (see Runtime_IsInPrototypeChain).
11789 if (!instance_filter->IsUndefined()) {
11790 Object* V = obj;
11791 while (true) {
11792 Object* prototype = V->GetPrototype();
11793 if (prototype->IsNull()) {
11794 break;
11795 }
11796 if (instance_filter == prototype) {
11797 obj = NULL; // Don't add this object.
11798 break;
11799 }
11800 V = prototype;
11801 }
11802 }
11803
11804 if (obj != NULL) {
11805 // Valid reference found add to instance array if supplied an update
11806 // count.
11807 if (instances != NULL && count < instances_size) {
11808 instances->set(count, obj);
11809 }
11810 last = obj;
11811 count++;
11812 }
11813 }
11814 }
11815 }
11816
11817 // Check for circular reference only. This can happen when the object is only
11818 // referenced from mirrors and has a circular reference in which case the
11819 // object is not really alive and would have been garbage collected if not
11820 // referenced from the mirror.
11821 if (count == 1 && last == target) {
11822 count = 0;
11823 }
11824
11825 // Return the number of referencing objects found.
11826 return count;
11827}
11828
11829
11830// Scan the heap for objects with direct references to an object
11831// args[0]: the object to find references to
11832// args[1]: constructor function for instances to exclude (Mirror)
11833// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011834RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011835 ASSERT(args.length() == 3);
11836
11837 // First perform a full GC in order to avoid references from dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011838 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011839
11840 // Check parameters.
11841 CONVERT_CHECKED(JSObject, target, args[0]);
11842 Object* instance_filter = args[1];
11843 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
11844 instance_filter->IsJSObject());
11845 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
11846 RUNTIME_ASSERT(max_references >= 0);
11847
11848 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011849 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011850 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011851 JSFunction* arguments_function =
11852 JSFunction::cast(arguments_boilerplate->map()->constructor());
11853
11854 // Get the number of referencing objects.
11855 int count;
11856 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000011857 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011858
11859 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011860 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011861 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011862 if (!maybe_object->ToObject(&object)) return maybe_object;
11863 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011864 FixedArray* instances = FixedArray::cast(object);
11865
11866 // Fill the referencing objects.
11867 count = DebugReferencedBy(target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000011868 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011869
11870 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011871 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011872 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
11873 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011874 if (!maybe_result->ToObject(&result)) return maybe_result;
11875 }
11876 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011877 return result;
11878}
11879
11880
11881// Helper function used by Runtime_DebugConstructedBy below.
11882static int DebugConstructedBy(JSFunction* constructor, int max_references,
11883 FixedArray* instances, int instances_size) {
11884 AssertNoAllocation no_alloc;
11885
11886 // Iterate the heap.
11887 int count = 0;
11888 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011889 HeapObject* heap_obj = NULL;
11890 while (((heap_obj = iterator.next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011891 (max_references == 0 || count < max_references)) {
11892 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011893 if (heap_obj->IsJSObject()) {
11894 JSObject* obj = JSObject::cast(heap_obj);
11895 if (obj->map()->constructor() == constructor) {
11896 // Valid reference found add to instance array if supplied an update
11897 // count.
11898 if (instances != NULL && count < instances_size) {
11899 instances->set(count, obj);
11900 }
11901 count++;
11902 }
11903 }
11904 }
11905
11906 // Return the number of referencing objects found.
11907 return count;
11908}
11909
11910
11911// Scan the heap for objects constructed by a specific function.
11912// args[0]: the constructor to find instances of
11913// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011914RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011915 ASSERT(args.length() == 2);
11916
11917 // First perform a full GC in order to avoid dead objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011918 isolate->heap()->CollectAllGarbage(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011919
11920 // Check parameters.
11921 CONVERT_CHECKED(JSFunction, constructor, args[0]);
11922 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
11923 RUNTIME_ASSERT(max_references >= 0);
11924
11925 // Get the number of referencing objects.
11926 int count;
11927 count = DebugConstructedBy(constructor, max_references, NULL, 0);
11928
11929 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011930 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011931 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000011932 if (!maybe_object->ToObject(&object)) return maybe_object;
11933 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011934 FixedArray* instances = FixedArray::cast(object);
11935
11936 // Fill the referencing objects.
11937 count = DebugConstructedBy(constructor, max_references, instances, count);
11938
11939 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011940 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011941 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
11942 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000011943 if (!maybe_result->ToObject(&result)) return maybe_result;
11944 }
11945 JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011946 return result;
11947}
11948
11949
ager@chromium.orgddb913d2009-01-27 10:01:48 +000011950// Find the effective prototype object as returned by __proto__.
11951// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011952RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011953 ASSERT(args.length() == 1);
11954
11955 CONVERT_CHECKED(JSObject, obj, args[0]);
11956
ager@chromium.orgddb913d2009-01-27 10:01:48 +000011957 // Use the __proto__ accessor.
11958 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011959}
11960
11961
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011962RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000011963 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011964 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011965 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011966}
11967
11968
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011969RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011970#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011971 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011972 ASSERT(args.length() == 1);
11973 // Get the function and make sure it is compiled.
11974 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011975 Handle<SharedFunctionInfo> shared(func->shared());
11976 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011977 return Failure::Exception();
11978 }
11979 func->code()->PrintLn();
11980#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011981 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000011982}
ager@chromium.org9085a012009-05-11 19:22:57 +000011983
11984
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011985RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011986#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011987 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011988 ASSERT(args.length() == 1);
11989 // Get the function and make sure it is compiled.
11990 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011991 Handle<SharedFunctionInfo> shared(func->shared());
11992 if (!EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011993 return Failure::Exception();
11994 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000011995 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011996#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011997 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000011998}
11999
12000
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012001RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000012002 NoHandleAllocation ha;
12003 ASSERT(args.length() == 1);
12004
12005 CONVERT_CHECKED(JSFunction, f, args[0]);
12006 return f->shared()->inferred_name();
12007}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012008
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012009
12010static int FindSharedFunctionInfosForScript(Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012011 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012012 AssertNoAllocation no_allocations;
12013
12014 int counter = 0;
12015 int buffer_size = buffer->length();
12016 HeapIterator iterator;
12017 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
12018 ASSERT(obj != NULL);
12019 if (!obj->IsSharedFunctionInfo()) {
12020 continue;
12021 }
12022 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
12023 if (shared->script() != script) {
12024 continue;
12025 }
12026 if (counter < buffer_size) {
12027 buffer->set(counter, shared);
12028 }
12029 counter++;
12030 }
12031 return counter;
12032}
12033
12034// For a script finds all SharedFunctionInfo's in the heap that points
12035// to this script. Returns JSArray of SharedFunctionInfo wrapped
12036// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012037RUNTIME_FUNCTION(MaybeObject*,
12038 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012039 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012040 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012041 CONVERT_CHECKED(JSValue, script_value, args[0]);
12042
12043 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
12044
12045 const int kBufferSize = 32;
12046
12047 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012048 array = isolate->factory()->NewFixedArray(kBufferSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012049 int number = FindSharedFunctionInfosForScript(*script, *array);
12050 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012051 array = isolate->factory()->NewFixedArray(number);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012052 FindSharedFunctionInfosForScript(*script, *array);
12053 }
12054
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012055 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012056 result->set_length(Smi::FromInt(number));
12057
12058 LiveEdit::WrapSharedFunctionInfos(result);
12059
12060 return *result;
12061}
12062
12063// For a script calculates compilation information about all its functions.
12064// The script source is explicitly specified by the second argument.
12065// The source of the actual script is not used, however it is important that
12066// all generated code keeps references to this particular instance of script.
12067// Returns a JSArray of compilation infos. The array is ordered so that
12068// each function with all its descendant is always stored in a continues range
12069// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012070RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012071 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012072 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012073 CONVERT_CHECKED(JSValue, script, args[0]);
12074 CONVERT_ARG_CHECKED(String, source, 1);
12075 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
12076
12077 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
12078
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012079 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012080 return Failure::Exception();
12081 }
12082
12083 return result;
12084}
12085
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012086// Changes the source of the script to a new_source.
12087// If old_script_name is provided (i.e. is a String), also creates a copy of
12088// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012089RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012090 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012091 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012092 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
12093 CONVERT_ARG_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012094 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012095
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012096 CONVERT_CHECKED(Script, original_script_pointer,
12097 original_script_value->value());
12098 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012099
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012100 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
12101 new_source,
12102 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012103
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012104 if (old_script->IsScript()) {
12105 Handle<Script> script_handle(Script::cast(old_script));
12106 return *(GetScriptWrapper(script_handle));
12107 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012108 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012109 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012110}
12111
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012112
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012113RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012114 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012115 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012116 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
12117 return LiveEdit::FunctionSourceUpdated(shared_info);
12118}
12119
12120
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012121// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012122RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012123 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012124 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012125 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
12126 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
12127
ager@chromium.orgac091b72010-05-05 07:34:42 +000012128 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012129}
12130
12131// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012132RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012133 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012134 HandleScope scope(isolate);
12135 Handle<Object> function_object(args[0], isolate);
12136 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012137
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012138 if (function_object->IsJSValue()) {
12139 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
12140 if (script_object->IsJSValue()) {
12141 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012142 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012143 }
12144
12145 LiveEdit::SetFunctionScript(function_wrapper, script_object);
12146 } else {
12147 // Just ignore this. We may not have a SharedFunctionInfo for some functions
12148 // and we check it in this function.
12149 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012150
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012151 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012152}
12153
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012154
12155// In a code of a parent function replaces original function as embedded object
12156// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012157RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012158 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012159 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012160
12161 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
12162 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
12163 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
12164
12165 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
12166 subst_wrapper);
12167
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012168 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012169}
12170
12171
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012172// Updates positions of a shared function info (first parameter) according
12173// to script source change. Text change is described in second parameter as
12174// array of groups of 3 numbers:
12175// (change_begin, change_end, change_end_new_position).
12176// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012177RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012178 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012179 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012180 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
12181 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
12182
ager@chromium.orgac091b72010-05-05 07:34:42 +000012183 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012184}
12185
12186
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012187// For array of SharedFunctionInfo's (each wrapped in JSValue)
12188// checks that none of them have activations on stacks (of any thread).
12189// Returns array of the same length with corresponding results of
12190// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012191RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012192 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012193 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012194 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000012195 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012196
ager@chromium.org357bf652010-04-12 11:30:10 +000012197 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012198}
12199
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012200// Compares 2 strings line-by-line, then token-wise and returns diff in form
12201// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
12202// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012203RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012204 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012205 HandleScope scope(isolate);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012206 CONVERT_ARG_CHECKED(String, s1, 0);
12207 CONVERT_ARG_CHECKED(String, s2, 1);
12208
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012209 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012210}
12211
12212
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012213// A testing entry. Returns statement position which is the closest to
12214// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012215RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012216 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012217 HandleScope scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012218 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12219 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
12220
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012221 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012222
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012223 if (code->kind() != Code::FUNCTION &&
12224 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012225 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012226 }
12227
12228 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012229 int closest_pc = 0;
12230 int distance = kMaxInt;
12231 while (!it.done()) {
12232 int statement_position = static_cast<int>(it.rinfo()->data());
12233 // Check if this break point is closer that what was previously found.
12234 if (source_position <= statement_position &&
12235 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000012236 closest_pc =
12237 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012238 distance = statement_position - source_position;
12239 // Check whether we can't get any closer.
12240 if (distance == 0) break;
12241 }
12242 it.next();
12243 }
12244
12245 return Smi::FromInt(closest_pc);
12246}
12247
12248
ager@chromium.org357bf652010-04-12 11:30:10 +000012249// Calls specified function with or without entering the debugger.
12250// This is used in unit tests to run code as if debugger is entered or simply
12251// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012252RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012253 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012254 HandleScope scope(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +000012255 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12256 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
12257
12258 Handle<Object> result;
12259 bool pending_exception;
12260 {
12261 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012262 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012263 &pending_exception);
12264 } else {
12265 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012266 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012267 &pending_exception);
12268 }
12269 }
12270 if (!pending_exception) {
12271 return *result;
12272 } else {
12273 return Failure::Exception();
12274 }
12275}
12276
12277
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012278// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012279RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012280 CONVERT_CHECKED(String, arg, args[0]);
12281 SmartPointer<char> flags =
12282 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
12283 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012284 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012285}
12286
12287
12288// Performs a GC.
12289// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012290RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012291 isolate->heap()->CollectAllGarbage(true);
12292 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012293}
12294
12295
12296// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012297RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012298 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012299 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012300 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012301 }
12302 return Smi::FromInt(usage);
12303}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012304
12305
12306// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012307RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012308#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012309 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012310#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012311 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012312#endif
12313}
12314
12315
12316// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012317RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012318#ifdef LIVE_OBJECT_LIST
12319 return LiveObjectList::Capture();
12320#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012321 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012322#endif
12323}
12324
12325
12326// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012327RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012328#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012329 CONVERT_SMI_ARG_CHECKED(id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012330 bool success = LiveObjectList::Delete(id);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012331 return isolate->heap()->ToBoolean(success);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012332#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012333 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012334#endif
12335}
12336
12337
12338// Generates the response to a debugger request for a dump of the objects
12339// contained in the difference between the captured live object lists
12340// specified by id1 and id2.
12341// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12342// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012343RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012344#ifdef LIVE_OBJECT_LIST
12345 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012346 CONVERT_SMI_ARG_CHECKED(id1, 0);
12347 CONVERT_SMI_ARG_CHECKED(id2, 1);
12348 CONVERT_SMI_ARG_CHECKED(start, 2);
12349 CONVERT_SMI_ARG_CHECKED(count, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012350 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
12351 EnterDebugger enter_debugger;
12352 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
12353#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012354 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012355#endif
12356}
12357
12358
12359// Gets the specified object as requested by the debugger.
12360// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012361RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012362#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012363 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012364 Object* result = LiveObjectList::GetObj(obj_id);
12365 return result;
12366#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012367 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012368#endif
12369}
12370
12371
12372// Gets the obj id for the specified address if valid.
12373// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012374RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012375#ifdef LIVE_OBJECT_LIST
12376 HandleScope scope;
12377 CONVERT_ARG_CHECKED(String, address, 0);
12378 Object* result = LiveObjectList::GetObjId(address);
12379 return result;
12380#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012381 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012382#endif
12383}
12384
12385
12386// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012387RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012388#ifdef LIVE_OBJECT_LIST
12389 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012390 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012391 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
12392 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
12393 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
12394 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
12395 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
12396
12397 Handle<JSObject> instance_filter;
12398 if (args[1]->IsJSObject()) {
12399 instance_filter = args.at<JSObject>(1);
12400 }
12401 bool verbose = false;
12402 if (args[2]->IsBoolean()) {
12403 verbose = args[2]->IsTrue();
12404 }
12405 int start = 0;
12406 if (args[3]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012407 start = args.smi_at(3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012408 }
12409 int limit = Smi::kMaxValue;
12410 if (args[4]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012411 limit = args.smi_at(4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012412 }
12413
12414 return LiveObjectList::GetObjRetainers(obj_id,
12415 instance_filter,
12416 verbose,
12417 start,
12418 limit,
12419 filter_obj);
12420#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012421 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012422#endif
12423}
12424
12425
12426// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012427RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012428#ifdef LIVE_OBJECT_LIST
12429 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012430 CONVERT_SMI_ARG_CHECKED(obj_id1, 0);
12431 CONVERT_SMI_ARG_CHECKED(obj_id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012432 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
12433
12434 Handle<JSObject> instance_filter;
12435 if (args[2]->IsJSObject()) {
12436 instance_filter = args.at<JSObject>(2);
12437 }
12438
12439 Object* result =
12440 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
12441 return result;
12442#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012443 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012444#endif
12445}
12446
12447
12448// Generates the response to a debugger request for a list of all
12449// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012450RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012451#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012452 CONVERT_SMI_ARG_CHECKED(start, 0);
12453 CONVERT_SMI_ARG_CHECKED(count, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012454 return LiveObjectList::Info(start, count);
12455#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012456 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012457#endif
12458}
12459
12460
12461// Gets a dump of the specified object as requested by the debugger.
12462// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012463RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012464#ifdef LIVE_OBJECT_LIST
12465 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012466 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012467 Object* result = LiveObjectList::PrintObj(obj_id);
12468 return result;
12469#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012470 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012471#endif
12472}
12473
12474
12475// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012476RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012477#ifdef LIVE_OBJECT_LIST
12478 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012479 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012480#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012481 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012482#endif
12483}
12484
12485
12486// Generates the response to a debugger request for a summary of the types
12487// of objects in the difference between the captured live object lists
12488// specified by id1 and id2.
12489// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12490// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012491RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012492#ifdef LIVE_OBJECT_LIST
12493 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012494 CONVERT_SMI_ARG_CHECKED(id1, 0);
12495 CONVERT_SMI_ARG_CHECKED(id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012496 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
12497
12498 EnterDebugger enter_debugger;
12499 return LiveObjectList::Summarize(id1, id2, filter_obj);
12500#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012501 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012502#endif
12503}
12504
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012505#endif // ENABLE_DEBUGGER_SUPPORT
12506
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012507
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012508RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012509 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012510 v8::V8::ResumeProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012511 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012512}
12513
12514
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012515RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012516 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012517 v8::V8::PauseProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012518 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012519}
12520
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012521
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012522// Finds the script object from the script data. NOTE: This operation uses
12523// heap traversal to find the function generated for the source position
12524// for the requested break point. For lazily compiled functions several heap
12525// traversals might be required rendering this operation as a rather slow
12526// operation. However for setting break points which is normally done through
12527// some kind of user interaction the performance is not crucial.
12528static Handle<Object> Runtime_GetScriptFromScriptName(
12529 Handle<String> script_name) {
12530 // Scan the heap for Script objects to find the script with the requested
12531 // script data.
12532 Handle<Script> script;
12533 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012534 HeapObject* obj = NULL;
12535 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012536 // If a script is found check if it has the script data requested.
12537 if (obj->IsScript()) {
12538 if (Script::cast(obj)->name()->IsString()) {
12539 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
12540 script = Handle<Script>(Script::cast(obj));
12541 }
12542 }
12543 }
12544 }
12545
12546 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012547 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012548
12549 // Return the script found.
12550 return GetScriptWrapper(script);
12551}
12552
12553
12554// Get the script object from script data. NOTE: Regarding performance
12555// see the NOTE for GetScriptFromScriptData.
12556// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012557RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012558 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012559
12560 ASSERT(args.length() == 1);
12561
12562 CONVERT_CHECKED(String, script_name, args[0]);
12563
12564 // Find the requested script.
12565 Handle<Object> result =
12566 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
12567 return *result;
12568}
12569
12570
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012571// Determines whether the given stack frame should be displayed in
12572// a stack trace. The caller is the error constructor that asked
12573// for the stack trace to be collected. The first time a construct
12574// call to this function is encountered it is skipped. The seen_caller
12575// in/out parameter is used to remember if the caller has been seen
12576// yet.
rossberg@chromium.org717967f2011-07-20 13:44:42 +000012577static bool ShowFrameInStackTrace(StackFrame* raw_frame,
12578 Object* caller,
12579 bool* seen_caller) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012580 // Only display JS frames.
12581 if (!raw_frame->is_java_script())
12582 return false;
12583 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
12584 Object* raw_fun = frame->function();
12585 // Not sure when this can happen but skip it just in case.
12586 if (!raw_fun->IsJSFunction())
12587 return false;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012588 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012589 *seen_caller = true;
12590 return false;
12591 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000012592 // Skip all frames until we've seen the caller.
12593 if (!(*seen_caller)) return false;
12594 // Also, skip the most obvious builtin calls. We recognize builtins
12595 // as (1) functions called with the builtins object as the receiver and
12596 // as (2) functions from native scripts called with undefined as the
12597 // receiver (direct calls to helper functions in the builtins
12598 // code). Some builtin calls (such as Number.ADD which is invoked
12599 // using 'call') are very difficult to recognize so we're leaving
12600 // them in for now.
12601 if (frame->receiver()->IsJSBuiltinsObject()) {
12602 return false;
12603 }
12604 JSFunction* fun = JSFunction::cast(raw_fun);
12605 Object* raw_script = fun->shared()->script();
12606 if (frame->receiver()->IsUndefined() && raw_script->IsScript()) {
12607 int script_type = Script::cast(raw_script)->type()->value();
12608 return script_type != Script::TYPE_NATIVE;
12609 }
12610 return true;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012611}
12612
12613
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012614// Collect the raw data for a stack trace. Returns an array of 4
12615// element segments each containing a receiver, function, code and
12616// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012617RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012618 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012619 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012620 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
12621
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012622 HandleScope scope(isolate);
12623 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012624
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000012625 limit = Max(limit, 0); // Ensure that limit is not negative.
12626 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012627 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012628 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012629
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012630 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012631 // If the caller parameter is a function we skip frames until we're
12632 // under it before starting to collect.
12633 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012634 int cursor = 0;
12635 int frames_seen = 0;
12636 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012637 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000012638 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012639 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012640 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012641 // Set initial size to the maximum inlining level + 1 for the outermost
12642 // function.
12643 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012644 frame->Summarize(&frames);
12645 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012646 if (cursor + 4 > elements->length()) {
12647 int new_capacity = JSObject::NewElementsCapacity(elements->length());
12648 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012649 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012650 for (int i = 0; i < cursor; i++) {
12651 new_elements->set(i, elements->get(i));
12652 }
12653 elements = new_elements;
12654 }
12655 ASSERT(cursor + 4 <= elements->length());
12656
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012657 Handle<Object> recv = frames[i].receiver();
12658 Handle<JSFunction> fun = frames[i].function();
12659 Handle<Code> code = frames[i].code();
12660 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012661 elements->set(cursor++, *recv);
12662 elements->set(cursor++, *fun);
12663 elements->set(cursor++, *code);
12664 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012665 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012666 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000012667 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012668 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012669 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012670 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000012671 return *result;
12672}
12673
12674
ager@chromium.org3811b432009-10-28 14:53:37 +000012675// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012676RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000012677 ASSERT_EQ(args.length(), 0);
12678
12679 NoHandleAllocation ha;
12680
12681 const char* version_string = v8::V8::GetVersion();
12682
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012683 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
12684 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000012685}
12686
12687
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012688RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012689 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012690 OS::PrintError("abort: %s\n",
12691 reinterpret_cast<char*>(args[0]) + args.smi_at(1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012692 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012693 OS::Abort();
12694 UNREACHABLE();
12695 return NULL;
12696}
12697
12698
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012699RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012700 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012701 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012702 Object* key = args[1];
12703
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012704 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012705 Object* o = cache->get(finger_index);
12706 if (o == key) {
12707 // The fastest case: hit the same place again.
12708 return cache->get(finger_index + 1);
12709 }
12710
12711 for (int i = finger_index - 2;
12712 i >= JSFunctionResultCache::kEntriesIndex;
12713 i -= 2) {
12714 o = cache->get(i);
12715 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012716 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012717 return cache->get(i + 1);
12718 }
12719 }
12720
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012721 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012722 ASSERT(size <= cache->length());
12723
12724 for (int i = size - 2; i > finger_index; i -= 2) {
12725 o = cache->get(i);
12726 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012727 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012728 return cache->get(i + 1);
12729 }
12730 }
12731
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012732 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012733 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012734
12735 Handle<JSFunctionResultCache> cache_handle(cache);
12736 Handle<Object> key_handle(key);
12737 Handle<Object> value;
12738 {
12739 Handle<JSFunction> factory(JSFunction::cast(
12740 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
12741 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012742 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012743 // This handle is nor shared, nor used later, so it's safe.
12744 Object** argv[] = { key_handle.location() };
12745 bool pending_exception = false;
12746 value = Execution::Call(factory,
12747 receiver,
12748 1,
12749 argv,
12750 &pending_exception);
12751 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012752 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000012753
12754#ifdef DEBUG
12755 cache_handle->JSFunctionResultCacheVerify();
12756#endif
12757
12758 // Function invocation may have cleared the cache. Reread all the data.
12759 finger_index = cache_handle->finger_index();
12760 size = cache_handle->size();
12761
12762 // If we have spare room, put new data into it, otherwise evict post finger
12763 // entry which is likely to be the least recently used.
12764 int index = -1;
12765 if (size < cache_handle->length()) {
12766 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
12767 index = size;
12768 } else {
12769 index = finger_index + JSFunctionResultCache::kEntrySize;
12770 if (index == cache_handle->length()) {
12771 index = JSFunctionResultCache::kEntriesIndex;
12772 }
12773 }
12774
12775 ASSERT(index % 2 == 0);
12776 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
12777 ASSERT(index < cache_handle->length());
12778
12779 cache_handle->set(index, *key_handle);
12780 cache_handle->set(index + 1, *value);
12781 cache_handle->set_finger_index(index);
12782
12783#ifdef DEBUG
12784 cache_handle->JSFunctionResultCacheVerify();
12785#endif
12786
12787 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012788}
12789
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012790
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012791RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012792 HandleScope scope(isolate);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012793 CONVERT_ARG_CHECKED(String, type, 0);
12794 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012795 return *isolate->factory()->NewJSMessageObject(
12796 type,
12797 arguments,
12798 0,
12799 0,
12800 isolate->factory()->undefined_value(),
12801 isolate->factory()->undefined_value(),
12802 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012803}
12804
12805
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012806RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012807 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12808 return message->type();
12809}
12810
12811
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012812RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012813 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12814 return message->arguments();
12815}
12816
12817
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012818RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012819 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12820 return Smi::FromInt(message->start_position());
12821}
12822
12823
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012824RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000012825 CONVERT_CHECKED(JSMessageObject, message, args[0]);
12826 return message->script();
12827}
12828
12829
kasper.lund44510672008-07-25 07:37:58 +000012830#ifdef DEBUG
12831// ListNatives is ONLY used by the fuzz-natives.js in debug mode
12832// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012833RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000012834 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012835 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012836#define COUNT_ENTRY(Name, argc, ressize) + 1
12837 int entry_count = 0
12838 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
12839 INLINE_FUNCTION_LIST(COUNT_ENTRY)
12840 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
12841#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012842 Factory* factory = isolate->factory();
12843 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012844 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012845 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000012846#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012847 { \
12848 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012849 Handle<String> name; \
12850 /* Inline runtime functions have an underscore in front of the name. */ \
12851 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012852 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012853 Vector<const char>("_" #Name, StrLength("_" #Name))); \
12854 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012855 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012856 Vector<const char>(#Name, StrLength(#Name))); \
12857 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012858 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012859 pair_elements->set(0, *name); \
12860 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012861 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012862 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012863 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012864 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012865 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012866 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012867 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000012868 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012869#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000012870 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012871 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012872 return *result;
12873}
kasper.lund44510672008-07-25 07:37:58 +000012874#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012875
12876
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012877RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012878 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000012879 CONVERT_CHECKED(String, format, args[0]);
12880 CONVERT_CHECKED(JSArray, elms, args[1]);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000012881 String::FlatContent format_content = format->GetFlatContent();
12882 RUNTIME_ASSERT(format_content.IsAscii());
12883 Vector<const char> chars = format_content.ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012884 LOGGER->LogRuntime(chars, elms);
12885 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000012886}
12887
12888
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012889RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012890 UNREACHABLE(); // implemented as macro in the parser
12891 return NULL;
12892}
12893
12894
ricow@chromium.org4f693d62011-07-04 14:01:31 +000012895#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
12896 RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \
12897 CONVERT_CHECKED(JSObject, obj, args[0]); \
12898 return isolate->heap()->ToBoolean(obj->Has##Name()); \
12899 }
12900
12901ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements)
12902ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
12903ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
12904ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements)
12905ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
12906ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements)
12907ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements)
12908ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements)
12909ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements)
12910ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements)
12911ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements)
12912ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements)
12913ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements)
12914
12915#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
12916
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012917// ----------------------------------------------------------------------------
12918// Implementation of Runtime
12919
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012920#define F(name, number_of_args, result_size) \
12921 { Runtime::k##name, Runtime::RUNTIME, #name, \
12922 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012923
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012924
12925#define I(name, number_of_args, result_size) \
12926 { Runtime::kInline##name, Runtime::INLINE, \
12927 "_" #name, NULL, number_of_args, result_size },
12928
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012929static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012930 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012931 INLINE_FUNCTION_LIST(I)
12932 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012933};
12934
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012935
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012936MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
12937 Object* dictionary) {
12938 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012939 ASSERT(dictionary != NULL);
12940 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
12941 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000012942 Object* name_symbol;
12943 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012944 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012945 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
12946 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012947 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012948 { MaybeObject* maybe_dictionary = string_dictionary->Add(
12949 String::cast(name_symbol),
12950 Smi::FromInt(i),
12951 PropertyDetails(NONE, NORMAL));
12952 if (!maybe_dictionary->ToObject(&dictionary)) {
12953 // Non-recoverable failure. Calling code must restart heap
12954 // initialization.
12955 return maybe_dictionary;
12956 }
12957 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012958 }
12959 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012960}
12961
12962
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012963const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
12964 Heap* heap = name->GetHeap();
12965 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012966 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012967 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012968 int function_index = Smi::cast(smi_index)->value();
12969 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012970 }
12971 return NULL;
12972}
12973
12974
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012975const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000012976 return &(kIntrinsicFunctions[static_cast<int>(id)]);
12977}
12978
12979
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012980void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012981 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012982 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012983 if (failure->IsRetryAfterGC()) {
12984 // Try to do a garbage collection; ignore it if it fails. The C
12985 // entry stub will throw an out-of-memory exception in that case.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012986 isolate->heap()->CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012987 } else {
12988 // Handle last resort GC and make sure to allow future allocations
12989 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000012990 isolate->counters()->gc_last_resort_from_js()->Increment();
12991 isolate->heap()->CollectAllGarbage(false);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000012992 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012993}
12994
12995
12996} } // namespace v8::internal